Reflection for RapidJSON  0.0.15
Reflection for serializing/deserializing with RapidJSON
jsonreflector.cpp
Go to the documentation of this file.
1 #include "../json/reflector.h"
2 #include "../json/serializable.h"
3 
4 #include <c++utilities/conversion/stringbuilder.h>
5 #include <c++utilities/conversion/stringconversion.h>
6 #include <c++utilities/io/misc.h>
7 #include <c++utilities/tests/testutils.h>
8 
9 using CppUtilities::operator<<; // must be visible prior to the call site
10 #include <cppunit/TestFixture.h>
11 #include <cppunit/extensions/HelperMacros.h>
12 
13 #include <rapidjson/document.h>
14 #include <rapidjson/stringbuffer.h>
15 #include <rapidjson/writer.h>
16 
17 #include <iostream>
18 #include <map>
19 #include <string>
20 #include <tuple>
21 #include <unordered_map>
22 #include <vector>
23 
24 using namespace std;
25 using namespace CPPUNIT_NS;
26 using namespace RAPIDJSON_NAMESPACE;
27 using namespace CppUtilities;
28 using namespace CppUtilities::Literals;
29 using namespace ReflectiveRapidJSON;
30 
32 
33 // define some enums and structs for testing serialization
34 
35 enum SomeEnum {
36  SomeEnumItem1,
37  SomeEnumItem2,
38  SomeEnumItem3,
39 };
40 
41 enum class SomeEnumClass {
42  Item1,
43  Item2,
44  Item3,
45 };
46 
47 struct TestObject : public JsonSerializable<TestObject> {
48  int number;
49  double number2;
50  vector<int> numbers;
51  string text;
52  bool boolean;
53  map<string, int> someMap;
54  unordered_map<string, bool> someHash;
55  multimap<string, int> someMultimap;
56  unordered_multimap<string, int> someMultiHash;
57  set<string> someSet;
58  multiset<string> someMultiset;
59  unordered_set<string> someUnorderedSet;
60  unordered_multiset<string> someUnorderedMultiset;
61  variant<monostate, string, int, float> someVariant;
62  variant<string, int, float> anotherVariant;
63  variant<string, int, float> yetAnotherVariant;
64 };
65 
66 struct NestingObject : public JsonSerializable<NestingObject> {
67  string name;
68  TestObject testObj;
69 };
70 
71 struct NestingArray : public JsonSerializable<NestingArray> {
72  string name;
73  vector<TestObject> testObjects;
74 };
75 
76 // pretend serialization code for structs has been generated
77 namespace ReflectiveRapidJSON {
78 namespace JsonReflector {
79 
80 template <> inline void push<TestObject>(const TestObject &reflectable, Value::Object &value, Document::AllocatorType &allocator)
81 {
82  push(reflectable.number, "number", value, allocator);
83  push(reflectable.number2, "number2", value, allocator);
84  push(reflectable.numbers, "numbers", value, allocator);
85  push(reflectable.text, "text", value, allocator);
86  push(reflectable.boolean, "boolean", value, allocator);
87  push(reflectable.someMap, "someMap", value, allocator);
88  push(reflectable.someHash, "someHash", value, allocator);
89  push(reflectable.someMultimap, "someMultimap", value, allocator);
90  push(reflectable.someMultiHash, "someMultiHash", value, allocator);
91  push(reflectable.someSet, "someSet", value, allocator);
92  push(reflectable.someMultiset, "someMultiset", value, allocator);
93  push(reflectable.someUnorderedSet, "someUnorderedSet", value, allocator);
94  push(reflectable.someUnorderedMultiset, "someUnorderedMultiset", value, allocator);
95  push(reflectable.someVariant, "someVariant", value, allocator);
96  push(reflectable.anotherVariant, "anotherVariant", value, allocator);
97  push(reflectable.yetAnotherVariant, "yetAnotherVariant", value, allocator);
98 }
99 
100 template <> inline void push<NestingObject>(const NestingObject &reflectable, Value::Object &value, Document::AllocatorType &allocator)
101 {
102  push(reflectable.name, "name", value, allocator);
103  push(reflectable.testObj, "testObj", value, allocator);
104 }
105 
106 template <> inline void push<NestingArray>(const NestingArray &reflectable, Value::Object &value, Document::AllocatorType &allocator)
107 {
108  push(reflectable.name, "name", value, allocator);
109  push(reflectable.testObjects, "testObjects", value, allocator);
110 }
111 
112 template <>
113 inline void pull<TestObject>(TestObject &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
114 {
115  const char *previousRecord;
116  if (errors) {
117  previousRecord = errors->currentRecord;
118  errors->currentRecord = "TestObject";
119  }
120  pull(reflectable.number, "number", value, errors);
121  pull(reflectable.number2, "number2", value, errors);
122  pull(reflectable.numbers, "numbers", value, errors);
123  pull(reflectable.text, "text", value, errors);
124  pull(reflectable.boolean, "boolean", value, errors);
125  pull(reflectable.someMap, "someMap", value, errors);
126  pull(reflectable.someHash, "someHash", value, errors);
127  pull(reflectable.someMultimap, "someMultimap", value, errors);
128  pull(reflectable.someMultiHash, "someMultiHash", value, errors);
129  pull(reflectable.someSet, "someSet", value, errors);
130  pull(reflectable.someMultiset, "someMultiset", value, errors);
131  pull(reflectable.someUnorderedSet, "someUnorderedSet", value, errors);
132  pull(reflectable.someUnorderedMultiset, "someUnorderedMultiset", value, errors);
133  pull(reflectable.someVariant, "someVariant", value, errors);
134  pull(reflectable.anotherVariant, "anotherVariant", value, errors);
135  pull(reflectable.yetAnotherVariant, "yetAnotherVariant", value, errors);
136  if (errors) {
137  errors->currentRecord = previousRecord;
138  }
139 }
140 
141 template <>
142 inline void pull<NestingObject>(NestingObject &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
143 {
144  const char *previousRecord;
145  if (errors) {
146  previousRecord = errors->currentRecord;
147  errors->currentRecord = "NestingObject";
148  }
149  pull(reflectable.name, "name", value, errors);
150  pull(reflectable.testObj, "testObj", value, errors);
151  if (errors) {
152  errors->currentRecord = previousRecord;
153  }
154 }
155 
156 template <>
157 inline void pull<NestingArray>(NestingArray &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
158 {
159  const char *previousRecord;
160  if (errors) {
161  previousRecord = errors->currentRecord;
162  errors->currentRecord = "NestingArray";
163  }
164  pull(reflectable.name, "name", value, errors);
165  pull(reflectable.testObjects, "testObjects", value, errors);
166  if (errors) {
167  errors->currentRecord = previousRecord;
168  }
169 }
170 
171 } // namespace JsonReflector
172 
173 // namespace JsonReflector
174 } // namespace ReflectiveRapidJSON
175 
177 
182 class JsonReflectorTests : public TestFixture {
183  CPPUNIT_TEST_SUITE(JsonReflectorTests);
184  CPPUNIT_TEST(testSerializePrimitives);
185  CPPUNIT_TEST(testSerializeSimpleObjects);
186  CPPUNIT_TEST(testSerializeNestedObjects);
187  CPPUNIT_TEST(testSerializeUniquePtr);
188  CPPUNIT_TEST(testSerializeSharedPtr);
189  CPPUNIT_TEST(testDeserializePrimitives);
190  CPPUNIT_TEST(testDeserializeSimpleObjects);
191  CPPUNIT_TEST(testDeserializeNestedObjects);
192  CPPUNIT_TEST(testDeserializeUniquePtr);
193  CPPUNIT_TEST(testDeserializeSharedPtr);
194  CPPUNIT_TEST(testHandlingParseError);
195  CPPUNIT_TEST(testHandlingTypeMismatch);
196  CPPUNIT_TEST_SUITE_END();
197 
198 public:
199  void setUp() override;
200  void tearDown() override;
201 
202  void experiment();
203  void testSerializePrimitives();
204  void testSerializeSimpleObjects();
205  void testSerializeNestedObjects();
206  void testSerializeUniquePtr();
207  void testSerializeSharedPtr();
208  void testDeserializePrimitives();
209  void testDeserializeSimpleObjects();
210  void testDeserializeNestedObjects();
211  void testDeserializeUniquePtr();
212  void testDeserializeSharedPtr();
213  void testHandlingParseError();
214  void testHandlingTypeMismatch();
215 
216 private:
217 };
218 
220 
222 {
223 }
224 
226 {
227 }
228 
233 {
234  Document doc(kArrayType);
235  Document::AllocatorType &alloc = doc.GetAllocator();
236  doc.SetArray();
237  Document::Array array(doc.GetArray());
238 
239  // string
240  const string foo("foo"); // musn't be destroyed until JSON is actually written
241  JsonReflector::push<string>(foo, array, alloc);
242  JsonReflector::push<const char *>("bar", array, alloc);
243  // number
244  JsonReflector::push<int>(25, array, alloc);
245  JsonReflector::push<double>(12.5, array, alloc);
246  // enum
247  JsonReflector::push<SomeEnum>(SomeEnumItem2, array, alloc);
248  JsonReflector::push<SomeEnumClass>(SomeEnumClass::Item2, array, alloc);
249  JsonReflector::push<SomeEnumClass>(SomeEnumClass::Item3, array, alloc);
250  // array
251  JsonReflector::push<vector<const char *>>({ "foo1", "bar1" }, array, alloc);
252  JsonReflector::push<list<const char *>>({ "foo2", "bar2" }, array, alloc);
253  JsonReflector::push<initializer_list<const char *>>({ "foo3", "bar3" }, array, alloc);
254  JsonReflector::push<tuple<int, double>>(make_tuple(2, 413.0), array, alloc);
255  // boolean
256  JsonReflector::push<bool>(true, array, alloc);
257  JsonReflector::push<bool>(false, array, alloc);
258 
259  StringBuffer strbuf;
260  Writer<StringBuffer> jsonWriter(strbuf);
261  doc.Accept(jsonWriter);
262  CPPUNIT_ASSERT_EQUAL("[\"foo\",\"bar\",25,12.5,1,1,2,[\"foo1\",\"bar1\"],[\"foo2\",\"bar2\"],[\"foo3\",\"bar3\"],[2,413.0],true,false]"s,
263  string(strbuf.GetString()));
264 }
265 
270 {
271  TestObject testObj;
272  testObj.number = 42;
273  testObj.number2 = 3.141592653589793;
274  testObj.numbers = { 1, 2, 3, 4 };
275  testObj.text = "test";
276  testObj.boolean = false;
277  testObj.someMap = { { "a", 1 }, { "b", 2 } };
278  testObj.someHash = { { "c", true }, { "d", false } };
279  testObj.someMultimap = { { "a", 1 }, { "a", 2 }, { "b", 3 } };
280  testObj.someMultiHash = { { "a", 1 } };
281  testObj.someSet = { "a", "b", "c" };
282  testObj.someMultiset = { "a", "b", "b" };
283  testObj.someUnorderedSet = { "a" };
284  testObj.someUnorderedMultiset = { "b", "b", "b" };
285  testObj.someVariant = std::monostate{};
286  testObj.anotherVariant = "foo";
287  testObj.yetAnotherVariant = 42;
288  CPPUNIT_ASSERT_EQUAL(
289  "{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{\"a\":1,\"b\":2},\"someHash\":{\"d\":false,\"c\":true},\"someMultimap\":{\"a\":[1,2],\"b\":[3]},\"someMultiHash\":{\"a\":[1]},\"someSet\":[\"a\",\"b\",\"c\"],\"someMultiset\":[\"a\",\"b\",\"b\"],\"someUnorderedSet\":[\"a\"],\"someUnorderedMultiset\":[\"b\",\"b\",\"b\"],\"someVariant\":{\"index\":0,\"data\":null},\"anotherVariant\":{\"index\":0,\"data\":\"foo\"},\"yetAnotherVariant\":{\"index\":1,\"data\":42}}"s,
290  string(testObj.toJson().GetString()));
291 }
292 
297 {
298  NestingObject nestingObj;
299  nestingObj.name = "nesting";
300  TestObject &testObj = nestingObj.testObj;
301  testObj.number = 42;
302  testObj.number2 = 3.141592653589793;
303  testObj.numbers = { 1, 2, 3, 4 };
304  testObj.text = "test";
305  testObj.boolean = false;
306  CPPUNIT_ASSERT_EQUAL(
307  "{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{},\"someMultimap\":{},\"someMultiHash\":{},\"someSet\":[],\"someMultiset\":[],\"someUnorderedSet\":[],\"someUnorderedMultiset\":[],\"someVariant\":{\"index\":0,\"data\":null},\"anotherVariant\":{\"index\":0,\"data\":\"\"},\"yetAnotherVariant\":{\"index\":0,\"data\":\"\"}}}"s,
308  string(nestingObj.toJson().GetString()));
309 
310  NestingArray nestingArray;
311  nestingArray.name = "nesting2";
312  nestingArray.testObjects.emplace_back(testObj);
313  nestingArray.testObjects.emplace_back(testObj);
314  nestingArray.testObjects.back().number = 43;
315  CPPUNIT_ASSERT_EQUAL(
316  "{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{},\"someMultimap\":{},\"someMultiHash\":{},\"someSet\":[],\"someMultiset\":[],\"someUnorderedSet\":[],\"someUnorderedMultiset\":[],\"someVariant\":{\"index\":0,\"data\":null},\"anotherVariant\":{\"index\":0,\"data\":\"\"},\"yetAnotherVariant\":{\"index\":0,\"data\":\"\"}},{\"number\":43,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{},\"someMultimap\":{},\"someMultiHash\":{},\"someSet\":[],\"someMultiset\":[],\"someUnorderedSet\":[],\"someUnorderedMultiset\":[],\"someVariant\":{\"index\":0,\"data\":null},\"anotherVariant\":{\"index\":0,\"data\":\"\"},\"yetAnotherVariant\":{\"index\":0,\"data\":\"\"}}]}"s,
317  string(nestingArray.toJson().GetString()));
318 
319  vector<TestObject> nestedInVector;
320  nestedInVector.emplace_back(testObj);
321  CPPUNIT_ASSERT_EQUAL(
322  "[{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{},\"someMultimap\":{},\"someMultiHash\":{},\"someSet\":[],\"someMultiset\":[],\"someUnorderedSet\":[],\"someUnorderedMultiset\":[],\"someVariant\":{\"index\":0,\"data\":null},\"anotherVariant\":{\"index\":0,\"data\":\"\"},\"yetAnotherVariant\":{\"index\":0,\"data\":\"\"}}]"s,
323  string(JsonReflector::toJson(nestedInVector).GetString()));
324 }
325 
327 {
328  Document doc(kArrayType);
329  Document::AllocatorType &alloc = doc.GetAllocator();
330  doc.SetArray();
331  Document::Array array(doc.GetArray());
332 
333  const auto str = make_unique<string>("foo");
334  std::unique_ptr<string> nullStr;
335  const auto obj = make_unique<TestObject>();
336  obj->number = 42;
337  obj->number2 = 3.141592653589793;
338  obj->numbers = { 1, 2, 3, 4 };
339  obj->text = "bar";
340  obj->boolean = false;
341 
342  JsonReflector::push(str, array, alloc);
343  JsonReflector::push(nullStr, array, alloc);
344  JsonReflector::push(obj, array, alloc);
345 
346  StringBuffer strbuf;
347  Writer<StringBuffer> jsonWriter(strbuf);
348  doc.Accept(jsonWriter);
349  CPPUNIT_ASSERT_EQUAL(
350  "[\"foo\",null,{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"bar\",\"boolean\":false,\"someMap\":{},\"someHash\":{},\"someMultimap\":{},\"someMultiHash\":{},\"someSet\":[],\"someMultiset\":[],\"someUnorderedSet\":[],\"someUnorderedMultiset\":[],\"someVariant\":{\"index\":0,\"data\":null},\"anotherVariant\":{\"index\":0,\"data\":\"\"},\"yetAnotherVariant\":{\"index\":0,\"data\":\"\"}}]"s,
351  string(strbuf.GetString()));
352 }
353 
355 {
356  Document doc(kArrayType);
357  Document::AllocatorType &alloc = doc.GetAllocator();
358  doc.SetArray();
359  Document::Array array(doc.GetArray());
360 
361  const auto str = make_shared<string>("foo");
362  std::unique_ptr<string> nullStr;
363  const auto obj = make_shared<TestObject>();
364  obj->number = 42;
365  obj->number2 = 3.141592653589793;
366  obj->numbers = { 1, 2, 3, 4 };
367  obj->text = "bar";
368  obj->boolean = false;
369 
370  JsonReflector::push(str, array, alloc);
371  JsonReflector::push(nullStr, array, alloc);
372  JsonReflector::push(obj, array, alloc);
373 
374  StringBuffer strbuf;
375  Writer<StringBuffer> jsonWriter(strbuf);
376  doc.Accept(jsonWriter);
377  CPPUNIT_ASSERT_EQUAL(
378  "[\"foo\",null,{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"bar\",\"boolean\":false,\"someMap\":{},\"someHash\":{},\"someMultimap\":{},\"someMultiHash\":{},\"someSet\":[],\"someMultiset\":[],\"someUnorderedSet\":[],\"someUnorderedMultiset\":[],\"someVariant\":{\"index\":0,\"data\":null},\"anotherVariant\":{\"index\":0,\"data\":\"\"},\"yetAnotherVariant\":{\"index\":0,\"data\":\"\"}}]"s,
379  string(strbuf.GetString()));
380 }
381 
386 {
387  Document doc(kArrayType);
388 
389  doc.Parse("[\"a\", 5, 5.0, 5e6, 4, \"test\", true, 4.125, false]");
390  auto array = doc.GetArray().begin();
391 
392  string str1, str2;
393  int int1 = 0, int2 = 0;
394  bool bool1 = false, bool2 = true;
395  float float1 = 0.0f, float2 = 0.0f;
396  double double1 = 0.0;
398  JsonReflector::pull(str1, array, &errors);
399  JsonReflector::pull(int1, array, &errors);
400  JsonReflector::pull(int2, array, &errors);
401  JsonReflector::pull(float1, array, &errors);
402  JsonReflector::pull(float2, array, &errors);
403  JsonReflector::pull(str2, array, &errors);
404  JsonReflector::pull(bool1, array, &errors);
405  JsonReflector::pull(double1, array, &errors);
406  JsonReflector::pull(bool2, array, &errors);
407 
408  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
409  CPPUNIT_ASSERT_EQUAL("a"s, str1);
410  CPPUNIT_ASSERT_EQUAL(5, int1);
411  CPPUNIT_ASSERT_EQUAL(5, int2);
412  CPPUNIT_ASSERT_EQUAL(5e6f, float1);
413  CPPUNIT_ASSERT_EQUAL(4.f, float2);
414  CPPUNIT_ASSERT_EQUAL("test"s, str2);
415  CPPUNIT_ASSERT_EQUAL(true, bool1);
416  CPPUNIT_ASSERT_EQUAL(4.125, double1);
417  CPPUNIT_ASSERT_EQUAL(false, bool2);
418 
419  // deserialize primitives as tuple
420  tuple<string, int, int, float, float, string, bool, double, bool> arrayAsTuple;
421  JsonReflector::pull(arrayAsTuple, doc, &errors);
422  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
423  CPPUNIT_ASSERT_EQUAL("a"s, get<0>(arrayAsTuple));
424  CPPUNIT_ASSERT_EQUAL(5, get<1>(arrayAsTuple));
425  CPPUNIT_ASSERT_EQUAL(5, get<2>(arrayAsTuple));
426  CPPUNIT_ASSERT_EQUAL(5e6f, get<3>(arrayAsTuple));
427  CPPUNIT_ASSERT_EQUAL(4.f, get<4>(arrayAsTuple));
428  CPPUNIT_ASSERT_EQUAL("test"s, get<5>(arrayAsTuple));
429  CPPUNIT_ASSERT_EQUAL(true, get<6>(arrayAsTuple));
430  CPPUNIT_ASSERT_EQUAL(4.125, get<7>(arrayAsTuple));
431  CPPUNIT_ASSERT_EQUAL(false, get<8>(arrayAsTuple));
432  tuple<string, int> anotherTuple;
433  JsonReflector::pull(anotherTuple, doc, &errors);
434  CPPUNIT_ASSERT_EQUAL(1_st, errors.size());
435  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::ArraySizeMismatch, errors.front().kind);
436 }
437 
442 {
443  const auto testObj
444  = TestObject::fromJson("{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":"
445  "false,\"someMap\":{\"a\":1,\"b\":2},\"someHash\":{\"c\":true,\"d\":false},\"someMultimap\":{\"a\":[1,2],\"b\":[3]},"
446  "\"someMultiHash\":{\"a\":[4,5],\"b\":[6]},"
447  "\"someSet\":[\"a\",\"b\"],\"someMultiset\":["
448  "\"a\",\"a\"],\"someUnorderedSet\":[\"a\",\"b\"],\"someUnorderedMultiset\":[\"a\",\"a\"],\"someVariant\":{\"index\":0,"
449  "\"data\":null},\"anotherVariant\":{\"index\":0,\"data\":\"foo\"},\"yetAnotherVariant\":{\"index\":1,\"data\":42}}");
450 
451  CPPUNIT_ASSERT_EQUAL(42, testObj.number);
452  CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2);
453  CPPUNIT_ASSERT_EQUAL(vector<int>({ 1, 2, 3, 4 }), testObj.numbers);
454  CPPUNIT_ASSERT_EQUAL("test"s, testObj.text);
455  CPPUNIT_ASSERT_EQUAL(false, testObj.boolean);
456  const map<string, int> expectedMap{ { "a", 1 }, { "b", 2 } };
457  CPPUNIT_ASSERT_EQUAL(expectedMap, testObj.someMap);
458  const unordered_map<string, bool> expectedHash{ { "c", true }, { "d", false } };
459  CPPUNIT_ASSERT_EQUAL(expectedHash, testObj.someHash);
460  const multimap<string, int> expectedMultiMap{ { "a", 1 }, { "a", 2 }, { "b", 3 } };
461  CPPUNIT_ASSERT_EQUAL(expectedMultiMap, testObj.someMultimap);
462  const unordered_multimap<string, int> expectedUnorderedMultiMap{ { "a", 4 }, { "a", 5 }, { "b", 6 } };
463  CPPUNIT_ASSERT_EQUAL(expectedUnorderedMultiMap, testObj.someMultiHash);
464  CPPUNIT_ASSERT_EQUAL(set<string>({ "a", "b" }), testObj.someSet);
465  CPPUNIT_ASSERT_EQUAL(multiset<string>({ "a", "a" }), testObj.someMultiset);
466  CPPUNIT_ASSERT_EQUAL(unordered_set<string>({ "a", "b" }), testObj.someUnorderedSet);
467  CPPUNIT_ASSERT_EQUAL(unordered_multiset<string>({ "a", "a" }), testObj.someUnorderedMultiset);
468  CPPUNIT_ASSERT_EQUAL(0_st, testObj.someVariant.index());
469  CPPUNIT_ASSERT_EQUAL(0_st, testObj.anotherVariant.index());
470  CPPUNIT_ASSERT_EQUAL("foo"s, std::get<0>(testObj.anotherVariant));
471  CPPUNIT_ASSERT_EQUAL(1_st, testObj.yetAnotherVariant.index());
472  CPPUNIT_ASSERT_EQUAL(42, std::get<1>(testObj.yetAnotherVariant));
473 }
474 
479 {
481  const NestingObject nestingObj(NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,"
482  "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}}",
483  &errors));
484  const TestObject &testObj = nestingObj.testObj;
485  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
486  CPPUNIT_ASSERT_EQUAL("nesting"s, nestingObj.name);
487  CPPUNIT_ASSERT_EQUAL(42, testObj.number);
488  CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2);
489  CPPUNIT_ASSERT_EQUAL(vector<int>({ 1, 2, 3, 4 }), testObj.numbers);
490  CPPUNIT_ASSERT_EQUAL("test"s, testObj.text);
491  CPPUNIT_ASSERT_EQUAL(false, testObj.boolean);
492 
493  const NestingArray nestingArray(NestingArray::fromJson("{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,"
494  "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},{\"number\":43,\"number2\":3."
495  "141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}",
496  &errors));
497  const vector<TestObject> &testObjects = nestingArray.testObjects;
498  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
499  CPPUNIT_ASSERT_EQUAL("nesting2"s, nestingArray.name);
500  CPPUNIT_ASSERT_EQUAL(2_st, testObjects.size());
501  CPPUNIT_ASSERT_EQUAL(42, testObjects[0].number);
502  CPPUNIT_ASSERT_EQUAL(43, testObjects[1].number);
503  for (const TestObject &testObj : testObjects) {
504  CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2);
505  CPPUNIT_ASSERT_EQUAL(vector<int>({ 1, 2, 3, 4 }), testObj.numbers);
506  CPPUNIT_ASSERT_EQUAL("test"s, testObj.text);
507  CPPUNIT_ASSERT_EQUAL(false, testObj.boolean);
508  }
509 
510  const auto nestedInVector(JsonReflector::fromJson<vector<TestObject>>(
511  "[{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{}}]",
512  &errors));
513  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
514  CPPUNIT_ASSERT_EQUAL(1_st, nestedInVector.size());
515  CPPUNIT_ASSERT_EQUAL(42, nestedInVector[0].number);
516  CPPUNIT_ASSERT_EQUAL(4_st, nestedInVector[0].numbers.size());
517  CPPUNIT_ASSERT_EQUAL("test"s, nestedInVector[0].text);
518 }
519 
521 {
522  Document doc(kArrayType);
523  doc.Parse("[\"foo\",null,{\"text\":\"bar\"}]");
524  auto array = doc.GetArray().begin();
525 
526  unique_ptr<string> str;
527  unique_ptr<string> nullStr;
528  unique_ptr<TestObject> obj;
530  JsonReflector::pull(str, array, &errors);
531  JsonReflector::pull(nullStr, array, &errors);
532  JsonReflector::pull(obj, array, &errors);
533 
534  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
535  CPPUNIT_ASSERT(str);
536  CPPUNIT_ASSERT_EQUAL("foo"s, *str);
537  CPPUNIT_ASSERT(!nullStr);
538  CPPUNIT_ASSERT(obj);
539  CPPUNIT_ASSERT_EQUAL("bar"s, obj->text);
540 }
541 
543 {
544  Document doc(kArrayType);
545  doc.Parse("[\"foo\",null,{\"text\":\"bar\"}]");
546  auto array = doc.GetArray().begin();
547 
548  shared_ptr<string> str;
549  shared_ptr<string> nullStr;
550  shared_ptr<TestObject> obj;
552  JsonReflector::pull(str, array, &errors);
553  JsonReflector::pull(nullStr, array, &errors);
554  JsonReflector::pull(obj, array, &errors);
555 
556  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
557  CPPUNIT_ASSERT(str);
558  CPPUNIT_ASSERT_EQUAL("foo"s, *str);
559  CPPUNIT_ASSERT(!nullStr);
560  CPPUNIT_ASSERT(obj);
561  CPPUNIT_ASSERT_EQUAL("bar"s, obj->text);
562 }
563 
568 {
569  try {
570  NestingObject::fromJson("{\"name\":nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":"
571  "\"test\",\"boolean\":false}}");
572  CPPUNIT_FAIL("expected ParseResult thrown");
573  } catch (const RAPIDJSON_NAMESPACE::ParseResult &res) {
574  CPPUNIT_ASSERT_EQUAL(RAPIDJSON_NAMESPACE::kParseErrorValueInvalid, res.Code());
575  CPPUNIT_ASSERT_EQUAL(9_st, res.Offset());
576  }
577 }
578 
583 {
585  NestingArray::fromJson("{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,"
586  "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},{\"number\":43,\"number2\":3."
587  "141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}",
588  &errors);
589  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
590 
591  NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":\"42\",\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":"
592  "\"test\",\"boolean\":false,\"someSet\":[\"a\",\"a\"],\"someMultiset\":[\"a\",\"a\"],\"someUnorderedSet\":[\"a\",\"a\"],"
593  "\"someUnorderedMultiset\":[\"a\",\"a\"]}}",
594  &errors);
595  CPPUNIT_ASSERT_EQUAL(3_st, errors.size());
596  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
597  CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors.front().expectedType);
598  CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.front().actualType);
599  CPPUNIT_ASSERT_EQUAL("number"s, string(errors.front().member));
600  CPPUNIT_ASSERT_EQUAL("TestObject"s, string(errors.front().record));
601  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::UnexpectedDuplicate, errors[1].kind);
602  CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors[1].expectedType);
603  CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors[1].actualType);
604  CPPUNIT_ASSERT_EQUAL("someSet"s, string(errors[1].member));
605  CPPUNIT_ASSERT_EQUAL("TestObject"s, string(errors[1].record));
606  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::UnexpectedDuplicate, errors[2].kind);
607  CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors[2].expectedType);
608  CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors[2].actualType);
609  CPPUNIT_ASSERT_EQUAL("someUnorderedSet"s, string(errors[2].member));
610  CPPUNIT_ASSERT_EQUAL("TestObject"s, string(errors[2].record));
611  errors.clear();
612 
613  NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":1,\"text\":"
614  "\"test\",\"boolean\":false}}",
615  &errors);
616  CPPUNIT_ASSERT_EQUAL(1_st, errors.size());
617  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
618  CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors.front().expectedType);
619  CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors.front().actualType);
620  CPPUNIT_ASSERT_EQUAL("numbers"s, string(errors.front().member));
621  CPPUNIT_ASSERT_EQUAL("TestObject"s, string(errors.front().record));
622  errors.clear();
623 
624  NestingObject::fromJson("{\"name\":[],\"testObj\":\"this is not an object\"}", &errors);
625  CPPUNIT_ASSERT_EQUAL(2_st, errors.size());
626  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
627  CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.front().expectedType);
628  CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors.front().actualType);
629  CPPUNIT_ASSERT_EQUAL("name"s, string(errors.front().member));
630  CPPUNIT_ASSERT_EQUAL("NestingObject"s, string(errors.front().record));
631  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.back().kind);
632  CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors.back().expectedType);
633  CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.back().actualType);
634  CPPUNIT_ASSERT_EQUAL("testObj"s, string(errors.back().member));
635  CPPUNIT_ASSERT_EQUAL("NestingObject"s, string(errors.back().record));
636  errors.clear();
637 
638  const NestingArray nestingArray(
639  NestingArray::fromJson("{\"name\":\"nesting2\",\"testObjects\":[25,{\"number\":42,\"number2\":3.141592653589793,"
640  "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},\"foo\",{\"number\":43,\"number2\":3."
641  "141592653589793,\"numbers\":[1,2,3,4,\"bar\"],\"text\":\"test\",\"boolean\":false}]}",
642  &errors));
643  CPPUNIT_ASSERT_EQUAL(3_st, errors.size());
644  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[0].kind);
645  CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors[0].expectedType);
646  CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors[0].actualType);
647  CPPUNIT_ASSERT_EQUAL("testObjects"s, string(errors[0].member));
648  CPPUNIT_ASSERT_EQUAL("NestingArray"s, string(errors[0].record));
649  CPPUNIT_ASSERT_EQUAL(0_st, errors[0].index);
650  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[1].kind);
651  CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors[1].expectedType);
652  CPPUNIT_ASSERT_EQUAL(JsonType::String, errors[1].actualType);
653  CPPUNIT_ASSERT_EQUAL(2_st, errors[1].index);
654  CPPUNIT_ASSERT_EQUAL("testObjects"s, string(errors[1].member));
655  CPPUNIT_ASSERT_EQUAL("NestingArray"s, string(errors[1].record));
656  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[2].kind);
657  CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors[2].expectedType);
658  CPPUNIT_ASSERT_EQUAL(JsonType::String, errors[2].actualType);
659  CPPUNIT_ASSERT_EQUAL("numbers"s, string(errors[2].member));
660  CPPUNIT_ASSERT_EQUAL("TestObject"s, string(errors[2].record));
661  CPPUNIT_ASSERT_EQUAL(4_st, errors[2].index);
662  errors.clear();
663 
664  errors.throwOn = JsonDeserializationErrors::ThrowOn::TypeMismatch;
665  CPPUNIT_ASSERT_THROW(NestingObject::fromJson("{\"name\":[],\"testObj\":\"this is not an object\"}", &errors), JsonDeserializationError);
666 }
ReflectiveRapidJSON::JsonDeserializationErrors
The JsonDeserializationErrors struct can be passed to fromJson() for error handling.
Definition: errorhandling.h:154
JsonReflectorTests::testDeserializeSimpleObjects
void testDeserializeSimpleObjects()
Tests deserializing simple objects.
Definition: jsonreflector.cpp:441
ReflectiveRapidJSON::JsonReflector::fromJson
Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors=nullptr)
Deserializes the specified JSON to.
Definition: reflector.h:1059
JsonReflectorTests::testSerializeSimpleObjects
void testSerializeSimpleObjects()
Tests serializing objects.
Definition: jsonreflector.cpp:269
ReflectiveRapidJSON::JsonReflector::pull
void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue< RAPIDJSON_NAMESPACE::UTF8< char >>::ConstObject &value, JsonDeserializationErrors *errors)
Pulls the reflectable which has a custom type from the specified object.
Definition: reflector-boosthana.h:40
JsonReflectorTests::testHandlingTypeMismatch
void testHandlingTypeMismatch()
Tests whether errors are added on type mismatch and in other cases.
Definition: jsonreflector.cpp:582
JsonReflectorTests::testDeserializePrimitives
void testDeserializePrimitives()
Tests deserializing strings, numbers (int, float, double) and boolean.
Definition: jsonreflector.cpp:385
ReflectiveRapidJSON::JsonDeserializationErrors::currentRecord
const char * currentRecord
The name of the class or struct which is currently being processed.
Definition: errorhandling.h:163
ReflectiveRapidJSON::JsonReflector::toJson
RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable)
Serializes the specified reflectable.
Definition: reflector.h:1047
ReflectiveRapidJSON
Definition: traits.h:13
JsonReflectorTests::tearDown
void tearDown() override
Definition: jsonreflector.cpp:225
JsonReflectorTests::testSerializeNestedObjects
void testSerializeNestedObjects()
Tests serializing nested object and arrays.
Definition: jsonreflector.cpp:296
JsonReflectorTests::testDeserializeUniquePtr
void testDeserializeUniquePtr()
Definition: jsonreflector.cpp:520
JsonReflectorTests::setUp
void setUp() override
Definition: jsonreflector.cpp:221
JsonReflectorTests::experiment
void experiment()
ReflectiveRapidJSON::JsonReflector::push
void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
Pushes the specified reflectable to the specified value.
Definition: reflector.h:140
JsonReflectorTests::testSerializePrimitives
void testSerializePrimitives()
Tests serializing strings, numbers, arrays and boolean.
Definition: jsonreflector.cpp:232
ReflectiveRapidJSON::JsonSerializable
The JsonSerializable class provides the CRTP-base for (de)serializable objects.
Definition: reflector.h:33
JsonReflectorTests
The JsonReflectorTests class tests RapidJSON wrapper which is used to ease code generation.
Definition: jsonreflector.cpp:182
ReflectiveRapidJSON::JsonDeserializationError
The JsonDeserializationError struct describes any errors of fromJson() except such caused by invalid ...
Definition: errorhandling.h:109
JsonReflectorTests::testSerializeSharedPtr
void testSerializeSharedPtr()
Definition: jsonreflector.cpp:354
ReflectiveRapidJSON::JsonDeserializationErrors::throwOn
enum ReflectiveRapidJSON::JsonDeserializationErrors::ThrowOn throwOn
JsonReflectorTests::testDeserializeSharedPtr
void testDeserializeSharedPtr()
Definition: jsonreflector.cpp:542
JsonReflectorTests::testDeserializeNestedObjects
void testDeserializeNestedObjects()
Tests deserializing nested objects and arrays.
Definition: jsonreflector.cpp:478
JsonReflectorTests::testSerializeUniquePtr
void testSerializeUniquePtr()
Definition: jsonreflector.cpp:326
JsonReflectorTests::testHandlingParseError
void testHandlingParseError()
Tests whether RAPIDJSON_NAMESPACE::ParseResult is thrown correctly when passing invalid JSON to fromJ...
Definition: jsonreflector.cpp:567
CPPUNIT_TEST_SUITE_REGISTRATION
CPPUNIT_TEST_SUITE_REGISTRATION(JsonReflectorTests)