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