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