Reflection for RapidJSON  0.0.9
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  set<string> someSet;
56  multiset<string> someMultiset;
57  unordered_set<string> someUnorderedSet;
58  unordered_multiset<string> someUnorderedMultiset;
59 };
60 
61 struct NestingObject : public JsonSerializable<NestingObject> {
62  string name;
63  TestObject testObj;
64 };
65 
66 struct NestingArray : public JsonSerializable<NestingArray> {
67  string name;
68  vector<TestObject> testObjects;
69 };
70 
71 // pretend serialization code for structs has been generated
72 namespace ReflectiveRapidJSON {
73 namespace JsonReflector {
74 
75 template <> inline void push<TestObject>(const TestObject &reflectable, Value::Object &value, Document::AllocatorType &allocator)
76 {
77  push(reflectable.number, "number", value, allocator);
78  push(reflectable.number2, "number2", value, allocator);
79  push(reflectable.numbers, "numbers", value, allocator);
80  push(reflectable.text, "text", value, allocator);
81  push(reflectable.boolean, "boolean", value, allocator);
82  push(reflectable.someMap, "someMap", value, allocator);
83  push(reflectable.someHash, "someHash", value, allocator);
84  push(reflectable.someSet, "someSet", value, allocator);
85  push(reflectable.someMultiset, "someMultiset", value, allocator);
86  push(reflectable.someUnorderedSet, "someUnorderedSet", value, allocator);
87  push(reflectable.someUnorderedMultiset, "someUnorderedMultiset", value, allocator);
88 }
89 
90 template <> inline void push<NestingObject>(const NestingObject &reflectable, Value::Object &value, Document::AllocatorType &allocator)
91 {
92  push(reflectable.name, "name", value, allocator);
93  push(reflectable.testObj, "testObj", value, allocator);
94 }
95 
96 template <> inline void push<NestingArray>(const NestingArray &reflectable, Value::Object &value, Document::AllocatorType &allocator)
97 {
98  push(reflectable.name, "name", value, allocator);
99  push(reflectable.testObjects, "testObjects", value, allocator);
100 }
101 
102 template <>
103 inline void pull<TestObject>(TestObject &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
104 {
105  const char *previousRecord;
106  if (errors) {
107  previousRecord = errors->currentRecord;
108  errors->currentRecord = "TestObject";
109  }
110  pull(reflectable.number, "number", value, errors);
111  pull(reflectable.number2, "number2", value, errors);
112  pull(reflectable.numbers, "numbers", value, errors);
113  pull(reflectable.text, "text", value, errors);
114  pull(reflectable.boolean, "boolean", value, errors);
115  pull(reflectable.someMap, "someMap", value, errors);
116  pull(reflectable.someHash, "someHash", value, errors);
117  pull(reflectable.someSet, "someSet", value, errors);
118  pull(reflectable.someMultiset, "someMultiset", value, errors);
119  pull(reflectable.someUnorderedSet, "someUnorderedSet", value, errors);
120  pull(reflectable.someUnorderedMultiset, "someUnorderedMultiset", value, errors);
121  if (errors) {
122  errors->currentRecord = previousRecord;
123  }
124 }
125 
126 template <>
127 inline void pull<NestingObject>(NestingObject &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
128 {
129  const char *previousRecord;
130  if (errors) {
131  previousRecord = errors->currentRecord;
132  errors->currentRecord = "NestingObject";
133  }
134  pull(reflectable.name, "name", value, errors);
135  pull(reflectable.testObj, "testObj", value, errors);
136  if (errors) {
137  errors->currentRecord = previousRecord;
138  }
139 }
140 
141 template <>
142 inline void pull<NestingArray>(NestingArray &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
143 {
144  const char *previousRecord;
145  if (errors) {
146  previousRecord = errors->currentRecord;
147  errors->currentRecord = "NestingArray";
148  }
149  pull(reflectable.name, "name", value, errors);
150  pull(reflectable.testObjects, "testObjects", value, errors);
151  if (errors) {
152  errors->currentRecord = previousRecord;
153  }
154 }
155 
156 } // namespace JsonReflector
157 
158 // namespace JsonReflector
159 } // namespace ReflectiveRapidJSON
160 
162 
167 class JsonReflectorTests : public TestFixture {
168  CPPUNIT_TEST_SUITE(JsonReflectorTests);
169  CPPUNIT_TEST(testSerializePrimitives);
170  CPPUNIT_TEST(testSerializeSimpleObjects);
171  CPPUNIT_TEST(testSerializeNestedObjects);
172  CPPUNIT_TEST(testSerializeUniquePtr);
173  CPPUNIT_TEST(testSerializeSharedPtr);
174  CPPUNIT_TEST(testDeserializePrimitives);
175  CPPUNIT_TEST(testDeserializeSimpleObjects);
176  CPPUNIT_TEST(testDeserializeNestedObjects);
177  CPPUNIT_TEST(testDeserializeUniquePtr);
178  CPPUNIT_TEST(testDeserializeSharedPtr);
179  CPPUNIT_TEST(testHandlingParseError);
180  CPPUNIT_TEST(testHandlingTypeMismatch);
181  CPPUNIT_TEST_SUITE_END();
182 
183 public:
184  void setUp();
185  void tearDown();
186 
187  void experiment();
188  void testSerializePrimitives();
189  void testSerializeSimpleObjects();
190  void testSerializeNestedObjects();
191  void testSerializeUniquePtr();
192  void testSerializeSharedPtr();
193  void testDeserializePrimitives();
194  void testDeserializeSimpleObjects();
195  void testDeserializeNestedObjects();
196  void testDeserializeUniquePtr();
197  void testDeserializeSharedPtr();
198  void testHandlingParseError();
199  void testHandlingTypeMismatch();
200 
201 private:
202 };
203 
205 
207 {
208 }
209 
211 {
212 }
213 
218 {
219  Document doc(kArrayType);
220  Document::AllocatorType &alloc = doc.GetAllocator();
221  doc.SetArray();
222  Document::Array array(doc.GetArray());
223 
224  // string
225  const string foo("foo"); // musn't be destroyed until JSON is actually written
226  JsonReflector::push<string>(foo, array, alloc);
227  JsonReflector::push<const char *>("bar", array, alloc);
228  // number
229  JsonReflector::push<int>(25, array, alloc);
230  JsonReflector::push<double>(12.5, array, alloc);
231  // enum
232  JsonReflector::push<SomeEnum>(SomeEnumItem2, array, alloc);
233  JsonReflector::push<SomeEnumClass>(SomeEnumClass::Item2, array, alloc);
234  JsonReflector::push<SomeEnumClass>(SomeEnumClass::Item3, array, alloc);
235  // array
236  JsonReflector::push<vector<const char *>>({ "foo1", "bar1" }, array, alloc);
237  JsonReflector::push<list<const char *>>({ "foo2", "bar2" }, array, alloc);
238  JsonReflector::push<initializer_list<const char *>>({ "foo3", "bar3" }, array, alloc);
239  JsonReflector::push<tuple<int, double>>(make_tuple(2, 413.0), array, alloc);
240  // boolean
241  JsonReflector::push<bool>(true, array, alloc);
242  JsonReflector::push<bool>(false, array, alloc);
243 
244  StringBuffer strbuf;
245  Writer<StringBuffer> jsonWriter(strbuf);
246  doc.Accept(jsonWriter);
247  CPPUNIT_ASSERT_EQUAL("[\"foo\",\"bar\",25,12.5,1,1,2,[\"foo1\",\"bar1\"],[\"foo2\",\"bar2\"],[\"foo3\",\"bar3\"],[2,413.0],true,false]"s,
248  string(strbuf.GetString()));
249 }
250 
255 {
256  TestObject testObj;
257  testObj.number = 42;
258  testObj.number2 = 3.141592653589793;
259  testObj.numbers = { 1, 2, 3, 4 };
260  testObj.text = "test";
261  testObj.boolean = false;
262  testObj.someMap = { { "a", 1 }, { "b", 2 } };
263  testObj.someHash = { { "c", true }, { "d", false } };
264  testObj.someSet = { "a", "b", "c" };
265  testObj.someMultiset = { "a", "b", "b" };
266  testObj.someUnorderedSet = { "a" };
267  testObj.someUnorderedMultiset = { "b", "b", "b" };
268  CPPUNIT_ASSERT_EQUAL(
269  "{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{\"a\":1,\"b\":2},\"someHash\":{\"d\":false,\"c\":true},\"someSet\":[\"a\",\"b\",\"c\"],\"someMultiset\":[\"a\",\"b\",\"b\"],\"someUnorderedSet\":[\"a\"],\"someUnorderedMultiset\":[\"b\",\"b\",\"b\"]}"s,
270  string(testObj.toJson().GetString()));
271 }
272 
277 {
278  NestingObject nestingObj;
279  nestingObj.name = "nesting";
280  TestObject &testObj = nestingObj.testObj;
281  testObj.number = 42;
282  testObj.number2 = 3.141592653589793;
283  testObj.numbers = { 1, 2, 3, 4 };
284  testObj.text = "test";
285  testObj.boolean = false;
286  CPPUNIT_ASSERT_EQUAL(
287  "{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{},\"someSet\":[],\"someMultiset\":[],\"someUnorderedSet\":[],\"someUnorderedMultiset\":[]}}"s,
288  string(nestingObj.toJson().GetString()));
289 
290  NestingArray nestingArray;
291  nestingArray.name = "nesting2";
292  nestingArray.testObjects.emplace_back(testObj);
293  nestingArray.testObjects.emplace_back(testObj);
294  nestingArray.testObjects.back().number = 43;
295  CPPUNIT_ASSERT_EQUAL(
296  "{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{},\"someSet\":[],\"someMultiset\":[],\"someUnorderedSet\":[],\"someUnorderedMultiset\":[]},{\"number\":43,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{},\"someSet\":[],\"someMultiset\":[],\"someUnorderedSet\":[],\"someUnorderedMultiset\":[]}]}"s,
297  string(nestingArray.toJson().GetString()));
298 
299  vector<TestObject> nestedInVector;
300  nestedInVector.emplace_back(testObj);
301  CPPUNIT_ASSERT_EQUAL(
302  "[{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{},\"someSet\":[],\"someMultiset\":[],\"someUnorderedSet\":[],\"someUnorderedMultiset\":[]}]"s,
303  string(JsonReflector::toJson(nestedInVector).GetString()));
304 }
305 
307 {
308  Document doc(kArrayType);
309  Document::AllocatorType &alloc = doc.GetAllocator();
310  doc.SetArray();
311  Document::Array array(doc.GetArray());
312 
313  const auto str = make_unique<string>("foo");
314  std::unique_ptr<string> nullStr;
315  const auto obj = make_unique<TestObject>();
316  obj->number = 42;
317  obj->number2 = 3.141592653589793;
318  obj->numbers = { 1, 2, 3, 4 };
319  obj->text = "bar";
320  obj->boolean = false;
321 
322  JsonReflector::push(str, array, alloc);
323  JsonReflector::push(nullStr, array, alloc);
324  JsonReflector::push(obj, array, alloc);
325 
326  StringBuffer strbuf;
327  Writer<StringBuffer> jsonWriter(strbuf);
328  doc.Accept(jsonWriter);
329  CPPUNIT_ASSERT_EQUAL(
330  "[\"foo\",null,{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"bar\",\"boolean\":false,\"someMap\":{},\"someHash\":{},\"someSet\":[],\"someMultiset\":[],\"someUnorderedSet\":[],\"someUnorderedMultiset\":[]}]"s,
331  string(strbuf.GetString()));
332 }
333 
335 {
336  Document doc(kArrayType);
337  Document::AllocatorType &alloc = doc.GetAllocator();
338  doc.SetArray();
339  Document::Array array(doc.GetArray());
340 
341  const auto str = make_shared<string>("foo");
342  std::unique_ptr<string> nullStr;
343  const auto obj = make_shared<TestObject>();
344  obj->number = 42;
345  obj->number2 = 3.141592653589793;
346  obj->numbers = { 1, 2, 3, 4 };
347  obj->text = "bar";
348  obj->boolean = false;
349 
350  JsonReflector::push(str, array, alloc);
351  JsonReflector::push(nullStr, array, alloc);
352  JsonReflector::push(obj, array, alloc);
353 
354  StringBuffer strbuf;
355  Writer<StringBuffer> jsonWriter(strbuf);
356  doc.Accept(jsonWriter);
357  CPPUNIT_ASSERT_EQUAL(
358  "[\"foo\",null,{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"bar\",\"boolean\":false,\"someMap\":{},\"someHash\":{},\"someSet\":[],\"someMultiset\":[],\"someUnorderedSet\":[],\"someUnorderedMultiset\":[]}]"s,
359  string(strbuf.GetString()));
360 }
361 
366 {
367  Document doc(kArrayType);
368 
369  doc.Parse("[\"a\", 5, 5.0, 5e6, 4, \"test\", true, 4.125, false]");
370  auto array = doc.GetArray().begin();
371 
372  string str1, str2;
373  int int1 = 0, int2 = 0;
374  bool bool1 = false, bool2 = true;
375  float float1 = 0.0f, float2 = 0.0f;
376  double double1 = 0.0;
378  JsonReflector::pull(str1, array, &errors);
379  JsonReflector::pull(int1, array, &errors);
380  JsonReflector::pull(int2, array, &errors);
381  JsonReflector::pull(float1, array, &errors);
382  JsonReflector::pull(float2, array, &errors);
383  JsonReflector::pull(str2, array, &errors);
384  JsonReflector::pull(bool1, array, &errors);
385  JsonReflector::pull(double1, array, &errors);
386  JsonReflector::pull(bool2, array, &errors);
387 
388  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
389  CPPUNIT_ASSERT_EQUAL("a"s, str1);
390  CPPUNIT_ASSERT_EQUAL(5, int1);
391  CPPUNIT_ASSERT_EQUAL(5, int2);
392  CPPUNIT_ASSERT_EQUAL(5e6f, float1);
393  CPPUNIT_ASSERT_EQUAL(4.f, float2);
394  CPPUNIT_ASSERT_EQUAL("test"s, str2);
395  CPPUNIT_ASSERT_EQUAL(true, bool1);
396  CPPUNIT_ASSERT_EQUAL(4.125, double1);
397  CPPUNIT_ASSERT_EQUAL(false, bool2);
398 
399  // deserialize primitives as tuple
400  tuple<string, int, int, float, float, string, bool, double, bool> arrayAsTuple;
401  JsonReflector::pull(arrayAsTuple, doc, &errors);
402  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
403  CPPUNIT_ASSERT_EQUAL("a"s, get<0>(arrayAsTuple));
404  CPPUNIT_ASSERT_EQUAL(5, get<1>(arrayAsTuple));
405  CPPUNIT_ASSERT_EQUAL(5, get<2>(arrayAsTuple));
406  CPPUNIT_ASSERT_EQUAL(5e6f, get<3>(arrayAsTuple));
407  CPPUNIT_ASSERT_EQUAL(4.f, get<4>(arrayAsTuple));
408  CPPUNIT_ASSERT_EQUAL("test"s, get<5>(arrayAsTuple));
409  CPPUNIT_ASSERT_EQUAL(true, get<6>(arrayAsTuple));
410  CPPUNIT_ASSERT_EQUAL(4.125, get<7>(arrayAsTuple));
411  CPPUNIT_ASSERT_EQUAL(false, get<8>(arrayAsTuple));
412  tuple<string, int> anotherTuple;
413  JsonReflector::pull(anotherTuple, doc, &errors);
414  CPPUNIT_ASSERT_EQUAL(1_st, errors.size());
415  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::ArraySizeMismatch, errors.front().kind);
416 }
417 
422 {
423  const TestObject testObj(
424  TestObject::fromJson("{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":"
425  "false,\"someMap\":{\"a\":1,\"b\":2},\"someHash\":{\"c\":true,\"d\":false},\"someSet\":[\"a\",\"b\"],\"someMultiset\":["
426  "\"a\",\"a\"],\"someUnorderedSet\":[\"a\",\"b\"],\"someUnorderedMultiset\":[\"a\",\"a\"]}"));
427 
428  CPPUNIT_ASSERT_EQUAL(42, testObj.number);
429  CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2);
430  CPPUNIT_ASSERT_EQUAL(vector<int>({ 1, 2, 3, 4 }), testObj.numbers);
431  CPPUNIT_ASSERT_EQUAL("test"s, testObj.text);
432  CPPUNIT_ASSERT_EQUAL(false, testObj.boolean);
433  const map<string, int> expectedMap{ { "a", 1 }, { "b", 2 } };
434  CPPUNIT_ASSERT_EQUAL(expectedMap, testObj.someMap);
435  const unordered_map<string, bool> expectedHash{ { "c", true }, { "d", false } };
436  CPPUNIT_ASSERT_EQUAL(expectedHash, testObj.someHash);
437  CPPUNIT_ASSERT_EQUAL(set<string>({ "a", "b" }), testObj.someSet);
438  CPPUNIT_ASSERT_EQUAL(multiset<string>({ "a", "a" }), testObj.someMultiset);
439  CPPUNIT_ASSERT_EQUAL(unordered_set<string>({ "a", "b" }), testObj.someUnorderedSet);
440  CPPUNIT_ASSERT_EQUAL(unordered_multiset<string>({ "a", "a" }), testObj.someUnorderedMultiset);
441 }
442 
447 {
449  const NestingObject nestingObj(NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,"
450  "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}}",
451  &errors));
452  const TestObject &testObj = nestingObj.testObj;
453  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
454  CPPUNIT_ASSERT_EQUAL("nesting"s, nestingObj.name);
455  CPPUNIT_ASSERT_EQUAL(42, testObj.number);
456  CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2);
457  CPPUNIT_ASSERT_EQUAL(vector<int>({ 1, 2, 3, 4 }), testObj.numbers);
458  CPPUNIT_ASSERT_EQUAL("test"s, testObj.text);
459  CPPUNIT_ASSERT_EQUAL(false, testObj.boolean);
460 
461  const NestingArray nestingArray(NestingArray::fromJson("{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,"
462  "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},{\"number\":43,\"number2\":3."
463  "141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}",
464  &errors));
465  const vector<TestObject> &testObjects = nestingArray.testObjects;
466  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
467  CPPUNIT_ASSERT_EQUAL("nesting2"s, nestingArray.name);
468  CPPUNIT_ASSERT_EQUAL(2_st, testObjects.size());
469  CPPUNIT_ASSERT_EQUAL(42, testObjects[0].number);
470  CPPUNIT_ASSERT_EQUAL(43, testObjects[1].number);
471  for (const TestObject &testObj : testObjects) {
472  CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2);
473  CPPUNIT_ASSERT_EQUAL(vector<int>({ 1, 2, 3, 4 }), testObj.numbers);
474  CPPUNIT_ASSERT_EQUAL("test"s, testObj.text);
475  CPPUNIT_ASSERT_EQUAL(false, testObj.boolean);
476  }
477 
478  const auto nestedInVector(JsonReflector::fromJson<vector<TestObject>>(
479  "[{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{}}]",
480  &errors));
481  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
482  CPPUNIT_ASSERT_EQUAL(1_st, nestedInVector.size());
483  CPPUNIT_ASSERT_EQUAL(42, nestedInVector[0].number);
484  CPPUNIT_ASSERT_EQUAL(4_st, nestedInVector[0].numbers.size());
485  CPPUNIT_ASSERT_EQUAL("test"s, nestedInVector[0].text);
486 }
487 
489 {
490  Document doc(kArrayType);
491  doc.Parse("[\"foo\",null,{\"text\":\"bar\"}]");
492  auto array = doc.GetArray().begin();
493 
494  unique_ptr<string> str;
495  unique_ptr<string> nullStr;
496  unique_ptr<TestObject> obj;
498  JsonReflector::pull(str, array, &errors);
499  JsonReflector::pull(nullStr, array, &errors);
500  JsonReflector::pull(obj, array, &errors);
501 
502  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
503  CPPUNIT_ASSERT(str);
504  CPPUNIT_ASSERT_EQUAL("foo"s, *str);
505  CPPUNIT_ASSERT(!nullStr);
506  CPPUNIT_ASSERT(obj);
507  CPPUNIT_ASSERT_EQUAL("bar"s, obj->text);
508 }
509 
511 {
512  Document doc(kArrayType);
513  doc.Parse("[\"foo\",null,{\"text\":\"bar\"}]");
514  auto array = doc.GetArray().begin();
515 
516  shared_ptr<string> str;
517  shared_ptr<string> nullStr;
518  shared_ptr<TestObject> obj;
520  JsonReflector::pull(str, array, &errors);
521  JsonReflector::pull(nullStr, array, &errors);
522  JsonReflector::pull(obj, array, &errors);
523 
524  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
525  CPPUNIT_ASSERT(str);
526  CPPUNIT_ASSERT_EQUAL("foo"s, *str);
527  CPPUNIT_ASSERT(!nullStr);
528  CPPUNIT_ASSERT(obj);
529  CPPUNIT_ASSERT_EQUAL("bar"s, obj->text);
530 }
531 
536 {
537  try {
538  NestingObject::fromJson("{\"name\":nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":"
539  "\"test\",\"boolean\":false}}");
540  CPPUNIT_FAIL("expected ParseResult thrown");
541  } catch (const RAPIDJSON_NAMESPACE::ParseResult &res) {
542  CPPUNIT_ASSERT_EQUAL(RAPIDJSON_NAMESPACE::kParseErrorValueInvalid, res.Code());
543  CPPUNIT_ASSERT_EQUAL(9_st, res.Offset());
544  }
545 }
546 
551 {
553  NestingArray::fromJson("{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,"
554  "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},{\"number\":43,\"number2\":3."
555  "141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}",
556  &errors);
557  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
558 
559  NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":\"42\",\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":"
560  "\"test\",\"boolean\":false,\"someSet\":[\"a\",\"a\"],\"someMultiset\":[\"a\",\"a\"],\"someUnorderedSet\":[\"a\",\"a\"],"
561  "\"someUnorderedMultiset\":[\"a\",\"a\"]}}",
562  &errors);
563  CPPUNIT_ASSERT_EQUAL(3_st, errors.size());
564  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
565  CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors.front().expectedType);
566  CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.front().actualType);
567  CPPUNIT_ASSERT_EQUAL("number"s, string(errors.front().member));
568  CPPUNIT_ASSERT_EQUAL("TestObject"s, string(errors.front().record));
569  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::UnexpectedDuplicate, errors[1].kind);
570  CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors[1].expectedType);
571  CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors[1].actualType);
572  CPPUNIT_ASSERT_EQUAL("someSet"s, string(errors[1].member));
573  CPPUNIT_ASSERT_EQUAL("TestObject"s, string(errors[1].record));
574  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::UnexpectedDuplicate, errors[2].kind);
575  CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors[2].expectedType);
576  CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors[2].actualType);
577  CPPUNIT_ASSERT_EQUAL("someUnorderedSet"s, string(errors[2].member));
578  CPPUNIT_ASSERT_EQUAL("TestObject"s, string(errors[2].record));
579  errors.clear();
580 
581  NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":1,\"text\":"
582  "\"test\",\"boolean\":false}}",
583  &errors);
584  CPPUNIT_ASSERT_EQUAL(1_st, errors.size());
585  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
586  CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors.front().expectedType);
587  CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors.front().actualType);
588  CPPUNIT_ASSERT_EQUAL("numbers"s, string(errors.front().member));
589  CPPUNIT_ASSERT_EQUAL("TestObject"s, string(errors.front().record));
590  errors.clear();
591 
592  NestingObject::fromJson("{\"name\":[],\"testObj\":\"this is not an object\"}", &errors);
593  CPPUNIT_ASSERT_EQUAL(2_st, errors.size());
594  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
595  CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.front().expectedType);
596  CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors.front().actualType);
597  CPPUNIT_ASSERT_EQUAL("name"s, string(errors.front().member));
598  CPPUNIT_ASSERT_EQUAL("NestingObject"s, string(errors.front().record));
599  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.back().kind);
600  CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors.back().expectedType);
601  CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.back().actualType);
602  CPPUNIT_ASSERT_EQUAL("testObj"s, string(errors.back().member));
603  CPPUNIT_ASSERT_EQUAL("NestingObject"s, string(errors.back().record));
604  errors.clear();
605 
606  const NestingArray nestingArray(
607  NestingArray::fromJson("{\"name\":\"nesting2\",\"testObjects\":[25,{\"number\":42,\"number2\":3.141592653589793,"
608  "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},\"foo\",{\"number\":43,\"number2\":3."
609  "141592653589793,\"numbers\":[1,2,3,4,\"bar\"],\"text\":\"test\",\"boolean\":false}]}",
610  &errors));
611  CPPUNIT_ASSERT_EQUAL(3_st, errors.size());
612  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[0].kind);
613  CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors[0].expectedType);
614  CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors[0].actualType);
615  CPPUNIT_ASSERT_EQUAL("testObjects"s, string(errors[0].member));
616  CPPUNIT_ASSERT_EQUAL("NestingArray"s, string(errors[0].record));
617  CPPUNIT_ASSERT_EQUAL(0_st, errors[0].index);
618  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[1].kind);
619  CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors[1].expectedType);
620  CPPUNIT_ASSERT_EQUAL(JsonType::String, errors[1].actualType);
621  CPPUNIT_ASSERT_EQUAL(2_st, errors[1].index);
622  CPPUNIT_ASSERT_EQUAL("testObjects"s, string(errors[1].member));
623  CPPUNIT_ASSERT_EQUAL("NestingArray"s, string(errors[1].record));
624  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[2].kind);
625  CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors[2].expectedType);
626  CPPUNIT_ASSERT_EQUAL(JsonType::String, errors[2].actualType);
627  CPPUNIT_ASSERT_EQUAL("numbers"s, string(errors[2].member));
628  CPPUNIT_ASSERT_EQUAL("TestObject"s, string(errors[2].record));
629  CPPUNIT_ASSERT_EQUAL(4_st, errors[2].index);
630  errors.clear();
631 
632  errors.throwOn = JsonDeserializationErrors::ThrowOn::TypeMismatch;
633  CPPUNIT_ASSERT_THROW(NestingObject::fromJson("{\"name\":[],\"testObj\":\"this is not an object\"}", &errors), JsonDeserializationError);
634 }
ReflectiveRapidJSON::JsonDeserializationErrors
The JsonDeserializationErrors struct can be passed to fromJson() for error handling.
Definition: errorhandling.h:152
JsonReflectorTests::testDeserializeSimpleObjects
void testDeserializeSimpleObjects()
Tests deserializing simple objects.
Definition: jsonreflector.cpp:421
ReflectiveRapidJSON::JsonReflector::fromJson
Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors=nullptr)
Deserializes the specified JSON to.
Definition: reflector.h:860
ReflectiveRapidJSON::JsonDeserializationErrors::throwOn
enum ReflectiveRapidJSON::JsonDeserializationErrors::ThrowOn throwOn
JsonReflectorTests::testSerializeSimpleObjects
void testSerializeSimpleObjects()
Tests serializing objects.
Definition: jsonreflector.cpp:254
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:550
JsonReflectorTests::testDeserializePrimitives
void testDeserializePrimitives()
Tests deserializing strings, numbers (int, float, double) and boolean.
Definition: jsonreflector.cpp:365
ReflectiveRapidJSON::JsonDeserializationErrors::currentRecord
const char * currentRecord
The name of the class or struct which is currently being processed.
Definition: errorhandling.h:161
ReflectiveRapidJSON::JsonReflector::toJson
RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable)
Serializes the specified reflectable.
Definition: reflector.h:848
JsonReflectorTests::tearDown
void tearDown()
Definition: jsonreflector.cpp:210
ReflectiveRapidJSON
Definition: traits.h:12
JsonReflectorTests::testSerializeNestedObjects
void testSerializeNestedObjects()
Tests serializing nested object and arrays.
Definition: jsonreflector.cpp:276
JsonReflectorTests::testDeserializeUniquePtr
void testDeserializeUniquePtr()
Definition: jsonreflector.cpp:488
JsonReflectorTests::setUp
void setUp()
Definition: jsonreflector.cpp:206
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:132
JsonReflectorTests::testSerializePrimitives
void testSerializePrimitives()
Tests serializing strings, numbers, arrays and boolean.
Definition: jsonreflector.cpp:217
ReflectiveRapidJSON::JsonSerializable
The JsonSerializable class provides the CRTP-base for (de)serializable objects.
Definition: reflector.h:26
JsonReflectorTests
The JsonReflectorTests class tests RapidJSON wrapper which is used to ease code generation.
Definition: jsonreflector.cpp:167
ReflectiveRapidJSON::JsonDeserializationError
The JsonDeserializationError struct describes any errors of fromJson() except such caused by invalid ...
Definition: errorhandling.h:107
JsonReflectorTests::testSerializeSharedPtr
void testSerializeSharedPtr()
Definition: jsonreflector.cpp:334
JsonReflectorTests::testDeserializeSharedPtr
void testDeserializeSharedPtr()
Definition: jsonreflector.cpp:510
JsonReflectorTests::testDeserializeNestedObjects
void testDeserializeNestedObjects()
Tests deserializing nested objects and arrays.
Definition: jsonreflector.cpp:446
JsonReflectorTests::testSerializeUniquePtr
void testSerializeUniquePtr()
Definition: jsonreflector.cpp:306
JsonReflectorTests::testHandlingParseError
void testHandlingParseError()
Tests whether RAPIDJSON_NAMESPACE::ParseResult is thrown correctly when passing invalid JSON to fromJ...
Definition: jsonreflector.cpp:535
CPPUNIT_TEST_SUITE_REGISTRATION
CPPUNIT_TEST_SUITE_REGISTRATION(JsonReflectorTests)