Reflection for RapidJSON  0.0.6
Reflection for serializing/deserializing with RapidJSON
binaryreflector.cpp
Go to the documentation of this file.
1 #include "../binary/reflector-chronoutilities.h"
2 #include "../binary/reflector.h"
3 #include "../binary/serializable.h"
4 
5 #include <c++utilities/conversion/stringbuilder.h>
6 #include <c++utilities/conversion/stringconversion.h>
7 #include <c++utilities/io/misc.h>
8 #include <c++utilities/tests/testutils.h>
9 
10 using TestUtilities::operator<<; // must be visible prior to the call site
11 #include <cppunit/TestFixture.h>
12 #include <cppunit/extensions/HelperMacros.h>
13 
14 #include <iostream>
15 #include <map>
16 #include <sstream>
17 #include <string>
18 #include <tuple>
19 #include <unordered_map>
20 #include <vector>
21 
22 using namespace std;
23 using namespace CPPUNIT_NS;
24 using namespace IoUtilities;
25 using namespace ChronoUtilities;
26 using namespace ConversionUtilities;
27 using namespace TestUtilities;
28 using namespace TestUtilities::Literals;
29 using namespace ReflectiveRapidJSON;
30 
32 
33 // define some enums and structs for testing serialization
34 enum SomeEnum {
35  SomeEnumItem1,
36  SomeEnumItem2,
37  SomeEnumItem3,
38 };
39 
40 enum class SomeEnumClass : uint16 {
41  Item1,
42  Item2,
43  Item3,
44 };
45 
46 struct TestObjectBinary : public BinarySerializable<TestObjectBinary> {
47  int number;
48  double number2;
49  vector<int> numbers;
50  string text;
51  bool boolean;
52  map<string, int> someMap;
53  unordered_map<string, bool> someHash;
54  set<string> someSet;
55  multiset<string> someMultiset;
56  unordered_set<string> someUnorderedSet;
57  unordered_multiset<string> someUnorderedMultiset;
58  SomeEnum someEnum;
59  SomeEnumClass someEnumClass;
60  TimeSpan timeSpan;
61  DateTime dateTime;
62 };
63 
64 struct NestingArrayBinary : public BinarySerializable<NestingArrayBinary> {
65  string name;
66  vector<TestObjectBinary> testObjects;
67 };
68 
69 // pretend serialization code for structs has been generated
70 namespace ReflectiveRapidJSON {
71 namespace BinaryReflector {
72 
73 template <> void readCustomType<TestObjectBinary>(BinaryDeserializer &deserializer, TestObjectBinary &customType)
74 {
75  deserializer.read(customType.number);
76  deserializer.read(customType.number2);
77  deserializer.read(customType.numbers);
78  deserializer.read(customType.text);
79  deserializer.read(customType.boolean);
80  deserializer.read(customType.someMap);
81  deserializer.read(customType.someHash);
82  deserializer.read(customType.someSet);
83  deserializer.read(customType.someMultiset);
84  deserializer.read(customType.someUnorderedSet);
85  deserializer.read(customType.someUnorderedMultiset);
86  deserializer.read(customType.someEnum);
87  deserializer.read(customType.someEnumClass);
88  deserializer.read(customType.timeSpan);
89  deserializer.read(customType.dateTime);
90 }
91 
92 template <> void writeCustomType<TestObjectBinary>(BinarySerializer &serializer, const TestObjectBinary &customType)
93 {
94  serializer.write(customType.number);
95  serializer.write(customType.number2);
96  serializer.write(customType.numbers);
97  serializer.write(customType.text);
98  serializer.write(customType.boolean);
99  serializer.write(customType.someMap);
100  serializer.write(customType.someHash);
101  serializer.write(customType.someSet);
102  serializer.write(customType.someMultiset);
103  serializer.write(customType.someUnorderedSet);
104  serializer.write(customType.someUnorderedMultiset);
105  serializer.write(customType.someEnum);
106  serializer.write(customType.someEnumClass);
107  serializer.write(customType.timeSpan);
108  serializer.write(customType.dateTime);
109 }
110 
111 template <> void readCustomType<NestingArrayBinary>(BinaryDeserializer &deserializer, NestingArrayBinary &customType)
112 {
113  deserializer.read(customType.name);
114  deserializer.read(customType.testObjects);
115 }
116 
117 template <> void writeCustomType<NestingArrayBinary>(BinarySerializer &serializer, const NestingArrayBinary &customType)
118 {
119  serializer.write(customType.name);
120  serializer.write(customType.testObjects);
121 }
122 
123 } // namespace BinaryReflector
124 
125 // namespace BinaryReflector
126 } // namespace ReflectiveRapidJSON
127 
129 
134 class BinaryReflectorTests : public TestFixture {
135  CPPUNIT_TEST_SUITE(BinaryReflectorTests);
136  CPPUNIT_TEST(testSerializeSimpleStruct);
137  CPPUNIT_TEST(testDeserializeSimpleStruct);
138  CPPUNIT_TEST(testSerializeNestedStruct);
139  CPPUNIT_TEST(testDeserializeNestedStruct);
140  CPPUNIT_TEST_SUITE_END();
141 
142 public:
144 
145  void setUp();
146  void tearDown();
147 
148  void testSerializeSimpleStruct();
149  void testDeserializeSimpleStruct();
150  void testSerializeNestedStruct();
151  void testDeserializeNestedStruct();
152  void assertTestObject(const TestObjectBinary &deserialized);
153 
154 private:
155  vector<unsigned char> m_buffer;
156  TestObjectBinary m_testObj;
157  NestingArrayBinary m_nestedTestObj;
158  vector<unsigned char> m_expectedTestObj;
159  vector<unsigned char> m_expectedNestedTestObj;
160 };
161 
163 
164 // clang-format off
166  : m_buffer()
167  , m_testObj()
168  , m_nestedTestObj()
169  , m_expectedTestObj({
170  0x00, 0x00, 0x00, 0x05,
171  0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
172  0x85,
173  0x00, 0x00, 0x00, 0x01,
174  0x00, 0x00, 0x00, 0x02,
175  0x00, 0x00, 0x00, 0x03,
176  0x00, 0x00, 0x00, 0x04,
177  0x00, 0x00, 0x00, 0x05,
178  0x89,
179  0x73, 0x6F, 0x6D, 0x65, 0x20, 0x74, 0x65, 0x78, 0x74,
180  0x01,
181  0x82,
182  0x83, 0x62, 0x61, 0x72, 0x00, 0x00, 0x00, 0x13,
183  0x83, 0x66, 0x6f, 0x6f, 0x00, 0x00, 0x00, 0x11,
184  0x80,
185  0x83,
186  0x81, 0x31,
187  0x81, 0x32,
188  0x81, 0x33,
189  0x84,
190  0x81, 0x31,
191  0x81, 0x32,
192  0x81, 0x32,
193  0x81, 0x33,
194  0x80,
195  0x80,
196  0x00, 0x00, 0x00, 0x01,
197  0x00, 0x02,
198  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xCD,
199  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xAB,
200  })
201  , m_expectedNestedTestObj({
202  0x93, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6e, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67,
203  0x82,
204  })
205 {
206 }
207 // clang-format on
208 
210 {
211  m_testObj.number = 5;
212  m_testObj.number2 = 2.5;
213  m_testObj.numbers = { 1, 2, 3, 4, 5 };
214  m_testObj.text = "some text";
215  m_testObj.boolean = true;
216  m_testObj.someMap = {
217  { "foo", 17 },
218  { "bar", 19 },
219  };
220  m_testObj.someSet = { "1", "2", "3", "2" };
221  m_testObj.someMultiset = { "1", "2", "3", "2" };
222  m_testObj.someEnum = SomeEnumItem2;
223  m_testObj.someEnumClass = SomeEnumClass::Item3;
224  m_testObj.timeSpan = TimeSpan(0xABCD);
225  m_testObj.dateTime = DateTime(0xEFAB);
226  m_nestedTestObj.name = "struct with nesting";
227  m_expectedNestedTestObj.reserve(m_expectedNestedTestObj.size() + 2 * m_expectedTestObj.size());
228  m_expectedNestedTestObj.insert(m_expectedNestedTestObj.end(), m_expectedTestObj.cbegin(), m_expectedTestObj.cend());
229  m_expectedNestedTestObj.insert(m_expectedNestedTestObj.end(), m_expectedTestObj.cbegin(), m_expectedTestObj.cend());
230  m_nestedTestObj.testObjects.insert(m_nestedTestObj.testObjects.end(), 2, m_testObj);
231 }
232 
234 {
235 }
236 
238 {
239  stringstream stream(ios_base::out | ios_base::binary);
240  stream.exceptions(ios_base::failbit | ios_base::badbit);
241  m_buffer.resize(m_expectedTestObj.size());
242  stream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(m_buffer.data()), static_cast<streamsize>(m_buffer.size()));
243  m_testObj.toBinary(stream);
244 
245  CPPUNIT_ASSERT_EQUAL(m_expectedTestObj, m_buffer);
246 }
247 
249 {
250  stringstream stream(ios_base::in | ios_base::binary);
251  stream.exceptions(ios_base::failbit | ios_base::badbit);
252  stream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(m_expectedTestObj.data()), static_cast<streamsize>(m_expectedTestObj.size()));
253  const auto deserialized(TestObjectBinary::fromBinary(stream));
254  assertTestObject(deserialized);
255 }
256 
258 {
259  stringstream stream(ios_base::out | ios_base::binary);
260  stream.exceptions(ios_base::failbit | ios_base::badbit);
261  m_buffer.resize(m_expectedNestedTestObj.size());
262  stream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(m_buffer.data()), static_cast<streamsize>(m_buffer.size()));
263  m_nestedTestObj.toBinary(stream);
264 
265  CPPUNIT_ASSERT_EQUAL(m_expectedNestedTestObj, m_buffer);
266 }
267 
269 {
270  stringstream stream(ios_base::in | ios_base::binary);
271  stream.exceptions(ios_base::failbit | ios_base::badbit);
272  stream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(m_expectedNestedTestObj.data()), static_cast<streamsize>(m_expectedNestedTestObj.size()));
273 
274  const auto deserialized(NestingArrayBinary::fromBinary(stream));
275  CPPUNIT_ASSERT_EQUAL(m_nestedTestObj.name, deserialized.name);
276  for (const auto &testObj : deserialized.testObjects) {
277  assertTestObject(testObj);
278  }
279 }
280 
281 void BinaryReflectorTests::assertTestObject(const TestObjectBinary &deserialized)
282 {
283  CPPUNIT_ASSERT_EQUAL(m_testObj.number, deserialized.number);
284  CPPUNIT_ASSERT_EQUAL(m_testObj.number2, deserialized.number2);
285  CPPUNIT_ASSERT_EQUAL(m_testObj.numbers, deserialized.numbers);
286  CPPUNIT_ASSERT_EQUAL(m_testObj.text, deserialized.text);
287  CPPUNIT_ASSERT_EQUAL(m_testObj.boolean, deserialized.boolean);
288  CPPUNIT_ASSERT_EQUAL(m_testObj.someMap, deserialized.someMap);
289  CPPUNIT_ASSERT_EQUAL(m_testObj.someHash, deserialized.someHash);
290  CPPUNIT_ASSERT_EQUAL(m_testObj.someSet, deserialized.someSet);
291  CPPUNIT_ASSERT_EQUAL(m_testObj.someMultiset, deserialized.someMultiset);
292  CPPUNIT_ASSERT_EQUAL(m_testObj.someUnorderedSet, deserialized.someUnorderedSet);
293  CPPUNIT_ASSERT_EQUAL(m_testObj.someUnorderedMultiset, deserialized.someUnorderedMultiset);
294 }
CPPUNIT_TEST_SUITE_REGISTRATION(BinaryReflectorTests)
STL namespace.
void assertTestObject(const TestObjectBinary &deserialized)
The BinaryReflectorTests class tests the (de)serializer.
The BinarySerializable class provides the CRTP-base for (de)serializable objects. ...
Definition: reflector.h:33