1//     __ _____ _____ _____
2//  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
3// |  |  |__   |  |  | | | |  version 3.11.2
4// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5//
6// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
7// SPDX-License-Identifier: MIT
8
9#include "doctest_compatibility.h"
10
11// for some reason including this after the json header leads to linker errors with VS 2017...
12#include <locale>
13
14#define JSON_TESTS_PRIVATE
15#include <nlohmann/json.hpp>
16using nlohmann::json;
17#ifdef JSON_TEST_NO_GLOBAL_UDLS
18    using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
19#endif
20
21#include <fstream>
22#include <sstream>
23#include <list>
24#include <cstdio>
25#include "make_test_data_available.hpp"
26
27#ifdef JSON_HAS_CPP_17
28    #include <variant>
29#endif
30
31#include "fifo_map.hpp"
32
33/////////////////////////////////////////////////////////////////////
34// for #972
35/////////////////////////////////////////////////////////////////////
36
37template<class K, class V, class dummy_compare, class A>
38using my_workaround_fifo_map = nlohmann::fifo_map<K, V, nlohmann::fifo_map_compare<K>, A>;
39using my_json = nlohmann::basic_json<my_workaround_fifo_map>;
40
41/////////////////////////////////////////////////////////////////////
42// for #977
43/////////////////////////////////////////////////////////////////////
44
45namespace ns
46{
47struct foo
48{
49    int x;
50};
51
52template <typename, typename SFINAE = void>
53struct foo_serializer;
54
55template<typename T>
56struct foo_serializer<T, typename std::enable_if<std::is_same<foo, T>::value>::type>
57{
58    template <typename BasicJsonType>
59    static void to_json(BasicJsonType& j, const T& value)
60    {
61        j = BasicJsonType{{"x", value.x}};
62    }
63    template <typename BasicJsonType>
64    static void from_json(const BasicJsonType& j, T& value)     // !!!
65    {
66        nlohmann::from_json(j.at("x"), value.x);
67    }
68};
69
70template<typename T>
71struct foo_serializer < T, typename std::enable_if < !std::is_same<foo, T>::value >::type >
72{
73    template <typename BasicJsonType>
74    static void to_json(BasicJsonType& j, const T& value) noexcept // NOLINT(bugprone-exception-escape)
75    {
76        ::nlohmann::to_json(j, value);
77    }
78    template <typename BasicJsonType>
79    static void from_json(const BasicJsonType& j, T& value)   //!!!
80    {
81        ::nlohmann::from_json(j, value);
82    }
83};
84} // namespace ns
85
86using foo_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t,
87      std::uint64_t, double, std::allocator, ns::foo_serializer, std::vector<std::uint8_t>>;
88
89/////////////////////////////////////////////////////////////////////
90// for #805
91/////////////////////////////////////////////////////////////////////
92
93namespace
94{
95struct nocopy // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
96{
97    nocopy() = default;
98    nocopy(const nocopy&) = delete;
99    nocopy(nocopy&&) = delete;
100    nocopy& operator=(const nocopy&) = delete;
101    nocopy& operator=(nocopy&&) = delete;
102
103    int val = 0;
104
105    friend void to_json(json& j, const nocopy& n)
106    {
107        j = {{"val", n.val}};
108    }
109};
110} // namespace
111
112TEST_CASE("regression tests 1")
113{
114    SECTION("issue #60 - Double quotation mark is not parsed correctly")
115    {
116        SECTION("escape_doublequote")
117        {
118            const auto* s = R"(["\"foo\""])";
119            json j = json::parse(s);
120            auto expected = R"(["\"foo\""])"_json;
121            CHECK(j == expected);
122        }
123    }
124
125    SECTION("issue #70 - Handle infinity and NaN cases")
126    {
127        // previously, NAN/INFINITY created a null value; now, the values are
128        // properly stored, but are dumped as "null"
129        SECTION("NAN value")
130        {
131            CHECK(json(NAN).dump() == "null");
132            CHECK(json(json::number_float_t(NAN)).dump() == "null");
133        }
134
135        SECTION("infinity")
136        {
137            CHECK(json(INFINITY).dump() == "null");
138            CHECK(json(json::number_float_t(INFINITY)).dump() == "null");
139        }
140
141        // With 3.0.0, the semantics of this changed: NAN and infinity are
142        // stored properly inside the JSON value (no exception or conversion
143        // to null), but are serialized as null.
144        SECTION("NAN value")
145        {
146            json j1 = NAN;
147            CHECK(j1.is_number_float());
148            json::number_float_t f1{j1};
149            CHECK(std::isnan(f1));
150
151            json j2 = static_cast<json::number_float_t>(NAN);
152            CHECK(j2.is_number_float());
153            json::number_float_t f2{j2};
154            CHECK(std::isnan(f2));
155        }
156
157        SECTION("infinity")
158        {
159            json j1 = INFINITY;
160            CHECK(j1.is_number_float());
161            json::number_float_t f1{j1};
162            CHECK(!std::isfinite(f1));
163
164            json j2 = static_cast<json::number_float_t>(INFINITY);
165            CHECK(j2.is_number_float());
166            json::number_float_t f2{j2};
167            CHECK(!std::isfinite(f2));
168        }
169    }
170
171    SECTION("pull request #71 - handle enum type")
172    {
173        enum { t = 0, u = 102};
174        json j = json::array();
175        j.push_back(t);
176
177        // maybe this is not the place to test this?
178        json j2 = u;
179
180        auto anon_enum_value = j2.get<decltype(u)>();
181        CHECK(u == anon_enum_value);
182
183        // check if the actual value was stored
184        CHECK(j2 == 102);
185
186        static_assert(std::is_same<decltype(anon_enum_value), decltype(u)>::value, "types must be the same");
187
188        j.push_back(json::object(
189        {
190            {"game_type", t}
191        }));
192    }
193
194    SECTION("issue #76 - dump() / parse() not idempotent")
195    {
196        // create JSON object
197        json fields;
198        fields["one"] = std::string("one");
199        fields["two"] = std::string("two three");
200        fields["three"] = std::string("three \"four\"");
201
202        // create another JSON object by deserializing the serialization
203        std::string payload = fields.dump();
204        json parsed_fields = json::parse(payload);
205
206        // check individual fields to match both objects
207        CHECK(parsed_fields["one"] == fields["one"]);
208        CHECK(parsed_fields["two"] == fields["two"]);
209        CHECK(parsed_fields["three"] == fields["three"]);
210
211        // check individual fields to match original input
212        CHECK(parsed_fields["one"] == std::string("one"));
213        CHECK(parsed_fields["two"] == std::string("two three"));
214        CHECK(parsed_fields["three"] == std::string("three \"four\""));
215
216        // check equality of the objects
217        CHECK(parsed_fields == fields);
218
219        // check equality of the serialized objects
220        CHECK(fields.dump() == parsed_fields.dump());
221
222        // check everything in one line
223        CHECK(fields == json::parse(fields.dump()));
224    }
225
226    SECTION("issue #82 - lexer::get_number return NAN")
227    {
228        const auto* const content = R"(
229        {
230            "Test":"Test1",
231            "Number":100,
232            "Foo":42.42
233        })";
234
235        std::stringstream ss;
236        ss << content;
237        json j;
238        ss >> j;
239
240        auto test = j["Test"].get<std::string>();
241        CHECK(test == "Test1");
242        int number{j["Number"]};
243        CHECK(number == 100);
244        float foo{j["Foo"]};
245        CHECK(static_cast<double>(foo) == Approx(42.42));
246    }
247
248    SECTION("issue #89 - nonstandard integer type")
249    {
250        // create JSON class with nonstandard integer number type
251        using custom_json =
252            nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float>;
253        custom_json j;
254        j["int_1"] = 1;
255        CHECK(j["int_1"] == 1);
256
257        // tests for correct handling of non-standard integers that overflow the type selected by the user
258
259        // unsigned integer object creation - expected to wrap and still be stored as an integer
260        j = 4294967296U; // 2^32
261        CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_unsigned));
262        CHECK(j.get<uint32_t>() == 0);  // Wrap
263
264        // unsigned integer parsing - expected to overflow and be stored as a float
265        j = custom_json::parse("4294967296"); // 2^32
266        CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_float));
267        CHECK(j.get<float>() == 4294967296.0f);
268
269        // integer object creation - expected to wrap and still be stored as an integer
270        j = -2147483649LL; // -2^31-1
271        CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_integer));
272        CHECK(j.get<int32_t>() == 2147483647);  // Wrap
273
274        // integer parsing - expected to overflow and be stored as a float with rounding
275        j = custom_json::parse("-2147483649"); // -2^31
276        CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_float));
277        CHECK(j.get<float>() == -2147483650.0f);
278    }
279
280    SECTION("issue #93 reverse_iterator operator inheritance problem")
281    {
282        {
283            json a = {1, 2, 3};
284            json::reverse_iterator rit = a.rbegin();
285            ++rit;
286            CHECK(*rit == json(2));
287            CHECK(rit.value() == json(2));
288        }
289        {
290            json a = {1, 2, 3};
291            json::reverse_iterator rit = ++a.rbegin();
292            CHECK(*rit == json(2));
293            CHECK(rit.value() == json(2));
294        }
295        {
296            json a = {1, 2, 3};
297            json::reverse_iterator rit = a.rbegin();
298            ++rit;
299            json b = {0, 0, 0};
300            std::transform(rit, a.rend(), b.rbegin(), [](json el)
301            {
302                return el;
303            });
304            CHECK(b == json({0, 1, 2}));
305        }
306        {
307            json a = {1, 2, 3};
308            json b = {0, 0, 0};
309            std::transform(++a.rbegin(), a.rend(), b.rbegin(), [](json el)
310            {
311                return el;
312            });
313            CHECK(b == json({0, 1, 2}));
314        }
315    }
316
317    SECTION("issue #100 - failed to iterator json object with reverse_iterator")
318    {
319        json config =
320        {
321            { "111", 111 },
322            { "112", 112 },
323            { "113", 113 }
324        };
325
326        std::stringstream ss;
327
328        for (auto it = config.begin(); it != config.end(); ++it)
329        {
330            ss << it.key() << ": " << it.value() << '\n';
331        }
332
333        for (auto it = config.rbegin(); it != config.rend(); ++it)
334        {
335            ss << it.key() << ": " << it.value() << '\n';
336        }
337
338        CHECK(ss.str() == "111: 111\n112: 112\n113: 113\n113: 113\n112: 112\n111: 111\n");
339    }
340
341    SECTION("issue #101 - binary string causes numbers to be dumped as hex")
342    {
343        int64_t number = 10;
344        std::string bytes{"\x00" "asdf\n", 6};
345        json j;
346        j["int64"] = number;
347        j["binary string"] = bytes;
348        // make sure the number is really printed as decimal "10" and not as
349        // hexadecimal "a"
350        CHECK(j.dump() == "{\"binary string\":\"\\u0000asdf\\n\",\"int64\":10}");
351    }
352
353    SECTION("issue #111 - subsequent unicode chars")
354    {
355        std::string bytes{0x7, 0x7};
356        json j;
357        j["string"] = bytes;
358        CHECK(j["string"] == "\u0007\u0007");
359    }
360
361#if JSON_USE_IMPLICIT_CONVERSIONS
362    SECTION("issue #144 - implicit assignment to std::string fails")
363    {
364        json o = {{"name", "value"}};
365
366        std::string s1 = o["name"];
367        CHECK(s1 == "value");
368
369        std::string s2;
370        s2 = o["name"];
371
372        CHECK(s2 == "value");
373
374        // improve coverage
375        o["int"] = 1;
376#if JSON_DIAGNOSTICS
377        CHECK_THROWS_WITH_AS(s2 = o["int"], "[json.exception.type_error.302] (/int) type must be string, but is number", json::type_error);
378#else
379        CHECK_THROWS_WITH_AS(s2 = o["int"], "[json.exception.type_error.302] type must be string, but is number", json::type_error);
380#endif
381    }
382#endif
383
384    SECTION("issue #146 - character following a surrogate pair is skipped")
385    {
386        CHECK(json::parse("\"\\ud80c\\udc60abc\"").get<json::string_t>() == "\xf0\x93\x81\xa0\x61\x62\x63");
387    }
388
389    SECTION("issue #171 - Cannot index by key of type static constexpr const char*")
390    {
391        json j;
392
393        // Non-const access with key as "char []"
394        char array_key[] = "Key1"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
395        CHECK_NOTHROW(j[array_key] = 1);
396        CHECK(j[array_key] == json(1));
397
398        // Non-const access with key as "const char[]"
399        const char const_array_key[] = "Key2"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
400        CHECK_NOTHROW(j[const_array_key] = 2);
401        CHECK(j[const_array_key] == json(2));
402
403        // Non-const access with key as "char *"
404        char _ptr_key[] = "Key3"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
405        char* ptr_key = &_ptr_key[0]; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
406        CHECK_NOTHROW(j[ptr_key] = 3);
407        CHECK(j[ptr_key] == json(3));
408
409        // Non-const access with key as "const char *"
410        const char* const_ptr_key = "Key4";
411        CHECK_NOTHROW(j[const_ptr_key] = 4);
412        CHECK(j[const_ptr_key] == json(4));
413
414        // Non-const access with key as "static constexpr const char *"
415        static constexpr const char* constexpr_ptr_key = "Key5";
416        CHECK_NOTHROW(j[constexpr_ptr_key] = 5);
417        CHECK(j[constexpr_ptr_key] == json(5));
418
419        const json j_const = j;
420
421        // Const access with key as "char []"
422        CHECK(j_const[array_key] == json(1));
423
424        // Const access with key as "const char[]"
425        CHECK(j_const[const_array_key] == json(2));
426
427        // Const access with key as "char *"
428        CHECK(j_const[ptr_key] == json(3));
429
430        // Const access with key as "const char *"
431        CHECK(j_const[const_ptr_key] == json(4));
432
433        // Const access with key as "static constexpr const char *"
434        CHECK(j_const[constexpr_ptr_key] == json(5));
435    }
436
437    SECTION("issue #186 miloyip/nativejson-benchmark: floating-point parsing")
438    {
439        json j;
440
441        j = json::parse("-0.0");
442        CHECK(j.get<double>() == -0.0);
443
444        j = json::parse("2.22507385850720113605740979670913197593481954635164564e-308");
445        CHECK(j.get<double>() == 2.2250738585072009e-308);
446
447        j = json::parse("0.999999999999999944488848768742172978818416595458984374");
448        CHECK(j.get<double>() == 0.99999999999999989);
449
450        j = json::parse("1.00000000000000011102230246251565404236316680908203126");
451        CHECK(j.get<double>() == 1.00000000000000022);
452
453        j = json::parse("7205759403792793199999e-5");
454        CHECK(j.get<double>() == 72057594037927928.0);
455
456        j = json::parse("922337203685477529599999e-5");
457        CHECK(j.get<double>() == 9223372036854774784.0);
458
459        j = json::parse("1014120480182583464902367222169599999e-5");
460        CHECK(j.get<double>() == 10141204801825834086073718800384.0);
461
462        j = json::parse("5708990770823839207320493820740630171355185151999e-3");
463        CHECK(j.get<double>() == 5708990770823838890407843763683279797179383808.0);
464
465        // create JSON class with nonstandard float number type
466
467        // float
468        nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float> j_float =
469            1.23e25f;
470        CHECK(j_float.get<float>() == 1.23e25f);
471
472        // double
473        nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, double> j_double =
474            1.23e35;
475        CHECK(j_double.get<double>() == 1.23e35);
476
477        // long double
478        nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, long double>
479        j_long_double = 1.23e45L;
480        CHECK(j_long_double.get<long double>() == 1.23e45L);
481    }
482
483    SECTION("issue #228 - double values are serialized with commas as decimal points")
484    {
485        json j1a = 2312.42;
486        json j1b = json::parse("2312.42");
487
488        json j2a = 2342e-2;
489        //issue #230
490        //json j2b = json::parse("2342e-2");
491
492        json j3a = 10E3;
493        json j3b = json::parse("10E3");
494        json j3c = json::parse("10e3");
495
496        // class to create a locale that would use a comma for decimals
497        class CommaDecimalSeparator : public std::numpunct<char>
498        {
499          protected:
500            char do_decimal_point() const override
501            {
502                return ',';
503            }
504
505            char do_thousands_sep() const override
506            {
507                return '.';
508            }
509
510            std::string do_grouping() const override
511            {
512                return "\03";
513            }
514        };
515
516        // change locale to mess with decimal points
517        auto orig_locale = std::locale::global(std::locale(std::locale(), new CommaDecimalSeparator));
518
519        CHECK(j1a.dump() == "2312.42");
520        CHECK(j1b.dump() == "2312.42");
521
522        // check if locale is properly reset
523        std::stringstream ss;
524        ss.imbue(std::locale(std::locale(), new CommaDecimalSeparator));
525        ss << 4712.11;
526        CHECK(ss.str() == "4.712,11");
527        ss << j1a;
528        CHECK(ss.str() == "4.712,112312.42");
529        ss << 47.11;
530        CHECK(ss.str() == "4.712,112312.4247,11");
531
532        CHECK(j2a.dump() == "23.42");
533        //issue #230
534        //CHECK(j2b.dump() == "23.42");
535
536        CHECK(j3a.dump() == "10000.0");
537        CHECK(j3b.dump() == "10000.0");
538        CHECK(j3c.dump() == "10000.0");
539        //CHECK(j3b.dump() == "1E04"); // roundtrip error
540        //CHECK(j3c.dump() == "1e04"); // roundtrip error
541
542        std::locale::global(orig_locale);
543    }
544
545    SECTION("issue #378 - locale-independent num-to-str")
546    {
547        static_cast<void>(setlocale(LC_NUMERIC, "de_DE.UTF-8"));
548
549        // verify that dumped correctly with '.' and no grouping
550        const json j1 = 12345.67;
551        CHECK(json(12345.67).dump() == "12345.67");
552        static_cast<void>(setlocale(LC_NUMERIC, "C"));
553    }
554
555    SECTION("issue #379 - locale-independent str-to-num")
556    {
557        static_cast<void>(setlocale(LC_NUMERIC, "de_DE.UTF-8"));
558
559        // verify that parsed correctly despite using strtod internally
560        CHECK(json::parse("3.14").get<double>() == 3.14);
561
562        // check a different code path
563        CHECK(json::parse("1.000000000000000000000000000000000000000000000000000000000000000000000000").get<double>() == 1.0);
564    }
565
566    SECTION("issue #233 - Can't use basic_json::iterator as a base iterator for std::move_iterator")
567    {
568        json source = {"a", "b", "c"};
569        json expected = {"a", "b"};
570        json dest;
571
572        std::copy_n(std::make_move_iterator(source.begin()), 2, std::back_inserter(dest));
573
574        CHECK(dest == expected);
575    }
576
577    SECTION("issue #235 - ambiguous overload for 'push_back' and 'operator+='")
578    {
579        json data = {{"key", "value"}};
580        data.push_back({"key2", "value2"});
581        data += {"key3", "value3"};
582
583        CHECK(data == json({{"key", "value"}, {"key2", "value2"}, {"key3", "value3"}}));
584    }
585
586    SECTION("issue #269 - diff generates incorrect patch when removing multiple array elements")
587    {
588        json doc = R"( { "arr1": [1, 2, 3, 4] } )"_json;
589        json expected = R"( { "arr1": [1, 2] } )"_json;
590
591        // check roundtrip
592        CHECK(doc.patch(json::diff(doc, expected)) == expected);
593    }
594
595    SECTION("issue #283 - value() does not work with _json_pointer types")
596    {
597        json j =
598        {
599            {"object", {{"key1", 1}, {"key2", 2}}},
600        };
601
602        int at_integer{j.at("/object/key2"_json_pointer)};
603        int val_integer = j.value("/object/key2"_json_pointer, 0);
604
605        CHECK(at_integer == val_integer);
606    }
607
608    SECTION("issue #304 - Unused variable warning")
609    {
610        // code triggered a "warning: unused variable" warning and is left
611        // here to avoid the warning in the future
612        json object;
613        json patch = json::array();
614        object = object.patch(patch);
615    }
616
617    SECTION("issue #306 - Parsing fails without space at end of file")
618    {
619        for (const auto* filename :
620                {
621                    TEST_DATA_DIRECTORY "/regression/broken_file.json",
622                    TEST_DATA_DIRECTORY "/regression/working_file.json"
623                })
624        {
625            CAPTURE(filename)
626            json j;
627            std::ifstream f(filename);
628            CHECK_NOTHROW(f >> j);
629        }
630    }
631
632    SECTION("issue #310 - make json_benchmarks no longer working in 2.0.4")
633    {
634        for (const auto* filename :
635                {
636                    TEST_DATA_DIRECTORY "/regression/floats.json",
637                    TEST_DATA_DIRECTORY "/regression/signed_ints.json",
638                    TEST_DATA_DIRECTORY "/regression/unsigned_ints.json",
639                    TEST_DATA_DIRECTORY "/regression/small_signed_ints.json"
640                })
641        {
642            CAPTURE(filename)
643            json j;
644            std::ifstream f(filename);
645            CHECK_NOTHROW(f >> j);
646        }
647    }
648
649    SECTION("issue #323 - add nested object capabilities to pointers")
650    {
651        json j;
652        j["/this/that/2"_json_pointer] = 27;
653        CHECK(j == json({{"this", {{"that", {nullptr, nullptr, 27}}}}}));
654    }
655
656    SECTION("issue #329 - serialized value not always can be parsed")
657    {
658        json _;
659        CHECK_THROWS_WITH_AS(_ = json::parse("22e2222"), "[json.exception.out_of_range.406] number overflow parsing '22e2222'", json::out_of_range&);
660    }
661
662    SECTION("issue #360 - Loss of precision when serializing <double>")
663    {
664        auto check_roundtrip = [](double number)
665        {
666            CAPTURE(number)
667
668            json j = number;
669            CHECK(j.is_number_float());
670
671            std::stringstream ss;
672            ss << j;
673
674            CHECK_NOTHROW(ss >> j);
675            CHECK(j.is_number_float());
676            CHECK(j.get<json::number_float_t>() == number);
677        };
678
679        check_roundtrip(100000000000.1236);
680        check_roundtrip((std::numeric_limits<json::number_float_t>::max)());
681
682        // Some more numbers which fail to roundtrip when serialized with digits10 significand digits (instead of max_digits10)
683        check_roundtrip(1.541888611948064e-17);
684        check_roundtrip(5.418771028591015e-16);
685        check_roundtrip(9.398685592608595e-15);
686        check_roundtrip(8.826843952762347e-14);
687        check_roundtrip(8.143291313475335e-13);
688        check_roundtrip(4.851328172762508e-12);
689        check_roundtrip(6.677850998084358e-11);
690        check_roundtrip(3.995398518174525e-10);
691        check_roundtrip(1.960452605645124e-9);
692        check_roundtrip(3.551812586302883e-8);
693        check_roundtrip(2.947988411689261e-7);
694        check_roundtrip(8.210166748056192e-6);
695        check_roundtrip(6.104889704266753e-5);
696        check_roundtrip(0.0008629954631330876);
697        check_roundtrip(0.004936993881051611);
698        check_roundtrip(0.08309725102608073);
699        check_roundtrip(0.5210494268499783);
700        check_roundtrip(6.382927930939767);
701        check_roundtrip(59.94947245358671);
702        check_roundtrip(361.0838651266122);
703        check_roundtrip(4678.354596181877);
704        check_roundtrip(61412.17658956043);
705        check_roundtrip(725696.0799057782);
706        check_roundtrip(2811732.583399828);
707        check_roundtrip(30178351.07533605);
708        check_roundtrip(689684880.3235844);
709        check_roundtrip(5714887673.555147);
710        check_roundtrip(84652038821.18808);
711        check_roundtrip(156510583431.7721);
712        check_roundtrip(5938450569021.732);
713        check_roundtrip(83623297654460.33);
714        check_roundtrip(701466573254773.6);
715        check_roundtrip(1369013370304513);
716        check_roundtrip(96963648023094720); // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
717        check_roundtrip(3.478237409280108e+17);
718    }
719
720    SECTION("issue #366 - json::parse on failed stream gets stuck")
721    {
722        std::ifstream f("file_not_found.json");
723        json _;
724        CHECK_THROWS_WITH_AS(_ = json::parse(f), "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
725    }
726
727    SECTION("issue #367 - calling stream at EOF")
728    {
729        std::stringstream ss;
730        json j;
731        ss << "123";
732        CHECK_NOTHROW(ss >> j);
733
734        // see https://github.com/nlohmann/json/issues/367#issuecomment-262841893:
735        // ss is not at EOF; this yielded an error before the fix
736        // (threw basic_string::append). No, it should just throw
737        // a parse error because of the EOF.
738        CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
739    }
740
741    SECTION("issue #367 - behavior of operator>> should more closely resemble that of built-in overloads")
742    {
743        SECTION("(empty)")
744        {
745            std::stringstream ss;
746            json j;
747            CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
748        }
749
750        SECTION("(whitespace)")
751        {
752            std::stringstream ss;
753            ss << "   ";
754            json j;
755            CHECK_THROWS_WITH_AS(ss >> j,
756                                 "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
757        }
758
759        SECTION("one value")
760        {
761            std::stringstream ss;
762            ss << "111";
763            json j;
764            CHECK_NOTHROW(ss >> j);
765            CHECK(j == 111);
766
767            CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
768        }
769
770        SECTION("one value + whitespace")
771        {
772            std::stringstream ss;
773            ss << "222 \t\n";
774            json j;
775            CHECK_NOTHROW(ss >> j);
776            CHECK(j == 222);
777
778            CHECK_THROWS_WITH_AS(ss >> j,
779                                 "[json.exception.parse_error.101] parse error at line 2, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
780        }
781
782        SECTION("whitespace + one value")
783        {
784            std::stringstream ss;
785            ss << "\n\t 333";
786            json j;
787            CHECK_NOTHROW(ss >> j);
788            CHECK(j == 333);
789
790            CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
791        }
792
793        SECTION("three values")
794        {
795            std::stringstream ss;
796            ss << " 111 \n222\n \n  333";
797            json j;
798            CHECK_NOTHROW(ss >> j);
799            CHECK(j == 111);
800            CHECK_NOTHROW(ss >> j);
801            CHECK(j == 222);
802            CHECK_NOTHROW(ss >> j);
803            CHECK(j == 333);
804
805            CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
806        }
807
808        SECTION("literals without whitespace")
809        {
810            std::stringstream ss;
811            ss << "truefalsenull\"\"";
812            json j;
813            CHECK_NOTHROW(ss >> j);
814            CHECK(j == true);
815            CHECK_NOTHROW(ss >> j);
816            CHECK(j == false);
817            CHECK_NOTHROW(ss >> j);
818            CHECK(j == nullptr);
819            CHECK_NOTHROW(ss >> j);
820            CHECK(j == "");
821
822            CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
823        }
824
825        SECTION("example from #529")
826        {
827            std::stringstream ss;
828            ss << "{\n    \"one\"   : 1,\n    \"two\"   : 2\n}\n{\n    \"three\" : 3\n}";
829            json j;
830            CHECK_NOTHROW(ss >> j);
831            CHECK(j == json({{"one", 1}, {"two", 2}}));
832            CHECK_NOTHROW(ss >> j);
833            CHECK(j == json({{"three", 3}}));
834
835            CHECK_THROWS_WITH_AS(ss >> j, "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
836        }
837
838        SECTION("second example from #529")
839        {
840            std::string str = "{\n\"one\"   : 1,\n\"two\"   : 2\n}\n{\n\"three\" : 3\n}";
841
842            {
843                std::ofstream file("test.json");
844                file << str;
845            }
846
847            std::ifstream stream("test.json", std::ifstream::in);
848            json val;
849
850            size_t i = 0;
851            while (stream.peek() != EOF)
852            {
853                CAPTURE(i)
854                CHECK_NOTHROW(stream >> val);
855
856                CHECK(i < 2);
857
858                if (i == 0)
859                {
860                    CHECK(val == json({{"one", 1}, {"two", 2}}));
861                }
862
863                if (i == 1)
864                {
865                    CHECK(val == json({{"three", 3}}));
866                }
867
868                ++i;
869            }
870
871            static_cast<void>(std::remove("test.json"));
872        }
873    }
874
875    SECTION("issue #389 - Integer-overflow (OSS-Fuzz issue 267)")
876    {
877        // original test case
878        json j1 = json::parse("-9223372036854775808");
879        CHECK(j1.is_number_integer());
880        CHECK(j1.get<json::number_integer_t>() == INT64_MIN);
881
882        // edge case (+1; still an integer)
883        json j2 = json::parse("-9223372036854775807");
884        CHECK(j2.is_number_integer());
885        CHECK(j2.get<json::number_integer_t>() == INT64_MIN + 1);
886
887        // edge case (-1; overflow -> floats)
888        json j3 = json::parse("-9223372036854775809");
889        CHECK(j3.is_number_float());
890    }
891
892    SECTION("issue #380 - bug in overflow detection when parsing integers")
893    {
894        json j = json::parse("166020696663385964490");
895        CHECK(j.is_number_float());
896        CHECK(j.get<json::number_float_t>() == 166020696663385964490.0);
897    }
898
899    SECTION("issue #405 - Heap-buffer-overflow (OSS-Fuzz issue 342)")
900    {
901        // original test case
902        std::vector<uint8_t> vec {0x65, 0xf5, 0x0a, 0x48, 0x21};
903        json _;
904        CHECK_THROWS_WITH_AS(_ = json::from_cbor(vec), "[json.exception.parse_error.110] parse error at byte 6: syntax error while parsing CBOR string: unexpected end of input", json::parse_error&);
905    }
906
907    SECTION("issue #407 - Heap-buffer-overflow (OSS-Fuzz issue 343)")
908    {
909        json _;
910
911        // original test case: incomplete float64
912        std::vector<uint8_t> vec1 {0xcb, 0x8f, 0x0a};
913        CHECK_THROWS_WITH_AS(_ = json::from_msgpack(vec1), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing MessagePack number: unexpected end of input", json::parse_error&);
914
915        // related test case: incomplete float32
916        std::vector<uint8_t> vec2 {0xca, 0x8f, 0x0a};
917        CHECK_THROWS_WITH_AS(_ = json::from_msgpack(vec2), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing MessagePack number: unexpected end of input", json::parse_error&);
918
919        // related test case: incomplete Half-Precision Float (CBOR)
920        std::vector<uint8_t> vec3 {0xf9, 0x8f};
921        CHECK_THROWS_WITH_AS(_ = json::from_cbor(vec3), "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR number: unexpected end of input", json::parse_error&);
922
923        // related test case: incomplete Single-Precision Float (CBOR)
924        std::vector<uint8_t> vec4 {0xfa, 0x8f, 0x0a};
925        CHECK_THROWS_WITH_AS(_ = json::from_cbor(vec4), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR number: unexpected end of input", json::parse_error&);
926
927        // related test case: incomplete Double-Precision Float (CBOR)
928        std::vector<uint8_t> vec5 {0xfb, 0x8f, 0x0a};
929        CHECK_THROWS_WITH_AS(_ = json::from_cbor(vec5), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR number: unexpected end of input", json::parse_error&);
930    }
931
932    SECTION("issue #408 - Heap-buffer-overflow (OSS-Fuzz issue 344)")
933    {
934        json _;
935
936        // original test case
937        std::vector<uint8_t> vec1 {0x87};
938        CHECK_THROWS_WITH_AS(_ = json::from_msgpack(vec1), "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing MessagePack string: unexpected end of input", json::parse_error&);
939
940        // more test cases for MessagePack
941        for (auto b :
942                {
943                    0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, // fixmap
944                    0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, // fixarray
945                    0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, // fixstr
946                    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf
947                })
948        {
949            std::vector<uint8_t> vec(1, static_cast<uint8_t>(b));
950            CHECK_THROWS_AS(_ = json::from_msgpack(vec), json::parse_error&);
951        }
952
953        // more test cases for CBOR
954        for (auto b :
955                {
956                    0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
957                    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, // UTF-8 string
958                    0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
959                    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, // array
960                    0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
961                    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7 // map
962                })
963        {
964            std::vector<uint8_t> vec(1, static_cast<uint8_t>(b));
965            CHECK_THROWS_AS(_ = json::from_cbor(vec), json::parse_error&);
966        }
967
968        // special case: empty input
969        std::vector<uint8_t> vec2;
970        CHECK_THROWS_WITH_AS(_ = json::from_cbor(vec2), "[json.exception.parse_error.110] parse error at byte 1: syntax error while parsing CBOR value: unexpected end of input", json::parse_error&);
971        CHECK_THROWS_WITH_AS(_ = json::from_msgpack(vec2), "[json.exception.parse_error.110] parse error at byte 1: syntax error while parsing MessagePack value: unexpected end of input", json::parse_error&);
972    }
973
974    SECTION("issue #411 - Heap-buffer-overflow (OSS-Fuzz issue 366)")
975    {
976        json _;
977
978        // original test case: empty UTF-8 string (indefinite length)
979        std::vector<uint8_t> vec1 {0x7f};
980        CHECK_THROWS_WITH_AS(_ = json::from_cbor(vec1), "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR string: unexpected end of input", json::parse_error&);
981
982        // related test case: empty array (indefinite length)
983        std::vector<uint8_t> vec2 {0x9f};
984        CHECK_THROWS_WITH_AS(_ = json::from_cbor(vec2), "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR value: unexpected end of input", json::parse_error&);
985
986        // related test case: empty map (indefinite length)
987        std::vector<uint8_t> vec3 {0xbf};
988        CHECK_THROWS_WITH_AS(_ = json::from_cbor(vec3), "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR string: unexpected end of input", json::parse_error&);
989    }
990
991    SECTION("issue #412 - Heap-buffer-overflow (OSS-Fuzz issue 367)")
992    {
993        // original test case
994        std::vector<uint8_t> vec
995        {
996            0xab, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
997            0x98, 0x98, 0x98, 0x98, 0x98, 0x00, 0x00, 0x00,
998            0x60, 0xab, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
999            0x98, 0x98, 0x98, 0x98, 0x98, 0x00, 0x00, 0x00,
1000            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
1001            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
1002            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
1003            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
1004            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
1005            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
1006            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0xa0, 0x9f,
1007            0x9f, 0x97, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
1008            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
1009            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
1010            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
1011            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
1012            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60
1013        };
1014
1015        json _;
1016        CHECK_THROWS_WITH_AS(_ = json::from_cbor(vec), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing CBOR string: expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x98", json::parse_error&);
1017
1018        // related test case: nonempty UTF-8 string (indefinite length)
1019        std::vector<uint8_t> vec1 {0x7f, 0x61, 0x61};
1020        CHECK_THROWS_WITH_AS(_ = json::from_cbor(vec1), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR string: unexpected end of input", json::parse_error&);
1021
1022        // related test case: nonempty array (indefinite length)
1023        std::vector<uint8_t> vec2 {0x9f, 0x01};
1024        CHECK_THROWS_WITH_AS(_ = json::from_cbor(vec2), "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR value: unexpected end of input", json::parse_error&);
1025
1026        // related test case: nonempty map (indefinite length)
1027        std::vector<uint8_t> vec3 {0xbf, 0x61, 0x61, 0x01};
1028        CHECK_THROWS_WITH_AS(_ = json::from_cbor(vec3), "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing CBOR string: unexpected end of input", json::parse_error&);
1029    }
1030
1031    SECTION("issue #414 - compare with literal 0)")
1032    {
1033#define CHECK_TYPE(v) \
1034    CHECK((json(v) == (v)));\
1035    CHECK(((v) == json(v)));\
1036    CHECK_FALSE((json(v) != (v)));\
1037    CHECK_FALSE(((v) != json(v)));
1038
1039        CHECK_TYPE(nullptr)
1040        CHECK_TYPE(0)
1041        CHECK_TYPE(0u)
1042        CHECK_TYPE(0L)
1043        CHECK_TYPE(0.0)
1044        CHECK_TYPE("") // NOLINT(readability-container-size-empty)
1045
1046#undef CHECK_TYPE
1047    }
1048
1049    SECTION("issue #416 - Use-of-uninitialized-value (OSS-Fuzz issue 377)")
1050    {
1051        // original test case
1052        std::vector<uint8_t> vec1
1053        {
1054            0x94, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
1055            0x3a, 0x96, 0x96, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
1056            0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0x71,
1057            0xb4, 0xb4, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0x3a,
1058            0x96, 0x96, 0xb4, 0xb4, 0xfa, 0x94, 0x94, 0x61,
1059            0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xfa
1060        };
1061
1062        json _;
1063        CHECK_THROWS_WITH_AS(_ = json::from_cbor(vec1), "[json.exception.parse_error.113] parse error at byte 13: syntax error while parsing CBOR string: expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0xB4", json::parse_error&);
1064
1065        // related test case: double-precision
1066        std::vector<uint8_t> vec2
1067        {
1068            0x94, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
1069            0x3a, 0x96, 0x96, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
1070            0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0x71,
1071            0xb4, 0xb4, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0x3a,
1072            0x96, 0x96, 0xb4, 0xb4, 0xfa, 0x94, 0x94, 0x61,
1073            0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xfb
1074        };
1075        CHECK_THROWS_WITH_AS(_ = json::from_cbor(vec2), "[json.exception.parse_error.113] parse error at byte 13: syntax error while parsing CBOR string: expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0xB4", json::parse_error&);
1076    }
1077
1078    SECTION("issue #452 - Heap-buffer-overflow (OSS-Fuzz issue 585)")
1079    {
1080        std::vector<uint8_t> vec = {'-', '0', '1', '2', '2', '7', '4'};
1081        json _;
1082        CHECK_THROWS_AS(_ = json::parse(vec), json::parse_error&);
1083    }
1084
1085    SECTION("issue #454 - doubles are printed as integers")
1086    {
1087        json j = R"({"bool_value":true,"double_value":2.0,"int_value":10,"level1":{"list_value":[3,"hi",false],"tmp":5.0},"string_value":"hello"})"_json;
1088        CHECK(j["double_value"].is_number_float());
1089    }
1090
1091#if JSON_USE_IMPLICIT_CONVERSIONS
1092    SECTION("issue #464 - VS2017 implicit to std::string conversion fix")
1093    {
1094        json v = "test";
1095        std::string test;
1096        test = v;
1097        CHECK(v == "test");
1098    }
1099#endif
1100
1101    SECTION("issue #465 - roundtrip error while parsing 1000000000000000010E5")
1102    {
1103        json j1 = json::parse("1000000000000000010E5");
1104        std::string s1 = j1.dump();
1105        json j2 = json::parse(s1);
1106        std::string s2 = j2.dump();
1107        CHECK(s1 == s2);
1108    }
1109
1110#if JSON_USE_IMPLICIT_CONVERSIONS
1111    SECTION("issue #473 - inconsistent behavior in conversion to array type")
1112    {
1113        json j_array = {1, 2, 3, 4};
1114        json j_number = 42;
1115        json j_null = nullptr;
1116
1117        SECTION("std::vector")
1118        {
1119            auto create = [](const json & j)
1120            {
1121                std::vector<int> v = j;
1122            };
1123
1124            CHECK_NOTHROW(create(j_array));
1125            CHECK_THROWS_WITH_AS(create(j_number), "[json.exception.type_error.302] type must be array, but is number", json::type_error&);
1126            CHECK_THROWS_WITH_AS(create(j_null), "[json.exception.type_error.302] type must be array, but is null", json::type_error&);
1127        }
1128
1129        SECTION("std::list")
1130        {
1131            auto create = [](const json & j)
1132            {
1133                std::list<int> v = j;
1134            };
1135
1136            CHECK_NOTHROW(create(j_array));
1137            CHECK_THROWS_WITH_AS(create(j_number), "[json.exception.type_error.302] type must be array, but is number", json::type_error&);
1138            CHECK_THROWS_WITH_AS(create(j_null), "[json.exception.type_error.302] type must be array, but is null", json::type_error&);
1139        }
1140
1141        SECTION("std::forward_list")
1142        {
1143            auto create = [](const json & j)
1144            {
1145                std::forward_list<int> v = j;
1146            };
1147
1148            CHECK_NOTHROW(create(j_array));
1149            CHECK_THROWS_WITH_AS(create(j_number), "[json.exception.type_error.302] type must be array, but is number", json::type_error&);
1150            CHECK_THROWS_WITH_AS(create(j_null), "[json.exception.type_error.302] type must be array, but is null", json::type_error&);
1151        }
1152    }
1153#endif
1154
1155    SECTION("issue #486 - json::value_t can't be a map's key type in VC++ 2015")
1156    {
1157        // the code below must compile with MSVC
1158        std::map<json::value_t, std::string> jsonTypes ;
1159        jsonTypes[json::value_t::array] = "array";
1160    }
1161
1162    SECTION("issue #494 - conversion from vector<bool> to json fails to build")
1163    {
1164        std::vector<bool> boolVector = {false, true, false, false};
1165        json j;
1166        j["bool_vector"] = boolVector;
1167
1168        CHECK(j["bool_vector"].dump() == "[false,true,false,false]");
1169    }
1170
1171    SECTION("issue #504 - assertion error (OSS-Fuzz 856)")
1172    {
1173        std::vector<uint8_t> vec1 = {0xf9, 0xff, 0xff, 0x4a, 0x3a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x37, 0x02, 0x38};
1174        json j1 = json::from_cbor(vec1, false);
1175
1176        // step 2: round trip
1177        std::vector<uint8_t> vec2 = json::to_cbor(j1);
1178
1179        // parse serialization
1180        json j2 = json::from_cbor(vec2);
1181
1182        // NaN is dumped to "null"
1183        CHECK(j2.is_number_float());
1184        CHECK(std::isnan(j2.get<json::number_float_t>()));
1185        CHECK(j2.dump() == "null");
1186
1187        // check if serializations match
1188        CHECK(json::to_cbor(j2) == vec2);
1189    }
1190
1191    SECTION("issue #512 - use of overloaded operator '<=' is ambiguous")
1192    {
1193        json j;
1194        j["a"] = 5;
1195
1196        // json op scalar
1197        CHECK(j["a"] == 5);
1198        CHECK(j["a"] != 4);
1199
1200        CHECK(j["a"] <= 7);
1201        CHECK(j["a"] <  7);
1202        CHECK(j["a"] >= 3);
1203        CHECK(j["a"] >  3);
1204
1205
1206        CHECK(!(j["a"] <= 4));
1207        CHECK(!(j["a"] <  4));
1208        CHECK(!(j["a"] >= 6));
1209        CHECK(!(j["a"] >  6));
1210
1211        // scalar op json
1212        CHECK(5 == j["a"]);
1213        CHECK(4 != j["a"]);
1214
1215        CHECK(7 >= j["a"]);
1216        CHECK(7 >  j["a"]);
1217        CHECK(3 <= j["a"]);
1218        CHECK(3 <  j["a"]);
1219
1220        CHECK(!(4 >= j["a"]));
1221        CHECK(!(4 >  j["a"]));
1222        CHECK(!(6 <= j["a"]));
1223        CHECK(!(6 <  j["a"]));
1224    }
1225
1226    SECTION("issue #575 - heap-buffer-overflow (OSS-Fuzz 1400)")
1227    {
1228        json _;
1229        std::vector<uint8_t> vec = {'"', '\\', '"', 'X', '"', '"'};
1230        CHECK_THROWS_AS(_ = json::parse(vec), json::parse_error&);
1231    }
1232
1233#if JSON_USE_IMPLICIT_CONVERSIONS
1234    SECTION("issue #600 - how does one convert a map in Json back to std::map?")
1235    {
1236        SECTION("example 1")
1237        {
1238            // create a map
1239            std::map<std::string, int> m1 {{"key", 1}};
1240
1241            // create and print a JSON from the map
1242            json j = m1;
1243
1244            // get the map out of JSON
1245            std::map<std::string, int> m2 = j;
1246
1247            // make sure the roundtrip succeeds
1248            CHECK(m1 == m2);
1249        }
1250
1251        SECTION("example 2")
1252        {
1253            // create a map
1254            std::map<std::string, std::string> m1 {{"key", "val"}};
1255
1256            // create and print a JSON from the map
1257            json j = m1;
1258
1259            // get the map out of JSON
1260            std::map<std::string, std::string> m2 = j;
1261
1262            // make sure the roundtrip succeeds
1263            CHECK(m1 == m2);
1264        }
1265    }
1266#endif
1267
1268    SECTION("issue #602 - BOM not skipped when using json:parse(iterator)")
1269    {
1270        std::string i = "\xef\xbb\xbf{\n   \"foo\": true\n}";
1271        json _;
1272        CHECK_NOTHROW(_ = json::parse(i.begin(), i.end()));
1273    }
1274
1275#if JSON_USE_IMPLICIT_CONVERSIONS
1276    SECTION("issue #702 - conversion from valarray<double> to json fails to build")
1277    {
1278        SECTION("original example")
1279        {
1280            std::valarray<double> v;
1281            nlohmann::json j;
1282            j["test"] = v;
1283        }
1284
1285        SECTION("full example")
1286        {
1287            std::valarray<double> v = {1.2, 2.3, 3.4, 4.5};
1288            json j = v;
1289            std::valarray<double> vj = j;
1290
1291            CHECK(j == json(vj));
1292            CHECK(v.size() == vj.size());
1293            for (size_t i = 0; i < v.size(); ++i)
1294            {
1295                CHECK(v[i] == vj[i]);
1296                CHECK(v[i] == j[i]);
1297            }
1298
1299            CHECK_THROWS_WITH_AS(json().get<std::valarray<double>>(), "[json.exception.type_error.302] type must be array, but is null", json::type_error&);
1300        }
1301    }
1302#endif
1303
1304    SECTION("issue #367 - Behavior of operator>> should more closely resemble that of built-in overloads.")
1305    {
1306        SECTION("example 1")
1307        {
1308            std::istringstream i1_2_3( R"({"first": "one" }{"second": "two"}3)" );
1309            json j1;
1310            json j2;
1311            json j3;
1312            i1_2_3 >> j1;
1313            i1_2_3 >> j2;
1314            i1_2_3 >> j3;
1315
1316            auto m1 = j1.get<std::map<std::string, std::string>>();
1317            auto m2 = j2.get<std::map<std::string, std::string>>();
1318            int i3{j3};
1319
1320            CHECK( m1 == ( std::map<std::string, std::string> {{ "first",  "one" }} ));
1321            CHECK( m2 == ( std::map<std::string, std::string> {{ "second", "two" }} ));
1322            CHECK( i3 == 3 );
1323        }
1324    }
1325
1326    SECTION("issue #714 - throw std::ios_base::failure exception when failbit set to true")
1327    {
1328        {
1329            std::ifstream is;
1330            is.exceptions(
1331                is.exceptions()
1332                | std::ios_base::failbit
1333                | std::ios_base::badbit
1334            ); // handle different exceptions as 'file not found', 'permission denied'
1335
1336            is.open(TEST_DATA_DIRECTORY "/regression/working_file.json");
1337            json _;
1338            CHECK_NOTHROW(_ = nlohmann::json::parse(is));
1339        }
1340
1341        {
1342            std::ifstream is;
1343            is.exceptions(
1344                is.exceptions()
1345                | std::ios_base::failbit
1346                | std::ios_base::badbit
1347            ); // handle different exceptions as 'file not found', 'permission denied'
1348
1349            is.open(TEST_DATA_DIRECTORY "/json_nlohmann_tests/all_unicode.json.cbor",
1350                    std::ios_base::in | std::ios_base::binary);
1351            json _;
1352            CHECK_NOTHROW(_ = nlohmann::json::from_cbor(is));
1353        }
1354    }
1355
1356    SECTION("issue #805 - copy constructor is used with std::initializer_list constructor.")
1357    {
1358        nocopy n;
1359        json j;
1360        j = {{"nocopy", n}};
1361        CHECK(j["nocopy"]["val"] == 0);
1362    }
1363
1364    SECTION("issue #838 - incorrect parse error with binary data in keys")
1365    {
1366        std::array<uint8_t, 28> key1 = {{ 103, 92, 117, 48, 48, 48, 55, 92, 114, 215, 126, 214, 95, 92, 34, 174, 40, 71, 38, 174, 40, 71, 38, 223, 134, 247, 127, 0 }};
1367        std::string key1_str(reinterpret_cast<char*>(key1.data()));
1368        json j = key1_str;
1369        CHECK_THROWS_WITH_AS(j.dump(), "[json.exception.type_error.316] invalid UTF-8 byte at index 10: 0x7E", json::type_error&);
1370    }
1371
1372#if JSON_USE_IMPLICIT_CONVERSIONS
1373    SECTION("issue #843 - converting to array not working")
1374    {
1375        json j;
1376        std::array<int, 4> ar = {{1, 1, 1, 1}};
1377        j = ar;
1378        ar = j;
1379    }
1380#endif
1381
1382    SECTION("issue #894 - invalid RFC6902 copy operation succeeds")
1383    {
1384        auto model = R"({
1385            "one": {
1386                "two": {
1387                    "three": "hello",
1388                    "four": 42
1389                }
1390            }
1391        })"_json;
1392
1393        auto p1 = R"([{"op": "move",
1394                       "from": "/one/two/three",
1395                       "path": "/a/b/c"}])"_json;
1396        CHECK_THROWS_WITH_AS(model.patch(p1),
1397                             "[json.exception.out_of_range.403] key 'a' not found", json::out_of_range&);
1398
1399        auto p2 = R"([{"op": "copy",
1400                       "from": "/one/two/three",
1401                       "path": "/a/b/c"}])"_json;
1402        CHECK_THROWS_WITH_AS(model.patch(p2),
1403                             "[json.exception.out_of_range.403] key 'a' not found", json::out_of_range&);
1404    }
1405
1406    SECTION("issue #961 - incorrect parsing of indefinite length CBOR strings")
1407    {
1408        std::vector<uint8_t> v_cbor =
1409        {
1410            0x7F,
1411            0x64,
1412            'a', 'b', 'c', 'd',
1413            0x63,
1414            '1', '2', '3',
1415            0xFF
1416        };
1417        json j = json::from_cbor(v_cbor);
1418        CHECK(j == "abcd123");
1419    }
1420
1421    SECTION("issue #962 - Timeout (OSS-Fuzz 6034)")
1422    {
1423        json _;
1424        std::vector<uint8_t> v_ubjson = {'[', '$', 'Z', '#', 'L', 0x78, 0x28, 0x00, 0x68, 0x28, 0x69, 0x69, 0x17};
1425        CHECK_THROWS_AS(_ = json::from_ubjson(v_ubjson), json::out_of_range&);
1426        //CHECK_THROWS_WITH(json::from_ubjson(v_ubjson),
1427        //                  "[json.exception.out_of_range.408] excessive array size: 8658170730974374167");
1428
1429        v_ubjson[0] = '{';
1430        CHECK_THROWS_AS(_ = json::from_ubjson(v_ubjson), json::out_of_range&);
1431        //CHECK_THROWS_WITH(json::from_ubjson(v_ubjson),
1432        //                  "[json.exception.out_of_range.408] excessive object size: 8658170730974374167");
1433    }
1434
1435    SECTION("issue #971 - Add a SAX parser - late bug")
1436    {
1437        // a JSON text
1438        const auto* text = R"(
1439    {
1440        "Image": {
1441            "Width":  800,
1442            "Height": 600,
1443            "Title":  "View from 15th Floor",
1444            "Thumbnail": {
1445                "Url":    "http://www.example.com/image/481989943",
1446                "Height": 125,
1447                "Width":  100
1448            },
1449            "Animated" : false,
1450            "IDs": [116, 943, 234, 38793]
1451        }
1452    }
1453    )";
1454
1455        // define parser callback
1456        json::parser_callback_t cb = [](int /*depth*/, json::parse_event_t event, json & parsed)
1457        {
1458            // skip object elements with key "Thumbnail"
1459            return !(event == json::parse_event_t::key && parsed == json("Thumbnail"));
1460        };
1461
1462        // parse (with callback) and serialize JSON
1463        json j_filtered = json::parse(text, cb);
1464
1465        CHECK(j_filtered == R"({"Image":{"Animated":false,"Height":600,"IDs":[116,943,234,38793], "Title":"View from 15th Floor","Width":800}})"_json);
1466    }
1467
1468    SECTION("issue #972 - Segmentation fault on G++ when trying to assign json string literal to custom json type")
1469    {
1470        my_json foo = R"([1, 2, 3])"_json;
1471    }
1472
1473    SECTION("issue #977 - Assigning between different json types")
1474    {
1475        foo_json lj = ns::foo{3};
1476        ns::foo ff(lj);
1477        CHECK(lj.is_object());
1478        CHECK(lj.size() == 1);
1479        CHECK(lj["x"] == 3);
1480        CHECK(ff.x == 3);
1481        nlohmann::json nj = lj;                // This line works as expected
1482    }
1483}
1484
1485#if !defined(JSON_NOEXCEPTION)
1486TEST_CASE("regression tests, exceptions dependent")
1487{
1488    SECTION("issue #1340 - eof not set on exhausted input stream")
1489    {
1490        std::stringstream s("{}{}");
1491        json j;
1492        s >> j;
1493        s >> j;
1494        CHECK_THROWS_AS(s >> j, json::parse_error const&);
1495        CHECK(s.eof());
1496    }
1497}
1498#endif
1499
1500/////////////////////////////////////////////////////////////////////
1501// for #1642
1502/////////////////////////////////////////////////////////////////////
1503
1504// the code below fails with Clang on Windows, so we need to exclude it there
1505#if DOCTEST_CLANG && (defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__))
1506#else
1507template <typename T> class array {};
1508template <typename T> class object {};
1509template <typename T> class string {};
1510template <typename T> class number_integer {};
1511template <typename T> class number_unsigned {};
1512template <typename T> class number_float {};
1513#endif
1514