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