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 // cmake/test.cmake selects the C++ standard versions with which to build a
10 // unit test based on the presence of JSON_HAS_CPP_<VERSION> macros.
11 // When using macros that are only defined for particular versions of the standard
12 // (e.g., JSON_HAS_FILESYSTEM for C++17 and up), please mention the corresponding
13 // version macro in a comment close by, like this:
14 // JSON_HAS_CPP_<VERSION> (do not remove; see note at top of file)
15
16 #include "doctest_compatibility.h"
17
18 // for some reason including this after the json header leads to linker errors with VS 2017...
19 #include <locale>
20
21 #define JSON_TESTS_PRIVATE
22 #include <nlohmann/json.hpp>
23 using json = nlohmann::json;
24 using ordered_json = nlohmann::ordered_json;
25 #ifdef JSON_TEST_NO_GLOBAL_UDLS
26 using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
27 #endif
28
29 #include <cstdio>
30 #include <list>
31 #include <type_traits>
32 #include <utility>
33
34 #ifdef JSON_HAS_CPP_17
35 #include <any>
36 #include <variant>
37 #endif
38
39 #ifdef JSON_HAS_CPP_20
40 #include <span>
41 #endif
42
43 // NLOHMANN_JSON_SERIALIZE_ENUM uses a static std::pair
44 DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
45 DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors")
46
47 /////////////////////////////////////////////////////////////////////
48 // for #1021
49 /////////////////////////////////////////////////////////////////////
50
51 using float_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, float>;
52
53 /////////////////////////////////////////////////////////////////////
54 // for #1647
55 /////////////////////////////////////////////////////////////////////
56 namespace
57 {
58 struct NonDefaultFromJsonStruct
59 {};
60
operator ==(NonDefaultFromJsonStruct const &,NonDefaultFromJsonStruct const &)61 inline bool operator==(NonDefaultFromJsonStruct const& /*unused*/, NonDefaultFromJsonStruct const& /*unused*/)
62 {
63 return true;
64 }
65
66 enum class for_1647
67 {
68 one,
69 two
70 };
71
72 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays): this is a false positive
73 NLOHMANN_JSON_SERIALIZE_ENUM(for_1647,
74 {
75 {for_1647::one, "one"},
76 {for_1647::two, "two"},
77 })
78 } // namespace
79
80 /////////////////////////////////////////////////////////////////////
81 // for #1299
82 /////////////////////////////////////////////////////////////////////
83
84 struct Data
85 {
86 Data() = default;
DataData87 Data(std::string a_, std::string b_)
88 : a(std::move(a_))
89 , b(std::move(b_))
90 {}
91 std::string a{};
92 std::string b{};
93 };
94
95 void from_json(const json& j, Data& data);
from_json(const json & j,Data & data)96 void from_json(const json& j, Data& data)
97 {
98 j["a"].get_to(data.a);
99 j["b"].get_to(data.b);
100 }
101
102 bool operator==(Data const& lhs, Data const& rhs);
operator ==(Data const & lhs,Data const & rhs)103 bool operator==(Data const& lhs, Data const& rhs)
104 {
105 return lhs.a == rhs.a && lhs.b == rhs.b;
106 }
107
108 //bool operator!=(Data const& lhs, Data const& rhs)
109 //{
110 // return !(lhs == rhs);
111 //}
112
113 namespace nlohmann
114 {
115 template<>
116 struct adl_serializer<NonDefaultFromJsonStruct>
117 {
from_jsonnlohmann::adl_serializer118 static NonDefaultFromJsonStruct from_json(json const& /*unused*/) noexcept
119 {
120 return {};
121 }
122 };
123 } // namespace nlohmann
124
125 /////////////////////////////////////////////////////////////////////
126 // for #1805
127 /////////////////////////////////////////////////////////////////////
128
129 struct NotSerializableData
130 {
131 int mydata;
132 float myfloat;
133 };
134
135 /////////////////////////////////////////////////////////////////////
136 // for #2574
137 /////////////////////////////////////////////////////////////////////
138
139 struct NonDefaultConstructible
140 {
NonDefaultConstructibleNonDefaultConstructible141 explicit NonDefaultConstructible(int a)
142 : x(a)
143 {}
144 int x;
145 };
146
147 namespace nlohmann
148 {
149 template<>
150 struct adl_serializer<NonDefaultConstructible>
151 {
from_jsonnlohmann::adl_serializer152 static NonDefaultConstructible from_json(json const& j)
153 {
154 return NonDefaultConstructible(j.get<int>());
155 }
156 };
157 } // namespace nlohmann
158
159 /////////////////////////////////////////////////////////////////////
160 // for #2824
161 /////////////////////////////////////////////////////////////////////
162
163 class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json>
164 {
165 public:
sax_no_exception(json & j)166 explicit sax_no_exception(json& j)
167 : nlohmann::detail::json_sax_dom_parser<json>(j, false)
168 {}
169
parse_error(std::size_t,const std::string &,const json::exception & ex)170 static bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex)
171 {
172 error_string = new std::string(ex.what()); // NOLINT(cppcoreguidelines-owning-memory)
173 return false;
174 }
175
176 static std::string* error_string;
177 };
178
179 std::string* sax_no_exception::error_string = nullptr;
180
181 /////////////////////////////////////////////////////////////////////
182 // for #2982
183 /////////////////////////////////////////////////////////////////////
184
185 template<class T>
186 class my_allocator : public std::allocator<T>
187 {
188 public:
189 using std::allocator<T>::allocator;
190 };
191
192 /////////////////////////////////////////////////////////////////////
193 // for #3077
194 /////////////////////////////////////////////////////////////////////
195
196 class FooAlloc
197 {};
198
199 class Foo
200 {
201 public:
Foo(const FooAlloc &=FooAlloc ())202 explicit Foo(const FooAlloc& /* unused */ = FooAlloc()) {}
203
204 bool value = false;
205 };
206
207 class FooBar
208 {
209 public:
210 Foo foo{};
211 };
212
from_json(const nlohmann::json & j,FooBar & fb)213 inline void from_json(const nlohmann::json& j, FooBar& fb)
214 {
215 j.at("value").get_to(fb.foo.value);
216 }
217
218 /////////////////////////////////////////////////////////////////////
219 // for #3171
220 /////////////////////////////////////////////////////////////////////
221
222 struct for_3171_base // NOLINT(cppcoreguidelines-special-member-functions)
223 {
for_3171_basefor_3171_base224 for_3171_base(const std::string& /*unused*/ = {}) {}
225 virtual ~for_3171_base() = default;
226
_from_jsonfor_3171_base227 virtual void _from_json(const json& j)
228 {
229 j.at("str").get_to(str);
230 }
231
232 std::string str{};
233 };
234
235 struct for_3171_derived : public for_3171_base
236 {
237 for_3171_derived() = default;
for_3171_derivedfor_3171_derived238 explicit for_3171_derived(const std::string& /*unused*/) { }
239 };
240
from_json(const json & j,for_3171_base & tb)241 inline void from_json(const json& j, for_3171_base& tb)
242 {
243 tb._from_json(j);
244 }
245
246 /////////////////////////////////////////////////////////////////////
247 // for #3312
248 /////////////////////////////////////////////////////////////////////
249
250 #ifdef JSON_HAS_CPP_20
251 struct for_3312
252 {
253 std::string name;
254 };
255
from_json(const json & j,for_3312 & obj)256 inline void from_json(const json& j, for_3312& obj)
257 {
258 j.at("name").get_to(obj.name);
259 }
260 #endif
261
262 /////////////////////////////////////////////////////////////////////
263 // for #3204
264 /////////////////////////////////////////////////////////////////////
265
266 struct for_3204_foo
267 {
268 for_3204_foo() = default;
for_3204_foofor_3204_foo269 explicit for_3204_foo(std::string /*unused*/) {} // NOLINT(performance-unnecessary-value-param)
270 };
271
272 struct for_3204_bar
273 {
274 enum constructed_from_t
275 {
276 constructed_from_none = 0,
277 constructed_from_foo = 1,
278 constructed_from_json = 2
279 };
280
for_3204_barfor_3204_bar281 explicit for_3204_bar(std::function<void(for_3204_foo)> /*unused*/) noexcept // NOLINT(performance-unnecessary-value-param)
282 : constructed_from(constructed_from_foo) {}
for_3204_barfor_3204_bar283 explicit for_3204_bar(std::function<void(json)> /*unused*/) noexcept // NOLINT(performance-unnecessary-value-param)
284 : constructed_from(constructed_from_json) {}
285
286 constructed_from_t constructed_from = constructed_from_none;
287 };
288
289 /////////////////////////////////////////////////////////////////////
290 // for #3333
291 /////////////////////////////////////////////////////////////////////
292
293 struct for_3333 final
294 {
for_3333for_3333295 for_3333(int x_ = 0, int y_ = 0) : x(x_), y(y_) {}
296
297 template <class T>
for_3333for_3333298 for_3333(const T& /*unused*/)
299 {
300 CHECK(false);
301 }
302
303 int x = 0;
304 int y = 0;
305 };
306
307 template <>
for_3333(const json & j)308 inline for_3333::for_3333(const json& j)
309 : for_3333(j.value("x", 0), j.value("y", 0))
310 {}
311
312 TEST_CASE("regression tests 2")
313 {
314 SECTION("issue #1001 - Fix memory leak during parser callback")
315 {
316 const auto* geojsonExample = R"(
317 { "type": "FeatureCollection",
318 "features": [
319 { "type": "Feature",
320 "geometry": {"type": "Point", "coordinates": [102.0, 0.5]},
321 "properties": {"prop0": "value0"}
322 },
323 { "type": "Feature",
324 "geometry": {
325 "type": "LineString",
326 "coordinates": [
327 [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]
328 ]
329 },
330 "properties": {
331 "prop0": "value0",
332 "prop1": 0.0
333 }
334 },
335 { "type": "Feature",
336 "geometry": {
337 "type": "Polygon",
338 "coordinates": [
339 [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],
340 [100.0, 1.0], [100.0, 0.0] ]
341 ]
342 },
343 "properties": {
344 "prop0": "value0",
345 "prop1": {"this": "that"}
346 }
347 }
348 ]
349 })";
350
351 json::parser_callback_t cb = [&](int /*level*/, json::parse_event_t event, json & parsed) noexcept
__anon41d717960202(int , json::parse_event_t event, json & parsed) 352 {
353 // skip uninteresting events
354 if (event == json::parse_event_t::value && !parsed.is_primitive())
355 {
356 return false;
357 }
358
359 switch (event)
360 {
361 case json::parse_event_t::key:
362 {
363 return true;
364 }
365 case json::parse_event_t::value:
366 {
367 return false;
368 }
369 case json::parse_event_t::object_start:
370 {
371 return true;
372 }
373 case json::parse_event_t::object_end:
374 {
375 return false;
376 }
377 case json::parse_event_t::array_start:
378 {
379 return true;
380 }
381 case json::parse_event_t::array_end:
382 {
383 return false;
384 }
385
386 default:
387 {
388 return true;
389 }
390 }
391 };
392
393 auto j = json::parse(geojsonExample, cb, true);
394 CHECK(j == json());
395 }
396
397 SECTION("issue #1021 - to/from_msgpack only works with standard typization")
398 {
399 float_json j = 1000.0;
400 CHECK(float_json::from_cbor(float_json::to_cbor(j)) == j);
401 CHECK(float_json::from_msgpack(float_json::to_msgpack(j)) == j);
402 CHECK(float_json::from_ubjson(float_json::to_ubjson(j)) == j);
403
404 float_json j2 = {1000.0, 2000.0, 3000.0};
405 CHECK(float_json::from_ubjson(float_json::to_ubjson(j2, true, true)) == j2);
406 }
407
408 SECTION("issue #1045 - Using STL algorithms with JSON containers with expected results?")
409 {
410 json diffs = nlohmann::json::array();
411 json m1{{"key1", 42}};
412 json m2{{"key2", 42}};
413 auto p1 = m1.items();
414 auto p2 = m2.items();
415
416 using it_type = decltype(p1.begin());
417
418 std::set_difference(
419 p1.begin(),
420 p1.end(),
421 p2.begin(),
422 p2.end(),
423 std::inserter(diffs, diffs.end()),
424 [&](const it_type & e1, const it_type & e2) -> bool
__anon41d717960302(const it_type & e1, const it_type & e2) 425 {
426 using comper_pair = std::pair<std::string, decltype(e1.value())>; // Trying to avoid unneeded copy
427 return comper_pair(e1.key(), e1.value()) < comper_pair(e2.key(), e2.value()); // Using pair comper
428 });
429
430 CHECK(diffs.size() == 1); // Note the change here, was 2
431 }
432
433 #ifdef JSON_HAS_CPP_17
434 SECTION("issue #1292 - Serializing std::variant causes stack overflow")
435 {
436 static_assert(!std::is_constructible<json, std::variant<int, float>>::value, "unexpected value");
437 }
438 #endif
439
440 SECTION("issue #1299 - compile error in from_json converting to container "
441 "with std::pair")
442 {
443 json j =
444 {
445 {"1", {{"a", "testa_1"}, {"b", "testb_1"}}},
446 {"2", {{"a", "testa_2"}, {"b", "testb_2"}}},
447 {"3", {{"a", "testa_3"}, {"b", "testb_3"}}},
448 };
449
450 std::map<std::string, Data> expected
451 {
452 {"1", {"testa_1", "testb_1"}},
453 {"2", {"testa_2", "testb_2"}},
454 {"3", {"testa_3", "testb_3"}},
455 };
456 const auto data = j.get<decltype(expected)>();
457 CHECK(expected == data);
458 }
459
460 SECTION("issue #1445 - buffer overflow in dumping invalid utf-8 strings")
461 {
462 SECTION("a bunch of -1, ensure_ascii=true")
463 {
464 const auto length = 300;
465
466 json dump_test;
467 dump_test["1"] = std::string(length, -1);
468
469 std::string expected = R"({"1":")";
470 for (int i = 0; i < length; ++i)
471 {
472 expected += "\\ufffd";
473 }
474 expected += "\"}";
475
476 auto s = dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace);
477 CHECK(s == expected);
478 }
479 SECTION("a bunch of -2, ensure_ascii=false")
480 {
481 const auto length = 500;
482
483 json dump_test;
484 dump_test["1"] = std::string(length, -2);
485
486 std::string expected = R"({"1":")";
487 for (int i = 0; i < length; ++i)
488 {
489 expected += "\xEF\xBF\xBD";
490 }
491 expected += "\"}";
492
493 auto s = dump_test.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
494 CHECK(s == expected);
495 }
496 SECTION("test case in issue #1445")
497 {
498 nlohmann::json dump_test;
499 const std::array<int, 108> data =
500 {
501 {109, 108, 103, 125, -122, -53, 115, 18, 3, 0, 102, 19, 1, 15, -110, 13, -3, -1, -81, 32, 2, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -80, 2, 0, 0, 96, -118, 46, -116, 46, 109, -84, -87, 108, 14, 109, -24, -83, 13, -18, -51, -83, -52, -115, 14, 6, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 3, 0, 0, 0, 35, -74, -73, 55, 57, -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, -96, -54, -28, -26}
502 };
503 std::string s;
504 for (int i : data)
505 {
506 s += static_cast<char>(i);
507 }
508 dump_test["1"] = s;
509 dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace);
510 }
511 }
512
513 SECTION("issue #1447 - Integer Overflow (OSS-Fuzz 12506)")
514 {
515 json j = json::parse("[-9223372036854775808]");
516 CHECK(j.dump() == "[-9223372036854775808]");
517 }
518
519 SECTION("issue #1708 - minimum value of int64_t can be outputted")
520 {
521 constexpr auto smallest = (std::numeric_limits<int64_t>::min)();
522 json j = smallest;
523 CHECK(j.dump() == std::to_string(smallest));
524 }
525
526 SECTION("issue #1727 - Contains with non-const lvalue json_pointer picks the wrong overload")
527 {
528 json j = {{"root", {{"settings", {{"logging", true}}}}}};
529
530 auto jptr1 = "/root/settings/logging"_json_pointer;
531 auto jptr2 = json::json_pointer{"/root/settings/logging"};
532
533 CHECK(j.contains(jptr1));
534 CHECK(j.contains(jptr2));
535 }
536
537 SECTION("issue #1647 - compile error when deserializing enum if both non-default from_json and non-member operator== exists for other type")
538 {
539 // does not compile on ICPC when targeting C++20
540 #if !(defined(__INTEL_COMPILER) && __cplusplus >= 202000)
541 {
542 json j;
543 NonDefaultFromJsonStruct x(j);
544 NonDefaultFromJsonStruct y;
545 CHECK(x == y);
546 }
547 #endif
548
549 auto val = nlohmann::json("one").get<for_1647>();
550 CHECK(val == for_1647::one);
551 json j = val;
552 }
553
554 SECTION("issue #1715 - json::from_cbor does not respect allow_exceptions = false when input is string literal")
555 {
556 SECTION("string literal")
557 {
558 json cbor = json::from_cbor("B", true, false);
559 CHECK(cbor.is_discarded());
560 }
561
562 SECTION("string array")
563 {
564 const std::array<char, 2> input = {{'B', 0x00}};
565 json cbor = json::from_cbor(input, true, false);
566 CHECK(cbor.is_discarded());
567 }
568
569 SECTION("std::string")
570 {
571 json cbor = json::from_cbor(std::string("B"), true, false);
572 CHECK(cbor.is_discarded());
573 }
574 }
575
576 SECTION("issue #1805 - A pair<T1, T2> is json constructible only if T1 and T2 are json constructible")
577 {
578 static_assert(!std::is_constructible<json, std::pair<std::string, NotSerializableData>>::value, "unexpected result");
579 static_assert(!std::is_constructible<json, std::pair<NotSerializableData, std::string>>::value, "unexpected result");
580 static_assert(std::is_constructible<json, std::pair<int, std::string>>::value, "unexpected result");
581 }
582 SECTION("issue #1825 - A tuple<Args..> is json constructible only if all T in Args are json constructible")
583 {
584 static_assert(!std::is_constructible<json, std::tuple<std::string, NotSerializableData>>::value, "unexpected result");
585 static_assert(!std::is_constructible<json, std::tuple<NotSerializableData, std::string>>::value, "unexpected result");
586 static_assert(std::is_constructible<json, std::tuple<int, std::string>>::value, "unexpected result");
587 }
588
589 SECTION("issue #1983 - JSON patch diff for op=add formation is not as per standard (RFC 6902)")
590 {
591 const auto source = R"({ "foo": [ "1", "2" ] })"_json;
592 const auto target = R"({"foo": [ "1", "2", "3" ]})"_json;
593 const auto result = json::diff(source, target);
594 CHECK(result.dump() == R"([{"op":"add","path":"/foo/-","value":"3"}])");
595 }
596
597 SECTION("issue #2067 - cannot serialize binary data to text JSON")
598 {
599 const std::array<unsigned char, 23> data = {{0x81, 0xA4, 0x64, 0x61, 0x74, 0x61, 0xC4, 0x0F, 0x33, 0x30, 0x30, 0x32, 0x33, 0x34, 0x30, 0x31, 0x30, 0x37, 0x30, 0x35, 0x30, 0x31, 0x30}};
600 json j = json::from_msgpack(data.data(), data.size());
601 CHECK_NOTHROW(
602 j.dump(4, // Indent
603 ' ', // Indent char
604 false, // Ensure ascii
605 json::error_handler_t::strict // Error
606 ));
607 }
608
609 SECTION("PR #2181 - regression bug with lvalue")
610 {
611 // see https://github.com/nlohmann/json/pull/2181#issuecomment-653326060
612 json j{{"x", "test"}};
613 std::string defval = "default value";
614 auto val = j.value("x", defval);
615 auto val2 = j.value("y", defval);
616 }
617
618 SECTION("issue #2293 - eof doesn't cause parsing to stop")
619 {
620 std::vector<uint8_t> data =
621 {
622 0x7B,
623 0x6F,
624 0x62,
625 0x6A,
626 0x65,
627 0x63,
628 0x74,
629 0x20,
630 0x4F,
631 0x42
632 };
633 json result = json::from_cbor(data, true, false);
634 CHECK(result.is_discarded());
635 }
636
637 SECTION("issue #2315 - json.update and vector<pair>does not work with ordered_json")
638 {
639 nlohmann::ordered_json jsonAnimals = {{"animal", "dog"}};
640 nlohmann::ordered_json jsonCat = {{"animal", "cat"}};
641 jsonAnimals.update(jsonCat);
642 CHECK(jsonAnimals["animal"] == "cat");
643
644 auto jsonAnimals_parsed = nlohmann::ordered_json::parse(jsonAnimals.dump());
645 CHECK(jsonAnimals == jsonAnimals_parsed);
646
647 std::vector<std::pair<std::string, int64_t>> intData = {std::make_pair("aaaa", 11),
648 std::make_pair("bbb", 222)
649 };
650 nlohmann::ordered_json jsonObj;
651 for (const auto& data : intData)
652 {
653 jsonObj[data.first] = data.second;
654 }
655 CHECK(jsonObj["aaaa"] == 11);
656 CHECK(jsonObj["bbb"] == 222);
657 }
658
659 SECTION("issue #2330 - ignore_comment=true fails on multiple consecutive lines starting with comments")
660 {
661 std::string ss = "//\n//\n{\n}\n";
662 json j = json::parse(ss, nullptr, true, true);
663 CHECK(j.dump() == "{}");
664 }
665
666 #ifdef JSON_HAS_CPP_20
667 SECTION("issue #2546 - parsing containers of std::byte")
668 {
669 const char DATA[] = R"("Hello, world!")"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
670 const auto s = std::as_bytes(std::span(DATA));
671 json j = json::parse(s);
672 CHECK(j.dump() == "\"Hello, world!\"");
673 }
674 #endif
675
676 SECTION("issue #2574 - Deserialization to std::array, std::pair, and std::tuple with non-default constructable types fails")
677 {
678 SECTION("std::array")
679 {
680 {
681 json j = {7, 4};
682 auto arr = j.get<std::array<NonDefaultConstructible, 2>>();
683 CHECK(arr[0].x == 7);
684 CHECK(arr[1].x == 4);
685 }
686
687 {
688 json j = 7;
689 CHECK_THROWS_AS((j.get<std::array<NonDefaultConstructible, 1>>()), json::type_error);
690 }
691 }
692
693 SECTION("std::pair")
694 {
695 {
696 json j = {3, 8};
697 auto p = j.get<std::pair<NonDefaultConstructible, NonDefaultConstructible>>();
698 CHECK(p.first.x == 3);
699 CHECK(p.second.x == 8);
700 }
701
702 {
703 json j = {4, 1};
704 auto p = j.get<std::pair<int, NonDefaultConstructible>>();
705 CHECK(p.first == 4);
706 CHECK(p.second.x == 1);
707 }
708
709 {
710 json j = {6, 7};
711 auto p = j.get<std::pair<NonDefaultConstructible, int>>();
712 CHECK(p.first.x == 6);
713 CHECK(p.second == 7);
714 }
715
716 {
717 json j = 7;
718 CHECK_THROWS_AS((j.get<std::pair<NonDefaultConstructible, int>>()), json::type_error);
719 }
720 }
721
722 SECTION("std::tuple")
723 {
724 {
725 json j = {9};
726 auto t = j.get<std::tuple<NonDefaultConstructible>>();
727 CHECK(std::get<0>(t).x == 9);
728 }
729
730 {
731 json j = {9, 8, 7};
732 auto t = j.get<std::tuple<NonDefaultConstructible, int, NonDefaultConstructible>>();
733 CHECK(std::get<0>(t).x == 9);
734 CHECK(std::get<1>(t) == 8);
735 CHECK(std::get<2>(t).x == 7);
736 }
737
738 {
739 json j = 7;
740 CHECK_THROWS_AS((j.get<std::tuple<NonDefaultConstructible>>()), json::type_error);
741 }
742 }
743 }
744
745 SECTION("issue #2865 - ASAN detects memory leaks")
746 {
747 // the code below is expected to not leak memory
748 {
749 nlohmann::json o;
750 std::string s = "bar";
751
752 nlohmann::to_json(o["foo"], s);
753
754 nlohmann::json p = o;
755
756 // call to_json with a non-null JSON value
757 nlohmann::to_json(p["foo"], s);
758 }
759
760 {
761 nlohmann::json o;
762 std::string s = "bar";
763
764 nlohmann::to_json(o["foo"], s);
765
766 // call to_json with a non-null JSON value
767 nlohmann::to_json(o["foo"], s);
768 }
769 }
770
771 SECTION("issue #2824 - encoding of json::exception::what()")
772 {
773 json j;
774 sax_no_exception sax(j);
775
776 CHECK(!json::sax_parse("xyz", &sax));
777 CHECK(*sax_no_exception::error_string == "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'x'");
778 delete sax_no_exception::error_string; // NOLINT(cppcoreguidelines-owning-memory)
779 }
780
781 SECTION("issue #2825 - Properly constrain the basic_json conversion operator")
782 {
783 static_assert(std::is_copy_assignable<nlohmann::ordered_json>::value, "ordered_json must be copy assignable");
784 }
785
786 SECTION("issue #2958 - Inserting in unordered json using a pointer retains the leading slash")
787 {
788 std::string p = "/root";
789
790 json test1;
791 test1[json::json_pointer(p)] = json::object();
792 CHECK(test1.dump() == "{\"root\":{}}");
793
794 ordered_json test2;
795 test2[ordered_json::json_pointer(p)] = json::object();
796 CHECK(test2.dump() == "{\"root\":{}}");
797
798 // json::json_pointer and ordered_json::json_pointer are the same type; behave as above
799 ordered_json test3;
800 test3[json::json_pointer(p)] = json::object();
801 CHECK(std::is_same<json::json_pointer::string_t, ordered_json::json_pointer::string_t>::value);
802 CHECK(test3.dump() == "{\"root\":{}}");
803 }
804
805 SECTION("issue #2982 - to_{binary format} does not provide a mechanism for specifying a custom allocator for the returned type")
806 {
807 std::vector<std::uint8_t, my_allocator<std::uint8_t>> my_vector;
808 json j = {1, 2, 3, 4};
809 json::to_cbor(j, my_vector);
810 json k = json::from_cbor(my_vector);
811 CHECK(j == k);
812 }
813
814 #if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
815 // JSON_HAS_CPP_17 (do not remove; see note at top of file)
816 SECTION("issue #3070 - Version 3.10.3 breaks backward-compatibility with 3.10.2 ")
817 {
818 nlohmann::detail::std_fs::path text_path("/tmp/text.txt");
819 json j(text_path);
820
821 const auto j_path = j.get<nlohmann::detail::std_fs::path>();
822 CHECK(j_path == text_path);
823
824 #if DOCTEST_CLANG || DOCTEST_GCC >= DOCTEST_COMPILER(8, 4, 0)
825 // only known to work on Clang and GCC >=8.4
826 CHECK_THROWS_WITH_AS(nlohmann::detail::std_fs::path(json(1)), "[json.exception.type_error.302] type must be string, but is number", json::type_error);
827 #endif
828 }
829 #endif
830
831 SECTION("issue #3077 - explicit constructor with default does not compile")
832 {
833 json j;
834 j[0]["value"] = true;
835 std::vector<FooBar> foo;
836 j.get_to(foo);
837 }
838
839 SECTION("issue #3108 - ordered_json doesn't support range based erase")
840 {
841 ordered_json j = {1, 2, 2, 4};
842
843 auto last = std::unique(j.begin(), j.end());
844 j.erase(last, j.end());
845
846 CHECK(j.dump() == "[1,2,4]");
847
848 j.erase(std::remove_if(j.begin(), j.end(), [](const ordered_json & val)
__anon41d717960402(const ordered_json & val) 849 {
850 return val == 2;
851 }), j.end());
852
853 CHECK(j.dump() == "[1,4]");
854 }
855
856 SECTION("issue #3343 - json and ordered_json are not interchangable")
857 {
858 json::object_t jobj({ { "product", "one" } });
859 ordered_json::object_t ojobj({{"product", "one"}});
860
861 auto jit = jobj.begin();
862 auto ojit = ojobj.begin();
863
864 CHECK(jit->first == ojit->first);
865 CHECK(jit->second.get<std::string>() == ojit->second.get<std::string>());
866 }
867
868 SECTION("issue #3171 - if class is_constructible from std::string wrong from_json overload is being selected, compilation failed")
869 {
870 json j{{ "str", "value"}};
871
872 // failed with: error: no match for ‘operator=’ (operand types are ‘for_3171_derived’ and ‘const nlohmann::basic_json<>::string_t’
873 // {aka ‘const std::__cxx11::basic_string<char>’})
874 // s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
875 auto td = j.get<for_3171_derived>();
876
877 CHECK(td.str == "value");
878 }
879
880 #ifdef JSON_HAS_CPP_20
881 SECTION("issue #3312 - Parse to custom class from unordered_json breaks on G++11.2.0 with C++20")
882 {
883 // see test for #3171
884 ordered_json j = {{"name", "class"}};
885 for_3312 obj{};
886
887 j.get_to(obj);
888
889 CHECK(obj.name == "class");
890 }
891 #endif
892
893 #if defined(JSON_HAS_CPP_17) && JSON_USE_IMPLICIT_CONVERSIONS
894 SECTION("issue #3428 - Error occurred when converting nlohmann::json to std::any")
895 {
896 json j;
897 std::any a1 = j;
898 std::any&& a2 = j;
899
900 CHECK(a1.type() == typeid(j));
901 CHECK(a2.type() == typeid(j));
902 }
903 #endif
904
905 SECTION("issue #3204 - ambiguous regression")
906 {
__anon41d717960502(for_3204_foo) 907 for_3204_bar bar_from_foo([](for_3204_foo) noexcept {}); // NOLINT(performance-unnecessary-value-param)
__anon41d717960602(json) 908 for_3204_bar bar_from_json([](json) noexcept {}); // NOLINT(performance-unnecessary-value-param)
909
910 CHECK(bar_from_foo.constructed_from == for_3204_bar::constructed_from_foo);
911 CHECK(bar_from_json.constructed_from == for_3204_bar::constructed_from_json);
912 }
913
914 SECTION("issue #3333 - Ambiguous conversion from nlohmann::basic_json<> to custom class")
915 {
916 const json j
917 {
918 {"x", 1},
919 {"y", 2}
920 };
921 for_3333 p = j;
922
923 CHECK(p.x == 1);
924 CHECK(p.y == 2);
925 }
926 }
927
928 DOCTEST_CLANG_SUPPRESS_WARNING_POP
929