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>
9using CppUtilities::operator<<;
10#include <cppunit/TestFixture.h>
11#include <cppunit/extensions/HelperMacros.h>
13#include <rapidjson/document.h>
14#include <rapidjson/stringbuffer.h>
15#include <rapidjson/writer.h>
21#include <unordered_map>
25using namespace CPPUNIT_NS;
26using namespace RAPIDJSON_NAMESPACE;
27using namespace CppUtilities;
28using namespace CppUtilities::Literals;
41enum class SomeEnumClass {
53 map<string, int> someMap;
54 unordered_map<string, bool> someHash;
55 multimap<string, int> someMultimap;
56 unordered_multimap<string, int> someMultiHash;
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;
73 vector<TestObject> testObjects;
78namespace JsonReflector {
80template <>
inline void push<TestObject>(
const TestObject &reflectable, Value::Object &value, Document::AllocatorType &allocator)
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);
100template <>
inline void push<NestingObject>(
const NestingObject &reflectable, Value::Object &value, Document::AllocatorType &allocator)
102 push(reflectable.name,
"name", value, allocator);
103 push(reflectable.testObj,
"testObj", value, allocator);
106template <>
inline void push<NestingArray>(
const NestingArray &reflectable, Value::Object &value, Document::AllocatorType &allocator)
108 push(reflectable.name,
"name", value, allocator);
109 push(reflectable.testObjects,
"testObjects", value, allocator);
115 const char *previousRecord =
nullptr;
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);
144 const char *previousRecord =
nullptr;
149 pull(reflectable.name,
"name", value, errors);
150 pull(reflectable.testObj,
"testObj", value, errors);
159 const char *previousRecord =
nullptr;
164 pull(reflectable.name,
"name", value, errors);
165 pull(reflectable.testObjects,
"testObjects", value, errors);
198 CPPUNIT_TEST_SUITE_END();
201 void setUp()
override;
238 Document doc(kArrayType);
239 Document::AllocatorType &alloc = doc.GetAllocator();
241 Document::Array array(doc.GetArray());
244 const string foo(
"foo");
264 Writer<StringBuffer> jsonWriter(strbuf);
265 doc.Accept(jsonWriter);
266 CPPUNIT_ASSERT_EQUAL(
"[\"foo\",\"bar\",25,12.5,1,1,2,[\"foo1\",\"bar1\"],[\"foo2\",\"bar2\"],[\"foo3\",\"bar3\"],[2,413.0],true,false]"s,
267 string(strbuf.GetString()));
277 testObj.number2 = 3.141592653589793;
278 testObj.numbers = { 1, 2, 3, 4 };
279 testObj.text =
"test";
280 testObj.boolean =
false;
281 testObj.someMap = { {
"a", 1 }, {
"b", 2 } };
282 testObj.someHash = { {
"c",
true }, {
"d",
false } };
283 testObj.someMultimap = { {
"a", 1 }, {
"a", 2 }, {
"b", 3 } };
284 testObj.someMultiHash = { {
"a", 1 } };
285 testObj.someSet = {
"a",
"b",
"c" };
286 testObj.someMultiset = {
"a",
"b",
"b" };
287 testObj.someUnorderedSet = {
"a" };
288 testObj.someUnorderedMultiset = {
"b",
"b",
"b" };
289 testObj.someVariant = std::monostate{};
290 testObj.anotherVariant =
"foo";
291 testObj.yetAnotherVariant = 42;
292 CPPUNIT_ASSERT_EQUAL(
293 "{\"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,
294 string(testObj.toJson().GetString()));
302 NestingObject nestingObj;
303 nestingObj.name =
"nesting";
304 TestObject &testObj = nestingObj.testObj;
306 testObj.number2 = 3.141592653589793;
307 testObj.numbers = { 1, 2, 3, 4 };
308 testObj.text =
"test";
309 testObj.boolean =
false;
310 CPPUNIT_ASSERT_EQUAL(
311 "{\"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,
312 string(nestingObj.toJson().GetString()));
314 NestingArray nestingArray;
315 nestingArray.name =
"nesting2";
316 nestingArray.testObjects.emplace_back(testObj);
317 nestingArray.testObjects.emplace_back(testObj);
318 nestingArray.testObjects.back().number = 43;
319 CPPUNIT_ASSERT_EQUAL(
320 "{\"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,
321 string(nestingArray.toJson().GetString()));
323 vector<TestObject> nestedInVector;
324 nestedInVector.emplace_back(testObj);
325 CPPUNIT_ASSERT_EQUAL(
326 "[{\"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,
332 Document doc(kArrayType);
333 Document::AllocatorType &alloc = doc.GetAllocator();
335 Document::Array array(doc.GetArray());
337 const auto str = make_unique<string>(
"foo");
338 std::unique_ptr<string> nullStr;
339 const auto obj = make_unique<TestObject>();
341 obj->number2 = 3.141592653589793;
342 obj->numbers = { 1, 2, 3, 4 };
344 obj->boolean =
false;
351 Writer<StringBuffer> jsonWriter(strbuf);
352 doc.Accept(jsonWriter);
353 CPPUNIT_ASSERT_EQUAL(
354 "[\"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,
355 string(strbuf.GetString()));
360 Document doc(kArrayType);
361 Document::AllocatorType &alloc = doc.GetAllocator();
363 Document::Array array(doc.GetArray());
365 const auto str = make_shared<string>(
"foo");
366 std::unique_ptr<string> nullStr;
367 const auto obj = make_shared<TestObject>();
369 obj->number2 = 3.141592653589793;
370 obj->numbers = { 1, 2, 3, 4 };
372 obj->boolean =
false;
379 Writer<StringBuffer> jsonWriter(strbuf);
380 doc.Accept(jsonWriter);
381 CPPUNIT_ASSERT_EQUAL(
382 "[\"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,
383 string(strbuf.GetString()));
391 Document doc(kArrayType);
392 Document::AllocatorType &alloc = doc.GetAllocator();
394 Document::Array array(doc.GetArray());
396 const auto str = make_optional<std::string>(
"foo");
397 const auto nullStr = std::optional<std::string>();
403 Writer<StringBuffer> jsonWriter(strbuf);
404 doc.Accept(jsonWriter);
405 CPPUNIT_ASSERT_EQUAL(
"[\"foo\",null]"s, std::string(strbuf.GetString()));
413 Document doc(kArrayType);
415 doc.Parse(
"[\"a\", 5, 5.0, 5e6, 4, \"test\", true, 4.125, false]");
416 auto array = doc.GetArray().begin();
419 int int1 = 0, int2 = 0;
420 bool bool1 =
false, bool2 =
true;
421 float float1 = 0.0f, float2 = 0.0f;
422 double double1 = 0.0;
434 CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
435 CPPUNIT_ASSERT_EQUAL(
"a"s, str1);
436 CPPUNIT_ASSERT_EQUAL(5, int1);
437 CPPUNIT_ASSERT_EQUAL(5, int2);
438 CPPUNIT_ASSERT_EQUAL(5e6f, float1);
439 CPPUNIT_ASSERT_EQUAL(4.f, float2);
440 CPPUNIT_ASSERT_EQUAL(
"test"s, str2);
441 CPPUNIT_ASSERT_EQUAL(
true, bool1);
442 CPPUNIT_ASSERT_EQUAL(4.125, double1);
443 CPPUNIT_ASSERT_EQUAL(
false, bool2);
446 tuple<string, int, int, float, float, string, bool, double, bool> arrayAsTuple;
448 CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
449 CPPUNIT_ASSERT_EQUAL(
"a"s, get<0>(arrayAsTuple));
450 CPPUNIT_ASSERT_EQUAL(5, get<1>(arrayAsTuple));
451 CPPUNIT_ASSERT_EQUAL(5, get<2>(arrayAsTuple));
452 CPPUNIT_ASSERT_EQUAL(5e6f, get<3>(arrayAsTuple));
453 CPPUNIT_ASSERT_EQUAL(4.f, get<4>(arrayAsTuple));
454 CPPUNIT_ASSERT_EQUAL(
"test"s, get<5>(arrayAsTuple));
455 CPPUNIT_ASSERT_EQUAL(
true, get<6>(arrayAsTuple));
456 CPPUNIT_ASSERT_EQUAL(4.125, get<7>(arrayAsTuple));
457 CPPUNIT_ASSERT_EQUAL(
false, get<8>(arrayAsTuple));
458 tuple<string, int> anotherTuple;
460 CPPUNIT_ASSERT_EQUAL(1_st, errors.size());
461 CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::ArraySizeMismatch, errors.front().kind);
470 = TestObject::fromJson(
"{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":"
471 "false,\"someMap\":{\"a\":1,\"b\":2},\"someHash\":{\"c\":true,\"d\":false},\"someMultimap\":{\"a\":[1,2],\"b\":[3]},"
472 "\"someMultiHash\":{\"a\":[4,5],\"b\":[6]},"
473 "\"someSet\":[\"a\",\"b\"],\"someMultiset\":["
474 "\"a\",\"a\"],\"someUnorderedSet\":[\"a\",\"b\"],\"someUnorderedMultiset\":[\"a\",\"a\"],\"someVariant\":{\"index\":0,"
475 "\"data\":null},\"anotherVariant\":{\"index\":0,\"data\":\"foo\"},\"yetAnotherVariant\":{\"index\":1,\"data\":42}}");
477 CPPUNIT_ASSERT_EQUAL(42, testObj.number);
478 CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2);
479 CPPUNIT_ASSERT_EQUAL(vector<int>({ 1, 2, 3, 4 }), testObj.numbers);
480 CPPUNIT_ASSERT_EQUAL(
"test"s, testObj.text);
481 CPPUNIT_ASSERT_EQUAL(
false, testObj.boolean);
482 const map<string, int> expectedMap{ {
"a", 1 }, {
"b", 2 } };
483 CPPUNIT_ASSERT_EQUAL(expectedMap, testObj.someMap);
484 const unordered_map<string, bool> expectedHash{ {
"c",
true }, {
"d",
false } };
485 CPPUNIT_ASSERT_EQUAL(expectedHash, testObj.someHash);
486 const multimap<string, int> expectedMultiMap{ {
"a", 1 }, {
"a", 2 }, {
"b", 3 } };
487 CPPUNIT_ASSERT_EQUAL(expectedMultiMap, testObj.someMultimap);
488 const unordered_multimap<string, int> expectedUnorderedMultiMap{ {
"a", 4 }, {
"a", 5 }, {
"b", 6 } };
489 CPPUNIT_ASSERT_EQUAL(expectedUnorderedMultiMap, testObj.someMultiHash);
490 CPPUNIT_ASSERT_EQUAL(set<string>({
"a",
"b" }), testObj.someSet);
491 CPPUNIT_ASSERT_EQUAL(multiset<string>({
"a",
"a" }), testObj.someMultiset);
492 CPPUNIT_ASSERT_EQUAL(unordered_set<string>({
"a",
"b" }), testObj.someUnorderedSet);
493 CPPUNIT_ASSERT_EQUAL(unordered_multiset<string>({
"a",
"a" }), testObj.someUnorderedMultiset);
494 CPPUNIT_ASSERT_EQUAL(0_st, testObj.someVariant.index());
495 CPPUNIT_ASSERT_EQUAL(0_st, testObj.anotherVariant.index());
496 CPPUNIT_ASSERT_EQUAL(
"foo"s, std::get<0>(testObj.anotherVariant));
497 CPPUNIT_ASSERT_EQUAL(1_st, testObj.yetAnotherVariant.index());
498 CPPUNIT_ASSERT_EQUAL(42, std::get<1>(testObj.yetAnotherVariant));
507 const NestingObject nestingObj(NestingObject::fromJson(
"{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,"
508 "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}}",
510 const TestObject &testObj = nestingObj.testObj;
511 CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
512 CPPUNIT_ASSERT_EQUAL(
"nesting"s, nestingObj.name);
513 CPPUNIT_ASSERT_EQUAL(42, testObj.number);
514 CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2);
515 CPPUNIT_ASSERT_EQUAL(vector<int>({ 1, 2, 3, 4 }), testObj.numbers);
516 CPPUNIT_ASSERT_EQUAL(
"test"s, testObj.text);
517 CPPUNIT_ASSERT_EQUAL(
false, testObj.boolean);
519 const NestingArray nestingArray(NestingArray::fromJson(
"{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,"
520 "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},{\"number\":43,\"number2\":3."
521 "141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}",
523 const vector<TestObject> &testObjects = nestingArray.testObjects;
524 CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
525 CPPUNIT_ASSERT_EQUAL(
"nesting2"s, nestingArray.name);
526 CPPUNIT_ASSERT_EQUAL(2_st, testObjects.size());
527 CPPUNIT_ASSERT_EQUAL(42, testObjects[0].number);
528 CPPUNIT_ASSERT_EQUAL(43, testObjects[1].number);
529 for (
const TestObject &nestedTestObj : testObjects) {
530 CPPUNIT_ASSERT_EQUAL(3.141592653589793, nestedTestObj.number2);
531 CPPUNIT_ASSERT_EQUAL(vector<int>({ 1, 2, 3, 4 }), nestedTestObj.numbers);
532 CPPUNIT_ASSERT_EQUAL(
"test"s, nestedTestObj.text);
533 CPPUNIT_ASSERT_EQUAL(
false, nestedTestObj.boolean);
537 "[{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false,\"someMap\":{},\"someHash\":{}}]",
539 CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
540 CPPUNIT_ASSERT_EQUAL(1_st, nestedInVector.size());
541 CPPUNIT_ASSERT_EQUAL(42, nestedInVector[0].number);
542 CPPUNIT_ASSERT_EQUAL(4_st, nestedInVector[0].numbers.size());
543 CPPUNIT_ASSERT_EQUAL(
"test"s, nestedInVector[0].text);
551 Document doc(kArrayType);
552 doc.Parse(
"[\"foo\",null,{\"text\":\"bar\"}]");
553 auto array = doc.GetArray().begin();
555 unique_ptr<string> str;
556 unique_ptr<string> nullStr;
557 unique_ptr<TestObject> obj;
563 CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
565 CPPUNIT_ASSERT_EQUAL(
"foo"s, *str);
566 CPPUNIT_ASSERT(!nullStr);
568 CPPUNIT_ASSERT_EQUAL(
"bar"s, obj->text);
573 Document doc(kArrayType);
574 doc.Parse(
"[\"foo\",null,{\"text\":\"bar\"}]");
575 auto array = doc.GetArray().begin();
577 shared_ptr<string> str;
578 shared_ptr<string> nullStr;
579 shared_ptr<TestObject> obj;
585 CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
587 CPPUNIT_ASSERT_EQUAL(
"foo"s, *str);
588 CPPUNIT_ASSERT(!nullStr);
590 CPPUNIT_ASSERT_EQUAL(
"bar"s, obj->text);
595 Document doc(kArrayType);
596 doc.Parse(
"[\"foo\",null]");
597 auto array = doc.GetArray().begin();
599 optional<string> str =
"foo"s;
600 optional<string> nullStr;
603 CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
604 CPPUNIT_ASSERT(str.has_value());
605 CPPUNIT_ASSERT_EQUAL(
"foo"s, *str);
606 CPPUNIT_ASSERT(!nullStr.has_value());
615 NestingObject::fromJson(
"{\"name\":nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":"
616 "\"test\",\"boolean\":false}}");
617 CPPUNIT_FAIL(
"expected ParseResult thrown");
618 }
catch (
const RAPIDJSON_NAMESPACE::ParseResult &res) {
619 CPPUNIT_ASSERT_EQUAL(RAPIDJSON_NAMESPACE::kParseErrorValueInvalid, res.Code());
620 CPPUNIT_ASSERT_EQUAL(9_st, res.Offset());
630 NestingArray::fromJson(
"{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,"
631 "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},{\"number\":43,\"number2\":3."
632 "141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}",
634 CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
636 NestingObject::fromJson(
"{\"name\":\"nesting\",\"testObj\":{\"number\":\"42\",\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":"
637 "\"test\",\"boolean\":false,\"someSet\":[\"a\",\"a\"],\"someMultiset\":[\"a\",\"a\"],\"someUnorderedSet\":[\"a\",\"a\"],"
638 "\"someUnorderedMultiset\":[\"a\",\"a\"]}}",
640 CPPUNIT_ASSERT_EQUAL(3_st, errors.size());
641 CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
642 CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors.front().expectedType);
643 CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.front().actualType);
644 CPPUNIT_ASSERT_EQUAL(
"number"s,
string(errors.front().member));
645 CPPUNIT_ASSERT_EQUAL(
"TestObject"s,
string(errors.front().record));
646 CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::UnexpectedDuplicate, errors[1].kind);
647 CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors[1].expectedType);
648 CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors[1].actualType);
649 CPPUNIT_ASSERT_EQUAL(
"someSet"s,
string(errors[1].member));
650 CPPUNIT_ASSERT_EQUAL(
"TestObject"s,
string(errors[1].record));
651 CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::UnexpectedDuplicate, errors[2].kind);
652 CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors[2].expectedType);
653 CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors[2].actualType);
654 CPPUNIT_ASSERT_EQUAL(
"someUnorderedSet"s,
string(errors[2].member));
655 CPPUNIT_ASSERT_EQUAL(
"TestObject"s,
string(errors[2].record));
658 NestingObject::fromJson(
"{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":1,\"text\":"
659 "\"test\",\"boolean\":false}}",
661 CPPUNIT_ASSERT_EQUAL(1_st, errors.size());
662 CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
663 CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors.front().expectedType);
664 CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors.front().actualType);
665 CPPUNIT_ASSERT_EQUAL(
"numbers"s,
string(errors.front().member));
666 CPPUNIT_ASSERT_EQUAL(
"TestObject"s,
string(errors.front().record));
669 NestingObject::fromJson(
"{\"name\":[],\"testObj\":\"this is not an object\"}", &errors);
670 CPPUNIT_ASSERT_EQUAL(2_st, errors.size());
671 CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
672 CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.front().expectedType);
673 CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors.front().actualType);
674 CPPUNIT_ASSERT_EQUAL(
"name"s,
string(errors.front().member));
675 CPPUNIT_ASSERT_EQUAL(
"NestingObject"s,
string(errors.front().record));
676 CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.back().kind);
677 CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors.back().expectedType);
678 CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.back().actualType);
679 CPPUNIT_ASSERT_EQUAL(
"testObj"s,
string(errors.back().member));
680 CPPUNIT_ASSERT_EQUAL(
"NestingObject"s,
string(errors.back().record));
683 const NestingArray nestingArray(
684 NestingArray::fromJson(
"{\"name\":\"nesting2\",\"testObjects\":[25,{\"number\":42,\"number2\":3.141592653589793,"
685 "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},\"foo\",{\"number\":43,\"number2\":3."
686 "141592653589793,\"numbers\":[1,2,3,4,\"bar\"],\"text\":\"test\",\"boolean\":false}]}",
688 CPPUNIT_ASSERT_EQUAL(3_st, errors.size());
689 CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[0].kind);
690 CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors[0].expectedType);
691 CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors[0].actualType);
692 CPPUNIT_ASSERT_EQUAL(
"testObjects"s,
string(errors[0].member));
693 CPPUNIT_ASSERT_EQUAL(
"NestingArray"s,
string(errors[0].record));
694 CPPUNIT_ASSERT_EQUAL(0_st, errors[0].index);
695 CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[1].kind);
696 CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors[1].expectedType);
697 CPPUNIT_ASSERT_EQUAL(JsonType::String, errors[1].actualType);
698 CPPUNIT_ASSERT_EQUAL(2_st, errors[1].index);
699 CPPUNIT_ASSERT_EQUAL(
"testObjects"s,
string(errors[1].member));
700 CPPUNIT_ASSERT_EQUAL(
"NestingArray"s,
string(errors[1].record));
701 CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[2].kind);
702 CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors[2].expectedType);
703 CPPUNIT_ASSERT_EQUAL(JsonType::String, errors[2].actualType);
704 CPPUNIT_ASSERT_EQUAL(
"numbers"s,
string(errors[2].member));
705 CPPUNIT_ASSERT_EQUAL(
"TestObject"s,
string(errors[2].record));
706 CPPUNIT_ASSERT_EQUAL(4_st, errors[2].index);
709 errors.
throwOn = JsonDeserializationErrors::ThrowOn::TypeMismatch;
710 CPPUNIT_ASSERT_THROW(NestingObject::fromJson(
"{\"name\":[],\"testObj\":\"this is not an object\"}", &errors),
JsonDeserializationError);
The JsonReflectorTests class tests RapidJSON wrapper which is used to ease code generation.
void testDeserializeNestedObjects()
Tests deserializing nested objects and arrays.
void testSerializeSimpleObjects()
Tests serializing objects.
void testSerializePrimitives()
Tests serializing strings, numbers, arrays and boolean.
void testSerializeUniquePtr()
void testSerializeNestedObjects()
Tests serializing nested object and arrays.
void testDeserializePrimitives()
Tests deserializing strings, numbers (int, float, double) and boolean.
void testHandlingParseError()
Tests whether RAPIDJSON_NAMESPACE::ParseResult is thrown correctly when passing invalid JSON to fromJ...
void testDeserializeOptional()
void testDeserializeUniquePtr()
Tests deserializing std::optional.
void testDeserializeSharedPtr()
void testHandlingTypeMismatch()
Tests whether errors are added on type mismatch and in other cases.
void testSerializeOptional()
Tests serializing std::optional.
void testDeserializeSimpleObjects()
Tests deserializing simple objects.
void testSerializeSharedPtr()
Contains functions to (de)serialize basic types such as int, double, bool, std::string,...
Contains only the definition of the JsonSerializable template class which makes the reflection access...
CPPUNIT_TEST_SUITE_REGISTRATION(JsonReflectorTests)
RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable)
Serializes the specified reflectable.
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.
Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors=nullptr)
Deserializes the specified JSON to.
void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
Pushes the specified reflectable to the specified value.
The JsonDeserializationError struct describes any errors of fromJson() except such caused by invalid ...
The JsonDeserializationErrors struct can be passed to fromJson() for error handling.
const char * currentRecord
The name of the class or struct which is currently being processed.
enum ReflectiveRapidJSON::JsonDeserializationErrors::ThrowOn throwOn
The JsonSerializable class provides the CRTP-base for (de)serializable objects.