extension_test.cxx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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. using testing::Not;
  17. struct IsKeyOfConstraint : jvalidate::extension::ConstraintBase<IsKeyOfConstraint> {
  18. IsKeyOfConstraint(std::string_view ptr)
  19. : ptr(jvalidate::detail::RelativePointer::parse(ptr).value()) {
  20. EXPECT_M(ptr.find('/') != std::string_view::npos,
  21. "IsKeyOfConstraint requires a value-relative-pointer, not a key-relative-pointer");
  22. }
  23. jvalidate::detail::RelativePointer ptr;
  24. };
  25. template <jvalidate::Adapter A>
  26. class Visitor : public jvalidate::extension::Visitor<Visitor<A>, IsKeyOfConstraint> {
  27. public:
  28. Visitor(A const & root_document) : root_document_(root_document) {}
  29. template <jvalidate::Adapter A2>
  30. Status visit(IsKeyOfConstraint const & cons, A2 const & document, auto const & validator) const {
  31. validator.annotate(cons.ptr);
  32. auto const & object =
  33. std::get<1>(cons.ptr.inspect(validator.where_, root_document_)).as_object();
  34. if (object.find(document.as_string()) != object.end()) {
  35. return Status::Accept;
  36. }
  37. return Status::Reject;
  38. }
  39. private:
  40. A root_document_;
  41. };
  42. auto validate(Json::Value const & schema_doc, Json::Value const & instance_doc,
  43. jvalidate::schema::Version version = Draft2020_12) {
  44. using A = jvalidate::adapter::AdapterFor<Json::Value const>;
  45. jvalidate::ConstraintFactory<A> factory{{"is_key_of", [](auto const & context) {
  46. return ExtensionConstraint::make<IsKeyOfConstraint>(
  47. context.schema.as_string());
  48. }}};
  49. jvalidate::Schema const schema(schema_doc, version, factory);
  50. jvalidate::ValidationResult result;
  51. (void)jvalidate::Validator(schema, Visitor(A(instance_doc))).validate(instance_doc, &result);
  52. return result;
  53. }
  54. TEST(ExtensionConstraint, CanReportSuccess) {
  55. auto schema = R"({
  56. "properties": {
  57. "nodes": {
  58. "type": "object"
  59. },
  60. "edges": {
  61. "items": {
  62. "properties": {
  63. "destination": {
  64. "is_key_of": "3/nodes",
  65. "type": "string"
  66. },
  67. "source": {
  68. "is_key_of": "3/nodes",
  69. "type": "string"
  70. }
  71. },
  72. "type": "object"
  73. },
  74. "type": "array"
  75. }
  76. },
  77. "type": "object"
  78. })"_json;
  79. auto instance = R"({
  80. "nodes": {
  81. "A": {},
  82. "B": {}
  83. },
  84. "edges": [
  85. { "source": "A", "destination": "B" }
  86. ]
  87. })"_json;
  88. jvalidate::ValidationResult result = validate(schema, instance);
  89. EXPECT_THAT(result, Valid());
  90. }
  91. TEST(ExtensionConstraint, CanReportFailure) {
  92. auto schema = R"({
  93. "properties": {
  94. "nodes": {
  95. "type": "object"
  96. },
  97. "edges": {
  98. "items": {
  99. "properties": {
  100. "destination": {
  101. "is_key_of": "3/nodes",
  102. "type": "string"
  103. },
  104. "source": {
  105. "is_key_of": "3/nodes",
  106. "type": "string"
  107. }
  108. },
  109. "type": "object"
  110. },
  111. "type": "array"
  112. }
  113. },
  114. "type": "object"
  115. })"_json;
  116. auto instance = R"({
  117. "nodes": {
  118. "A": {},
  119. "B": {}
  120. },
  121. "edges": [
  122. { "source": "A", "destination": "C" }
  123. ]
  124. })"_json;
  125. jvalidate::ValidationResult result = validate(schema, instance);
  126. EXPECT_THAT(result, Not(Valid()));
  127. }
  128. int main(int argc, char ** argv) {
  129. testing::InitGoogleMock(&argc, argv);
  130. return RUN_ALL_TESTS();
  131. }