diff --git a/include/valijson/constraints/concrete_constraints.hpp b/include/valijson/constraints/concrete_constraints.hpp index b2bcdc3..fbbba00 100644 --- a/include/valijson/constraints/concrete_constraints.hpp +++ b/include/valijson/constraints/concrete_constraints.hpp @@ -40,11 +40,13 @@ class AllOfConstraint: public BasicConstraint { public: AllOfConstraint() - : subschemas(Allocator::rebind::other(allocator)) { } + : subschemas(Allocator::rebind::other(allocator)), + alwaysInvalid(false) { } AllOfConstraint(CustomAlloc allocFn, CustomFree freeFn) : BasicConstraint(allocFn, freeFn), - subschemas(Allocator::rebind::other(allocator)) { } + subschemas(Allocator::rebind::other(allocator)), + alwaysInvalid(false) { } void addSubschema(const Subschema *subschema) { @@ -64,12 +66,24 @@ public: } } + bool getAlwaysInvalid() const + { + return alwaysInvalid; + } + + void setAlwaysInvalid() + { + alwaysInvalid = true; + } + private: typedef std::vector > Subschemas; /// Collection of sub-schemas, all of which must be satisfied Subschemas subschemas; + + bool alwaysInvalid; }; /** @@ -83,7 +97,8 @@ class AnyOfConstraint: public BasicConstraint { public: AnyOfConstraint() - : subschemas(Allocator::rebind::other(allocator)) { } + : subschemas(Allocator::rebind::other(allocator)), + alwaysValid(false) { } AnyOfConstraint(CustomAlloc allocFn, CustomFree freeFn) : BasicConstraint(allocFn, freeFn), @@ -107,12 +122,24 @@ public: } } + bool getAlwaysValid() const + { + return alwaysValid; + } + + void setAlwaysValid() + { + alwaysValid = true; + } + private: typedef std::vector > Subschemas; + internal::CustomAllocator > Subschemas; /// Collection of sub-schemas, at least one of which must be satisfied Subschemas subschemas; + + bool alwaysValid; }; class ConditionalConstraint: public BasicConstraint diff --git a/include/valijson/schema_parser.hpp b/include/valijson/schema_parser.hpp index 077cbd8..30f3b2e 100644 --- a/include/valijson/schema_parser.hpp +++ b/include/valijson/schema_parser.hpp @@ -1096,17 +1096,25 @@ private: int index = 0; for (const AdapterType schemaNode : node.asArray()) { if (schemaNode.maybeObject()) { - const std::string childPath = nodePath + "/" + - std::to_string(index); + const std::string childPath = nodePath + "/" + std::to_string(index); const Subschema *subschema = makeOrReuseSchema( rootSchema, rootNode, schemaNode, currentScope, childPath, fetchDoc, NULL, NULL, docCache, schemaCache); constraint.addSubschema(subschema); index++; + } else if (version == kDraft7) { + if (schemaNode.maybeBool()) { + if (!schemaNode.asBool()) { + // Schema that always fails + constraint.setAlwaysInvalid(); + } + } else { + throw std::runtime_error( + "Expected element to be an object or boolean value in 'allOf' constraint"); + } } else { throw std::runtime_error( - "Expected array element to be an object value in " - "'allOf' constraint."); + "Expected element to be an object value in 'allOf' constraint."); } } @@ -1152,17 +1160,24 @@ private: int index = 0; for (const AdapterType schemaNode : node.asArray()) { if (schemaNode.maybeObject()) { - const std::string childPath = nodePath + "/" + - std::to_string(index); + const std::string childPath = nodePath + "/" + std::to_string(index); const Subschema *subschema = makeOrReuseSchema( rootSchema, rootNode, schemaNode, currentScope, childPath, fetchDoc, NULL, NULL, docCache, schemaCache); constraint.addSubschema(subschema); index++; + } else if (version == kDraft7) { + if (schemaNode.maybeBool()) { + if (schemaNode.asBool()) { + constraint.setAlwaysValid(); + } + } else { + throw std::runtime_error( + "Expected element to be an object or boolean value in 'allOf' constraint"); + } } else { throw std::runtime_error( - "Expected array element to be an object value in " - "'anyOf' constraint."); + "Expected array element to be an object value in 'anyOf' constraint."); } } diff --git a/include/valijson/validation_visitor.hpp b/include/valijson/validation_visitor.hpp index 18a3d90..78c37c7 100644 --- a/include/valijson/validation_visitor.hpp +++ b/include/valijson/validation_visitor.hpp @@ -108,8 +108,11 @@ public: */ virtual bool visit(const AllOfConstraint &constraint) { - bool validated = true; + if (constraint.getAlwaysInvalid()) { + return false; + } + bool validated = true; constraint.applyToSubschemas(ValidateSubschemas(target, context, true, false, *this, results, NULL, &validated)); @@ -135,6 +138,10 @@ public: */ virtual bool visit(const AnyOfConstraint &constraint) { + if (constraint.getAlwaysValid()) { + return true; + } + unsigned int numValidated = 0; ValidationResults newResults; diff --git a/tests/test_validator.cpp b/tests/test_validator.cpp index 2777fbd..9488d4d 100644 --- a/tests/test_validator.cpp +++ b/tests/test_validator.cpp @@ -190,6 +190,11 @@ protected: } }; +// +// draft 3 +// ------------------------------------------------------------------------------------------------ +// + TEST_F(TestValidator, Draft3_AdditionalItems) { processDraft3TestFile(TEST_SUITE_DIR "draft3/additionalItems.json"); @@ -290,6 +295,11 @@ TEST_F(TestValidator, Draft3_UniqueItems) processDraft3TestFile(TEST_SUITE_DIR "draft3/uniqueItems.json"); } +// +// draft 4 +// ------------------------------------------------------------------------------------------------ +// + TEST_F(TestValidator, Draft4_AdditionalItems) { processDraft4TestFile(TEST_SUITE_DIR "draft4/additionalItems.json");