validation_visitor_test.cxx 4.5 KB

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