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