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