#include #include #include #include #include #include // IWYU pragma: keep #include #include #include #include #include #include #include "matchers.h" using enum jvalidate::schema::Version; using jvalidate::Status; using jvalidate::constraint::ExtensionConstraint; using testing::Not; struct IsKeyOfConstraint : jvalidate::extension::ConstraintBase { explicit IsKeyOfConstraint(std::string_view ptr) : ptr(jvalidate::detail::RelativePointer::parse(ptr).value()) { EXPECT_M(ptr.find('/') != std::string_view::npos, "IsKeyOfConstraint requires a value-relative-pointer, not a key-relative-pointer"); } jvalidate::detail::RelativePointer ptr; }; class Visitor : public jvalidate::extension::Visitor { public: template Status visit(IsKeyOfConstraint const & cons, A2 const & document, auto const & validator) const { validator.annotate(cons.ptr); auto const & object = std::get<1>(cons.ptr.inspect(validator.where(), validator.root())).as_object(); if (object.find(document.as_string()) != object.end()) { return Status::Accept; } return Status::Reject; } }; namespace { auto validate(Json::Value const & schema_doc, Json::Value const & instance_doc, jvalidate::schema::Version version = Draft2020_12) { using A = jvalidate::adapter::AdapterFor; jvalidate::ConstraintFactory factory{{"is_key_of", [](auto const & context) { return ExtensionConstraint::make( context.schema.as_string()); }}}; jvalidate::Schema const schema(schema_doc, version, factory); jvalidate::ValidationResult result; (void)jvalidate::Validator(schema, Visitor()).validate(instance_doc, &result); return result; } } TEST(ExtensionConstraintTest, CanReportSuccess) { auto schema = R"({ "properties": { "nodes": { "type": "object" }, "edges": { "items": { "properties": { "destination": { "is_key_of": "3/nodes", "type": "string" }, "source": { "is_key_of": "3/nodes", "type": "string" } }, "type": "object" }, "type": "array" } }, "type": "object" })"_json; auto instance = R"({ "nodes": { "A": {}, "B": {} }, "edges": [ { "source": "A", "destination": "B" } ] })"_json; jvalidate::ValidationResult result = validate(schema, instance); EXPECT_THAT(result, Valid()); } TEST(ExtensionConstraintTest, CanReportFailure) { auto schema = R"({ "properties": { "nodes": { "type": "object" }, "edges": { "items": { "properties": { "destination": { "is_key_of": "3/nodes", "type": "string" }, "source": { "is_key_of": "3/nodes", "type": "string" } }, "type": "object" }, "type": "array" } }, "type": "object" })"_json; auto instance = R"({ "nodes": { "A": {}, "B": {} }, "edges": [ { "source": "A", "destination": "C" } ] })"_json; jvalidate::ValidationResult result = validate(schema, instance); EXPECT_THAT(result, Not(Valid())); } #if !defined(JVALIDATE_MONOTEST) int main(int argc, char ** argv) { testing::InitGoogleMock(&argc, argv); return RUN_ALL_TESTS(); } #endif