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