• 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 // 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