detail_test.cxx 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. #include <stdexcept>
  2. #include <type_traits>
  3. #include <gmock/gmock.h>
  4. #include <gtest/gtest.h>
  5. #include <jvalidate/adapters/jsoncpp.h>
  6. #include <jvalidate/detail/anchor.h>
  7. #include <jvalidate/detail/number.h>
  8. #include <jvalidate/detail/pointer.h>
  9. #include <jvalidate/detail/reference.h>
  10. #include <jvalidate/detail/relative_pointer.h>
  11. #include <jvalidate/detail/string.h>
  12. #include <jvalidate/detail/string_adapter.h>
  13. #include <jvalidate/enum.h>
  14. #include "matchers.h"
  15. using namespace jvalidate::detail;
  16. using JsonCppAdapter = jvalidate::adapter::JsonCppAdapter<Json::Value const>;
  17. using jvalidate::adapter::Type;
  18. using testing::Eq;
  19. using testing::Test;
  20. using testing::ThrowsMessage;
  21. using testing::Types;
  22. using testing::VariantWith;
  23. TEST(AnchorTest, PermitsEmpty) { EXPECT_NO_THROW(Anchor("")); }
  24. TEST(AnchorTest, PermitsFirstCharWord) { EXPECT_NO_THROW(Anchor("here")); }
  25. TEST(AnchorTest, PermitsFirstCharUnderscore) { EXPECT_NO_THROW(Anchor("_here")); }
  26. TEST(AnchorTest, ForbidsFirstCharNumber) { EXPECT_THROW(Anchor("0here"), std::runtime_error); }
  27. TEST(AnchorTest, AllowsDotDashAlnum) { EXPECT_NO_THROW(Anchor("here.0-_")); }
  28. TEST(AnchorTest, ForbidsSpecial) { EXPECT_THROW(Anchor("h$"), std::runtime_error); }
  29. TEST(AnchorTest, CanViewString) { EXPECT_THAT(static_cast<std::string>(Anchor("here")), "here"); }
  30. TEST(AnchorTest, Print) { EXPECT_THAT(testing::PrintToString(Anchor("here")), "here"); }
  31. TEST(PointerTest, BackCoercesIntToString) {
  32. EXPECT_THAT("/0"_jptr.back(), "0");
  33. EXPECT_THAT("/A"_jptr.back(), "A");
  34. }
  35. TEST(PointerTest, BackIsEmptySafe) { EXPECT_THAT(""_jptr.back(), ""); }
  36. TEST(PointerTest, ForbidsBadTilde) {
  37. EXPECT_NO_THROW("/~1"_jptr);
  38. EXPECT_THROW("/~2"_jptr, std::runtime_error);
  39. }
  40. TEST(PointerTest, CanConcatenate) { EXPECT_THAT("/A"_jptr / "/B"_jptr, "/A/B"_jptr); }
  41. TEST(PointerTest, CanGoToParent) { EXPECT_THAT("/A/B"_jptr / parent, "/A"_jptr); }
  42. TEST(PointerTest, Print) { EXPECT_THAT(testing::PrintToString(Pointer("/B/0/A")), "/B/0/A"); }
  43. TEST(RelatvivePointerTest, CannotPrefixWithZero) {
  44. EXPECT_THROW(RelativePointer("01"), std::runtime_error);
  45. }
  46. TEST(RelatvivePointerTest, Print) {
  47. EXPECT_THAT(testing::PrintToString(RelativePointer("0")), "0");
  48. EXPECT_THAT(testing::PrintToString(RelativePointer("1#")), "1#");
  49. EXPECT_THAT(testing::PrintToString(RelativePointer("1/B/0/A")), "1/B/0/A");
  50. }
  51. TEST(RelatvivePointerTest, ZeroIsHere) {
  52. Json::Value json;
  53. json["A"] = 1;
  54. RelativePointer const rel("0");
  55. EXPECT_THAT(rel.inspect("/A"_jptr, JsonCppAdapter(json)),
  56. VariantWith<JsonCppAdapter>(JsonCppAdapter(json["A"])))
  57. << rel;
  58. }
  59. TEST(RelatvivePointerTest, CanWalkBackwards) {
  60. Json::Value json;
  61. json["A"] = 1;
  62. RelativePointer const rel("1");
  63. EXPECT_THAT(rel.inspect("/A"_jptr, JsonCppAdapter(json)),
  64. VariantWith<JsonCppAdapter>(JsonCppAdapter(json)))
  65. << rel;
  66. }
  67. TEST(RelatvivePointerTest, CanFetchKey) {
  68. Json::Value json;
  69. json["A"] = 1;
  70. RelativePointer const rel("0#");
  71. EXPECT_THAT(rel.inspect("/A"_jptr, JsonCppAdapter(json)), VariantWith<std::string>(Eq("A")))
  72. << rel;
  73. }
  74. TEST(RelatvivePointerTest, CanGoUpAndDown) {
  75. Json::Value json;
  76. json["A"] = 1;
  77. json["B"] = 2;
  78. RelativePointer const rel("1/B");
  79. EXPECT_THAT(rel.inspect("/A"_jptr, JsonCppAdapter(json)),
  80. VariantWith<JsonCppAdapter>(JsonCppAdapter(json["B"])))
  81. << rel;
  82. }
  83. TEST(ReferenceTest, Print) {
  84. EXPECT_THAT(testing::PrintToString(Reference(jvalidate::URI("file://path/to/document.json"),
  85. Anchor("Anchor"), Pointer("/key/1/id"))),
  86. "file://path/to/document.json#Anchor/key/1/id");
  87. }
  88. TEST(ReferenceTest, RelativeBasedOnURIRelative) {
  89. {
  90. jvalidate::URI uri("file://path/to/document.json");
  91. EXPECT_FALSE(uri.is_relative());
  92. EXPECT_THAT(RootReference(uri).is_relative(), uri.is_relative());
  93. }
  94. {
  95. jvalidate::URI uri("/path/to/document.json");
  96. EXPECT_FALSE(uri.is_relative());
  97. EXPECT_THAT(RootReference(uri).is_relative(), uri.is_relative());
  98. }
  99. {
  100. jvalidate::URI uri("path/to/document.json");
  101. EXPECT_TRUE(uri.is_relative());
  102. EXPECT_THAT(RootReference(uri).is_relative(), uri.is_relative());
  103. }
  104. }
  105. template <typename T> class NumberFromStrTest : public Test {};
  106. using Integers = Types<char, size_t, int>;
  107. TYPED_TEST_SUITE(NumberFromStrTest, Integers);
  108. TEST(NumberTest, ULLFitsInInteger) {
  109. EXPECT_TRUE(fits_in_integer(9223372036854775807ULL));
  110. EXPECT_FALSE(fits_in_integer(9223372036854775808ULL));
  111. }
  112. TEST(NumberTest, DoubleDoesNotFitInIntegerWhenFractional) { EXPECT_FALSE(fits_in_integer(10.5)); }
  113. TEST(NumberTest, DoubleFitsInIntegerWhenWhole) { EXPECT_TRUE(fits_in_integer(10.0)); }
  114. TEST(NumberTest, DoubleOutOfIntegerRange) {
  115. EXPECT_FALSE(fits_in_integer(10000000000000000000.0));
  116. EXPECT_FALSE(fits_in_integer(-10000000000000000000.0));
  117. }
  118. TYPED_TEST(NumberFromStrTest, NumberParsesIntegers) { EXPECT_THAT(from_str<TypeParam>("10"), 10); }
  119. TYPED_TEST(NumberFromStrTest, NumberParsesNegativeIntegers) {
  120. if constexpr (std::is_signed_v<TypeParam>) {
  121. EXPECT_THAT(from_str<TypeParam>("-10"), -10);
  122. } else {
  123. EXPECT_THAT([] { from_str<TypeParam>("-10"); },
  124. ThrowsMessage<std::runtime_error>("Invalid argument"));
  125. }
  126. }
  127. TYPED_TEST(NumberFromStrTest, ThrowsOnPlusSign) {
  128. EXPECT_THAT([] { from_str<TypeParam>("+10"); },
  129. ThrowsMessage<std::runtime_error>("Invalid argument"));
  130. }
  131. TYPED_TEST(NumberFromStrTest, ThrowsOnTooManyChars) {
  132. EXPECT_THAT([] { from_str<TypeParam>("10 coconuts"); },
  133. ThrowsMessage<std::runtime_error>("NaN: 10 coconuts"));
  134. }
  135. TYPED_TEST(NumberFromStrTest, ThrowsOnOutOfRange) {
  136. EXPECT_THAT([] { from_str<TypeParam>("99999999999999999999999999999"); },
  137. ThrowsMessage<std::runtime_error>("Result too large"));
  138. }
  139. TEST(StringAdapterTest, IsStringy) {
  140. EXPECT_THAT(StringAdapter("").type(), Type::String);
  141. EXPECT_THAT(StringAdapter("lorem ipsum").as_string(), "lorem ipsum");
  142. }
  143. TEST(StringAdapterTest, DiesOnAccess) {
  144. EXPECT_THROW(StringAdapter("").as_boolean(), std::runtime_error);
  145. EXPECT_THROW(StringAdapter("").as_integer(), std::runtime_error);
  146. EXPECT_THROW(StringAdapter("").as_number(), std::runtime_error);
  147. EXPECT_THROW(StringAdapter("").as_array(), std::runtime_error);
  148. EXPECT_THROW(StringAdapter("").array_size(), std::runtime_error);
  149. EXPECT_THROW(StringAdapter("").as_object(), std::runtime_error);
  150. EXPECT_THROW(StringAdapter("").object_size(), std::runtime_error);
  151. }
  152. TEST(StringAdapterTest, DoesNotRunApplyArray) {
  153. StringAdapter("").apply_array([](auto const &) {
  154. ADD_FAILURE();
  155. return jvalidate::Status::Noop;
  156. });
  157. }
  158. TEST(StringAdapterTest, DoesNotRunApplyObject) {
  159. StringAdapter("").apply_object([](auto const &, auto const &) {
  160. ADD_FAILURE();
  161. return jvalidate::Status::Noop;
  162. });
  163. }
  164. TEST(UnsupportedArrayAdapterTest, Empty) {
  165. UnsupportedArrayAdapter<StringAdapter> array;
  166. EXPECT_THAT(array.size(), 0);
  167. EXPECT_THAT(array.begin(), array.end());
  168. }
  169. TEST(UnsupportedArrayAdapterTest, DiesWhenIndexed) {
  170. UnsupportedArrayAdapter<StringAdapter> array;
  171. EXPECT_THROW(array[0], std::runtime_error);
  172. }
  173. TEST(UnsupportedObjectAdapterTest, Empty) {
  174. UnsupportedObjectAdapter<StringAdapter> object;
  175. EXPECT_THAT(object.size(), 0);
  176. EXPECT_THAT(object.begin(), object.end());
  177. }
  178. TEST(UnsupportedObjectAdapterTest, DiesWhenIndexed) {
  179. UnsupportedObjectAdapter<StringAdapter> object;
  180. EXPECT_FALSE(object.contains(""));
  181. EXPECT_THROW(object[""], std::runtime_error);
  182. }
  183. #if JVALIDATE_HAS_ICU
  184. TEST(StringLengthTest, MultiCharLength) {
  185. // Dragon Emoji from non-bmp-regex test case
  186. EXPECT_THAT(length("\xF0\x9F\x90\xB2"), 1);
  187. }
  188. #endif
  189. #if !defined(JVALIDATE_MONOTEST)
  190. int main(int argc, char ** argv) {
  191. testing::InitGoogleMock(&argc, argv);
  192. return RUN_ALL_TESTS();
  193. }
  194. #endif