json_binder_polymorphic_test.cxx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. //
  2. // json_binder_polymorphic.t.h
  3. // json
  4. //
  5. // Created by Sam Jaffe on 11/14/18.
  6. // Copyright © 2018 Sam Jaffe. All rights reserved.
  7. //
  8. #include "json/json_binder.hpp"
  9. #include <gmock/gmock.h>
  10. struct Base {
  11. virtual ~Base() = default;
  12. virtual void run() const = 0;
  13. };
  14. struct Left : public Base {
  15. int a;
  16. void run() const override {}
  17. };
  18. struct Right : public Base {
  19. std::string a;
  20. void run() const override {}
  21. };
  22. struct Middle : public Base {
  23. std::tuple<int, std::string> a;
  24. void run() const override {}
  25. };
  26. bool operator==(Left const & lhs, Left const & rhs) { return lhs.a == rhs.a; }
  27. bool operator==(Right const & lhs, Right const & rhs) { return lhs.a == rhs.a; }
  28. using namespace json::binder;
  29. using namespace json::parser;
  30. class JsonBinderPolymorphicTest : public ::testing::Test {
  31. protected:
  32. using pBase = std::unique_ptr<Base>;
  33. polymorphic_binder<pBase> & GetBinder() {
  34. static polymorphic_binder<pBase> val = polymorphic_binder<pBase>()(
  35. "Left", object_binder<Left>()("a", &Left::a))(
  36. "Right", object_binder<Right>()("a", &Right::a));
  37. return val;
  38. }
  39. };
  40. template <typename T> bool instanceof (Base * ptr) {
  41. return dynamic_cast<T *>(ptr) != nullptr;
  42. }
  43. using namespace ::testing;
  44. TEST_F(JsonBinderPolymorphicTest, CanHitLeftPolymorph) {
  45. char data[] = "{\"@id\":\"Left\", \"@value\":{\"a\":1}}";
  46. pBase out;
  47. Left expected;
  48. expected.a = 1;
  49. EXPECT_NO_THROW(parse(json::binder::bind(out, GetBinder()), data));
  50. EXPECT_THAT(out, Not(IsNull()));
  51. EXPECT_PRED1(instanceof <Left>, out.get());
  52. EXPECT_THAT(dynamic_cast<Left &>(*out), expected);
  53. }
  54. TEST_F(JsonBinderPolymorphicTest, CanHitRightPolymorph) {
  55. char data[] = "{\"@id\":\"Right\", \"@value\":{\"a\":\"hello\"}}";
  56. pBase out;
  57. Right expected;
  58. expected.a = "hello";
  59. EXPECT_NO_THROW(parse(json::binder::bind(out, GetBinder()), data));
  60. EXPECT_THAT(out, Not(IsNull()));
  61. EXPECT_PRED1(instanceof <Right>, out.get());
  62. EXPECT_THAT(dynamic_cast<Right &>(*out), expected);
  63. }
  64. TEST_F(JsonBinderPolymorphicTest, ThrowsOnUnknownSubclass) {
  65. char data[] = "{\"@id\":\"Middle\", \"@value\":{\"a\":[]]}}";
  66. pBase out;
  67. EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
  68. json::malformed_json_exception);
  69. EXPECT_THAT(out, IsNull());
  70. }
  71. TEST_F(JsonBinderPolymorphicTest, ThrowsOnIdNotString) {
  72. char data[] = "{\"@id\":0, \"@value\":{\"a\":[]]}}";
  73. pBase out;
  74. EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
  75. json::malformed_json_exception);
  76. EXPECT_THAT(out, IsNull());
  77. }
  78. TEST_F(JsonBinderPolymorphicTest, ThrowsOnUnexpectedKey1) {
  79. char data[] = "{\"@class\":\"Left\", \"@value\":{\"a\":[]]}}";
  80. pBase out;
  81. EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
  82. json::malformed_json_exception);
  83. EXPECT_THAT(out, IsNull());
  84. }
  85. TEST_F(JsonBinderPolymorphicTest, ThrowsOnUnexpectedKey2) {
  86. char data[] = "{\"@id\":\"Left\", \"@impl\":null, \"@value\":{\"a\":[]]}}";
  87. pBase out;
  88. EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
  89. json::malformed_json_exception);
  90. EXPECT_THAT(out, IsNull());
  91. }
  92. TEST_F(JsonBinderPolymorphicTest, ThrowsOnUnexpectedKey3) {
  93. char data[] = "{\"@id\":\"Left\", \"@impl\":{\"a\":[]]}}";
  94. pBase out;
  95. EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
  96. json::malformed_json_exception);
  97. EXPECT_THAT(out, IsNull());
  98. }
  99. TEST_F(JsonBinderPolymorphicTest, ThrowsOnUnterminatedJson) {
  100. char data[] = "{\"@id\":\"Right\", \"@value\":{\"a\":\"hello\"}";
  101. pBase out;
  102. Right expected;
  103. expected.a = "hello";
  104. EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
  105. json::malformed_json_exception);
  106. EXPECT_THAT(out, Not(IsNull()));
  107. EXPECT_PRED1(instanceof <Right>, out.get());
  108. EXPECT_THAT(dynamic_cast<Right &>(*out), expected);
  109. }
  110. TEST_F(JsonBinderPolymorphicTest, ThrowsOnMoreData) {
  111. char data[] = "{\"@id\":\"Right\", \"@value\":{\"a\":\"hello\"},"
  112. " \"key\":null }";
  113. pBase out;
  114. Right expected;
  115. expected.a = "hello";
  116. EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
  117. json::malformed_json_exception);
  118. EXPECT_THAT(out, Not(IsNull()));
  119. EXPECT_PRED1(instanceof <Right>, out.get());
  120. EXPECT_THAT(dynamic_cast<Right &>(*out), expected);
  121. }
  122. TEST_F(JsonBinderPolymorphicTest, ThrowsOnNonObject) {
  123. char data[] = "[\"Right\", \"@value\":{\"a\":\"hello\"}]";
  124. pBase out;
  125. Right expected;
  126. expected.a = "hello";
  127. EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
  128. json::malformed_json_exception);
  129. EXPECT_THAT(out, IsNull());
  130. }
  131. TEST_F(JsonBinderPolymorphicTest, ThrowsMalformedObjectKey) {
  132. char data[] = "{@id\":\"Right\", \"@value\":{\"a\":\"hello\"}}";
  133. pBase out;
  134. Right expected;
  135. expected.a = "hello";
  136. EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
  137. json::malformed_json_exception);
  138. EXPECT_THAT(out, IsNull());
  139. }
  140. TEST_F(JsonBinderPolymorphicTest, ThrowsMalformedObjectAssoc) {
  141. char data[] = "{\"@id\"=\"Right\", \"@value\":{\"a\":\"hello\"}}";
  142. pBase out;
  143. Right expected;
  144. expected.a = "hello";
  145. EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
  146. json::malformed_json_exception);
  147. EXPECT_THAT(out, IsNull());
  148. }
  149. TEST_F(JsonBinderPolymorphicTest, WritesRightImplWithoutWhitespace) {
  150. std::string const expected = R"({"@id":"Right","@value":{"a":"hello"}})";
  151. Right in;
  152. in.a = "hello";
  153. pBase ptr(new Right(in));
  154. std::stringstream ss;
  155. EXPECT_NO_THROW(write(json::binder::bind(ptr, GetBinder()), ss));
  156. EXPECT_THAT(ss.str(), expected);
  157. }
  158. TEST_F(JsonBinderPolymorphicTest, WritesLeftImplWithoutWhitespace) {
  159. std::string const expected = R"({"@id":"Left","@value":{"a":1}})";
  160. Left in;
  161. in.a = 1;
  162. pBase ptr(new Left(in));
  163. std::stringstream ss;
  164. EXPECT_NO_THROW(write(json::binder::bind(ptr, GetBinder()), ss));
  165. EXPECT_THAT(ss.str(), expected);
  166. }
  167. TEST_F(JsonBinderPolymorphicTest, ThrowsWhenWritingUnboundImpl) {
  168. Middle in;
  169. in.a = {1, "hello"};
  170. pBase ptr(new Middle(in));
  171. std::stringstream ss;
  172. EXPECT_THROW(write(json::binder::bind(ptr, GetBinder()), ss),
  173. std::domain_error);
  174. }
  175. TEST_F(JsonBinderPolymorphicTest, ParsesNullSuccessfully) {
  176. char const data[] = "null";
  177. pBase out;
  178. EXPECT_NO_THROW(parse(json::binder::bind(out, GetBinder()), data));
  179. EXPECT_THAT(out, IsNull());
  180. }
  181. TEST_F(JsonBinderPolymorphicTest, WritesNullSuccessfully) {
  182. pBase ptr = nullptr;
  183. std::stringstream ss;
  184. EXPECT_NO_THROW(write(json::binder::bind(ptr, GetBinder()), ss));
  185. EXPECT_THAT(ss.str(), "null");
  186. }