Reflection for RapidJSON  0.0.7
Reflection for serializing/deserializing with RapidJSON
jsonreflector-boosthana.cpp
Go to the documentation of this file.
1 #include "../json/reflector-boosthana.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 TestUtilities::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 <string>
19 #include <vector>
20 
21 using namespace std;
22 using namespace CPPUNIT_NS;
23 using namespace RAPIDJSON_NAMESPACE;
24 using namespace IoUtilities;
25 using namespace ConversionUtilities;
26 using namespace TestUtilities;
27 using namespace TestUtilities::Literals;
28 using namespace ReflectiveRapidJSON;
29 
31 
32 // define some structs for testing serialization
33 struct TestObjectHana : public JsonSerializable<TestObjectHana> {
34  BOOST_HANA_DEFINE_STRUCT(TestObjectHana, (int, number), (double, number2), (vector<int>, numbers), (string, text), (bool, boolean));
35 };
36 
37 struct NestingObjectHana : public JsonSerializable<NestingObjectHana> {
38  BOOST_HANA_DEFINE_STRUCT(NestingObjectHana, (string, name), (TestObjectHana, testObj));
39 };
40 
41 struct NestingArrayHana : public JsonSerializable<NestingArrayHana> {
42  BOOST_HANA_DEFINE_STRUCT(NestingArrayHana, (string, name), (vector<TestObjectHana>, testObjects));
43 };
44 
46 
51 class JsonReflectorBoostHanaTests : public TestFixture {
52  CPPUNIT_TEST_SUITE(JsonReflectorBoostHanaTests);
53  CPPUNIT_TEST(testSerializeSimpleObjects);
54  CPPUNIT_TEST(testSerializeNestedObjects);
55  CPPUNIT_TEST(testDeserializeSimpleObjects);
56  CPPUNIT_TEST(testDeserializeNestedObjects);
57  CPPUNIT_TEST(testHandlingTypeMismatch);
58  CPPUNIT_TEST_SUITE_END();
59 
60 public:
61  void setUp();
62  void tearDown();
63 
64  void testSerializePrimitives();
65  void testSerializeSimpleObjects();
66  void testSerializeNestedObjects();
67  void testDeserializePrimitives();
68  void testDeserializeSimpleObjects();
69  void testDeserializeNestedObjects();
70  void testHandlingTypeMismatch();
71 
72 private:
73 };
74 
76 
78 {
79 }
80 
82 {
83 }
84 
89 {
90  TestObjectHana testObj;
91  testObj.number = 42;
92  testObj.number2 = 3.141592653589793;
93  testObj.numbers = { 1, 2, 3, 4 };
94  testObj.text = "test";
95  testObj.boolean = false;
96  CPPUNIT_ASSERT_EQUAL("{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}"s,
97  string(testObj.toJson().GetString()));
98 }
99 
104 {
105  NestingObjectHana nestingObj;
106  nestingObj.name = "nesting";
107  TestObjectHana &testObj = nestingObj.testObj;
108  testObj.number = 42;
109  testObj.number2 = 3.141592653589793;
110  testObj.numbers = { 1, 2, 3, 4 };
111  testObj.text = "test";
112  testObj.boolean = false;
113  CPPUNIT_ASSERT_EQUAL(
114  "{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}}"s,
115  string(nestingObj.toJson().GetString()));
116  NestingArrayHana nestingArray;
117  nestingArray.name = "nesting2";
118  nestingArray.testObjects.emplace_back(testObj);
119  nestingArray.testObjects.emplace_back(testObj);
120  nestingArray.testObjects.back().number = 43;
121  CPPUNIT_ASSERT_EQUAL(
122  "{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},{\"number\":43,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}"s,
123  string(nestingArray.toJson().GetString()));
124 }
125 
130 {
131  const TestObjectHana testObj(
132  TestObjectHana::fromJson("{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}"));
133 
134  CPPUNIT_ASSERT_EQUAL(42, testObj.number);
135  CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2);
136  CPPUNIT_ASSERT_EQUAL(vector<int>({ 1, 2, 3, 4 }), testObj.numbers);
137  CPPUNIT_ASSERT_EQUAL("test"s, testObj.text);
138  CPPUNIT_ASSERT_EQUAL(false, testObj.boolean);
139 }
140 
145 {
146  const NestingObjectHana nestingObj(NestingObjectHana::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,"
147  "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}}"));
148  const TestObjectHana &testObj = nestingObj.testObj;
149  CPPUNIT_ASSERT_EQUAL("nesting"s, nestingObj.name);
150  CPPUNIT_ASSERT_EQUAL(42, testObj.number);
151  CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2);
152  CPPUNIT_ASSERT_EQUAL(vector<int>({ 1, 2, 3, 4 }), testObj.numbers);
153  CPPUNIT_ASSERT_EQUAL("test"s, testObj.text);
154  CPPUNIT_ASSERT_EQUAL(false, testObj.boolean);
155 
156  const NestingArrayHana nestingArray(
157  NestingArrayHana::fromJson("{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,"
158  "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},{\"number\":43,\"number2\":3."
159  "141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}"));
160  const vector<TestObjectHana> &testObjects = nestingArray.testObjects;
161  CPPUNIT_ASSERT_EQUAL("nesting2"s, nestingArray.name);
162  CPPUNIT_ASSERT_EQUAL(2_st, testObjects.size());
163  CPPUNIT_ASSERT_EQUAL(42, testObjects[0].number);
164  CPPUNIT_ASSERT_EQUAL(43, testObjects[1].number);
165  for (const TestObjectHana &testObj : testObjects) {
166  CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2);
167  CPPUNIT_ASSERT_EQUAL(vector<int>({ 1, 2, 3, 4 }), testObj.numbers);
168  CPPUNIT_ASSERT_EQUAL("test"s, testObj.text);
169  CPPUNIT_ASSERT_EQUAL(false, testObj.boolean);
170  }
171 }
172 
177 {
179  NestingArrayHana::fromJson("{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,"
180  "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},{\"number\":43,\"number2\":3."
181  "141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}",
182  &errors);
183  CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
184 
185  NestingObjectHana::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":\"42\",\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":"
186  "\"test\",\"boolean\":false}}",
187  &errors);
188  CPPUNIT_ASSERT_EQUAL(1_st, errors.size());
189  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
190  CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors.front().expectedType);
191  CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.front().actualType);
192  CPPUNIT_ASSERT_EQUAL("number"s, string(errors.front().member));
193  CPPUNIT_ASSERT_EQUAL("[document]"s, string(errors.front().record));
194  errors.clear();
195 
196  NestingObjectHana::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":1,\"text\":"
197  "\"test\",\"boolean\":false}}",
198  &errors);
199  CPPUNIT_ASSERT_EQUAL(1_st, errors.size());
200  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
201  CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors.front().expectedType);
202  CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors.front().actualType);
203  CPPUNIT_ASSERT_EQUAL("numbers"s, string(errors.front().member));
204  CPPUNIT_ASSERT_EQUAL("[document]"s, string(errors.front().record));
205  errors.clear();
206 
207  NestingObjectHana::fromJson("{\"name\":[],\"testObj\":\"this is not an object\"}", &errors);
208  CPPUNIT_ASSERT_EQUAL(2_st, errors.size());
209  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.front().kind);
210  CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.front().expectedType);
211  CPPUNIT_ASSERT_EQUAL(JsonType::Array, errors.front().actualType);
212  CPPUNIT_ASSERT_EQUAL("name"s, string(errors.front().member));
213  CPPUNIT_ASSERT_EQUAL("[document]"s, string(errors.front().record));
214  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors.back().kind);
215  CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors.back().expectedType);
216  CPPUNIT_ASSERT_EQUAL(JsonType::String, errors.back().actualType);
217  CPPUNIT_ASSERT_EQUAL("testObj"s, string(errors.back().member));
218  CPPUNIT_ASSERT_EQUAL("[document]"s, string(errors.back().record));
219  errors.clear();
220 
221  const NestingArrayHana nestingArray(
222  NestingArrayHana::fromJson("{\"name\":\"nesting2\",\"testObjects\":[25,{\"number\":42,\"number2\":3.141592653589793,"
223  "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},\"foo\",{\"number\":43,\"number2\":3."
224  "141592653589793,\"numbers\":[1,2,3,4,\"bar\"],\"text\":\"test\",\"boolean\":false}]}",
225  &errors));
226  CPPUNIT_ASSERT_EQUAL(3_st, errors.size());
227  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[0].kind);
228  CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors[0].expectedType);
229  CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors[0].actualType);
230  CPPUNIT_ASSERT_EQUAL("testObjects"s, string(errors[0].member));
231  CPPUNIT_ASSERT_EQUAL("[document]"s, string(errors[0].record));
232  CPPUNIT_ASSERT_EQUAL(0_st, errors[0].index);
233  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[1].kind);
234  CPPUNIT_ASSERT_EQUAL(JsonType::Object, errors[1].expectedType);
235  CPPUNIT_ASSERT_EQUAL(JsonType::String, errors[1].actualType);
236  CPPUNIT_ASSERT_EQUAL(2_st, errors[1].index);
237  CPPUNIT_ASSERT_EQUAL("testObjects"s, string(errors[1].member));
238  CPPUNIT_ASSERT_EQUAL("[document]"s, string(errors[1].record));
239  CPPUNIT_ASSERT_EQUAL(JsonDeserializationErrorKind::TypeMismatch, errors[2].kind);
240  CPPUNIT_ASSERT_EQUAL(JsonType::Number, errors[2].expectedType);
241  CPPUNIT_ASSERT_EQUAL(JsonType::String, errors[2].actualType);
242  CPPUNIT_ASSERT_EQUAL("numbers"s, string(errors[2].member));
243  CPPUNIT_ASSERT_EQUAL("[document]"s, string(errors[2].record));
244  CPPUNIT_ASSERT_EQUAL(4_st, errors[2].index);
245  errors.clear();
246 
247  errors.throwOn = JsonDeserializationErrors::ThrowOn::TypeMismatch;
248  CPPUNIT_ASSERT_THROW(NestingObjectHana::fromJson("{\"name\":[],\"testObj\":\"this is not an object\"}", &errors), JsonDeserializationError);
249 }
void testHandlingTypeMismatch()
Tests whether JsonDeserializationError is thrown on type mismatch.
CPPUNIT_TEST_SUITE_REGISTRATION(JsonReflectorBoostHanaTests)
enum ReflectiveRapidJSON::JsonDeserializationErrors::ThrowOn throwOn
The JsonReflectorBoostHanaTests class tests the integration of Boost.Hana with the RapidJSON wrapper.
The JsonDeserializationErrors struct can be passed to fromJson() for error handling.
Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors=nullptr)
Deserializes the specified JSON to.
Definition: reflector.h:861
The JsonDeserializationError struct describes any errors of fromJson() except such caused by invalid ...
void testDeserializeSimpleObjects()
Tests deserializing simple objects.
The JsonSerializable class provides the CRTP-base for (de)serializable objects.
Definition: reflector.h:28
void testDeserializeNestedObjects()
Tests deserializing nested objects and arrays.
void testSerializeSimpleObjects()
Tests serializing objects.
void testSerializeNestedObjects()
Tests serializing nested object and arrays.