Reflection for RapidJSON  0.0.15
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 CppUtilities::operator<<; // must be visible prior to the call site
11 #include <cppunit/TestFixture.h>
12 #include <cppunit/extensions/HelperMacros.h>
13 
14 #include <cstdint>
15 #include <iostream>
16 #include <limits>
17 #include <map>
18 #include <sstream>
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 CppUtilities;
27 using namespace CppUtilities::Literals;
28 using namespace ReflectiveRapidJSON;
29 
31 
32 // define some enums and structs for testing serialization
33 enum SomeEnumBinary {
34  SomeEnumItem1,
35  SomeEnumItem2,
36  SomeEnumItem3,
37 };
38 
39 enum class SomeEnumClassBinary : std::uint16_t {
40  Item1,
41  Item2,
42  Item3,
43 };
44 
45 struct TestObjectBinary : public BinarySerializable<TestObjectBinary> {
46  int number;
47  double number2;
48  vector<int> numbers;
49  string text;
50  bool boolean;
51  map<string, int> someMap;
52  unordered_map<string, bool> someHash;
53  set<string> someSet;
54  multiset<string> someMultiset;
55  unordered_set<string> someUnorderedSet;
56  unordered_multiset<string> someUnorderedMultiset;
57  SomeEnumBinary someEnum;
58  SomeEnumClassBinary someEnumClass;
59  TimeSpan timeSpan;
60  DateTime dateTime;
61 };
62 
63 struct NestingArrayBinary : public BinarySerializable<NestingArrayBinary> {
64  string name;
65  vector<TestObjectBinary> testObjects;
66 };
67 
68 struct ObjectWithVariantsBinary : public BinarySerializable<ObjectWithVariantsBinary> {
69  variant<int, string, monostate> someVariant;
70  variant<string, float> anotherVariant;
71  variant<string, int> yetAnotherVariant;
72 };
73 
74 // pretend serialization code for structs has been generated
75 namespace ReflectiveRapidJSON {
76 namespace BinaryReflector {
77 
78 template <> void readCustomType<TestObjectBinary>(BinaryDeserializer &deserializer, TestObjectBinary &customType)
79 {
80  deserializer.read(customType.number);
81  deserializer.read(customType.number2);
82  deserializer.read(customType.numbers);
83  deserializer.read(customType.text);
84  deserializer.read(customType.boolean);
85  deserializer.read(customType.someMap);
86  deserializer.read(customType.someHash);
87  deserializer.read(customType.someSet);
88  deserializer.read(customType.someMultiset);
89  deserializer.read(customType.someUnorderedSet);
90  deserializer.read(customType.someUnorderedMultiset);
91  deserializer.read(customType.someEnum);
92  deserializer.read(customType.someEnumClass);
93  deserializer.read(customType.timeSpan);
94  deserializer.read(customType.dateTime);
95 }
96 
97 template <> void writeCustomType<TestObjectBinary>(BinarySerializer &serializer, const TestObjectBinary &customType)
98 {
99  serializer.write(customType.number);
100  serializer.write(customType.number2);
101  serializer.write(customType.numbers);
102  serializer.write(customType.text);
103  serializer.write(customType.boolean);
104  serializer.write(customType.someMap);
105  serializer.write(customType.someHash);
106  serializer.write(customType.someSet);
107  serializer.write(customType.someMultiset);
108  serializer.write(customType.someUnorderedSet);
109  serializer.write(customType.someUnorderedMultiset);
110  serializer.write(customType.someEnum);
111  serializer.write(customType.someEnumClass);
112  serializer.write(customType.timeSpan);
113  serializer.write(customType.dateTime);
114 }
115 
116 template <> void readCustomType<NestingArrayBinary>(BinaryDeserializer &deserializer, NestingArrayBinary &customType)
117 {
118  deserializer.read(customType.name);
119  deserializer.read(customType.testObjects);
120 }
121 
122 template <> void writeCustomType<NestingArrayBinary>(BinarySerializer &serializer, const NestingArrayBinary &customType)
123 {
124  serializer.write(customType.name);
125  serializer.write(customType.testObjects);
126 }
127 
128 template <> void readCustomType<ObjectWithVariantsBinary>(BinaryDeserializer &deserializer, ObjectWithVariantsBinary &customType)
129 {
130  deserializer.read(customType.someVariant);
131  deserializer.read(customType.anotherVariant);
132  deserializer.read(customType.yetAnotherVariant);
133 }
134 
135 template <> void writeCustomType<ObjectWithVariantsBinary>(BinarySerializer &serializer, const ObjectWithVariantsBinary &customType)
136 {
137  serializer.write(customType.someVariant);
138  serializer.write(customType.anotherVariant);
139  serializer.write(customType.yetAnotherVariant);
140 }
141 
142 } // namespace BinaryReflector
143 
144 // namespace BinaryReflector
145 } // namespace ReflectiveRapidJSON
146 
148 
153 class BinaryReflectorTests : public TestFixture {
154  CPPUNIT_TEST_SUITE(BinaryReflectorTests);
155  CPPUNIT_TEST(testSerializeSimpleStruct);
156  CPPUNIT_TEST(testDeserializeSimpleStruct);
157  CPPUNIT_TEST(testSerializeNestedStruct);
158  CPPUNIT_TEST(testDeserializeNestedStruct);
159  CPPUNIT_TEST(testSmallSharedPointer);
160  CPPUNIT_TEST(testBigSharedPointer);
161  CPPUNIT_TEST(testVariant);
162  CPPUNIT_TEST_SUITE_END();
163 
164 public:
166 
167  void setUp() override;
168  void tearDown() override;
169 
170  void testSerializeSimpleStruct();
171  void testDeserializeSimpleStruct();
172  void testSerializeNestedStruct();
173  void testDeserializeNestedStruct();
174  void assertTestObject(const TestObjectBinary &deserialized);
175  void testSharedPointer(std::uintptr_t fakePointer);
176  void testSmallSharedPointer();
177  void testBigSharedPointer();
178  void testVariant();
179 
180 private:
181  vector<unsigned char> m_buffer;
182  TestObjectBinary m_testObj;
183  NestingArrayBinary m_nestedTestObj;
184  vector<unsigned char> m_expectedTestObj;
185  vector<unsigned char> m_expectedNestedTestObj;
186 };
187 
189 
190 // clang-format off
192  : m_buffer()
193  , m_testObj()
194  , m_nestedTestObj()
195  , m_expectedTestObj({
196  0x00, 0x00, 0x00, 0x05,
197  0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198  0x85,
199  0x00, 0x00, 0x00, 0x01,
200  0x00, 0x00, 0x00, 0x02,
201  0x00, 0x00, 0x00, 0x03,
202  0x00, 0x00, 0x00, 0x04,
203  0x00, 0x00, 0x00, 0x05,
204  0x89,
205  0x73, 0x6F, 0x6D, 0x65, 0x20, 0x74, 0x65, 0x78, 0x74,
206  0x01,
207  0x82,
208  0x83, 0x62, 0x61, 0x72, 0x00, 0x00, 0x00, 0x13,
209  0x83, 0x66, 0x6f, 0x6f, 0x00, 0x00, 0x00, 0x11,
210  0x80,
211  0x83,
212  0x81, 0x31,
213  0x81, 0x32,
214  0x81, 0x33,
215  0x84,
216  0x81, 0x31,
217  0x81, 0x32,
218  0x81, 0x32,
219  0x81, 0x33,
220  0x80,
221  0x80,
222  0x00, 0x00, 0x00, 0x01,
223  0x00, 0x02,
224  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xCD,
225  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xAB,
226  })
227  , m_expectedNestedTestObj({
228  0x93, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6e, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67,
229  0x82,
230  })
231 {
232 }
233 // clang-format on
234 
236 {
237  m_testObj.number = 5;
238  m_testObj.number2 = 2.5;
239  m_testObj.numbers = { 1, 2, 3, 4, 5 };
240  m_testObj.text = "some text";
241  m_testObj.boolean = true;
242  m_testObj.someMap = {
243  { "foo", 17 },
244  { "bar", 19 },
245  };
246  m_testObj.someSet = { "1", "2", "3", "2" };
247  m_testObj.someMultiset = { "1", "2", "3", "2" };
248  m_testObj.someEnum = SomeEnumItem2;
249  m_testObj.someEnumClass = SomeEnumClassBinary::Item3;
250  m_testObj.timeSpan = TimeSpan(0xABCD);
251  m_testObj.dateTime = DateTime(0xEFAB);
252  m_nestedTestObj.name = "struct with nesting";
253  m_expectedNestedTestObj.reserve(m_expectedNestedTestObj.size() + 2 * m_expectedTestObj.size());
254  m_expectedNestedTestObj.insert(m_expectedNestedTestObj.end(), m_expectedTestObj.cbegin(), m_expectedTestObj.cend());
255  m_expectedNestedTestObj.insert(m_expectedNestedTestObj.end(), m_expectedTestObj.cbegin(), m_expectedTestObj.cend());
256  m_nestedTestObj.testObjects.insert(m_nestedTestObj.testObjects.end(), 2, m_testObj);
257 }
258 
260 {
261 }
262 
264 {
265  stringstream stream(ios_base::out | ios_base::binary);
266  stream.exceptions(ios_base::failbit | ios_base::badbit);
267  m_buffer.resize(m_expectedTestObj.size());
268  stream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(m_buffer.data()), static_cast<streamsize>(m_buffer.size()));
269  m_testObj.toBinary(stream);
270 
271  CPPUNIT_ASSERT_EQUAL(m_expectedTestObj, m_buffer);
272 }
273 
275 {
276  stringstream stream(ios_base::in | ios_base::binary);
277  stream.exceptions(ios_base::failbit | ios_base::badbit);
278  stream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(m_expectedTestObj.data()), static_cast<streamsize>(m_expectedTestObj.size()));
279  const auto deserialized(TestObjectBinary::fromBinary(stream));
280  assertTestObject(deserialized);
281 }
282 
284 {
285  stringstream stream(ios_base::out | ios_base::binary);
286  stream.exceptions(ios_base::failbit | ios_base::badbit);
287  m_buffer.resize(m_expectedNestedTestObj.size());
288  stream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(m_buffer.data()), static_cast<streamsize>(m_buffer.size()));
289  m_nestedTestObj.toBinary(stream);
290 
291  CPPUNIT_ASSERT_EQUAL(m_expectedNestedTestObj, m_buffer);
292 }
293 
295 {
296  stringstream stream(ios_base::in | ios_base::binary);
297  stream.exceptions(ios_base::failbit | ios_base::badbit);
298  stream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(m_expectedNestedTestObj.data()), static_cast<streamsize>(m_expectedNestedTestObj.size()));
299 
300  const auto deserialized(NestingArrayBinary::fromBinary(stream));
301  CPPUNIT_ASSERT_EQUAL(m_nestedTestObj.name, deserialized.name);
302  for (const auto &testObj : deserialized.testObjects) {
303  assertTestObject(testObj);
304  }
305 }
306 
307 void BinaryReflectorTests::assertTestObject(const TestObjectBinary &deserialized)
308 {
309  CPPUNIT_ASSERT_EQUAL(m_testObj.number, deserialized.number);
310  CPPUNIT_ASSERT_EQUAL(m_testObj.number2, deserialized.number2);
311  CPPUNIT_ASSERT_EQUAL(m_testObj.numbers, deserialized.numbers);
312  CPPUNIT_ASSERT_EQUAL(m_testObj.text, deserialized.text);
313  CPPUNIT_ASSERT_EQUAL(m_testObj.boolean, deserialized.boolean);
314  CPPUNIT_ASSERT_EQUAL(m_testObj.someMap, deserialized.someMap);
315  CPPUNIT_ASSERT_EQUAL(m_testObj.someHash, deserialized.someHash);
316  CPPUNIT_ASSERT_EQUAL(m_testObj.someSet, deserialized.someSet);
317  CPPUNIT_ASSERT_EQUAL(m_testObj.someMultiset, deserialized.someMultiset);
318  CPPUNIT_ASSERT_EQUAL(m_testObj.someUnorderedSet, deserialized.someUnorderedSet);
319  CPPUNIT_ASSERT_EQUAL(m_testObj.someUnorderedMultiset, deserialized.someUnorderedMultiset);
320 }
321 
322 void BinaryReflectorTests::testSharedPointer(uintptr_t fakePointer)
323 {
324  // create a shared pointer for the fake pointer ensuring that it is not actually deleted
325  shared_ptr<int> sharedPointer(reinterpret_cast<int *>(fakePointer), [](int *) {});
326 
327  // setup stream
328  stringstream stream(ios_base::in | ios_base::out | ios_base::binary);
329  stream.exceptions(ios_base::failbit | ios_base::badbit);
330 
331  // serialize the shared pointer assuming its contents have been written before (to prevent actually dereferencing it)
332  BinaryReflector::BinarySerializer serializer(&stream);
333  serializer.m_pointer[fakePointer] = true;
334  serializer.write(sharedPointer);
335 
336  // deserialize the shared pointer assuming it has already been read and the type does not match
337  BinaryReflector::BinaryDeserializer deserializer(&stream);
338  shared_ptr<int> readPtr;
339  deserializer.m_pointer[fakePointer] = "foo";
340  CPPUNIT_ASSERT_THROW(deserializer.read(readPtr), CppUtilities::ConversionException);
341  CPPUNIT_ASSERT(readPtr == nullptr);
342 
343  // deserialize the shared pointer assuming it has already been read and the type matches
344  stream.seekg(0);
345  deserializer.m_pointer[fakePointer] = make_shared<int>(42);
346  deserializer.read(readPtr);
347  CPPUNIT_ASSERT(readPtr != nullptr);
348  CPPUNIT_ASSERT_EQUAL(42, *readPtr);
349 }
350 
352 {
353  testSharedPointer(std::numeric_limits<std::uintptr_t>::min() + 1);
354 }
355 
357 {
358  testSharedPointer(std::numeric_limits<std::uintptr_t>::max());
359 }
360 
362 {
363  // create test object
364  ObjectWithVariantsBinary variants;
365  variants.someVariant = std::monostate{};
366  variants.anotherVariant = "foo";
367  variants.yetAnotherVariant = 42;
368 
369  // serialize test object
370  stringstream stream(ios_base::in | ios_base::out | ios_base::binary);
371  stream.exceptions(ios_base::failbit | ios_base::badbit);
372  variants.toBinary(stream);
373 
374  // deserialize the object again
375  const auto deserializedVariants = ObjectWithVariantsBinary::fromBinary(stream);
376 
377  CPPUNIT_ASSERT_EQUAL(2_st, deserializedVariants.someVariant.index());
378  CPPUNIT_ASSERT_EQUAL(0_st, deserializedVariants.anotherVariant.index());
379  CPPUNIT_ASSERT_EQUAL(1_st, deserializedVariants.yetAnotherVariant.index());
380  CPPUNIT_ASSERT_EQUAL("foo"s, get<0>(deserializedVariants.anotherVariant));
381  CPPUNIT_ASSERT_EQUAL(42, get<1>(deserializedVariants.yetAnotherVariant));
382 }
BinaryReflectorTests
The BinaryReflectorTests class tests the (de)serializer.
Definition: binaryreflector.cpp:153
BinaryReflectorTests::testSmallSharedPointer
void testSmallSharedPointer()
Definition: binaryreflector.cpp:351
CPPUNIT_TEST_SUITE_REGISTRATION
CPPUNIT_TEST_SUITE_REGISTRATION(BinaryReflectorTests)
BinaryReflectorTests::testDeserializeSimpleStruct
void testDeserializeSimpleStruct()
Definition: binaryreflector.cpp:274
ReflectiveRapidJSON::BinaryReflector::BinarySerializer
Definition: reflector.h:80
BinaryReflectorTests::testVariant
void testVariant()
Definition: binaryreflector.cpp:361
ReflectiveRapidJSON::BinaryReflector::BinarySerializer::write
void write(const Type &pair)
Definition: reflector.h:220
BinaryReflectorTests::testSerializeNestedStruct
void testSerializeNestedStruct()
Definition: binaryreflector.cpp:283
ReflectiveRapidJSON::BinaryReflector::BinaryDeserializer::read
void read(Type &pair)
Definition: reflector.h:104
BinaryReflectorTests::testSerializeSimpleStruct
void testSerializeSimpleStruct()
Definition: binaryreflector.cpp:263
ReflectiveRapidJSON
Definition: traits.h:13
BinaryReflectorTests::assertTestObject
void assertTestObject(const TestObjectBinary &deserialized)
Definition: binaryreflector.cpp:307
BinaryReflectorTests::tearDown
void tearDown() override
Definition: binaryreflector.cpp:259
ReflectiveRapidJSON::BinarySerializable
The BinarySerializable class provides the CRTP-base for (de)serializable objects.
Definition: reflector.h:36
BinaryReflectorTests::setUp
void setUp() override
Definition: binaryreflector.cpp:235
BinaryReflectorTests::testSharedPointer
void testSharedPointer(std::uintptr_t fakePointer)
Definition: binaryreflector.cpp:322
ReflectiveRapidJSON::BinaryReflector::BinaryDeserializer
Definition: reflector.h:56
BinaryReflectorTests::BinaryReflectorTests
BinaryReflectorTests()
Definition: binaryreflector.cpp:191
BinaryReflectorTests::testDeserializeNestedStruct
void testDeserializeNestedStruct()
Definition: binaryreflector.cpp:294
BinaryReflectorTests::testBigSharedPointer
void testBigSharedPointer()
Definition: binaryreflector.cpp:356