detail_test.cxx 7.8 KB

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