validation_visitor_test.cxx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #include <jvalidate/validation_visitor.h>
  2. #include <utility>
  3. #include <gmock/gmock.h>
  4. #include <gtest/gtest.h>
  5. #include <json/value.h>
  6. #include <jvalidate/adapters/jsoncpp.h>
  7. #include <jvalidate/constraint/extension_constraint.h>
  8. #include <jvalidate/constraint/general_constraint.h>
  9. #include <jvalidate/constraint/string_constraint.h>
  10. #include <jvalidate/detail/pointer.h>
  11. #include <jvalidate/enum.h>
  12. #include <jvalidate/forward.h>
  13. #include <jvalidate/regex.h>
  14. #include <jvalidate/schema.h>
  15. #include <jvalidate/status.h>
  16. #include <jvalidate/validation_config.h>
  17. #include <jvalidate/validation_result.h>
  18. #include <jvalidate/validator.h>
  19. #include "./matchers.h"
  20. using enum jvalidate::schema::Version;
  21. using jvalidate::Status;
  22. using enum jvalidate::adapter::Type;
  23. using jvalidate::adapter::JsonCppAdapter;
  24. using testing::Eq;
  25. namespace jvalidate {
  26. class ValidationVisitorTest : public testing::Test {
  27. protected:
  28. auto visit(jvalidate::detail::Pointer ptr, auto const & cons, Json::Value const & json,
  29. jvalidate::ValidationResult * result = nullptr, bool annotate_everything = false) {
  30. JsonCppAdapter const adapter(json);
  31. ValidationVisitor visitor(node_, adapter, cfg_, regex_, format_, extension_, result);
  32. if (annotate_everything) {
  33. visitor.tracking_ = StoreResults::ForAnything;
  34. }
  35. visitor.schema_path_ = std::move(ptr);
  36. return visitor.visit(cons, adapter);
  37. }
  38. auto visit(jvalidate::Not<jvalidate::detail::Pointer> auto const & cons, Json::Value const & json,
  39. jvalidate::ValidationResult * result = nullptr, bool annotate_everything = false) {
  40. return visit({}, cons, json, result, annotate_everything);
  41. }
  42. void config(jvalidate::ValidationConfig cfg) { cfg_ = cfg; }
  43. void format(FormatValidator::UserDefinedFormats && fmts) {
  44. format_ = {std::move(fmts), jvalidate::StdRegexEngine::is_regex};
  45. }
  46. private:
  47. jvalidate::schema::Node node_;
  48. jvalidate::StdRegexEngine regex_;
  49. jvalidate::FormatValidator format_{jvalidate::StdRegexEngine::is_regex};
  50. jvalidate::ValidationConfig cfg_;
  51. jvalidate::detail::StubExtensionVisitor extension_;
  52. };
  53. TEST_F(ValidationVisitorTest, StubExtensionIsNoop) {
  54. constraint::ExtensionConstraint cons;
  55. EXPECT_THAT(visit(cons, {}), Eq(Status::Noop));
  56. }
  57. TEST_F(ValidationVisitorTest, StubExtensionAnnotates) {
  58. constraint::ExtensionConstraint cons;
  59. ValidationResult result;
  60. visit("/extension"_jptr, cons, {}, &result);
  61. EXPECT_THAT(result, AnnotationAt("extension", "unsupported extension"));
  62. }
  63. TEST_F(ValidationVisitorTest, TypeMatchesType) {
  64. constraint::TypeConstraint cons{{Integer}};
  65. EXPECT_THAT(visit(cons, "5"_json), Eq(Status::Accept));
  66. }
  67. TEST_F(ValidationVisitorTest, TypeNumberMatchesInteger) {
  68. constraint::TypeConstraint cons{{Number}};
  69. EXPECT_THAT(visit(cons, "5"_json), Eq(Status::Accept));
  70. }
  71. TEST_F(ValidationVisitorTest, TypeIntegerMatchesWholeDecimal) {
  72. constraint::TypeConstraint cons{{Integer}};
  73. // JsonCppAdapter follows the convention of implicitly treating whole doubles
  74. // that fit in int64s as integer type, but the specification allows for much
  75. // wider integers than that as far as TypeConstraint is concerned.
  76. EXPECT_THAT(visit(cons, "10000000000000000000.0"_json), Eq(Status::Accept));
  77. }
  78. TEST_F(ValidationVisitorTest, TypeIntegerDoesNotMatchFractional) {
  79. constraint::TypeConstraint cons{{Integer}};
  80. EXPECT_THAT(visit(cons, "5.2"_json), Eq(Status::Reject));
  81. }
  82. TEST_F(ValidationVisitorTest, ConstConstraintCanPerformStrictOrLooseEquality) {
  83. constraint::ConstConstraint cons{JsonCppAdapter("\"true\""_json).freeze()};
  84. config({.strict_equality = false});
  85. EXPECT_THAT(visit(cons, "true"_json), Eq(Status::Accept));
  86. config({.strict_equality = true});
  87. EXPECT_THAT(visit(cons, "true"_json), Eq(Status::Reject));
  88. }
  89. TEST_F(ValidationVisitorTest, EnumConstraintCanPerformStrictOrLooseEquality) {
  90. constraint::EnumConstraint cons;
  91. cons.enumeration.push_back(JsonCppAdapter("\"true\""_json).freeze());
  92. config({.strict_equality = false});
  93. EXPECT_THAT(visit(cons, "true"_json), Eq(Status::Accept));
  94. config({.strict_equality = true});
  95. EXPECT_THAT(visit(cons, "true"_json), Eq(Status::Reject));
  96. }
  97. TEST_F(ValidationVisitorTest, EnumConstraintAnnotatesMatchingIndex) {
  98. constraint::EnumConstraint cons;
  99. cons.enumeration.push_back(JsonCppAdapter("\"true\""_json).freeze());
  100. cons.enumeration.push_back(JsonCppAdapter("true"_json).freeze());
  101. ValidationResult result;
  102. visit("/enum"_jptr, cons, "true"_json, &result, true);
  103. EXPECT_THAT(result, ErrorAt("enum", "1"));
  104. }
  105. TEST_F(ValidationVisitorTest, UnknownFormatIsAccept) {
  106. constraint::FormatConstraint cons{
  107. .format = "bogus", .for_version = Draft2020_12, .is_assertion = true};
  108. config({.validate_format = true});
  109. ValidationResult result;
  110. EXPECT_THAT(visit("/format"_jptr, cons, "\"Hello\""_json, &result), Eq(Status::Accept));
  111. }
  112. TEST_F(ValidationVisitorTest, UnimplementedFormatIsError) {
  113. constraint::FormatConstraint cons{
  114. .format = "bogus", .for_version = Draft2020_12, .is_assertion = true};
  115. config({.validate_format = true});
  116. format({{"bogus", nullptr}});
  117. ValidationResult result;
  118. EXPECT_THAT(visit("/format"_jptr, cons, "\"Hello\""_json, &result), Eq(Status::Reject));
  119. EXPECT_THAT(result, ErrorAt("format", "unimplemented format 'bogus'"));
  120. }
  121. }
  122. #if !defined(JVALIDATE_MONOTEST)
  123. int main(int argc, char ** argv) {
  124. testing::InitGoogleMock(&argc, argv);
  125. return RUN_ALL_TESTS();
  126. }
  127. #endif