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#define JSON_TESTS_PRIVATE
12#include <nlohmann/json.hpp>
13using nlohmann::json;
14#ifdef JSON_TEST_NO_GLOBAL_UDLS
15    using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
16#endif
17
18#include <valarray>
19
20namespace
21{
22class SaxEventLogger
23{
24  public:
25    bool null()
26    {
27        events.emplace_back("null()");
28        return true;
29    }
30
31    bool boolean(bool val)
32    {
33        events.emplace_back(val ? "boolean(true)" : "boolean(false)");
34        return true;
35    }
36
37    bool number_integer(json::number_integer_t val)
38    {
39        events.push_back("number_integer(" + std::to_string(val) + ")");
40        return true;
41    }
42
43    bool number_unsigned(json::number_unsigned_t val)
44    {
45        events.push_back("number_unsigned(" + std::to_string(val) + ")");
46        return true;
47    }
48
49    bool number_float(json::number_float_t /*unused*/, const std::string& s)
50    {
51        events.push_back("number_float(" + s + ")");
52        return true;
53    }
54
55    bool string(std::string& val)
56    {
57        events.push_back("string(" + val + ")");
58        return true;
59    }
60
61    bool binary(json::binary_t& val)
62    {
63        std::string binary_contents = "binary(";
64        std::string comma_space;
65        for (auto b : val)
66        {
67            binary_contents.append(comma_space);
68            binary_contents.append(std::to_string(static_cast<int>(b)));
69            comma_space = ", ";
70        }
71        binary_contents.append(")");
72        events.push_back(binary_contents);
73        return true;
74    }
75
76    bool start_object(std::size_t elements)
77    {
78        if (elements == static_cast<std::size_t>(-1))
79        {
80            events.emplace_back("start_object()");
81        }
82        else
83        {
84            events.push_back("start_object(" + std::to_string(elements) + ")");
85        }
86        return true;
87    }
88
89    bool key(std::string& val)
90    {
91        events.push_back("key(" + val + ")");
92        return true;
93    }
94
95    bool end_object()
96    {
97        events.emplace_back("end_object()");
98        return true;
99    }
100
101    bool start_array(std::size_t elements)
102    {
103        if (elements == static_cast<std::size_t>(-1))
104        {
105            events.emplace_back("start_array()");
106        }
107        else
108        {
109            events.push_back("start_array(" + std::to_string(elements) + ")");
110        }
111        return true;
112    }
113
114    bool end_array()
115    {
116        events.emplace_back("end_array()");
117        return true;
118    }
119
120    bool parse_error(std::size_t position, const std::string& /*unused*/, const json::exception& /*unused*/)
121    {
122        errored = true;
123        events.push_back("parse_error(" + std::to_string(position) + ")");
124        return false;
125    }
126
127    std::vector<std::string> events {};
128    bool errored = false;
129};
130
131class SaxCountdown : public nlohmann::json::json_sax_t
132{
133  public:
134    explicit SaxCountdown(const int count) : events_left(count)
135    {}
136
137    bool null() override
138    {
139        return events_left-- > 0;
140    }
141
142    bool boolean(bool /*val*/) override
143    {
144        return events_left-- > 0;
145    }
146
147    bool number_integer(json::number_integer_t /*val*/) override
148    {
149        return events_left-- > 0;
150    }
151
152    bool number_unsigned(json::number_unsigned_t /*val*/) override
153    {
154        return events_left-- > 0;
155    }
156
157    bool number_float(json::number_float_t /*val*/, const std::string& /*s*/) override
158    {
159        return events_left-- > 0;
160    }
161
162    bool string(std::string& /*val*/) override
163    {
164        return events_left-- > 0;
165    }
166
167    bool binary(json::binary_t& /*val*/) override
168    {
169        return events_left-- > 0;
170    }
171
172    bool start_object(std::size_t /*elements*/) override
173    {
174        return events_left-- > 0;
175    }
176
177    bool key(std::string& /*val*/) override
178    {
179        return events_left-- > 0;
180    }
181
182    bool end_object() override
183    {
184        return events_left-- > 0;
185    }
186
187    bool start_array(std::size_t /*elements*/) override
188    {
189        return events_left-- > 0;
190    }
191
192    bool end_array() override
193    {
194        return events_left-- > 0;
195    }
196
197    bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& /*ex*/) override
198    {
199        return false;
200    }
201
202  private:
203    int events_left = 0;
204};
205
206json parser_helper(const std::string& s);
207bool accept_helper(const std::string& s);
208void comments_helper(const std::string& s);
209
210json parser_helper(const std::string& s)
211{
212    json j;
213    json::parser(nlohmann::detail::input_adapter(s)).parse(true, j);
214
215    // if this line was reached, no exception occurred
216    // -> check if result is the same without exceptions
217    json j_nothrow;
218    CHECK_NOTHROW(json::parser(nlohmann::detail::input_adapter(s), nullptr, false).parse(true, j_nothrow));
219    CHECK(j_nothrow == j);
220
221    json j_sax;
222    nlohmann::detail::json_sax_dom_parser<json> sdp(j_sax);
223    json::sax_parse(s, &sdp);
224    CHECK(j_sax == j);
225
226    comments_helper(s);
227
228    return j;
229}
230
231bool accept_helper(const std::string& s)
232{
233    CAPTURE(s)
234
235    // 1. parse s without exceptions
236    json j;
237    CHECK_NOTHROW(json::parser(nlohmann::detail::input_adapter(s), nullptr, false).parse(true, j));
238    const bool ok_noexcept = !j.is_discarded();
239
240    // 2. accept s
241    const bool ok_accept = json::parser(nlohmann::detail::input_adapter(s)).accept(true);
242
243    // 3. check if both approaches come to the same result
244    CHECK(ok_noexcept == ok_accept);
245
246    // 4. parse with SAX (compare with relaxed accept result)
247    SaxEventLogger el;
248    CHECK_NOTHROW(json::sax_parse(s, &el, json::input_format_t::json, false));
249    CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept(false) == !el.errored);
250
251    // 5. parse with simple callback
252    json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept
253    {
254        return true;
255    };
256    json j_cb = json::parse(s, cb, false);
257    const bool ok_noexcept_cb = !j_cb.is_discarded();
258
259    // 6. check if this approach came to the same result
260    CHECK(ok_noexcept == ok_noexcept_cb);
261
262    // 7. check if comments are properly ignored
263    if (ok_accept)
264    {
265        comments_helper(s);
266    }
267
268    // 8. return result
269    return ok_accept;
270}
271
272void comments_helper(const std::string& s)
273{
274    json _;
275
276    // parse/accept with default parser
277    CHECK_NOTHROW(_ = json::parse(s));
278    CHECK(json::accept(s));
279
280    // parse/accept while skipping comments
281    CHECK_NOTHROW(_ = json::parse(s, nullptr, false, true));
282    CHECK(json::accept(s, true));
283
284    std::vector<std::string> json_with_comments;
285
286    // start with a comment
287    json_with_comments.push_back(std::string("// this is a comment\n") + s);
288    json_with_comments.push_back(std::string("/* this is a comment */") + s);
289    // end with a comment
290    json_with_comments.push_back(s + "// this is a comment");
291    json_with_comments.push_back(s + "/* this is a comment */");
292
293    // check all strings
294    for (const auto& json_with_comment : json_with_comments)
295    {
296        CAPTURE(json_with_comment)
297        CHECK_THROWS_AS(_ = json::parse(json_with_comment), json::parse_error);
298        CHECK(!json::accept(json_with_comment));
299
300        CHECK_NOTHROW(_ = json::parse(json_with_comment, nullptr, true, true));
301        CHECK(json::accept(json_with_comment, true));
302    }
303}
304
305} // namespace
306
307TEST_CASE("parser class")
308{
309    SECTION("parse")
310    {
311        SECTION("null")
312        {
313            CHECK(parser_helper("null") == json(nullptr));
314        }
315
316        SECTION("true")
317        {
318            CHECK(parser_helper("true") == json(true));
319        }
320
321        SECTION("false")
322        {
323            CHECK(parser_helper("false") == json(false));
324        }
325
326        SECTION("array")
327        {
328            SECTION("empty array")
329            {
330                CHECK(parser_helper("[]") == json(json::value_t::array));
331                CHECK(parser_helper("[ ]") == json(json::value_t::array));
332            }
333
334            SECTION("nonempty array")
335            {
336                CHECK(parser_helper("[true, false, null]") == json({true, false, nullptr}));
337            }
338        }
339
340        SECTION("object")
341        {
342            SECTION("empty object")
343            {
344                CHECK(parser_helper("{}") == json(json::value_t::object));
345                CHECK(parser_helper("{ }") == json(json::value_t::object));
346            }
347
348            SECTION("nonempty object")
349            {
350                CHECK(parser_helper("{\"\": true, \"one\": 1, \"two\": null}") == json({{"", true}, {"one", 1}, {"two", nullptr}}));
351            }
352        }
353
354        SECTION("string")
355        {
356            // empty string
357            CHECK(parser_helper("\"\"") == json(json::value_t::string));
358
359            SECTION("errors")
360            {
361                // error: tab in string
362                CHECK_THROWS_WITH_AS(parser_helper("\"\t\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t; last read: '\"<U+0009>'", json::parse_error&);
363                // error: newline in string
364                CHECK_THROWS_WITH_AS(parser_helper("\"\n\""), "[json.exception.parse_error.101] parse error at line 2, column 0: syntax error while parsing value - invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n; last read: '\"<U+000A>'", json::parse_error&);
365                CHECK_THROWS_WITH_AS(parser_helper("\"\r\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r; last read: '\"<U+000D>'", json::parse_error&);
366                // error: backspace in string
367                CHECK_THROWS_WITH_AS(parser_helper("\"\b\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b; last read: '\"<U+0008>'", json::parse_error&);
368                // improve code coverage
369                CHECK_THROWS_AS(parser_helper("\uFF01"), json::parse_error&);
370                CHECK_THROWS_AS(parser_helper("[-4:1,]"), json::parse_error&);
371                // unescaped control characters
372                CHECK_THROWS_WITH_AS(parser_helper("\"\x00\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: missing closing quote; last read: '\"'", json::parse_error&); // NOLINT(bugprone-string-literal-with-embedded-nul)
373                CHECK_THROWS_WITH_AS(parser_helper("\"\x01\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0001 (SOH) must be escaped to \\u0001; last read: '\"<U+0001>'", json::parse_error&);
374                CHECK_THROWS_WITH_AS(parser_helper("\"\x02\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0002 (STX) must be escaped to \\u0002; last read: '\"<U+0002>'", json::parse_error&);
375                CHECK_THROWS_WITH_AS(parser_helper("\"\x03\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0003 (ETX) must be escaped to \\u0003; last read: '\"<U+0003>'", json::parse_error&);
376                CHECK_THROWS_WITH_AS(parser_helper("\"\x04\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0004 (EOT) must be escaped to \\u0004; last read: '\"<U+0004>'", json::parse_error&);
377                CHECK_THROWS_WITH_AS(parser_helper("\"\x05\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0005 (ENQ) must be escaped to \\u0005; last read: '\"<U+0005>'", json::parse_error&);
378                CHECK_THROWS_WITH_AS(parser_helper("\"\x06\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0006 (ACK) must be escaped to \\u0006; last read: '\"<U+0006>'", json::parse_error&);
379                CHECK_THROWS_WITH_AS(parser_helper("\"\x07\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0007 (BEL) must be escaped to \\u0007; last read: '\"<U+0007>'", json::parse_error&);
380                CHECK_THROWS_WITH_AS(parser_helper("\"\x08\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b; last read: '\"<U+0008>'", json::parse_error&);
381                CHECK_THROWS_WITH_AS(parser_helper("\"\x09\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t; last read: '\"<U+0009>'", json::parse_error&);
382                CHECK_THROWS_WITH_AS(parser_helper("\"\x0a\""), "[json.exception.parse_error.101] parse error at line 2, column 0: syntax error while parsing value - invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n; last read: '\"<U+000A>'", json::parse_error&);
383                CHECK_THROWS_WITH_AS(parser_helper("\"\x0b\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000B (VT) must be escaped to \\u000B; last read: '\"<U+000B>'", json::parse_error&);
384                CHECK_THROWS_WITH_AS(parser_helper("\"\x0c\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f; last read: '\"<U+000C>'", json::parse_error&);
385                CHECK_THROWS_WITH_AS(parser_helper("\"\x0d\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r; last read: '\"<U+000D>'", json::parse_error&);
386                CHECK_THROWS_WITH_AS(parser_helper("\"\x0e\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000E (SO) must be escaped to \\u000E; last read: '\"<U+000E>'", json::parse_error&);
387                CHECK_THROWS_WITH_AS(parser_helper("\"\x0f\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000F (SI) must be escaped to \\u000F; last read: '\"<U+000F>'", json::parse_error&);
388                CHECK_THROWS_WITH_AS(parser_helper("\"\x10\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0010 (DLE) must be escaped to \\u0010; last read: '\"<U+0010>'", json::parse_error&);
389                CHECK_THROWS_WITH_AS(parser_helper("\"\x11\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0011 (DC1) must be escaped to \\u0011; last read: '\"<U+0011>'", json::parse_error&);
390                CHECK_THROWS_WITH_AS(parser_helper("\"\x12\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0012 (DC2) must be escaped to \\u0012; last read: '\"<U+0012>'", json::parse_error&);
391                CHECK_THROWS_WITH_AS(parser_helper("\"\x13\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0013 (DC3) must be escaped to \\u0013; last read: '\"<U+0013>'", json::parse_error&);
392                CHECK_THROWS_WITH_AS(parser_helper("\"\x14\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0014 (DC4) must be escaped to \\u0014; last read: '\"<U+0014>'", json::parse_error&);
393                CHECK_THROWS_WITH_AS(parser_helper("\"\x15\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0015 (NAK) must be escaped to \\u0015; last read: '\"<U+0015>'", json::parse_error&);
394                CHECK_THROWS_WITH_AS(parser_helper("\"\x16\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0016 (SYN) must be escaped to \\u0016; last read: '\"<U+0016>'", json::parse_error&);
395                CHECK_THROWS_WITH_AS(parser_helper("\"\x17\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0017 (ETB) must be escaped to \\u0017; last read: '\"<U+0017>'", json::parse_error&);
396                CHECK_THROWS_WITH_AS(parser_helper("\"\x18\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0018 (CAN) must be escaped to \\u0018; last read: '\"<U+0018>'", json::parse_error&);
397                CHECK_THROWS_WITH_AS(parser_helper("\"\x19\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0019 (EM) must be escaped to \\u0019; last read: '\"<U+0019>'", json::parse_error&);
398                CHECK_THROWS_WITH_AS(parser_helper("\"\x1a\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001A (SUB) must be escaped to \\u001A; last read: '\"<U+001A>'", json::parse_error&);
399                CHECK_THROWS_WITH_AS(parser_helper("\"\x1b\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001B (ESC) must be escaped to \\u001B; last read: '\"<U+001B>'", json::parse_error&);
400                CHECK_THROWS_WITH_AS(parser_helper("\"\x1c\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001C (FS) must be escaped to \\u001C; last read: '\"<U+001C>'", json::parse_error&);
401                CHECK_THROWS_WITH_AS(parser_helper("\"\x1d\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001D (GS) must be escaped to \\u001D; last read: '\"<U+001D>'", json::parse_error&);
402                CHECK_THROWS_WITH_AS(parser_helper("\"\x1e\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001E (RS) must be escaped to \\u001E; last read: '\"<U+001E>'", json::parse_error&);
403                CHECK_THROWS_WITH_AS(parser_helper("\"\x1f\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001F (US) must be escaped to \\u001F; last read: '\"<U+001F>'", json::parse_error&);
404
405                SECTION("additional test for null byte")
406                {
407                    // The test above for the null byte is wrong, because passing
408                    // a string to the parser only reads int until it encounters
409                    // a null byte. This test inserts the null byte later on and
410                    // uses an iterator range.
411                    std::string s = "\"1\"";
412                    s[1] = '\0';
413                    json _;
414                    CHECK_THROWS_WITH_AS(_ = json::parse(s.begin(), s.end()), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0000 (NUL) must be escaped to \\u0000; last read: '\"<U+0000>'", json::parse_error&);
415                }
416            }
417
418            SECTION("escaped")
419            {
420                // quotation mark "\""
421                auto r1 = R"("\"")"_json;
422                CHECK(parser_helper("\"\\\"\"") == r1);
423                // reverse solidus "\\"
424                auto r2 = R"("\\")"_json;
425                CHECK(parser_helper("\"\\\\\"") == r2);
426                // solidus
427                CHECK(parser_helper("\"\\/\"") == R"("/")"_json);
428                // backspace
429                CHECK(parser_helper("\"\\b\"") == json("\b"));
430                // formfeed
431                CHECK(parser_helper("\"\\f\"") == json("\f"));
432                // newline
433                CHECK(parser_helper("\"\\n\"") == json("\n"));
434                // carriage return
435                CHECK(parser_helper("\"\\r\"") == json("\r"));
436                // horizontal tab
437                CHECK(parser_helper("\"\\t\"") == json("\t"));
438
439                CHECK(parser_helper("\"\\u0001\"").get<json::string_t>() == "\x01");
440                CHECK(parser_helper("\"\\u000a\"").get<json::string_t>() == "\n");
441                CHECK(parser_helper("\"\\u00b0\"").get<json::string_t>() == "°");
442                CHECK(parser_helper("\"\\u0c00\"").get<json::string_t>() == "ఀ");
443                CHECK(parser_helper("\"\\ud000\"").get<json::string_t>() == "퀀");
444                CHECK(parser_helper("\"\\u000E\"").get<json::string_t>() == "\x0E");
445                CHECK(parser_helper("\"\\u00F0\"").get<json::string_t>() == "ð");
446                CHECK(parser_helper("\"\\u0100\"").get<json::string_t>() == "Ā");
447                CHECK(parser_helper("\"\\u2000\"").get<json::string_t>() == " ");
448                CHECK(parser_helper("\"\\uFFFF\"").get<json::string_t>() == "￿");
449                CHECK(parser_helper("\"\\u20AC\"").get<json::string_t>() == "€");
450                CHECK(parser_helper("\"€\"").get<json::string_t>() == "€");
451                CHECK(parser_helper("\"�\"").get<json::string_t>() == "�");
452
453                CHECK(parser_helper("\"\\ud80c\\udc60\"").get<json::string_t>() == "\xf0\x93\x81\xa0");
454                CHECK(parser_helper("\"\\ud83c\\udf1e\"").get<json::string_t>() == "�");
455            }
456        }
457
458        SECTION("number")
459        {
460            SECTION("integers")
461            {
462                SECTION("without exponent")
463                {
464                    CHECK(parser_helper("-128") == json(-128));
465                    CHECK(parser_helper("-0") == json(-0));
466                    CHECK(parser_helper("0") == json(0));
467                    CHECK(parser_helper("128") == json(128));
468                }
469
470                SECTION("with exponent")
471                {
472                    CHECK(parser_helper("0e1") == json(0e1));
473                    CHECK(parser_helper("0E1") == json(0e1));
474
475                    CHECK(parser_helper("10000E-4") == json(10000e-4));
476                    CHECK(parser_helper("10000E-3") == json(10000e-3));
477                    CHECK(parser_helper("10000E-2") == json(10000e-2));
478                    CHECK(parser_helper("10000E-1") == json(10000e-1));
479                    CHECK(parser_helper("10000E0") == json(10000e0));
480                    CHECK(parser_helper("10000E1") == json(10000e1));
481                    CHECK(parser_helper("10000E2") == json(10000e2));
482                    CHECK(parser_helper("10000E3") == json(10000e3));
483                    CHECK(parser_helper("10000E4") == json(10000e4));
484
485                    CHECK(parser_helper("10000e-4") == json(10000e-4));
486                    CHECK(parser_helper("10000e-3") == json(10000e-3));
487                    CHECK(parser_helper("10000e-2") == json(10000e-2));
488                    CHECK(parser_helper("10000e-1") == json(10000e-1));
489                    CHECK(parser_helper("10000e0") == json(10000e0));
490                    CHECK(parser_helper("10000e1") == json(10000e1));
491                    CHECK(parser_helper("10000e2") == json(10000e2));
492                    CHECK(parser_helper("10000e3") == json(10000e3));
493                    CHECK(parser_helper("10000e4") == json(10000e4));
494
495                    CHECK(parser_helper("-0e1") == json(-0e1));
496                    CHECK(parser_helper("-0E1") == json(-0e1));
497                    CHECK(parser_helper("-0E123") == json(-0e123));
498
499                    // numbers after exponent
500                    CHECK(parser_helper("10E0") == json(10e0));
501                    CHECK(parser_helper("10E1") == json(10e1));
502                    CHECK(parser_helper("10E2") == json(10e2));
503                    CHECK(parser_helper("10E3") == json(10e3));
504                    CHECK(parser_helper("10E4") == json(10e4));
505                    CHECK(parser_helper("10E5") == json(10e5));
506                    CHECK(parser_helper("10E6") == json(10e6));
507                    CHECK(parser_helper("10E7") == json(10e7));
508                    CHECK(parser_helper("10E8") == json(10e8));
509                    CHECK(parser_helper("10E9") == json(10e9));
510                    CHECK(parser_helper("10E+0") == json(10e0));
511                    CHECK(parser_helper("10E+1") == json(10e1));
512                    CHECK(parser_helper("10E+2") == json(10e2));
513                    CHECK(parser_helper("10E+3") == json(10e3));
514                    CHECK(parser_helper("10E+4") == json(10e4));
515                    CHECK(parser_helper("10E+5") == json(10e5));
516                    CHECK(parser_helper("10E+6") == json(10e6));
517                    CHECK(parser_helper("10E+7") == json(10e7));
518                    CHECK(parser_helper("10E+8") == json(10e8));
519                    CHECK(parser_helper("10E+9") == json(10e9));
520                    CHECK(parser_helper("10E-1") == json(10e-1));
521                    CHECK(parser_helper("10E-2") == json(10e-2));
522                    CHECK(parser_helper("10E-3") == json(10e-3));
523                    CHECK(parser_helper("10E-4") == json(10e-4));
524                    CHECK(parser_helper("10E-5") == json(10e-5));
525                    CHECK(parser_helper("10E-6") == json(10e-6));
526                    CHECK(parser_helper("10E-7") == json(10e-7));
527                    CHECK(parser_helper("10E-8") == json(10e-8));
528                    CHECK(parser_helper("10E-9") == json(10e-9));
529                }
530
531                SECTION("edge cases")
532                {
533                    // From RFC8259, Section 6:
534                    // Note that when such software is used, numbers that are
535                    // integers and are in the range [-(2**53)+1, (2**53)-1]
536                    // are interoperable in the sense that implementations will
537                    // agree exactly on their numeric values.
538
539                    // -(2**53)+1
540                    CHECK(parser_helper("-9007199254740991").get<int64_t>() == -9007199254740991);
541                    // (2**53)-1
542                    CHECK(parser_helper("9007199254740991").get<int64_t>() == 9007199254740991);
543                }
544
545                SECTION("over the edge cases")  // issue #178 - Integer conversion to unsigned (incorrect handling of 64 bit integers)
546                {
547                    // While RFC8259, Section 6 specifies a preference for support
548                    // for ranges in range of IEEE 754-2008 binary64 (double precision)
549                    // this does not accommodate 64 bit integers without loss of accuracy.
550                    // As 64 bit integers are now widely used in software, it is desirable
551                    // to expand support to to the full 64 bit (signed and unsigned) range
552                    // i.e. -(2**63) -> (2**64)-1.
553
554                    // -(2**63)    ** Note: compilers see negative literals as negated positive numbers (hence the -1))
555                    CHECK(parser_helper("-9223372036854775808").get<int64_t>() == -9223372036854775807 - 1);
556                    // (2**63)-1
557                    CHECK(parser_helper("9223372036854775807").get<int64_t>() == 9223372036854775807);
558                    // (2**64)-1
559                    CHECK(parser_helper("18446744073709551615").get<uint64_t>() == 18446744073709551615u);
560                }
561            }
562
563            SECTION("floating-point")
564            {
565                SECTION("without exponent")
566                {
567                    CHECK(parser_helper("-128.5") == json(-128.5));
568                    CHECK(parser_helper("0.999") == json(0.999));
569                    CHECK(parser_helper("128.5") == json(128.5));
570                    CHECK(parser_helper("-0.0") == json(-0.0));
571                }
572
573                SECTION("with exponent")
574                {
575                    CHECK(parser_helper("-128.5E3") == json(-128.5E3));
576                    CHECK(parser_helper("-128.5E-3") == json(-128.5E-3));
577                    CHECK(parser_helper("-0.0e1") == json(-0.0e1));
578                    CHECK(parser_helper("-0.0E1") == json(-0.0e1));
579                }
580            }
581
582            SECTION("overflow")
583            {
584                // overflows during parsing yield an exception
585                CHECK_THROWS_WITH_AS(parser_helper("1.18973e+4932").empty(), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&);
586            }
587
588            SECTION("invalid numbers")
589            {
590                // numbers must not begin with "+"
591                CHECK_THROWS_AS(parser_helper("+1"), json::parse_error&);
592                CHECK_THROWS_AS(parser_helper("+0"), json::parse_error&);
593
594                CHECK_THROWS_WITH_AS(parser_helper("01"),
595                                     "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - unexpected number literal; expected end of input", json::parse_error&);
596                CHECK_THROWS_WITH_AS(parser_helper("-01"),
597                                     "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - unexpected number literal; expected end of input", json::parse_error&);
598                CHECK_THROWS_WITH_AS(parser_helper("--1"),
599                                     "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '--'", json::parse_error&);
600                CHECK_THROWS_WITH_AS(parser_helper("1."),
601                                     "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '1.'", json::parse_error&);
602                CHECK_THROWS_WITH_AS(parser_helper("1E"),
603                                     "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E'", json::parse_error&);
604                CHECK_THROWS_WITH_AS(parser_helper("1E-"),
605                                     "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '1E-'", json::parse_error&);
606                CHECK_THROWS_WITH_AS(parser_helper("1.E1"),
607                                     "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '1.E'", json::parse_error&);
608                CHECK_THROWS_WITH_AS(parser_helper("-1E"),
609                                     "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '-1E'", json::parse_error&);
610                CHECK_THROWS_WITH_AS(parser_helper("-0E#"),
611                                     "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '-0E#'", json::parse_error&);
612                CHECK_THROWS_WITH_AS(parser_helper("-0E-#"),
613                                     "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '-0E-#'", json::parse_error&);
614                CHECK_THROWS_WITH_AS(parser_helper("-0#"),
615                                     "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: '-0#'; expected end of input", json::parse_error&);
616                CHECK_THROWS_WITH_AS(parser_helper("-0.0:"),
617                                     "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - unexpected ':'; expected end of input", json::parse_error&);
618                CHECK_THROWS_WITH_AS(parser_helper("-0.0Z"),
619                                     "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: '-0.0Z'; expected end of input", json::parse_error&);
620                CHECK_THROWS_WITH_AS(parser_helper("-0E123:"),
621                                     "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - unexpected ':'; expected end of input", json::parse_error&);
622                CHECK_THROWS_WITH_AS(parser_helper("-0e0-:"),
623                                     "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-:'; expected end of input", json::parse_error&);
624                CHECK_THROWS_WITH_AS(parser_helper("-0e-:"),
625                                     "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '-0e-:'", json::parse_error&);
626                CHECK_THROWS_WITH_AS(parser_helper("-0f"),
627                                     "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: '-0f'; expected end of input", json::parse_error&);
628            }
629        }
630    }
631
632    SECTION("accept")
633    {
634        SECTION("null")
635        {
636            CHECK(accept_helper("null"));
637        }
638
639        SECTION("true")
640        {
641            CHECK(accept_helper("true"));
642        }
643
644        SECTION("false")
645        {
646            CHECK(accept_helper("false"));
647        }
648
649        SECTION("array")
650        {
651            SECTION("empty array")
652            {
653                CHECK(accept_helper("[]"));
654                CHECK(accept_helper("[ ]"));
655            }
656
657            SECTION("nonempty array")
658            {
659                CHECK(accept_helper("[true, false, null]"));
660            }
661        }
662
663        SECTION("object")
664        {
665            SECTION("empty object")
666            {
667                CHECK(accept_helper("{}"));
668                CHECK(accept_helper("{ }"));
669            }
670
671            SECTION("nonempty object")
672            {
673                CHECK(accept_helper("{\"\": true, \"one\": 1, \"two\": null}"));
674            }
675        }
676
677        SECTION("string")
678        {
679            // empty string
680            CHECK(accept_helper("\"\""));
681
682            SECTION("errors")
683            {
684                // error: tab in string
685                CHECK(accept_helper("\"\t\"") == false);
686                // error: newline in string
687                CHECK(accept_helper("\"\n\"") == false);
688                CHECK(accept_helper("\"\r\"") == false);
689                // error: backspace in string
690                CHECK(accept_helper("\"\b\"") == false);
691                // improve code coverage
692                CHECK(accept_helper("\uFF01") == false);
693                CHECK(accept_helper("[-4:1,]") == false);
694                // unescaped control characters
695                CHECK(accept_helper("\"\x00\"") == false); // NOLINT(bugprone-string-literal-with-embedded-nul)
696                CHECK(accept_helper("\"\x01\"") == false);
697                CHECK(accept_helper("\"\x02\"") == false);
698                CHECK(accept_helper("\"\x03\"") == false);
699                CHECK(accept_helper("\"\x04\"") == false);
700                CHECK(accept_helper("\"\x05\"") == false);
701                CHECK(accept_helper("\"\x06\"") == false);
702                CHECK(accept_helper("\"\x07\"") == false);
703                CHECK(accept_helper("\"\x08\"") == false);
704                CHECK(accept_helper("\"\x09\"") == false);
705                CHECK(accept_helper("\"\x0a\"") == false);
706                CHECK(accept_helper("\"\x0b\"") == false);
707                CHECK(accept_helper("\"\x0c\"") == false);
708                CHECK(accept_helper("\"\x0d\"") == false);
709                CHECK(accept_helper("\"\x0e\"") == false);
710                CHECK(accept_helper("\"\x0f\"") == false);
711                CHECK(accept_helper("\"\x10\"") == false);
712                CHECK(accept_helper("\"\x11\"") == false);
713                CHECK(accept_helper("\"\x12\"") == false);
714                CHECK(accept_helper("\"\x13\"") == false);
715                CHECK(accept_helper("\"\x14\"") == false);
716                CHECK(accept_helper("\"\x15\"") == false);
717                CHECK(accept_helper("\"\x16\"") == false);
718                CHECK(accept_helper("\"\x17\"") == false);
719                CHECK(accept_helper("\"\x18\"") == false);
720                CHECK(accept_helper("\"\x19\"") == false);
721                CHECK(accept_helper("\"\x1a\"") == false);
722                CHECK(accept_helper("\"\x1b\"") == false);
723                CHECK(accept_helper("\"\x1c\"") == false);
724                CHECK(accept_helper("\"\x1d\"") == false);
725                CHECK(accept_helper("\"\x1e\"") == false);
726                CHECK(accept_helper("\"\x1f\"") == false);
727            }
728
729            SECTION("escaped")
730            {
731                // quotation mark "\""
732                auto r1 = R"("\"")"_json;
733                CHECK(accept_helper("\"\\\"\""));
734                // reverse solidus "\\"
735                auto r2 = R"("\\")"_json;
736                CHECK(accept_helper("\"\\\\\""));
737                // solidus
738                CHECK(accept_helper("\"\\/\""));
739                // backspace
740                CHECK(accept_helper("\"\\b\""));
741                // formfeed
742                CHECK(accept_helper("\"\\f\""));
743                // newline
744                CHECK(accept_helper("\"\\n\""));
745                // carriage return
746                CHECK(accept_helper("\"\\r\""));
747                // horizontal tab
748                CHECK(accept_helper("\"\\t\""));
749
750                CHECK(accept_helper("\"\\u0001\""));
751                CHECK(accept_helper("\"\\u000a\""));
752                CHECK(accept_helper("\"\\u00b0\""));
753                CHECK(accept_helper("\"\\u0c00\""));
754                CHECK(accept_helper("\"\\ud000\""));
755                CHECK(accept_helper("\"\\u000E\""));
756                CHECK(accept_helper("\"\\u00F0\""));
757                CHECK(accept_helper("\"\\u0100\""));
758                CHECK(accept_helper("\"\\u2000\""));
759                CHECK(accept_helper("\"\\uFFFF\""));
760                CHECK(accept_helper("\"\\u20AC\""));
761                CHECK(accept_helper("\"€\""));
762                CHECK(accept_helper("\"�\""));
763
764                CHECK(accept_helper("\"\\ud80c\\udc60\""));
765                CHECK(accept_helper("\"\\ud83c\\udf1e\""));
766            }
767        }
768
769        SECTION("number")
770        {
771            SECTION("integers")
772            {
773                SECTION("without exponent")
774                {
775                    CHECK(accept_helper("-128"));
776                    CHECK(accept_helper("-0"));
777                    CHECK(accept_helper("0"));
778                    CHECK(accept_helper("128"));
779                }
780
781                SECTION("with exponent")
782                {
783                    CHECK(accept_helper("0e1"));
784                    CHECK(accept_helper("0E1"));
785
786                    CHECK(accept_helper("10000E-4"));
787                    CHECK(accept_helper("10000E-3"));
788                    CHECK(accept_helper("10000E-2"));
789                    CHECK(accept_helper("10000E-1"));
790                    CHECK(accept_helper("10000E0"));
791                    CHECK(accept_helper("10000E1"));
792                    CHECK(accept_helper("10000E2"));
793                    CHECK(accept_helper("10000E3"));
794                    CHECK(accept_helper("10000E4"));
795
796                    CHECK(accept_helper("10000e-4"));
797                    CHECK(accept_helper("10000e-3"));
798                    CHECK(accept_helper("10000e-2"));
799                    CHECK(accept_helper("10000e-1"));
800                    CHECK(accept_helper("10000e0"));
801                    CHECK(accept_helper("10000e1"));
802                    CHECK(accept_helper("10000e2"));
803                    CHECK(accept_helper("10000e3"));
804                    CHECK(accept_helper("10000e4"));
805
806                    CHECK(accept_helper("-0e1"));
807                    CHECK(accept_helper("-0E1"));
808                    CHECK(accept_helper("-0E123"));
809                }
810
811                SECTION("edge cases")
812                {
813                    // From RFC8259, Section 6:
814                    // Note that when such software is used, numbers that are
815                    // integers and are in the range [-(2**53)+1, (2**53)-1]
816                    // are interoperable in the sense that implementations will
817                    // agree exactly on their numeric values.
818
819                    // -(2**53)+1
820                    CHECK(accept_helper("-9007199254740991"));
821                    // (2**53)-1
822                    CHECK(accept_helper("9007199254740991"));
823                }
824
825                SECTION("over the edge cases")  // issue #178 - Integer conversion to unsigned (incorrect handling of 64 bit integers)
826                {
827                    // While RFC8259, Section 6 specifies a preference for support
828                    // for ranges in range of IEEE 754-2008 binary64 (double precision)
829                    // this does not accommodate 64 bit integers without loss of accuracy.
830                    // As 64 bit integers are now widely used in software, it is desirable
831                    // to expand support to to the full 64 bit (signed and unsigned) range
832                    // i.e. -(2**63) -> (2**64)-1.
833
834                    // -(2**63)    ** Note: compilers see negative literals as negated positive numbers (hence the -1))
835                    CHECK(accept_helper("-9223372036854775808"));
836                    // (2**63)-1
837                    CHECK(accept_helper("9223372036854775807"));
838                    // (2**64)-1
839                    CHECK(accept_helper("18446744073709551615"));
840                }
841            }
842
843            SECTION("floating-point")
844            {
845                SECTION("without exponent")
846                {
847                    CHECK(accept_helper("-128.5"));
848                    CHECK(accept_helper("0.999"));
849                    CHECK(accept_helper("128.5"));
850                    CHECK(accept_helper("-0.0"));
851                }
852
853                SECTION("with exponent")
854                {
855                    CHECK(accept_helper("-128.5E3"));
856                    CHECK(accept_helper("-128.5E-3"));
857                    CHECK(accept_helper("-0.0e1"));
858                    CHECK(accept_helper("-0.0E1"));
859                }
860            }
861
862            SECTION("overflow")
863            {
864                // overflows during parsing
865                CHECK(!accept_helper("1.18973e+4932"));
866            }
867
868            SECTION("invalid numbers")
869            {
870                CHECK(accept_helper("01") == false);
871                CHECK(accept_helper("--1") == false);
872                CHECK(accept_helper("1.") == false);
873                CHECK(accept_helper("1E") == false);
874                CHECK(accept_helper("1E-") == false);
875                CHECK(accept_helper("1.E1") == false);
876                CHECK(accept_helper("-1E") == false);
877                CHECK(accept_helper("-0E#") == false);
878                CHECK(accept_helper("-0E-#") == false);
879                CHECK(accept_helper("-0#") == false);
880                CHECK(accept_helper("-0.0:") == false);
881                CHECK(accept_helper("-0.0Z") == false);
882                CHECK(accept_helper("-0E123:") == false);
883                CHECK(accept_helper("-0e0-:") == false);
884                CHECK(accept_helper("-0e-:") == false);
885                CHECK(accept_helper("-0f") == false);
886
887                // numbers must not begin with "+"
888                CHECK(accept_helper("+1") == false);
889                CHECK(accept_helper("+0") == false);
890            }
891        }
892    }
893
894    SECTION("parse errors")
895    {
896        // unexpected end of number
897        CHECK_THROWS_WITH_AS(parser_helper("0."),
898                             "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '0.'", json::parse_error&);
899        CHECK_THROWS_WITH_AS(parser_helper("-"),
900                             "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-'", json::parse_error&);
901        CHECK_THROWS_WITH_AS(parser_helper("--"),
902                             "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '--'", json::parse_error&);
903        CHECK_THROWS_WITH_AS(parser_helper("-0."),
904                             "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected digit after '.'; last read: '-0.'", json::parse_error&);
905        CHECK_THROWS_WITH_AS(parser_helper("-."),
906                             "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-.'", json::parse_error&);
907        CHECK_THROWS_WITH_AS(parser_helper("-:"),
908                             "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-:'", json::parse_error&);
909        CHECK_THROWS_WITH_AS(parser_helper("0.:"),
910                             "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '0.:'", json::parse_error&);
911        CHECK_THROWS_WITH_AS(parser_helper("e."),
912                             "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'e'", json::parse_error&);
913        CHECK_THROWS_WITH_AS(parser_helper("1e."),
914                             "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e.'", json::parse_error&);
915        CHECK_THROWS_WITH_AS(parser_helper("1e/"),
916                             "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e/'", json::parse_error&);
917        CHECK_THROWS_WITH_AS(parser_helper("1e:"),
918                             "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e:'", json::parse_error&);
919        CHECK_THROWS_WITH_AS(parser_helper("1E."),
920                             "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E.'", json::parse_error&);
921        CHECK_THROWS_WITH_AS(parser_helper("1E/"),
922                             "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E/'", json::parse_error&);
923        CHECK_THROWS_WITH_AS(parser_helper("1E:"),
924                             "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E:'", json::parse_error&);
925
926        // unexpected end of null
927        CHECK_THROWS_WITH_AS(parser_helper("n"),
928                             "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 'n'", json::parse_error&);
929        CHECK_THROWS_WITH_AS(parser_helper("nu"),
930                             "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'nu'", json::parse_error&);
931        CHECK_THROWS_WITH_AS(parser_helper("nul"),
932                             "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nul'", json::parse_error&);
933        CHECK_THROWS_WITH_AS(parser_helper("nulk"),
934                             "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nulk'", json::parse_error&);
935        CHECK_THROWS_WITH_AS(parser_helper("nulm"),
936                             "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nulm'", json::parse_error&);
937
938        // unexpected end of true
939        CHECK_THROWS_WITH_AS(parser_helper("t"),
940                             "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 't'", json::parse_error&);
941        CHECK_THROWS_WITH_AS(parser_helper("tr"),
942                             "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'tr'", json::parse_error&);
943        CHECK_THROWS_WITH_AS(parser_helper("tru"),
944                             "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'tru'", json::parse_error&);
945        CHECK_THROWS_WITH_AS(parser_helper("trud"),
946                             "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'trud'", json::parse_error&);
947        CHECK_THROWS_WITH_AS(parser_helper("truf"),
948                             "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'truf'", json::parse_error&);
949
950        // unexpected end of false
951        CHECK_THROWS_WITH_AS(parser_helper("f"),
952                             "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 'f'", json::parse_error&);
953        CHECK_THROWS_WITH_AS(parser_helper("fa"),
954                             "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'fa'", json::parse_error&);
955        CHECK_THROWS_WITH_AS(parser_helper("fal"),
956                             "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'fal'", json::parse_error&);
957        CHECK_THROWS_WITH_AS(parser_helper("fals"),
958                             "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'fals'", json::parse_error&);
959        CHECK_THROWS_WITH_AS(parser_helper("falsd"),
960                             "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'falsd'", json::parse_error&);
961        CHECK_THROWS_WITH_AS(parser_helper("falsf"),
962                             "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'falsf'", json::parse_error&);
963
964        // missing/unexpected end of array
965        CHECK_THROWS_WITH_AS(parser_helper("["),
966                             "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
967        CHECK_THROWS_WITH_AS(parser_helper("[1"),
968                             "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing array - unexpected end of input; expected ']'", json::parse_error&);
969        CHECK_THROWS_WITH_AS(parser_helper("[1,"),
970                             "[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&);
971        CHECK_THROWS_WITH_AS(parser_helper("[1,]"),
972                             "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal", json::parse_error&);
973        CHECK_THROWS_WITH_AS(parser_helper("]"),
974                             "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal", json::parse_error&);
975
976        // missing/unexpected end of object
977        CHECK_THROWS_WITH_AS(parser_helper("{"),
978                             "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing object key - unexpected end of input; expected string literal", json::parse_error&);
979        CHECK_THROWS_WITH_AS(parser_helper("{\"foo\""),
980                             "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing object separator - unexpected end of input; expected ':'", json::parse_error&);
981        CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":"),
982                             "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
983        CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":}"),
984                             "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected '}'; expected '[', '{', or a literal", json::parse_error&);
985        CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":1,}"),
986                             "[json.exception.parse_error.101] parse error at line 1, column 10: syntax error while parsing object key - unexpected '}'; expected string literal", json::parse_error&);
987        CHECK_THROWS_WITH_AS(parser_helper("}"),
988                             "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected '}'; expected '[', '{', or a literal", json::parse_error&);
989
990        // missing/unexpected end of string
991        CHECK_THROWS_WITH_AS(parser_helper("\""),
992                             "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: missing closing quote; last read: '\"'", json::parse_error&);
993        CHECK_THROWS_WITH_AS(parser_helper("\"\\\""),
994                             "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: missing closing quote; last read: '\"\\\"'", json::parse_error&);
995        CHECK_THROWS_WITH_AS(parser_helper("\"\\u\""),
996                             "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u\"'", json::parse_error&);
997        CHECK_THROWS_WITH_AS(parser_helper("\"\\u0\""),
998                             "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0\"'", json::parse_error&);
999        CHECK_THROWS_WITH_AS(parser_helper("\"\\u01\""),
1000                             "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01\"'", json::parse_error&);
1001        CHECK_THROWS_WITH_AS(parser_helper("\"\\u012\""),
1002                             "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012\"'", json::parse_error&);
1003        CHECK_THROWS_WITH_AS(parser_helper("\"\\u"),
1004                             "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u'", json::parse_error&);
1005        CHECK_THROWS_WITH_AS(parser_helper("\"\\u0"),
1006                             "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0'", json::parse_error&);
1007        CHECK_THROWS_WITH_AS(parser_helper("\"\\u01"),
1008                             "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01'", json::parse_error&);
1009        CHECK_THROWS_WITH_AS(parser_helper("\"\\u012"),
1010                             "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012'", json::parse_error&);
1011
1012        // invalid escapes
1013        for (int c = 1; c < 128; ++c)
1014        {
1015            auto s = std::string("\"\\") + std::string(1, static_cast<char>(c)) + "\"";
1016
1017            switch (c)
1018            {
1019                // valid escapes
1020                case ('"'):
1021                case ('\\'):
1022                case ('/'):
1023                case ('b'):
1024                case ('f'):
1025                case ('n'):
1026                case ('r'):
1027                case ('t'):
1028                {
1029                    CHECK_NOTHROW(parser_helper(s));
1030                    break;
1031                }
1032
1033                // \u must be followed with four numbers, so we skip it here
1034                case ('u'):
1035                {
1036                    break;
1037                }
1038
1039                // any other combination of backslash and character is invalid
1040                default:
1041                {
1042                    CHECK_THROWS_AS(parser_helper(s), json::parse_error&);
1043                    // only check error message if c is not a control character
1044                    if (c > 0x1f)
1045                    {
1046                        CHECK_THROWS_WITH_STD_STR(parser_helper(s),
1047                                                  "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid string: forbidden character after backslash; last read: '\"\\" + std::string(1, static_cast<char>(c)) + "'");
1048                    }
1049                    break;
1050                }
1051            }
1052        }
1053
1054        // invalid \uxxxx escapes
1055        {
1056            // check whether character is a valid hex character
1057            const auto valid = [](int c)
1058            {
1059                switch (c)
1060                {
1061                    case ('0'):
1062                    case ('1'):
1063                    case ('2'):
1064                    case ('3'):
1065                    case ('4'):
1066                    case ('5'):
1067                    case ('6'):
1068                    case ('7'):
1069                    case ('8'):
1070                    case ('9'):
1071                    case ('a'):
1072                    case ('b'):
1073                    case ('c'):
1074                    case ('d'):
1075                    case ('e'):
1076                    case ('f'):
1077                    case ('A'):
1078                    case ('B'):
1079                    case ('C'):
1080                    case ('D'):
1081                    case ('E'):
1082                    case ('F'):
1083                    {
1084                        return true;
1085                    }
1086
1087                    default:
1088                    {
1089                        return false;
1090                    }
1091                }
1092            };
1093
1094            for (int c = 1; c < 128; ++c)
1095            {
1096                std::string s = "\"\\u";
1097
1098                // create a string with the iterated character at each position
1099                auto s1 = s + "000" + std::string(1, static_cast<char>(c)) + "\"";
1100                auto s2 = s + "00" + std::string(1, static_cast<char>(c)) + "0\"";
1101                auto s3 = s + "0" + std::string(1, static_cast<char>(c)) + "00\"";
1102                auto s4 = s + std::string(1, static_cast<char>(c)) + "000\"";
1103
1104                if (valid(c))
1105                {
1106                    CAPTURE(s1)
1107                    CHECK_NOTHROW(parser_helper(s1));
1108                    CAPTURE(s2)
1109                    CHECK_NOTHROW(parser_helper(s2));
1110                    CAPTURE(s3)
1111                    CHECK_NOTHROW(parser_helper(s3));
1112                    CAPTURE(s4)
1113                    CHECK_NOTHROW(parser_helper(s4));
1114                }
1115                else
1116                {
1117                    CAPTURE(s1)
1118                    CHECK_THROWS_AS(parser_helper(s1), json::parse_error&);
1119                    // only check error message if c is not a control character
1120                    if (c > 0x1f)
1121                    {
1122                        CHECK_THROWS_WITH_STD_STR(parser_helper(s1),
1123                                                  "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s1.substr(0, 7) + "'");
1124                    }
1125
1126                    CAPTURE(s2)
1127                    CHECK_THROWS_AS(parser_helper(s2), json::parse_error&);
1128                    // only check error message if c is not a control character
1129                    if (c > 0x1f)
1130                    {
1131                        CHECK_THROWS_WITH_STD_STR(parser_helper(s2),
1132                                                  "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s2.substr(0, 6) + "'");
1133                    }
1134
1135                    CAPTURE(s3)
1136                    CHECK_THROWS_AS(parser_helper(s3), json::parse_error&);
1137                    // only check error message if c is not a control character
1138                    if (c > 0x1f)
1139                    {
1140                        CHECK_THROWS_WITH_STD_STR(parser_helper(s3),
1141                                                  "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s3.substr(0, 5) + "'");
1142                    }
1143
1144                    CAPTURE(s4)
1145                    CHECK_THROWS_AS(parser_helper(s4), json::parse_error&);
1146                    // only check error message if c is not a control character
1147                    if (c > 0x1f)
1148                    {
1149                        CHECK_THROWS_WITH_STD_STR(parser_helper(s4),
1150                                                  "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s4.substr(0, 4) + "'");
1151                    }
1152                }
1153            }
1154        }
1155
1156        json _;
1157
1158        // missing part of a surrogate pair
1159        CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\""), "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\"'", json::parse_error&);
1160        // invalid surrogate pair
1161        CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\uD80C\""),
1162                             "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uD80C'", json::parse_error&);
1163        CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\u0000\""),
1164                             "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\u0000'", json::parse_error&);
1165        CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\uFFFF\""),
1166                             "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uFFFF'", json::parse_error&);
1167    }
1168
1169    SECTION("parse errors (accept)")
1170    {
1171        // unexpected end of number
1172        CHECK(accept_helper("0.") == false);
1173        CHECK(accept_helper("-") == false);
1174        CHECK(accept_helper("--") == false);
1175        CHECK(accept_helper("-0.") == false);
1176        CHECK(accept_helper("-.") == false);
1177        CHECK(accept_helper("-:") == false);
1178        CHECK(accept_helper("0.:") == false);
1179        CHECK(accept_helper("e.") == false);
1180        CHECK(accept_helper("1e.") == false);
1181        CHECK(accept_helper("1e/") == false);
1182        CHECK(accept_helper("1e:") == false);
1183        CHECK(accept_helper("1E.") == false);
1184        CHECK(accept_helper("1E/") == false);
1185        CHECK(accept_helper("1E:") == false);
1186
1187        // unexpected end of null
1188        CHECK(accept_helper("n") == false);
1189        CHECK(accept_helper("nu") == false);
1190        CHECK(accept_helper("nul") == false);
1191
1192        // unexpected end of true
1193        CHECK(accept_helper("t") == false);
1194        CHECK(accept_helper("tr") == false);
1195        CHECK(accept_helper("tru") == false);
1196
1197        // unexpected end of false
1198        CHECK(accept_helper("f") == false);
1199        CHECK(accept_helper("fa") == false);
1200        CHECK(accept_helper("fal") == false);
1201        CHECK(accept_helper("fals") == false);
1202
1203        // missing/unexpected end of array
1204        CHECK(accept_helper("[") == false);
1205        CHECK(accept_helper("[1") == false);
1206        CHECK(accept_helper("[1,") == false);
1207        CHECK(accept_helper("[1,]") == false);
1208        CHECK(accept_helper("]") == false);
1209
1210        // missing/unexpected end of object
1211        CHECK(accept_helper("{") == false);
1212        CHECK(accept_helper("{\"foo\"") == false);
1213        CHECK(accept_helper("{\"foo\":") == false);
1214        CHECK(accept_helper("{\"foo\":}") == false);
1215        CHECK(accept_helper("{\"foo\":1,}") == false);
1216        CHECK(accept_helper("}") == false);
1217
1218        // missing/unexpected end of string
1219        CHECK(accept_helper("\"") == false);
1220        CHECK(accept_helper("\"\\\"") == false);
1221        CHECK(accept_helper("\"\\u\"") == false);
1222        CHECK(accept_helper("\"\\u0\"") == false);
1223        CHECK(accept_helper("\"\\u01\"") == false);
1224        CHECK(accept_helper("\"\\u012\"") == false);
1225        CHECK(accept_helper("\"\\u") == false);
1226        CHECK(accept_helper("\"\\u0") == false);
1227        CHECK(accept_helper("\"\\u01") == false);
1228        CHECK(accept_helper("\"\\u012") == false);
1229
1230        // unget of newline
1231        CHECK(parser_helper("\n123\n") == 123);
1232
1233        // invalid escapes
1234        for (int c = 1; c < 128; ++c)
1235        {
1236            auto s = std::string("\"\\") + std::string(1, static_cast<char>(c)) + "\"";
1237
1238            switch (c)
1239            {
1240                // valid escapes
1241                case ('"'):
1242                case ('\\'):
1243                case ('/'):
1244                case ('b'):
1245                case ('f'):
1246                case ('n'):
1247                case ('r'):
1248                case ('t'):
1249                {
1250                    CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept());
1251                    break;
1252                }
1253
1254                // \u must be followed with four numbers, so we skip it here
1255                case ('u'):
1256                {
1257                    break;
1258                }
1259
1260                // any other combination of backslash and character is invalid
1261                default:
1262                {
1263                    CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept() == false);
1264                    break;
1265                }
1266            }
1267        }
1268
1269        // invalid \uxxxx escapes
1270        {
1271            // check whether character is a valid hex character
1272            const auto valid = [](int c)
1273            {
1274                switch (c)
1275                {
1276                    case ('0'):
1277                    case ('1'):
1278                    case ('2'):
1279                    case ('3'):
1280                    case ('4'):
1281                    case ('5'):
1282                    case ('6'):
1283                    case ('7'):
1284                    case ('8'):
1285                    case ('9'):
1286                    case ('a'):
1287                    case ('b'):
1288                    case ('c'):
1289                    case ('d'):
1290                    case ('e'):
1291                    case ('f'):
1292                    case ('A'):
1293                    case ('B'):
1294                    case ('C'):
1295                    case ('D'):
1296                    case ('E'):
1297                    case ('F'):
1298                    {
1299                        return true;
1300                    }
1301
1302                    default:
1303                    {
1304                        return false;
1305                    }
1306                }
1307            };
1308
1309            for (int c = 1; c < 128; ++c)
1310            {
1311                std::string s = "\"\\u";
1312
1313                // create a string with the iterated character at each position
1314                const auto s1 = s + "000" + std::string(1, static_cast<char>(c)) + "\"";
1315                const auto s2 = s + "00" + std::string(1, static_cast<char>(c)) + "0\"";
1316                const auto s3 = s + "0" + std::string(1, static_cast<char>(c)) + "00\"";
1317                const auto s4 = s + std::string(1, static_cast<char>(c)) + "000\"";
1318
1319                if (valid(c))
1320                {
1321                    CAPTURE(s1)
1322                    CHECK(json::parser(nlohmann::detail::input_adapter(s1)).accept());
1323                    CAPTURE(s2)
1324                    CHECK(json::parser(nlohmann::detail::input_adapter(s2)).accept());
1325                    CAPTURE(s3)
1326                    CHECK(json::parser(nlohmann::detail::input_adapter(s3)).accept());
1327                    CAPTURE(s4)
1328                    CHECK(json::parser(nlohmann::detail::input_adapter(s4)).accept());
1329                }
1330                else
1331                {
1332                    CAPTURE(s1)
1333                    CHECK(json::parser(nlohmann::detail::input_adapter(s1)).accept() == false);
1334
1335                    CAPTURE(s2)
1336                    CHECK(json::parser(nlohmann::detail::input_adapter(s2)).accept() == false);
1337
1338                    CAPTURE(s3)
1339                    CHECK(json::parser(nlohmann::detail::input_adapter(s3)).accept() == false);
1340
1341                    CAPTURE(s4)
1342                    CHECK(json::parser(nlohmann::detail::input_adapter(s4)).accept() == false);
1343                }
1344            }
1345        }
1346
1347        // missing part of a surrogate pair
1348        CHECK(accept_helper("\"\\uD80C\"") == false);
1349        // invalid surrogate pair
1350        CHECK(accept_helper("\"\\uD80C\\uD80C\"") == false);
1351        CHECK(accept_helper("\"\\uD80C\\u0000\"") == false);
1352        CHECK(accept_helper("\"\\uD80C\\uFFFF\"") == false);
1353    }
1354
1355    SECTION("tests found by mutate++")
1356    {
1357        // test case to make sure no comma precedes the first key
1358        CHECK_THROWS_WITH_AS(parser_helper("{,\"key\": false}"), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing object key - unexpected ','; expected string literal", json::parse_error&);
1359        // test case to make sure an object is properly closed
1360        CHECK_THROWS_WITH_AS(parser_helper("[{\"key\": false true]"), "[json.exception.parse_error.101] parse error at line 1, column 19: syntax error while parsing object - unexpected true literal; expected '}'", json::parse_error&);
1361
1362        // test case to make sure the callback is properly evaluated after reading a key
1363        {
1364            json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t event, json& /*unused*/) noexcept
1365            {
1366                return event != json::parse_event_t::key;
1367            };
1368
1369            json x = json::parse("{\"key\": false}", cb);
1370            CHECK(x == json::object());
1371        }
1372    }
1373
1374    SECTION("callback function")
1375    {
1376        const auto* s_object = R"(
1377            {
1378                "foo": 2,
1379                "bar": {
1380                    "baz": 1
1381                }
1382            }
1383        )";
1384
1385        const auto* s_array = R"(
1386            [1,2,[3,4,5],4,5]
1387        )";
1388
1389        const auto* structured_array = R"(
1390            [
1391                1,
1392                {
1393                     "foo": "bar"
1394                },
1395                {
1396                     "qux": "baz"
1397                }
1398            ]
1399        )";
1400
1401        SECTION("filter nothing")
1402        {
1403            json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
1404            {
1405                return true;
1406            });
1407
1408            CHECK (j_object == json({{"foo", 2}, {"bar", {{"baz", 1}}}}));
1409
1410            json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
1411            {
1412                return true;
1413            });
1414
1415            CHECK (j_array == json({1, 2, {3, 4, 5}, 4, 5}));
1416        }
1417
1418        SECTION("filter everything")
1419        {
1420            json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
1421            {
1422                return false;
1423            });
1424
1425            // the top-level object will be discarded, leaving a null
1426            CHECK (j_object.is_null());
1427
1428            json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
1429            {
1430                return false;
1431            });
1432
1433            // the top-level array will be discarded, leaving a null
1434            CHECK (j_array.is_null());
1435        }
1436
1437        SECTION("filter specific element")
1438        {
1439            json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t event, const json & j) noexcept
1440            {
1441                // filter all number(2) elements
1442                return event != json::parse_event_t::value || j != json(2);
1443            });
1444
1445            CHECK (j_object == json({{"bar", {{"baz", 1}}}}));
1446
1447            json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t event, const json & j) noexcept
1448            {
1449                return event != json::parse_event_t::value || j != json(2);
1450            });
1451
1452            CHECK (j_array == json({1, {3, 4, 5}, 4, 5}));
1453        }
1454
1455        SECTION("filter object in array")
1456        {
1457            json j_filtered1 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json & parsed)
1458            {
1459                return !(e == json::parse_event_t::object_end && parsed.contains("foo"));
1460            });
1461
1462            // the specified object will be discarded, and removed.
1463            CHECK (j_filtered1.size() == 2);
1464            CHECK (j_filtered1 == json({1, {{"qux", "baz"}}}));
1465
1466            json j_filtered2 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json& /*parsed*/) noexcept
1467            {
1468                return e != json::parse_event_t::object_end;
1469            });
1470
1471            // removed all objects in array.
1472            CHECK (j_filtered2.size() == 1);
1473            CHECK (j_filtered2 == json({1}));
1474        }
1475
1476        SECTION("filter specific events")
1477        {
1478            SECTION("first closing event")
1479            {
1480                {
1481                    json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept
1482                    {
1483                        static bool first = true;
1484                        if (e == json::parse_event_t::object_end && first)
1485                        {
1486                            first = false;
1487                            return false;
1488                        }
1489
1490                        return true;
1491                    });
1492
1493                    // the first completed object will be discarded
1494                    CHECK (j_object == json({{"foo", 2}}));
1495                }
1496
1497                {
1498                    json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept
1499                    {
1500                        static bool first = true;
1501                        if (e == json::parse_event_t::array_end && first)
1502                        {
1503                            first = false;
1504                            return false;
1505                        }
1506
1507                        return true;
1508                    });
1509
1510                    // the first completed array will be discarded
1511                    CHECK (j_array == json({1, 2, 4, 5}));
1512                }
1513            }
1514        }
1515
1516        SECTION("special cases")
1517        {
1518            // the following test cases cover the situation in which an empty
1519            // object and array is discarded only after the closing character
1520            // has been read
1521
1522            json j_empty_object = json::parse("{}", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept
1523            {
1524                return e != json::parse_event_t::object_end;
1525            });
1526            CHECK(j_empty_object == json());
1527
1528            json j_empty_array = json::parse("[]", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept
1529            {
1530                return e != json::parse_event_t::array_end;
1531            });
1532            CHECK(j_empty_array == json());
1533        }
1534    }
1535
1536    SECTION("constructing from contiguous containers")
1537    {
1538        SECTION("from std::vector")
1539        {
1540            std::vector<uint8_t> v = {'t', 'r', 'u', 'e'};
1541            json j;
1542            json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j);
1543            CHECK(j == json(true));
1544        }
1545
1546        SECTION("from std::array")
1547        {
1548            std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e'} };
1549            json j;
1550            json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j);
1551            CHECK(j == json(true));
1552        }
1553
1554        SECTION("from array")
1555        {
1556            uint8_t v[] = {'t', 'r', 'u', 'e'}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
1557            json j;
1558            json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j);
1559            CHECK(j == json(true));
1560        }
1561
1562        SECTION("from char literal")
1563        {
1564            CHECK(parser_helper("true") == json(true));
1565        }
1566
1567        SECTION("from std::string")
1568        {
1569            std::string v = {'t', 'r', 'u', 'e'};
1570            json j;
1571            json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j);
1572            CHECK(j == json(true));
1573        }
1574
1575        SECTION("from std::initializer_list")
1576        {
1577            std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e'};
1578            json j;
1579            json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j);
1580            CHECK(j == json(true));
1581        }
1582
1583        SECTION("from std::valarray")
1584        {
1585            std::valarray<uint8_t> v = {'t', 'r', 'u', 'e'};
1586            json j;
1587            json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j);
1588            CHECK(j == json(true));
1589        }
1590    }
1591
1592    SECTION("improve test coverage")
1593    {
1594        SECTION("parser with callback")
1595        {
1596            json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept
1597            {
1598                return true;
1599            };
1600
1601            CHECK(json::parse("{\"foo\": true:", cb, false).is_discarded());
1602
1603            json _;
1604            CHECK_THROWS_WITH_AS(_ = json::parse("{\"foo\": true:", cb), "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing object - unexpected ':'; expected '}'", json::parse_error&);
1605
1606            CHECK_THROWS_WITH_AS(_ = json::parse("1.18973e+4932", cb), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&);
1607        }
1608
1609        SECTION("SAX parser")
1610        {
1611            SECTION("} without value")
1612            {
1613                SaxCountdown s(1);
1614                CHECK(json::sax_parse("{}", &s) == false);
1615            }
1616
1617            SECTION("} with value")
1618            {
1619                SaxCountdown s(3);
1620                CHECK(json::sax_parse("{\"k1\": true}", &s) == false);
1621            }
1622
1623            SECTION("second key")
1624            {
1625                SaxCountdown s(3);
1626                CHECK(json::sax_parse("{\"k1\": true, \"k2\": false}", &s) == false);
1627            }
1628
1629            SECTION("] without value")
1630            {
1631                SaxCountdown s(1);
1632                CHECK(json::sax_parse("[]", &s) == false);
1633            }
1634
1635            SECTION("] with value")
1636            {
1637                SaxCountdown s(2);
1638                CHECK(json::sax_parse("[1]", &s) == false);
1639            }
1640
1641            SECTION("float")
1642            {
1643                SaxCountdown s(0);
1644                CHECK(json::sax_parse("3.14", &s) == false);
1645            }
1646
1647            SECTION("false")
1648            {
1649                SaxCountdown s(0);
1650                CHECK(json::sax_parse("false", &s) == false);
1651            }
1652
1653            SECTION("null")
1654            {
1655                SaxCountdown s(0);
1656                CHECK(json::sax_parse("null", &s) == false);
1657            }
1658
1659            SECTION("true")
1660            {
1661                SaxCountdown s(0);
1662                CHECK(json::sax_parse("true", &s) == false);
1663            }
1664
1665            SECTION("unsigned")
1666            {
1667                SaxCountdown s(0);
1668                CHECK(json::sax_parse("12", &s) == false);
1669            }
1670
1671            SECTION("integer")
1672            {
1673                SaxCountdown s(0);
1674                CHECK(json::sax_parse("-12", &s) == false);
1675            }
1676
1677            SECTION("string")
1678            {
1679                SaxCountdown s(0);
1680                CHECK(json::sax_parse("\"foo\"", &s) == false);
1681            }
1682        }
1683    }
1684
1685    SECTION("error messages for comments")
1686    {
1687        json _;
1688        CHECK_THROWS_WITH_AS(_ = json::parse("/a", nullptr, true, true), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid comment; expecting '/' or '*' after '/'; last read: '/a'", json::parse_error);
1689        CHECK_THROWS_WITH_AS(_ = json::parse("/*", nullptr, true, true), "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid comment; missing closing '*/'; last read: '/*<U+0000>'", json::parse_error);
1690    }
1691}
1692