• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //     __ _____ _____ _____
2 //  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
3 // |  |  |__   |  |  | | | |  version 3.11.2
4 // |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5 //
6 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
7 // SPDX-License-Identifier: MIT
8 
9 #include <string>
10 #include <vector>
11 #include "doctest_compatibility.h"
12 
13 #include <nlohmann/json.hpp>
14 using nlohmann::json;
15 
16 namespace persons
17 {
18 class person_with_private_data
19 {
20   private:
21     std::string name{};
22     int age = 0;
23     json metadata = nullptr;
24 
25   public:
operator ==(const person_with_private_data & rhs) const26     bool operator==(const person_with_private_data& rhs) const
27     {
28         return name == rhs.name && age == rhs.age && metadata == rhs.metadata;
29     }
30 
31     person_with_private_data() = default;
person_with_private_data(std::string name_,int age_,json metadata_)32     person_with_private_data(std::string name_, int age_, json metadata_)
33         : name(std::move(name_))
34         , age(age_)
35         , metadata(std::move(metadata_))
36     {}
37 
38     NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_with_private_data, age, name, metadata)
39 };
40 
41 class person_with_private_data_2
42 {
43   private:
44     std::string name{};
45     int age = 0;
46     json metadata = nullptr;
47 
48   public:
operator ==(const person_with_private_data_2 & rhs) const49     bool operator==(const person_with_private_data_2& rhs) const
50     {
51         return name == rhs.name && age == rhs.age && metadata == rhs.metadata;
52     }
53 
54     person_with_private_data_2() = default;
person_with_private_data_2(std::string name_,int age_,json metadata_)55     person_with_private_data_2(std::string name_, int age_, json metadata_)
56         : name(std::move(name_))
57         , age(age_)
58         , metadata(std::move(metadata_))
59     {}
60 
getName() const61     std::string getName() const
62     {
63         return name;
64     }
getAge() const65     int getAge() const
66     {
67         return age;
68     }
getMetadata() const69     json getMetadata() const
70     {
71         return metadata;
72     }
73 
74     NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(person_with_private_data_2, age, name, metadata)
75 };
76 
77 class person_without_private_data_1
78 {
79   public:
80     std::string name{};
81     int age = 0;
82     json metadata = nullptr;
83 
operator ==(const person_without_private_data_1 & rhs) const84     bool operator==(const person_without_private_data_1& rhs) const
85     {
86         return name == rhs.name && age == rhs.age && metadata == rhs.metadata;
87     }
88 
89     person_without_private_data_1() = default;
person_without_private_data_1(std::string name_,int age_,json metadata_)90     person_without_private_data_1(std::string name_, int age_, json metadata_)
91         : name(std::move(name_))
92         , age(age_)
93         , metadata(std::move(metadata_))
94     {}
95 
96     NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_without_private_data_1, age, name, metadata)
97 };
98 
99 class person_without_private_data_2
100 {
101   public:
102     std::string name{};
103     int age = 0;
104     json metadata = nullptr;
105 
operator ==(const person_without_private_data_2 & rhs) const106     bool operator==(const person_without_private_data_2& rhs) const
107     {
108         return name == rhs.name && age == rhs.age && metadata == rhs.metadata;
109     }
110 
111     person_without_private_data_2() = default;
person_without_private_data_2(std::string name_,int age_,json metadata_)112     person_without_private_data_2(std::string name_, int age_, json metadata_)
113         : name(std::move(name_))
114         , age(age_)
115         , metadata(std::move(metadata_))
116     {}
117 };
118 
119 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person_without_private_data_2, age, name, metadata)
120 
121 class person_without_private_data_3
122 {
123   public:
124     std::string name{};
125     int age = 0;
126     json metadata = nullptr;
127 
operator ==(const person_without_private_data_3 & rhs) const128     bool operator==(const person_without_private_data_3& rhs) const
129     {
130         return name == rhs.name && age == rhs.age && metadata == rhs.metadata;
131     }
132 
133     person_without_private_data_3() = default;
person_without_private_data_3(std::string name_,int age_,json metadata_)134     person_without_private_data_3(std::string name_, int age_, json metadata_)
135         : name(std::move(name_))
136         , age(age_)
137         , metadata(std::move(metadata_))
138     {}
139 
getName() const140     std::string getName() const
141     {
142         return name;
143     }
getAge() const144     int getAge() const
145     {
146         return age;
147     }
getMetadata() const148     json getMetadata() const
149     {
150         return metadata;
151     }
152 };
153 
154 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(person_without_private_data_3, age, name, metadata)
155 
156 class person_with_private_alphabet
157 {
158   public:
operator ==(const person_with_private_alphabet & other) const159     bool operator==(const person_with_private_alphabet& other) const
160     {
161         return  a == other.a &&
162                 b == other.b &&
163                 c == other.c &&
164                 d == other.d &&
165                 e == other.e &&
166                 f == other.f &&
167                 g == other.g &&
168                 h == other.h &&
169                 i == other.i &&
170                 j == other.j &&
171                 k == other.k &&
172                 l == other.l &&
173                 m == other.m &&
174                 n == other.n &&
175                 o == other.o &&
176                 p == other.p &&
177                 q == other.q &&
178                 r == other.r &&
179                 s == other.s &&
180                 t == other.t &&
181                 u == other.u &&
182                 v == other.v &&
183                 w == other.w &&
184                 x == other.x &&
185                 y == other.y &&
186                 z == other.z;
187     }
188 
189   private:
190     int a = 0;
191     int b = 0;
192     int c = 0;
193     int d = 0;
194     int e = 0;
195     int f = 0;
196     int g = 0;
197     int h = 0;
198     int i = 0;
199     int j = 0;
200     int k = 0;
201     int l = 0;
202     int m = 0;
203     int n = 0;
204     int o = 0;
205     int p = 0;
206     int q = 0;
207     int r = 0;
208     int s = 0;
209     int t = 0;
210     int u = 0;
211     int v = 0;
212     int w = 0;
213     int x = 0;
214     int y = 0;
215     int z = 0;
216     NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_with_private_alphabet, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z)
217 };
218 
219 class person_with_public_alphabet
220 {
221   public:
operator ==(const person_with_public_alphabet & other) const222     bool operator==(const person_with_public_alphabet& other) const
223     {
224         return  a == other.a &&
225                 b == other.b &&
226                 c == other.c &&
227                 d == other.d &&
228                 e == other.e &&
229                 f == other.f &&
230                 g == other.g &&
231                 h == other.h &&
232                 i == other.i &&
233                 j == other.j &&
234                 k == other.k &&
235                 l == other.l &&
236                 m == other.m &&
237                 n == other.n &&
238                 o == other.o &&
239                 p == other.p &&
240                 q == other.q &&
241                 r == other.r &&
242                 s == other.s &&
243                 t == other.t &&
244                 u == other.u &&
245                 v == other.v &&
246                 w == other.w &&
247                 x == other.x &&
248                 y == other.y &&
249                 z == other.z;
250     }
251 
252     int a = 0;
253     int b = 0;
254     int c = 0;
255     int d = 0;
256     int e = 0;
257     int f = 0;
258     int g = 0;
259     int h = 0;
260     int i = 0;
261     int j = 0;
262     int k = 0;
263     int l = 0;
264     int m = 0;
265     int n = 0;
266     int o = 0;
267     int p = 0;
268     int q = 0;
269     int r = 0;
270     int s = 0;
271     int t = 0;
272     int u = 0;
273     int v = 0;
274     int w = 0;
275     int x = 0;
276     int y = 0;
277     int z = 0;
278 };
279 
280 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person_with_public_alphabet, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z)
281 
282 } // namespace persons
283 
284 TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRUSIVE and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE", T,
285                    persons::person_with_private_data,
286                    persons::person_without_private_data_1,
287                    persons::person_without_private_data_2)
288 {
289     SECTION("person")
290     {
291         // serialization
292         T p1("Erik", 1, {{"haircuts", 2}});
293         CHECK(json(p1).dump() == "{\"age\":1,\"metadata\":{\"haircuts\":2},\"name\":\"Erik\"}");
294 
295         // deserialization
296         auto p2 = json(p1).get<T>();
297         CHECK(p2 == p1);
298 
299         // roundtrip
300         CHECK(T(json(p1)) == p1);
301         CHECK(json(T(json(p1))) == json(p1));
302 
303         // check exception in case of missing field
304         json j = json(p1);
305         j.erase("age");
306         CHECK_THROWS_WITH_AS(j.get<T>(), "[json.exception.out_of_range.403] key 'age' not found", json::out_of_range);
307     }
308 }
309 
310 TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT", T,
311                    persons::person_with_private_data_2,
312                    persons::person_without_private_data_3)
313 {
314     SECTION("person with default values")
315     {
316         // serialization of default constructed object
317         T p0;
318         CHECK(json(p0).dump() == "{\"age\":0,\"metadata\":null,\"name\":\"\"}");
319 
320         // serialization
321         T p1("Erik", 1, {{"haircuts", 2}});
322         CHECK(json(p1).dump() == "{\"age\":1,\"metadata\":{\"haircuts\":2},\"name\":\"Erik\"}");
323 
324         // deserialization
325         auto p2 = json(p1).get<T>();
326         CHECK(p2 == p1);
327 
328         // roundtrip
329         CHECK(T(json(p1)) == p1);
330         CHECK(json(T(json(p1))) == json(p1));
331 
332         // check default value in case of missing field
333         json j = json(p1);
334         j.erase("name");
335         j.erase("age");
336         j.erase("metadata");
337         T p3 = j.get<T>();
338         CHECK(p3.getName() == "");
339         CHECK(p3.getAge() == 0);
340         CHECK(p3.getMetadata() == nullptr);
341     }
342 }
343 
344 TEST_CASE_TEMPLATE("Serialization/deserialization of classes with 26 public/private member variables via NLOHMANN_DEFINE_TYPE_INTRUSIVE and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE", T,
345                    persons::person_with_private_alphabet,
346                    persons::person_with_public_alphabet)
347 {
348     SECTION("alphabet")
349     {
350         {
351             T obj1;
352             nlohmann::json j = obj1; //via json object
353             T obj2;
354             j.get_to(obj2);
355             bool ok = (obj1 == obj2);
356             CHECK(ok);
357         }
358 
359         {
360             T obj1;
361             nlohmann::json j1 = obj1; //via json string
362             std::string s = j1.dump();
363             nlohmann::json j2 = nlohmann::json::parse(s);
364             T obj2;
365             j2.get_to(obj2);
366             bool ok = (obj1 == obj2);
367             CHECK(ok);
368         }
369 
370         {
371             T obj1;
372             nlohmann::json j1 = obj1; //via msgpack
373             std::vector<uint8_t> buf = nlohmann::json::to_msgpack(j1);
374             nlohmann::json j2 = nlohmann::json::from_msgpack(buf);
375             T obj2;
376             j2.get_to(obj2);
377             bool ok = (obj1 == obj2);
378             CHECK(ok);
379         }
380 
381         {
382             T obj1;
383             nlohmann::json j1 = obj1; //via bson
384             std::vector<uint8_t> buf = nlohmann::json::to_bson(j1);
385             nlohmann::json j2 = nlohmann::json::from_bson(buf);
386             T obj2;
387             j2.get_to(obj2);
388             bool ok = (obj1 == obj2);
389             CHECK(ok);
390         }
391 
392         {
393             T obj1;
394             nlohmann::json j1 = obj1; //via cbor
395             std::vector<uint8_t> buf = nlohmann::json::to_cbor(j1);
396             nlohmann::json j2 = nlohmann::json::from_cbor(buf);
397             T obj2;
398             j2.get_to(obj2);
399             bool ok = (obj1 == obj2);
400             CHECK(ok);
401         }
402 
403         {
404             T obj1;
405             nlohmann::json j1 = obj1; //via ubjson
406             std::vector<uint8_t> buf = nlohmann::json::to_ubjson(j1);
407             nlohmann::json j2 = nlohmann::json::from_ubjson(buf);
408             T obj2;
409             j2.get_to(obj2);
410             bool ok = (obj1 == obj2);
411             CHECK(ok);
412         }
413     }
414 }
415