extension_test.cxx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #include <jvalidate/extension.h>
  2. #include <gmock/gmock.h>
  3. #include <gtest/gtest.h>
  4. #include <json/value.h>
  5. #include <jvalidate/adapters/jsoncpp.h>
  6. #include <jvalidate/constraint/extension_constraint.h>
  7. #include <jvalidate/detail/expect.h>
  8. #include <jvalidate/detail/relative_pointer.h>
  9. #include <jvalidate/forward.h>
  10. #include <jvalidate/status.h>
  11. #include <jvalidate/validator.h>
  12. #include "matchers.h"
  13. using enum jvalidate::schema::Version;
  14. using jvalidate::Status;
  15. using jvalidate::constraint::ExtensionConstraint;
  16. struct IsKeyOfConstraint : jvalidate::extension::ConstraintBase<IsKeyOfConstraint> {
  17. IsKeyOfConstraint(std::string_view ptr) : ptr(ptr) {
  18. EXPECT_M(ptr.find('/') != std::string_view::npos,
  19. "IsKeyOfConstraint requires a value-relative-pointer, not a key-relative-pointer");
  20. }
  21. jvalidate::detail::RelativePointer ptr;
  22. };
  23. template <jvalidate::Adapter A>
  24. class Visitor : public jvalidate::extension::Visitor<Visitor<A>, IsKeyOfConstraint> {
  25. public:
  26. Visitor(A const & root_document) : root_document_(root_document) {}
  27. template <jvalidate::Adapter A2>
  28. Status visit(IsKeyOfConstraint const & cons, A2 const & document, auto const & validator) const {
  29. auto const & object =
  30. std::get<1>(cons.ptr.inspect(validator.where_, root_document_)).as_object();
  31. if (object.find(document.as_string()) != object.end()) {
  32. return Status::Accept;
  33. }
  34. return Status::Reject;
  35. }
  36. private:
  37. A const & root_document_;
  38. };
  39. auto validate(Json::Value const & schema_doc, Json::Value const & instance_doc,
  40. jvalidate::schema::Version version = Draft2020_12) {
  41. jvalidate::ConstraintFactory<jvalidate::adapter::AdapterFor<Json::Value>> factory{
  42. {"is_key_of", [](auto const & context) {
  43. return ExtensionConstraint::make<IsKeyOfConstraint>(context.schema.as_string());
  44. }}};
  45. jvalidate::Schema const schema(schema_doc, version);
  46. jvalidate::ValidationResult result;
  47. (void)jvalidate::Validator(schema).validate(instance_doc, &result);
  48. return result;
  49. }
  50. TEST(ExtensionConstraint, CanExtend) {
  51. auto schema = R"({
  52. "properties": {
  53. "nodes": {
  54. "type": "object"
  55. },
  56. "edges": {
  57. "items": {
  58. "properties": {
  59. "destination": {
  60. "is_key_of": "3/nodes",
  61. "type": "string"
  62. },
  63. "source": {
  64. "is_key_of": "3/nodes",
  65. "type": "string"
  66. }
  67. },
  68. "type": "object"
  69. },
  70. "type": "array"
  71. }
  72. },
  73. "type": "object"
  74. })"_json;
  75. auto instance = R"({
  76. "nodes": {
  77. "A": {},
  78. "B": {}
  79. },
  80. "edges": [
  81. { "source": "A", "destination": "B" }
  82. ]
  83. })"_json;
  84. jvalidate::ValidationResult result = validate(schema, instance);
  85. EXPECT_THAT(result, Valid()) << result;
  86. }
  87. int main(int argc, char ** argv) {
  88. testing::InitGoogleMock(&argc, argv);
  89. return RUN_ALL_TESTS();
  90. }