Reflection for RapidJSON 0.0.17
Reflection for serializing/deserializing with RapidJSON
Loading...
Searching...
No Matches
jsongenerator.cpp
Go to the documentation of this file.
1#include "./helper.h"
2#include "./structs.h"
3
4#include "../codefactory.h"
6
7#include "resources/config.h"
8
9#include <c++utilities/conversion/stringbuilder.h>
10#include <c++utilities/conversion/stringconversion.h>
11#include <c++utilities/io/misc.h>
12#include <c++utilities/tests/testutils.h>
13
14#include <cppunit/TestFixture.h>
15#include <cppunit/extensions/HelperMacros.h>
16
17#include <iostream>
18
19using namespace CPPUNIT_NS;
20using namespace CppUtilities;
21using namespace CppUtilities::Literals;
22
26class JsonGeneratorTests : public TestFixture {
27 CPPUNIT_TEST_SUITE(JsonGeneratorTests);
28 CPPUNIT_TEST(testGeneratorItself);
29 CPPUNIT_TEST(testCLI);
30 CPPUNIT_TEST(testIncludingGeneratedHeader);
31 CPPUNIT_TEST(testNesting);
32 CPPUNIT_TEST(testSingleInheritence);
33 CPPUNIT_TEST(testMultipleInheritence);
34 CPPUNIT_TEST(testCustomSerialization);
35 CPPUNIT_TEST(test3rdPartyAdaption);
36 CPPUNIT_TEST(testHandlingConstMembers);
37 CPPUNIT_TEST_SUITE_END();
38
39public:
42 void testCLI();
44 void testNesting();
50
51private:
52 const vector<string> m_expectedCode;
53};
54
56
58 : m_expectedCode(toArrayOfLines(readFile(testFilePath("some_structs_json_serialization.h"), 3 * 1024)))
59{
60}
61
66{
67 const auto inputFilePath = testFilePath("some_structs.h");
68 const auto inputFiles = vector<const char *>{ inputFilePath.data() };
69 const auto clangOptions
70 = vector<std::string_view>{ "-resource-dir", REFLECTION_GENERATOR_CLANG_RESOURCE_DIR, "-std=c++17", "-I", CPP_UTILITIES_INCLUDE_DIRS,
71#ifdef RAPIDJSON_INCLUDE_DIRS
72 "-I", RAPIDJSON_INCLUDE_DIRS
73#endif
74 };
75
76 stringstream buffer;
78 jsonOptions.additionalClassesArg.occurrenceInfo().emplace_back(0);
79 jsonOptions.additionalClassesArg.occurrenceInfo().back().values.emplace_back("TestNamespace2::ThirdPartyStruct");
80 CodeFactory factory(TestApplication::appPath(), inputFiles, clangOptions, buffer);
81 factory.addGenerator<JsonSerializationCodeGenerator>(jsonOptions);
82 CPPUNIT_ASSERT(factory.run());
83 assertEqualityLinewise(m_expectedCode, toArrayOfLines(buffer.str()));
84}
85
92{
93#ifdef PLATFORM_UNIX
94 string stdout, stderr;
95
96 const string inputFilePath(testFilePath("some_structs.h"));
97 const char *const args1[] = { PROJECT_NAME, "--input-file", inputFilePath.data(), "--json-classes", "TestNamespace2::ThirdPartyStruct",
98 "--clang-opt", "-resource-dir", REFLECTION_GENERATOR_CLANG_RESOURCE_DIR, "-std=c++17", "-I", CPP_UTILITIES_INCLUDE_DIRS,
99#ifdef RAPIDJSON_INCLUDE_DIRS
100 "-I", RAPIDJSON_INCLUDE_DIRS,
101#endif
102 nullptr };
103 TESTUTILS_ASSERT_EXEC(args1);
104 assertEqualityLinewise(m_expectedCode, toArrayOfLines(stdout));
105#endif
106}
107
113{
114 TestStruct test;
115 test.someInt = 42;
116 test.someSize = 0xAAAAAAAA;
117 test.someString = "the answer";
118 test.yetAnotherString = "but what was the question";
119 const string expectedJSON(
120 "{\"someInt\":42,\"someSize\":2863311530,\"someString\":\"the answer\",\"yetAnotherString\":\"but what was the question\"}");
121
122 // test serialization
123 CPPUNIT_ASSERT_EQUAL(expectedJSON, string(test.toJson().GetString()));
124
125 // test deserialization
126 const TestStruct parsedTest(TestStruct::fromJson(expectedJSON));
127 CPPUNIT_ASSERT_EQUAL(test.someInt, parsedTest.someInt);
128 CPPUNIT_ASSERT_EQUAL(test.someSize, parsedTest.someSize);
129 CPPUNIT_ASSERT_EQUAL(test.someString, parsedTest.someString);
130 CPPUNIT_ASSERT_EQUAL(test.yetAnotherString, parsedTest.yetAnotherString);
131}
132
137{
138 TestStruct test;
139 test.someInt = 42;
140 test.someSize = 0xAAAAAAAA;
141 test.someString = "the answer";
142 test.yetAnotherString = "but what was the question";
143 NestedTestStruct nested;
144 nested.nested.emplace_front(vector<TestStruct>{ test });
145 nested.deq.emplace_back(3.14);
146 const string expectedJSON(
147 "{\"nested\":[[{\"someInt\":42,\"someSize\":2863311530,\"someString\":\"the answer\",\"yetAnotherString\":\"but what was the "
148 "question\"}]],\"ptr\":null,\"deq\":[3.14]}");
149
150 // test serialization
151 CPPUNIT_ASSERT_EQUAL(expectedJSON, string(nested.toJson().GetString()));
152
153 // test deserialization
154 const NestedTestStruct parsedNested(NestedTestStruct::fromJson(expectedJSON));
155 CPPUNIT_ASSERT_EQUAL(1_st, parsedNested.nested.size());
156 CPPUNIT_ASSERT_EQUAL(1_st, parsedNested.nested.front().size());
157 CPPUNIT_ASSERT_EQUAL(1_st, parsedNested.deq.size());
158 const TestStruct &parsedTest(parsedNested.nested.front().front());
159 CPPUNIT_ASSERT_EQUAL(test.someInt, parsedTest.someInt);
160 CPPUNIT_ASSERT_EQUAL(test.someSize, parsedTest.someSize);
161 CPPUNIT_ASSERT_EQUAL(test.someString, parsedTest.someString);
162 CPPUNIT_ASSERT_EQUAL(test.yetAnotherString, parsedTest.yetAnotherString);
163 CPPUNIT_ASSERT_EQUAL(3.14, parsedNested.deq.front());
164}
165
170{
172 test.someInt = 42;
173 test.someSize = 5;
174 test.someString = "the answer";
175 test.yetAnotherString = "but what was the question";
176 test.someBool = false;
177 const string expectedJSONForBase(
178 "{\"someInt\":42,\"someSize\":5,\"someString\":\"the answer\",\"yetAnotherString\":\"but what was the question\"}");
179 const string expectedJSONForDerived(
180 "{\"someInt\":42,\"someSize\":5,\"someString\":\"the answer\",\"yetAnotherString\":\"but what was the question\",\"someBool\":false}");
181
182 // test serialization
183 CPPUNIT_ASSERT_EQUAL(expectedJSONForBase, string(as<TestStruct>(test).toJson().GetString()));
184 CPPUNIT_ASSERT_EQUAL(expectedJSONForDerived, string(as<DerivedTestStruct>(test).toJson().GetString()));
185
186 // test deserialization
187 const DerivedTestStruct parsedTest(JsonSerializable<DerivedTestStruct>::fromJson(expectedJSONForDerived));
188 CPPUNIT_ASSERT_EQUAL(test.someInt, parsedTest.someInt);
189 CPPUNIT_ASSERT_EQUAL(test.someSize, parsedTest.someSize);
190 CPPUNIT_ASSERT_EQUAL(test.someString, parsedTest.someString);
191 CPPUNIT_ASSERT_EQUAL(test.yetAnotherString, parsedTest.yetAnotherString);
192 CPPUNIT_ASSERT_EQUAL(test.someBool, parsedTest.someBool);
193}
194
199{
201 test.someInt = 42;
202 test.someSize = 4294967274;
203 test.someString = "the answer";
204 test.yetAnotherString = "but what was the question";
205 test.someBool = false;
206 test.arrayOfStrings = { "array", "of", "strings" };
207 const string expectedJSONForDerived(
208 "{\"someInt\":42,\"someSize\":4294967274,\"someString\":\"the answer\",\"yetAnotherString\":\"but what was the "
209 "question\",\"arrayOfStrings\":[\"array\",\"of\",\"strings\"],\"someBool\":false}");
210
211 // test serialization
212 CPPUNIT_ASSERT_EQUAL(expectedJSONForDerived, string(as<MultipleDerivedTestStruct>(test).toJson().GetString()));
213
214 // test deserialization
215 const MultipleDerivedTestStruct parsedTest(JsonSerializable<MultipleDerivedTestStruct>::fromJson(expectedJSONForDerived));
216 CPPUNIT_ASSERT_EQUAL(test.someInt, parsedTest.someInt);
217 CPPUNIT_ASSERT_EQUAL(test.someSize, parsedTest.someSize);
218 CPPUNIT_ASSERT_EQUAL(test.someString, parsedTest.someString);
219 CPPUNIT_ASSERT_EQUAL(test.yetAnotherString, parsedTest.yetAnotherString);
220 CPPUNIT_ASSERT_EQUAL(test.someBool, parsedTest.someBool);
221 CPPUNIT_ASSERT_EQUAL(test.arrayOfStrings, parsedTest.arrayOfStrings);
222}
223
228{
229 const StructWithCustomTypes test;
230 const string str("{\"dt\":\"2017-04-02T15:31:21.165125\",\"ts\":\"03:15:19.125\"}");
231
232 // test serialization
233 CPPUNIT_ASSERT_EQUAL(str, string(test.toJson().GetString()));
234
235 // test deserialization
236 const StructWithCustomTypes parsedTest(StructWithCustomTypes::fromJson(str));
237 CPPUNIT_ASSERT_EQUAL(test.dt.toString(), parsedTest.dt.toString());
238 CPPUNIT_ASSERT_EQUAL(test.ts.toString(), parsedTest.ts.toString());
239}
240
245{
246 // test whether specializations of AdaptedJsonSerializable are generated
247 static_assert(
248 ReflectiveRapidJSON::AdaptedJsonSerializable<NotJsonSerializable>::value, "can serialize NotJsonSerializable because of adaption macro");
249 static_assert(ReflectiveRapidJSON::AdaptedJsonSerializable<NestedNotJsonSerializable>::value,
250 "can serialize NestedNotJsonSerializable because of adaption macro");
251 static_assert(!ReflectiveRapidJSON::AdaptedJsonSerializable<OtherNotJsonSerializable>::value,
252 "can not serialize OtherNotJsonSerializable because adaption macro missing");
253 static_assert(!ReflectiveRapidJSON::AdaptedJsonSerializable<ReallyNotJsonSerializable>::value, "can not serialize ReallyNotJsonSerializable");
254
255 const NotJsonSerializable simple;
256 const string strSimple("{\"butSerializableAnyways\":\"useful to adapt 3rd party structs\"}");
257 const NestedNotJsonSerializable nested{ { "foo" }, { { "1" }, { "2" }, { "3" } }, { 42, { "bar" } } };
258 const string strNested("{\"asMember\":{\"butSerializableAnyways\":\"foo\"},\"asArrayElement\":[{\"butSerializableAnyways\":\"1\"},{"
259 "\"butSerializableAnyways\":\"2\"},{\"butSerializableAnyways\":\"3\"}],\"asTupleElement\":[42,{\"butSerializableAnyways\":"
260 "\"bar\"}]}");
261
262 // test serialization
263 CPPUNIT_ASSERT_EQUAL(strSimple, string(ReflectiveRapidJSON::JsonReflector::toJson(simple).GetString()));
264 CPPUNIT_ASSERT_EQUAL(strNested, string(ReflectiveRapidJSON::JsonReflector::toJson(nested).GetString()));
265
266 // test deserialization
267 JsonDeserializationErrors errors;
268 const auto parsedSimple(ReflectiveRapidJSON::JsonReflector::fromJson<NotJsonSerializable>(strSimple, &errors));
269 CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
270 CPPUNIT_ASSERT_EQUAL(simple.butSerializableAnyways, parsedSimple.butSerializableAnyways);
271 const auto parsedNested(ReflectiveRapidJSON::JsonReflector::fromJson<NestedNotJsonSerializable>(strNested, &errors));
272 CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
273 CPPUNIT_ASSERT_EQUAL(nested.asMember.butSerializableAnyways, parsedNested.asMember.butSerializableAnyways);
274 CPPUNIT_ASSERT_EQUAL(nested.asMember.butSerializableAnyways, parsedNested.asMember.butSerializableAnyways);
275 CPPUNIT_ASSERT_EQUAL(nested.asArrayElement.size(), parsedNested.asArrayElement.size());
276 CPPUNIT_ASSERT_EQUAL(nested.asArrayElement.at(0).butSerializableAnyways, parsedNested.asArrayElement.at(0).butSerializableAnyways);
277 CPPUNIT_ASSERT_EQUAL(nested.asArrayElement.at(1).butSerializableAnyways, parsedNested.asArrayElement.at(1).butSerializableAnyways);
278 CPPUNIT_ASSERT_EQUAL(nested.asArrayElement.at(2).butSerializableAnyways, parsedNested.asArrayElement.at(2).butSerializableAnyways);
279 CPPUNIT_ASSERT_EQUAL(get<0>(nested.asTupleElement), get<0>(parsedNested.asTupleElement));
280 CPPUNIT_ASSERT_EQUAL(get<1>(nested.asTupleElement).butSerializableAnyways, get<1>(parsedNested.asTupleElement).butSerializableAnyways);
281}
282
288{
289 ConstStruct constStruct;
290 constStruct.modifiableInt = 24;
291 const string strConstStruct("{\"modifiableInt\":24,\"constInt\":42}");
292 CPPUNIT_ASSERT_EQUAL(strConstStruct, string(constStruct.toJson().GetString()));
293
294 JsonDeserializationErrors errors;
295 auto parsedConstStruct(constStruct.fromJson(strConstStruct));
296 CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
297 CPPUNIT_ASSERT_EQUAL(24, parsedConstStruct.modifiableInt);
298 CPPUNIT_ASSERT_EQUAL(42, parsedConstStruct.constInt);
299}
300
301// include file required for reflection of TestStruct and other structs defined in structs.h
302// NOTE: * generation of this header is triggered using the CMake function add_reflection_generator_invocation()
303// * the include must happen in exactly one translation unit of the project at a point where the structs are defined
304#include "reflection/structs.h"
305
306// include file required for reflection of structs defined in morestructs.h
307// NOTE: this inclusion should not lead to multiple definition errors (despite the fact that structs.h included morestructs.h)
308#include "reflection/morestructs.h"
309
310// this file should also be generated via add_reflection_generator_invocation() and hence includeable
311// it is included to test the "empty" case when a unit doesn't contain relevant classes
312#include "reflection/visitor.h"
CPPUNIT_TEST_SUITE_REGISTRATION(BinaryGeneratorTests)
The JsonGeneratorTests class tests the overall functionality of the code generator (CLI and generator...
void testNesting()
Like testIncludingGeneratedHeader() but also for nested structures.
void testGeneratorItself()
Tests whether the generator works by using it directly.
void test3rdPartyAdaption()
Tests whether adapting (de)serialization for 3rd party structs works.
void testCLI()
Tests the generator CLI explicitly.
void testMultipleInheritence()
Like testIncludingGeneratedHeader() but also tests multiple inheritance.
void testIncludingGeneratedHeader()
Tests whether the generated reflection code actually works.
void testSingleInheritence()
Like testIncludingGeneratedHeader() but also tests single inheritance.
void testCustomSerialization()
Like testIncludingGeneratedHeader() but also tests custom (de)serialization.
void testHandlingConstMembers()
Tests whether const member variables are ignored when deserializing.
The CodeFactory class produces additional (reflection) code for a specified list of C++ source files.
Definition codefactory.h:27
bool run()
Reads (relevant) AST elements using Clang and generates code.
void addGenerator(Args &&...args)
Instantiates a code generator of the specified type and adds it to the current instance.
Definition codefactory.h:67
The JsonSerializationCodeGenerator class generates code for JSON (de)serialization of objects inherit...
void assertEqualityLinewise(const Iteratable &iteratable1, const Iteratable &iteratable2)
Asserts equality of two iteratables printing the differing indices.
Definition helper.h:19
vector< string > arrayOfStrings
Definition structs.h:68
The ConstStruct struct is used to test handling of const members.
Definition morestructs.h:30
int modifiableInt
Definition morestructs.h:31
The DerivedTestStruct struct inherits from JsonSerializable and should hence have functional fromJson...
Definition structs.h:75
The MultipleDerivedTestStruct struct inherits from JsonSerializable and should hence have functional ...
Definition structs.h:93
The NestedNotJsonSerializable struct is used to test (de)serialization for 3rd party structs (which d...
Definition structs.h:120
NotJsonSerializable asMember
Definition structs.h:121
tuple< int, NotJsonSerializable > asTupleElement
Definition structs.h:123
vector< NotJsonSerializable > asArrayElement
Definition structs.h:122
The NestedTestStruct struct inherits from JsonSerializable and should hence have functional fromJson(...
Definition structs.h:51
list< vector< TestStruct > > nested
Definition structs.h:56
The NotJsonSerializable struct is used to test (de)serialization for 3rd party structs (which do not ...
Definition structs.h:111
std::string butSerializableAnyways
Definition structs.h:112
The StructWithCustomTypes struct inherits from JsonSerializable and should hence have functional from...
Definition structs.h:101
CppUtilities::DateTime dt
Definition structs.h:102
CppUtilities::TimeSpan ts
Definition structs.h:103
The TestStruct struct inherits from JsonSerializable and should hence have functional fromJson() and ...
Definition structs.h:28
size_t someSize
Definition structs.h:30
string yetAnotherString
Definition structs.h:32
int someInt
Definition structs.h:29
string someString
Definition structs.h:31