jsonizer_test.cxx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. //
  2. // jsonizer_test.cxx
  3. // serializer-test
  4. //
  5. // Created by Sam Jaffe on 3/16/23.
  6. //
  7. #include "xcode_gtest_helper.h"
  8. #include <map>
  9. #include <set>
  10. #include <vector>
  11. #include <serializer/jsonizer.tpp>
  12. #define CONCAT2(A, B) A##B
  13. #define CONCAT(A, B) CONCAT2(A, B)
  14. #define EXPECT_ROUNDTRIP(izer, value, as_json) \
  15. Json::Value CONCAT(json_, __LINE__) = izer.to_json(value); \
  16. EXPECT_THAT(CONCAT(json_, __LINE__), as_json); \
  17. EXPECT_THAT(izer.from_json<decltype(value)>(CONCAT(json_, __LINE__)), value)
  18. using std::operator""s;
  19. using std::operator""sv;
  20. using namespace magic_enum::bitwise_operators;
  21. using testing::Field;
  22. using testing::IsNull;
  23. using testing::NotNull;
  24. using testing::Pointee;
  25. enum class Color { RED, BLUE, GREEN };
  26. enum class Mask { LEFT = 1, RIGHT = 2 };
  27. Json::Value operator""_json(char const * str, size_t len) {
  28. Json::Value rval;
  29. Json::Reader reader;
  30. if (!reader.parse(str, str + len, rval)) {
  31. throw std::invalid_argument(reader.getFormattedErrorMessages());
  32. }
  33. return rval;
  34. }
  35. TEST(JsonizerTest, ParsesNumbers) {
  36. serializer::Jsonizer izer;
  37. EXPECT_ROUNDTRIP(izer, 1.5f, "1.5"_json);
  38. EXPECT_ROUNDTRIP(izer, 1.5, "1.5"_json);
  39. EXPECT_ROUNDTRIP(izer, 3, "3"_json);
  40. EXPECT_ROUNDTRIP(izer, true, "true"_json);
  41. }
  42. TEST(JsonizerTest, ParsesStrings) {
  43. serializer::Jsonizer izer;
  44. EXPECT_ROUNDTRIP(izer, "hello"s, "\"hello\""_json);
  45. EXPECT_THAT(izer.to_json("hello"), "\"hello\""_json);
  46. EXPECT_THAT(izer.to_json("hello"sv), "\"hello\""_json);
  47. }
  48. TEST(JsonizerTest, ParsesEnums) {
  49. serializer::Jsonizer izer;
  50. EXPECT_ROUNDTRIP(izer, Color::RED, "\"RED\""_json);
  51. EXPECT_TRUE(magic_enum::detail::is_flags_v<Mask>);
  52. EXPECT_ROUNDTRIP(izer, Mask::LEFT | Mask::RIGHT, "\"LEFT|RIGHT\""_json);
  53. }
  54. TEST(JsonizerTest, ParsesTuples) {
  55. serializer::Jsonizer izer;
  56. EXPECT_ROUNDTRIP(izer, std::make_pair(1, true), "[1, true]"_json);
  57. EXPECT_ROUNDTRIP(izer, std::make_tuple(1, true, 1.5, "hi"s),
  58. "[1, true, 1.5, \"hi\"]"_json);
  59. }
  60. TEST(JsonizerTest, ParsesCollection) {
  61. serializer::Jsonizer izer;
  62. EXPECT_ROUNDTRIP(izer, std::vector({1, 2, 3, 1}), "[1, 2, 3, 1]"_json);
  63. EXPECT_ROUNDTRIP(izer, std::set({1, 2, 3, 1}), "[1, 2, 3]"_json);
  64. }
  65. TEST(JsonizerTest, ThrowsOnParsingCollectionFromNonArray) {
  66. serializer::Jsonizer izer;
  67. std::vector<int> out;
  68. EXPECT_THROW(izer.from_json(out, "1"_json), std::invalid_argument);
  69. }
  70. TEST(JsonizerTest, ParsesAssociative) {
  71. serializer::Jsonizer izer;
  72. EXPECT_ROUNDTRIP(izer, (std::map<int, int>{{1, 2}, {3, 1}}),
  73. "{\"1\":2, \"3\":1}"_json);
  74. }
  75. TEST(JsonizerTest, AssociativeCanParseFromPairListOrObject) {
  76. using Type = std::map<std::string, int>;
  77. serializer::Jsonizer izer;
  78. EXPECT_THAT(izer.from_json<Type>("[[\"A\", 2], [\"B\", 1]]"_json),
  79. (Type{{"A", 2}, {"B", 1}}));
  80. EXPECT_THAT(izer.from_json<Type>("{ \"A\": 2, \"B\": 1 }"_json),
  81. (Type{{"A", 2}, {"B", 1}}));
  82. }
  83. TEST(JsonizerTest, AssociativeWithNonTrivialKeyIsPairList) {
  84. using Type = std::map<std::pair<int, int>, int>;
  85. serializer::Jsonizer izer;
  86. EXPECT_ROUNDTRIP(izer, (Type{{{1, 2}, 1}, {{2, 1}, 2}}),
  87. "[[[1, 2], 1], [[2, 1], 2]]"_json);
  88. }
  89. TEST(JsonizerTest, ThrowsOnParsingAssociativeFromNonCollection) {
  90. serializer::Jsonizer izer;
  91. std::map<int, int> out;
  92. EXPECT_THROW(izer.from_json(out, "1"_json), std::invalid_argument);
  93. }
  94. struct Cacheable {
  95. std::string name;
  96. };
  97. template <>
  98. void serializer::Jsonizer::from_json(Cacheable & value,
  99. Json::Value const & json) const {
  100. from_json(value.name, json["name"]);
  101. }
  102. TEST(JsonizerTest, CanAttemptToLoadFromCache) {
  103. serializer::Jsonizer izer;
  104. std::shared_ptr<Cacheable const> ptr;
  105. EXPECT_THROW(izer.from_json(ptr, "\"ONE\""_json), std::domain_error);
  106. EXPECT_THAT(ptr, IsNull());
  107. EXPECT_NO_THROW(izer.from_json(ptr, "{\"name\":\"ONE\"}"_json));
  108. EXPECT_THAT(ptr, NotNull());
  109. EXPECT_THAT(ptr, Pointee(Field(&Cacheable::name, "ONE")));
  110. }
  111. struct Serializable {
  112. using serial_type = std::map<int, int>;
  113. Serializable(std::vector<int> value = {}) : value(value) {}
  114. Serializable(serial_type vals) {
  115. for (auto [k, v] : vals) {
  116. while (v--) {
  117. value.push_back(k);
  118. }
  119. }
  120. }
  121. operator serial_type() const {
  122. serial_type rval;
  123. for (auto v : value) {
  124. ++rval[v];
  125. }
  126. return rval;
  127. }
  128. std::vector<int> value;
  129. };
  130. bool operator==(Serializable const & lhs, Serializable const & rhs) {
  131. return lhs.value == rhs.value;
  132. }
  133. TEST(JsonizerTest, CanConstructFromAltType) {
  134. serializer::Jsonizer izer;
  135. EXPECT_ROUNDTRIP(izer, Serializable({1, 1, 1, 1, 2, 2, 2, 3, 3, 4}),
  136. "{\"1\":4, \"2\":3, \"3\":2, \"4\":1}"_json);
  137. }