diff --git a/include/valijson/constraints/concrete_constraints.hpp b/include/valijson/constraints/concrete_constraints.hpp index 693b4a9..025dabb 100644 --- a/include/valijson/constraints/concrete_constraints.hpp +++ b/include/valijson/constraints/concrete_constraints.hpp @@ -172,6 +172,34 @@ private: const Subschema *elseSubschema; }; +class ConstConstraint: public BasicConstraint +{ +public: + ConstConstraint() + : value(nullptr) { } + + ConstConstraint(CustomAlloc allocFn, CustomFree freeFn) + : BasicConstraint(allocFn, freeFn), + value(nullptr) { } + + ConstConstraint(const ConstConstraint &other) + : BasicConstraint(other), + value(other.value->clone()) { } + + adapters::FrozenValue * getValue() const + { + return value; + } + + void setValue(const adapters::Adapter &value) + { + this->value = value.freeze(); + } + +private: + adapters::FrozenValue *value; +}; + /** * @brief Represents a 'contains' constraint * diff --git a/include/valijson/constraints/constraint_visitor.hpp b/include/valijson/constraints/constraint_visitor.hpp index ebd5ffb..aa4cab9 100644 --- a/include/valijson/constraints/constraint_visitor.hpp +++ b/include/valijson/constraints/constraint_visitor.hpp @@ -6,6 +6,7 @@ namespace constraints { class AllOfConstraint; class AnyOfConstraint; class ConditionalConstraint; +class ConstConstraint; class ContainsConstraint; class DependenciesConstraint; class EnumConstraint; @@ -40,6 +41,7 @@ protected: typedef constraints::AllOfConstraint AllOfConstraint; typedef constraints::AnyOfConstraint AnyOfConstraint; typedef constraints::ConditionalConstraint ConditionalConstraint; + typedef constraints::ConstConstraint ConstConstraint; typedef constraints::ContainsConstraint ContainsConstraint; typedef constraints::DependenciesConstraint DependenciesConstraint; typedef constraints::EnumConstraint EnumConstraint; @@ -69,6 +71,7 @@ public: virtual bool visit(const AllOfConstraint &) = 0; virtual bool visit(const AnyOfConstraint &) = 0; virtual bool visit(const ConditionalConstraint &) = 0; + virtual bool visit(const ConstConstraint &) = 0; virtual bool visit(const ContainsConstraint &) = 0; virtual bool visit(const DependenciesConstraint &) = 0; virtual bool visit(const EnumConstraint &) = 0; diff --git a/include/valijson/schema_parser.hpp b/include/valijson/schema_parser.hpp index a54d856..98c34ac 100644 --- a/include/valijson/schema_parser.hpp +++ b/include/valijson/schema_parser.hpp @@ -649,6 +649,10 @@ private: &subschema); } + if ((itr = object.find("const")) != object.end()) { + rootSchema.addConstraintToSubschema(makeConstConstraint(itr->second), &subschema); + } + if ((itr = object.find("contains")) != object.end()) { rootSchema.addConstraintToSubschema( makeContainsConstraint(rootSchema, rootNode, itr->second, @@ -1250,6 +1254,21 @@ private: return constraint; } + /** + * @brief Make a new ConstConstraint object. + * + * @param node JSON node containing an arbitrary value + * + * @return pointer to a new MinimumConstraint that belongs to the caller + */ + template + constraints::ConstConstraint makeConstConstraint(const AdapterType &node) + { + constraints::ConstConstraint constraint; + constraint.setValue(node); + return constraint; + } + /** * @brief Make a new ContainsConstraint object. * diff --git a/include/valijson/validation_visitor.hpp b/include/valijson/validation_visitor.hpp index 476ef50..947d7ec 100644 --- a/include/valijson/validation_visitor.hpp +++ b/include/valijson/validation_visitor.hpp @@ -164,7 +164,7 @@ public: /** * @brief Validate current node using a set of 'if', 'then' and 'else' subschemas * - * A conditional constraint allows a document to validated against one of two additional + * A conditional constraint allows a document to be validated against one of two additional * subschemas (specified via 'then' or 'else' properties) depending on whether the document * satifies an optional subschema (specified via the 'if' property). * @@ -182,11 +182,33 @@ public: const Subschema *thenSubschema = constraint.getThenSubschema(); return thenSubschema == nullptr || thenElseValidator.validateSchema(*thenSubschema); - } else { - const Subschema *elseSubschema = constraint.getElseSubschema(); - return elseSubschema == nullptr || - thenElseValidator.validateSchema(*elseSubschema); } + + const Subschema *elseSubschema = constraint.getElseSubschema(); + return elseSubschema == nullptr || + thenElseValidator.validateSchema(*elseSubschema); + } + + /** + * @brief Validate current node using a 'const' constraint + * + * A const constraint allows a document to be validated against a specific value. + * + * @param constraint ConstConstraint that the current node must validate against + * + * @return \c true if validation passes; \f false otherwise + */ + virtual bool visit(const ConstConstraint &constraint) + { + if (!constraint.getValue()->equalTo(target, strictTypes)) { + if (results) { + results->pushError(context, + "Failed to match expected value set by 'const' constraint."); + } + return false; + } + + return true; } /** diff --git a/tests/test_validator.cpp b/tests/test_validator.cpp index 6d65345..00ca154 100644 --- a/tests/test_validator.cpp +++ b/tests/test_validator.cpp @@ -451,12 +451,13 @@ TEST_F(TestValidator, Draft7_BooleanSchema) processDraft7TestFile(TEST_SUITE_DIR "draft7/boolean_schema.json"); } -// TODO: untested const +TEST_F(TestValidator, Draft7_Const) +{ + processDraft7TestFile(TEST_SUITE_DIR "draft7/const.json"); +} TEST_F(TestValidator, Draft7_Contains) { - // TODO: currently failing due to missing support for const - processDraft7TestFile(TEST_SUITE_DIR "draft7/contains.json"); }