• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //     __ _____ _____ _____
2 //  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
3 // |  |  |__   |  |  | | | |  version 3.11.3
4 // |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5 //
6 // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
7 // SPDX-License-Identifier: MIT
8 
9 #include "doctest_compatibility.h"
10 
11 #define JSON_TESTS_PRIVATE
12 #include <nlohmann/json.hpp>
13 using 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 
20 namespace
21 {
22 class SaxEventLogger
23 {
24   public:
null()25     bool null()
26     {
27         events.emplace_back("null()");
28         return true;
29     }
30 
boolean(bool val)31     bool boolean(bool val)
32     {
33         events.emplace_back(val ? "boolean(true)" : "boolean(false)");
34         return true;
35     }
36 
number_integer(json::number_integer_t val)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 
number_unsigned(json::number_unsigned_t val)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 
number_float(json::number_float_t,const std::string & s)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 
string(std::string & val)55     bool string(std::string& val)
56     {
57         events.push_back("string(" + val + ")");
58         return true;
59     }
60 
binary(json::binary_t & val)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 
start_object(std::size_t elements)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 
key(std::string & val)89     bool key(std::string& val)
90     {
91         events.push_back("key(" + val + ")");
92         return true;
93     }
94 
end_object()95     bool end_object()
96     {
97         events.emplace_back("end_object()");
98         return true;
99     }
100 
start_array(std::size_t elements)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 
end_array()114     bool end_array()
115     {
116         events.emplace_back("end_array()");
117         return true;
118     }
119 
parse_error(std::size_t position,const std::string &,const json::exception &)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 
131 class SaxCountdown : public nlohmann::json::json_sax_t
132 {
133   public:
SaxCountdown(const int count)134     explicit SaxCountdown(const int count) : events_left(count)
135     {}
136 
null()137     bool null() override
138     {
139         return events_left-- > 0;
140     }
141 
boolean(bool)142     bool boolean(bool /*val*/) override
143     {
144         return events_left-- > 0;
145     }
146 
number_integer(json::number_integer_t)147     bool number_integer(json::number_integer_t /*val*/) override
148     {
149         return events_left-- > 0;
150     }
151 
number_unsigned(json::number_unsigned_t)152     bool number_unsigned(json::number_unsigned_t /*val*/) override
153     {
154         return events_left-- > 0;
155     }
156 
number_float(json::number_float_t,const std::string &)157     bool number_float(json::number_float_t /*val*/, const std::string& /*s*/) override
158     {
159         return events_left-- > 0;
160     }
161 
string(std::string &)162     bool string(std::string& /*val*/) override
163     {
164         return events_left-- > 0;
165     }
166 
binary(json::binary_t &)167     bool binary(json::binary_t& /*val*/) override
168     {
169         return events_left-- > 0;
170     }
171 
start_object(std::size_t)172     bool start_object(std::size_t /*elements*/) override
173     {
174         return events_left-- > 0;
175     }
176 
key(std::string &)177     bool key(std::string& /*val*/) override
178     {
179         return events_left-- > 0;
180     }
181 
end_object()182     bool end_object() override
183     {
184         return events_left-- > 0;
185     }
186 
start_array(std::size_t)187     bool start_array(std::size_t /*elements*/) override
188     {
189         return events_left-- > 0;
190     }
191 
end_array()192     bool end_array() override
193     {
194         return events_left-- > 0;
195     }
196 
parse_error(std::size_t,const std::string &,const json::exception &)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 
206 json parser_helper(const std::string& s);
207 bool accept_helper(const std::string& s);
208 void comments_helper(const std::string& s);
209 
parser_helper(const std::string & s)210 json 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 
accept_helper(const std::string & s)231 bool 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 const cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept
253     {
254         return true;
255     };
256     json const 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 
comments_helper(const std::string & s)272 void 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 
307 TEST_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 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)
__anon9dc15d840302(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 const 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)
__anon9dc15d840402(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 const 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 const cb = [](int /*unused*/, json::parse_event_t event, json& /*unused*/) noexcept
__anon9dc15d840502(int , json::parse_event_t event, json& ) 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
__anon9dc15d840602(int , json::parse_event_t , const json& ) 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
__anon9dc15d840702(int , json::parse_event_t , const json& ) 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 const j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
__anon9dc15d840802(int , json::parse_event_t , const json& ) 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 const j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept
__anon9dc15d840902(int , json::parse_event_t , const json& ) 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
__anon9dc15d840a02(int , json::parse_event_t event, const json & j) 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
__anon9dc15d840b02(int , json::parse_event_t event, const json & j) 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)
__anon9dc15d840c02(int , 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
__anon9dc15d840d02(int , json::parse_event_t e, const json& ) 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
__anon9dc15d840e02(int , json::parse_event_t e, const json& ) 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
__anon9dc15d840f02(int , json::parse_event_t e, const json& ) 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
__anon9dc15d841002(int , json::parse_event_t e, const json& ) 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
__anon9dc15d841102(int , json::parse_event_t e, const json& ) 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> const 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 const cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept
__anon9dc15d841202(int , json::parse_event_t , json& ) 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