Line data Source code
1 : // Copyright (c) 2021-2022 Made to Order Software Corporation
2 : //
3 : // https://snapwebsites.org/project/libutf8
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 : // libutf8
21 : //
22 : #include <libutf8/json_tokens.h>
23 :
24 : #include <libutf8/libutf8.h>
25 :
26 :
27 : // unit test
28 : //
29 : #include "catch_main.h"
30 :
31 :
32 : // snapdev
33 : //
34 : #include <snapdev/file_contents.h>
35 :
36 :
37 : // C++
38 : //
39 : #include <cctype>
40 : #include <iomanip>
41 : #include <iostream>
42 :
43 :
44 : // last include
45 : //
46 : #include <snapdev/poison.h>
47 :
48 :
49 :
50 : #pragma GCC diagnostic push
51 : #pragma GCC diagnostic ignored "-Wfloat-equal"
52 6 : CATCH_TEST_CASE("json_tokens", "[json][iterator]")
53 : {
54 8 : CATCH_START_SECTION("json_tokens: valid JSON tokens")
55 : {
56 1 : std::string valid_json(
57 : "{\n"
58 : "\"array-of-numbers\": [\n"
59 : "\t1,\r\n"
60 : "\t1.0,\r"
61 : "\t-0.1\r\n"
62 : "] , \n"
63 : "\"color\" :true ,\n"
64 : "\"temporary\" :false, \r"
65 : "\"flowers\":null\r\n"
66 : "}"
67 2 : );
68 :
69 : #if 0
70 : snap::file_contents f("test.json");
71 : f.contents(valid_json);
72 : f.write_all();
73 : #endif
74 :
75 2 : libutf8::json_tokens jt(valid_json);
76 1 : CATCH_REQUIRE(jt.line() == 0);
77 1 : CATCH_REQUIRE(jt.column() == 0);
78 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
79 1 : CATCH_REQUIRE(jt.line() == 1);
80 1 : CATCH_REQUIRE(jt.column() == 1);
81 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
82 1 : CATCH_REQUIRE(jt.string() == "array-of-numbers");
83 1 : CATCH_REQUIRE(jt.line() == 2);
84 1 : CATCH_REQUIRE(jt.column() == 1);
85 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
86 1 : CATCH_REQUIRE(jt.line() == 2);
87 1 : CATCH_REQUIRE(jt.column() == 19);
88 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_ARRAY);
89 1 : CATCH_REQUIRE(jt.line() == 2);
90 1 : CATCH_REQUIRE(jt.column() == 21);
91 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
92 1 : CATCH_REQUIRE(jt.number() == 1.0_a);
93 1 : CATCH_REQUIRE(jt.line() == 3);
94 1 : CATCH_REQUIRE(jt.column() == 2);
95 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
96 1 : CATCH_REQUIRE(jt.line() == 3);
97 1 : CATCH_REQUIRE(jt.column() == 3 + 1); // error due to the unget
98 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
99 1 : CATCH_REQUIRE(jt.number() == 1.0_a);
100 1 : CATCH_REQUIRE(jt.line() == 4);
101 1 : CATCH_REQUIRE(jt.column() == 2);
102 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
103 1 : CATCH_REQUIRE(jt.line() == 4);
104 1 : CATCH_REQUIRE(jt.column() == 5 + 1); // error due to the unget
105 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
106 1 : CATCH_REQUIRE(jt.number() == -0.1_a);
107 1 : CATCH_REQUIRE(jt.line() == 5);
108 1 : CATCH_REQUIRE(jt.column() == 2);
109 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_ARRAY);
110 1 : CATCH_REQUIRE(jt.line() == 6);
111 1 : CATCH_REQUIRE(jt.column() == 1);
112 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
113 1 : CATCH_REQUIRE(jt.line() == 6);
114 1 : CATCH_REQUIRE(jt.column() == 5);
115 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
116 1 : CATCH_REQUIRE(jt.string() == "color");
117 1 : CATCH_REQUIRE(jt.line() == 7);
118 1 : CATCH_REQUIRE(jt.column() == 1);
119 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
120 1 : CATCH_REQUIRE(jt.line() == 7);
121 1 : CATCH_REQUIRE(jt.column() == 14);
122 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_TRUE);
123 1 : CATCH_REQUIRE(jt.line() == 7);
124 1 : CATCH_REQUIRE(jt.column() == 15);
125 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
126 1 : CATCH_REQUIRE(jt.line() == 7);
127 1 : CATCH_REQUIRE(jt.column() == 21);
128 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
129 1 : CATCH_REQUIRE(jt.string() == "temporary");
130 1 : CATCH_REQUIRE(jt.line() == 8);
131 1 : CATCH_REQUIRE(jt.column() == 1);
132 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
133 1 : CATCH_REQUIRE(jt.line() == 8);
134 1 : CATCH_REQUIRE(jt.column() == 14);
135 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_FALSE);
136 1 : CATCH_REQUIRE(jt.line() == 8);
137 1 : CATCH_REQUIRE(jt.column() == 15);
138 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
139 1 : CATCH_REQUIRE(jt.line() == 8);
140 1 : CATCH_REQUIRE(jt.column() == 20);
141 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
142 1 : CATCH_REQUIRE(jt.string() == "flowers");
143 1 : CATCH_REQUIRE(jt.line() == 9);
144 1 : CATCH_REQUIRE(jt.column() == 1);
145 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
146 1 : CATCH_REQUIRE(jt.line() == 9);
147 1 : CATCH_REQUIRE(jt.column() == 10);
148 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NULL);
149 1 : CATCH_REQUIRE(jt.line() == 9);
150 1 : CATCH_REQUIRE(jt.column() == 11);
151 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_OBJECT);
152 1 : CATCH_REQUIRE(jt.line() == 10);
153 1 : CATCH_REQUIRE(jt.column() == 1);
154 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
155 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
156 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
157 : }
158 : CATCH_END_SECTION()
159 :
160 8 : CATCH_START_SECTION("json_tokens: valid JSON numbers")
161 : {
162 1 : std::string valid_json(
163 : "["
164 : "733,"
165 : "-1892,"
166 : "-1.892,"
167 : "-9.892e33,"
168 : "101.302e+3,"
169 : "5031.70232e-13"
170 : "]"
171 2 : );
172 :
173 2 : libutf8::json_tokens jt(valid_json);
174 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_ARRAY);
175 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
176 1 : CATCH_REQUIRE_FLOATING_POINT(jt.number(), 733.0);
177 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
178 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
179 1 : CATCH_REQUIRE_FLOATING_POINT(jt.number(), -1892.0);
180 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
181 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
182 1 : CATCH_REQUIRE_FLOATING_POINT(jt.number(), -1.892);
183 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
184 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
185 1 : CATCH_REQUIRE_FLOATING_POINT(jt.number(), -9.892e33);
186 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
187 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
188 1 : CATCH_REQUIRE_FLOATING_POINT(jt.number(), 101.302e3);
189 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
190 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
191 1 : CATCH_REQUIRE_FLOATING_POINT(jt.number(), 5031.70232e-13);
192 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_ARRAY);
193 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
194 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
195 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
196 : }
197 : CATCH_END_SECTION()
198 :
199 8 : CATCH_START_SECTION("json_tokens: valid JSON special escaped characters")
200 : {
201 1 : std::string valid_json(
202 : "{"
203 : "\"backslash\":\"\\\\\","
204 : "\"quote\":\"\\\"\","
205 : "\"slash\":\"\\/\","
206 : "\"backspace\":\"\\b\","
207 : "\"formfeed\":\"\\f\","
208 : "\"newline\":\"\\n\","
209 : "\"carriage-return\":\"\\r\","
210 : "\"tab\":\"\\t\""
211 : "}"
212 2 : );
213 :
214 2 : libutf8::json_tokens jt(valid_json);
215 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
216 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
217 1 : CATCH_REQUIRE(jt.string() == "backslash");
218 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
219 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
220 1 : CATCH_REQUIRE(jt.string() == "\\");
221 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
222 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
223 1 : CATCH_REQUIRE(jt.string() == "quote");
224 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
225 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
226 1 : CATCH_REQUIRE(jt.string() == "\"");
227 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
228 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
229 1 : CATCH_REQUIRE(jt.string() == "slash");
230 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
231 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
232 1 : CATCH_REQUIRE(jt.string() == "/");
233 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
234 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
235 1 : CATCH_REQUIRE(jt.string() == "backspace");
236 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
237 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
238 1 : CATCH_REQUIRE(jt.string() == "\b");
239 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
240 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
241 1 : CATCH_REQUIRE(jt.string() == "formfeed");
242 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
243 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
244 1 : CATCH_REQUIRE(jt.string() == "\f");
245 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
246 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
247 1 : CATCH_REQUIRE(jt.string() == "newline");
248 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
249 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
250 1 : CATCH_REQUIRE(jt.string() == "\n");
251 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
252 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
253 1 : CATCH_REQUIRE(jt.string() == "carriage-return");
254 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
255 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
256 1 : CATCH_REQUIRE(jt.string() == "\r");
257 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
258 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
259 1 : CATCH_REQUIRE(jt.string() == "tab");
260 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
261 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
262 1 : CATCH_REQUIRE(jt.string() == "\t");
263 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_OBJECT);
264 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
265 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
266 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
267 : }
268 : CATCH_END_SECTION()
269 :
270 8 : CATCH_START_SECTION("json_tokens: valid JSON unicode escaped characters")
271 : {
272 1114112 : for(char32_t c(1); c < 0x110000; ++c)
273 : {
274 1114111 : if(c >= 0xD800 && c <= 0xDFFF)
275 : {
276 2048 : continue;
277 : }
278 :
279 2224126 : std::stringstream ss;
280 2224126 : std::string valid_json;
281 1112063 : valid_json += "{\"unicode\":\"\\u";
282 1112063 : if(c > 0xFFFF)
283 : {
284 1048576 : int s(c - 0x10000);
285 1048576 : ss << std::hex << std::setw(4) << std::setfill('0') << ((s >> 10) | 0xD800)
286 1048576 : << "\\u" << std::setw(4) << std::setfill('0') << ((s & 0x3FF) | 0xDC00);
287 : }
288 : else
289 : {
290 63487 : ss << std::hex << std::setw(4) << std::setfill('0') << static_cast<int>(c);
291 : }
292 1112063 : valid_json += ss.str();
293 1112063 : valid_json += "\"}";
294 :
295 2224126 : libutf8::json_tokens jt(valid_json);
296 1112063 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
297 1112063 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
298 1112063 : CATCH_REQUIRE(jt.string() == "unicode");
299 1112063 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
300 1112063 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
301 2224126 : std::string expected(libutf8::to_u8string(c));
302 1112063 : CATCH_REQUIRE_LONG_STRING(jt.string(), expected);
303 1112063 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_OBJECT);
304 1112063 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
305 1112063 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
306 1112063 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
307 : }
308 : }
309 : CATCH_END_SECTION()
310 4 : }
311 : #pragma GCC diagnostic pop
312 :
313 :
314 22 : CATCH_TEST_CASE("json_tokens_invalid", "[json][iterator][invalid]")
315 : {
316 40 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON negative number")
317 : {
318 1 : std::string valid_json(
319 : "-a"
320 2 : );
321 :
322 2 : libutf8::json_tokens jt(valid_json);
323 1 : CATCH_REQUIRE(jt.line() == 0);
324 1 : CATCH_REQUIRE(jt.column() == 0);
325 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
326 1 : CATCH_REQUIRE(jt.line() == 1);
327 1 : CATCH_REQUIRE(jt.column() == 1);
328 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: '-'");
329 : }
330 : CATCH_END_SECTION()
331 :
332 40 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON number with fraction")
333 : {
334 1 : std::string valid_json(
335 : "-3., 2."
336 2 : );
337 :
338 2 : libutf8::json_tokens jt(valid_json);
339 1 : CATCH_REQUIRE(jt.line() == 0);
340 1 : CATCH_REQUIRE(jt.column() == 0);
341 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
342 1 : CATCH_REQUIRE(jt.line() == 1);
343 1 : CATCH_REQUIRE(jt.column() == 1);
344 1 : CATCH_REQUIRE(jt.error() == "number cannot end with a period (\"1.\" is not valid JSON)");
345 : }
346 : CATCH_END_SECTION()
347 :
348 40 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON number exponent")
349 : {
350 1 : std::string valid_json(
351 : "-3.0e+a, 2.1"
352 2 : );
353 :
354 2 : libutf8::json_tokens jt(valid_json);
355 1 : CATCH_REQUIRE(jt.line() == 0);
356 1 : CATCH_REQUIRE(jt.column() == 0);
357 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
358 1 : CATCH_REQUIRE(jt.line() == 1);
359 1 : CATCH_REQUIRE(jt.column() == 1);
360 1 : CATCH_REQUIRE(jt.error() == "number exponent must include at least one digit");
361 : }
362 : CATCH_END_SECTION()
363 :
364 40 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON number with fraction")
365 : {
366 1 : std::string valid_json(
367 : "\"back\\slash\""
368 2 : );
369 :
370 2 : libutf8::json_tokens jt(valid_json);
371 1 : CATCH_REQUIRE(jt.line() == 0);
372 1 : CATCH_REQUIRE(jt.column() == 0);
373 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
374 1 : CATCH_REQUIRE(jt.line() == 1);
375 1 : CATCH_REQUIRE(jt.column() == 1);
376 1 : CATCH_REQUIRE(jt.error() == "unexpected escape character: 's'");
377 : }
378 : CATCH_END_SECTION()
379 :
380 40 : CATCH_START_SECTION("json_tokens_invalid: unsupported JSON backslash character")
381 : {
382 : {
383 1 : std::string valid_json(
384 : "\"back\\slash\""
385 2 : );
386 :
387 2 : libutf8::json_tokens jt(valid_json);
388 1 : CATCH_REQUIRE(jt.line() == 0);
389 1 : CATCH_REQUIRE(jt.column() == 0);
390 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
391 1 : CATCH_REQUIRE(jt.line() == 1);
392 1 : CATCH_REQUIRE(jt.column() == 1);
393 1 : CATCH_REQUIRE(jt.error() == "unexpected escape character: 's'");
394 : }
395 :
396 : }
397 : CATCH_END_SECTION()
398 :
399 40 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: too short")
400 : {
401 : {
402 1 : std::string valid_json(
403 : "\"\\u0"
404 2 : );
405 :
406 2 : libutf8::json_tokens jt(valid_json);
407 1 : CATCH_REQUIRE(jt.line() == 0);
408 1 : CATCH_REQUIRE(jt.column() == 0);
409 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
410 1 : CATCH_REQUIRE(jt.line() == 1);
411 1 : CATCH_REQUIRE(jt.column() == 1);
412 1 : CATCH_REQUIRE(jt.error() == "invalid unicode character: 'EOS'");
413 : }
414 :
415 : {
416 1 : std::string valid_json(
417 : "\"\\u20"
418 2 : );
419 :
420 2 : libutf8::json_tokens jt(valid_json);
421 1 : CATCH_REQUIRE(jt.line() == 0);
422 1 : CATCH_REQUIRE(jt.column() == 0);
423 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
424 1 : CATCH_REQUIRE(jt.line() == 1);
425 1 : CATCH_REQUIRE(jt.column() == 1);
426 1 : CATCH_REQUIRE(jt.error() == "invalid unicode character: 'EOS'");
427 : }
428 :
429 : {
430 1 : std::string valid_json(
431 : "\"\\u301"
432 2 : );
433 :
434 2 : libutf8::json_tokens jt(valid_json);
435 1 : CATCH_REQUIRE(jt.line() == 0);
436 1 : CATCH_REQUIRE(jt.column() == 0);
437 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
438 1 : CATCH_REQUIRE(jt.line() == 1);
439 1 : CATCH_REQUIRE(jt.column() == 1);
440 1 : CATCH_REQUIRE(jt.error() == "invalid unicode character: 'EOS'");
441 : }
442 :
443 : }
444 : CATCH_END_SECTION()
445 :
446 40 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: low surrogate missing backslash")
447 : {
448 1 : std::string valid_json(
449 : "\"\\uD91Fmissing\""
450 2 : );
451 :
452 2 : libutf8::json_tokens jt(valid_json);
453 1 : CATCH_REQUIRE(jt.line() == 0);
454 1 : CATCH_REQUIRE(jt.column() == 0);
455 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
456 1 : CATCH_REQUIRE(jt.line() == 1);
457 1 : CATCH_REQUIRE(jt.column() == 1);
458 1 : CATCH_REQUIRE(jt.error() == "expected a low surrogate right after a high surrogate, backslash (\\) mising");
459 : }
460 : CATCH_END_SECTION()
461 :
462 40 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: low surrogate missing 'u'")
463 : {
464 1 : std::string valid_json(
465 : "\"\\uD91F\\missing\""
466 2 : );
467 :
468 2 : libutf8::json_tokens jt(valid_json);
469 1 : CATCH_REQUIRE(jt.line() == 0);
470 1 : CATCH_REQUIRE(jt.column() == 0);
471 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
472 1 : CATCH_REQUIRE(jt.line() == 1);
473 1 : CATCH_REQUIRE(jt.column() == 1);
474 1 : CATCH_REQUIRE(jt.error() == "expected a low surrogate right after a high surrogate, 'u' missing");
475 : }
476 : CATCH_END_SECTION()
477 :
478 40 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: low surrogate expected")
479 : {
480 : {
481 1 : std::string valid_json(
482 : "\"\\uD91F\\u0010\""
483 2 : );
484 :
485 2 : libutf8::json_tokens jt(valid_json);
486 1 : CATCH_REQUIRE(jt.line() == 0);
487 1 : CATCH_REQUIRE(jt.column() == 0);
488 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
489 1 : CATCH_REQUIRE(jt.line() == 1);
490 1 : CATCH_REQUIRE(jt.column() == 1);
491 1 : CATCH_REQUIRE(jt.error() == "expected a low surrogate right after a high surrogate");
492 : }
493 :
494 : {
495 1 : std::string valid_json(
496 : "\"\\uD91F\\uDBFF\""
497 2 : );
498 :
499 2 : libutf8::json_tokens jt(valid_json);
500 1 : CATCH_REQUIRE(jt.line() == 0);
501 1 : CATCH_REQUIRE(jt.column() == 0);
502 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
503 1 : CATCH_REQUIRE(jt.line() == 1);
504 1 : CATCH_REQUIRE(jt.column() == 1);
505 1 : CATCH_REQUIRE(jt.error() == "expected a low surrogate right after a high surrogate");
506 : }
507 :
508 : {
509 1 : std::string valid_json(
510 : "\"\\uD91F\\uE030"
511 2 : );
512 :
513 2 : libutf8::json_tokens jt(valid_json);
514 1 : CATCH_REQUIRE(jt.line() == 0);
515 1 : CATCH_REQUIRE(jt.column() == 0);
516 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
517 1 : CATCH_REQUIRE(jt.line() == 1);
518 1 : CATCH_REQUIRE(jt.column() == 1);
519 1 : CATCH_REQUIRE(jt.error() == "expected a low surrogate right after a high surrogate");
520 : }
521 : }
522 : CATCH_END_SECTION()
523 :
524 40 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: low surrogate too short")
525 : {
526 : {
527 1 : std::string valid_json(
528 : "\"\\uD91F\\u0"
529 2 : );
530 :
531 2 : libutf8::json_tokens jt(valid_json);
532 1 : CATCH_REQUIRE(jt.line() == 0);
533 1 : CATCH_REQUIRE(jt.column() == 0);
534 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
535 1 : CATCH_REQUIRE(jt.line() == 1);
536 1 : CATCH_REQUIRE(jt.column() == 1);
537 1 : CATCH_REQUIRE(jt.error() == "invalid unicode character: 'EOS'");
538 : }
539 :
540 : {
541 1 : std::string valid_json(
542 : "\"\\uD91F\\u0f"
543 2 : );
544 :
545 2 : libutf8::json_tokens jt(valid_json);
546 1 : CATCH_REQUIRE(jt.line() == 0);
547 1 : CATCH_REQUIRE(jt.column() == 0);
548 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
549 1 : CATCH_REQUIRE(jt.line() == 1);
550 1 : CATCH_REQUIRE(jt.column() == 1);
551 1 : CATCH_REQUIRE(jt.error() == "invalid unicode character: 'EOS'");
552 : }
553 :
554 : {
555 1 : std::string valid_json(
556 : "\"\\uD91F\\u0fa"
557 2 : );
558 :
559 2 : libutf8::json_tokens jt(valid_json);
560 1 : CATCH_REQUIRE(jt.line() == 0);
561 1 : CATCH_REQUIRE(jt.column() == 0);
562 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
563 1 : CATCH_REQUIRE(jt.line() == 1);
564 1 : CATCH_REQUIRE(jt.column() == 1);
565 1 : CATCH_REQUIRE(jt.error() == "invalid unicode character: 'EOS'");
566 : }
567 : }
568 : CATCH_END_SECTION()
569 :
570 40 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: invalid hexadecimal digit (low surrogate)")
571 : {
572 : {
573 1 : std::string valid_json(
574 : "\"\\udb31\\u0t\""
575 2 : );
576 :
577 2 : libutf8::json_tokens jt(valid_json);
578 1 : CATCH_REQUIRE(jt.line() == 0);
579 1 : CATCH_REQUIRE(jt.column() == 0);
580 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
581 1 : CATCH_REQUIRE(jt.line() == 1);
582 1 : CATCH_REQUIRE(jt.column() == 1);
583 1 : CATCH_REQUIRE(jt.error() == "invalid unicode character: 't'");
584 : }
585 :
586 : {
587 1 : std::string valid_json(
588 : "\"\\udb31\\u3eg\""
589 2 : );
590 :
591 2 : libutf8::json_tokens jt(valid_json);
592 1 : CATCH_REQUIRE(jt.line() == 0);
593 1 : CATCH_REQUIRE(jt.column() == 0);
594 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
595 1 : CATCH_REQUIRE(jt.line() == 1);
596 1 : CATCH_REQUIRE(jt.column() == 1);
597 1 : CATCH_REQUIRE(jt.error() == "invalid unicode character: 'g'");
598 : }
599 :
600 : {
601 1 : std::string valid_json(
602 : "\"\\udb31\\ua3e!\""
603 2 : );
604 :
605 2 : libutf8::json_tokens jt(valid_json);
606 1 : CATCH_REQUIRE(jt.line() == 0);
607 1 : CATCH_REQUIRE(jt.column() == 0);
608 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
609 1 : CATCH_REQUIRE(jt.line() == 1);
610 1 : CATCH_REQUIRE(jt.column() == 1);
611 1 : CATCH_REQUIRE(jt.error() == "invalid unicode character: '!'");
612 : }
613 : }
614 : CATCH_END_SECTION()
615 :
616 40 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: low surrogate first")
617 : {
618 1025 : for(char32_t c(0xDC00); c <= 0xDFFF; ++c)
619 : {
620 2048 : std::stringstream ss;
621 1024 : ss << "\\u" << std::hex << std::setw(4)
622 1024 : << std::setfill('0') << static_cast<int>(c);
623 :
624 2048 : libutf8::json_tokens jt("\"" + ss.str() + "\"");
625 1024 : CATCH_REQUIRE(jt.line() == 0);
626 1024 : CATCH_REQUIRE(jt.column() == 0);
627 1024 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
628 1024 : CATCH_REQUIRE(jt.line() == 1);
629 1024 : CATCH_REQUIRE(jt.column() == 1);
630 3072 : std::string const msg("low surrogate " + ss.str()
631 3072 : + " found before a high surrogate");
632 1024 : CATCH_REQUIRE(jt.error() == msg);
633 : }
634 :
635 : }
636 : CATCH_END_SECTION()
637 :
638 40 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: invalid hexadecimal digit")
639 : {
640 : {
641 1 : std::string valid_json(
642 : "\"\\u5z"
643 2 : );
644 :
645 2 : libutf8::json_tokens jt(valid_json);
646 1 : CATCH_REQUIRE(jt.line() == 0);
647 1 : CATCH_REQUIRE(jt.column() == 0);
648 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
649 1 : CATCH_REQUIRE(jt.line() == 1);
650 1 : CATCH_REQUIRE(jt.column() == 1);
651 1 : CATCH_REQUIRE(jt.error() == "invalid unicode character: 'z'");
652 : }
653 :
654 : {
655 1 : std::string valid_json(
656 : "\"\\uaa$"
657 2 : );
658 :
659 2 : libutf8::json_tokens jt(valid_json);
660 1 : CATCH_REQUIRE(jt.line() == 0);
661 1 : CATCH_REQUIRE(jt.column() == 0);
662 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
663 1 : CATCH_REQUIRE(jt.line() == 1);
664 1 : CATCH_REQUIRE(jt.column() == 1);
665 1 : CATCH_REQUIRE(jt.error() == "invalid unicode character: '$'");
666 : }
667 :
668 : {
669 1 : std::string valid_json(
670 : "\"\\ua9a\001"
671 2 : );
672 :
673 2 : libutf8::json_tokens jt(valid_json);
674 1 : CATCH_REQUIRE(jt.line() == 0);
675 1 : CATCH_REQUIRE(jt.column() == 0);
676 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
677 1 : CATCH_REQUIRE(jt.line() == 1);
678 1 : CATCH_REQUIRE(jt.column() == 1);
679 1 : CATCH_REQUIRE(jt.error() == "invalid unicode character: '^A'");
680 : }
681 : }
682 : CATCH_END_SECTION()
683 :
684 40 : CATCH_START_SECTION("json_tokens_invalid: unterminated JSON string")
685 : {
686 2 : libutf8::json_tokens jt("\"unterminated");
687 1 : CATCH_REQUIRE(jt.line() == 0);
688 1 : CATCH_REQUIRE(jt.column() == 0);
689 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
690 1 : CATCH_REQUIRE(jt.line() == 1);
691 1 : CATCH_REQUIRE(jt.column() == 1);
692 1 : CATCH_REQUIRE(jt.error() == "unclosed string");
693 :
694 : }
695 : CATCH_END_SECTION()
696 :
697 40 : CATCH_START_SECTION("json_tokens_invalid: JSON true with missing characters")
698 : {
699 : {
700 2 : libutf8::json_tokens jt("{\"bad-true\":tru}");
701 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
702 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
703 1 : CATCH_REQUIRE(jt.string() == "bad-true");
704 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
705 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
706 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 't'");
707 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
708 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'r'");
709 : }
710 :
711 : {
712 2 : libutf8::json_tokens jt("{\"bad-true\":tr}");
713 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
714 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
715 1 : CATCH_REQUIRE(jt.string() == "bad-true");
716 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
717 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
718 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 't'");
719 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
720 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'r'");
721 : }
722 :
723 : {
724 2 : libutf8::json_tokens jt("{\"bad-true\":t}");
725 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
726 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
727 1 : CATCH_REQUIRE(jt.string() == "bad-true");
728 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
729 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
730 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 't'");
731 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_OBJECT);
732 : }
733 : }
734 : CATCH_END_SECTION()
735 :
736 40 : CATCH_START_SECTION("json_tokens_invalid: JSON false with missing characters")
737 : {
738 : {
739 2 : libutf8::json_tokens jt("{\"bad-false\":fals}");
740 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
741 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
742 1 : CATCH_REQUIRE(jt.string() == "bad-false");
743 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
744 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
745 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'f'");
746 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
747 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'a'");
748 : }
749 :
750 : {
751 2 : libutf8::json_tokens jt("{\"bad-false\":fal}");
752 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
753 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
754 1 : CATCH_REQUIRE(jt.string() == "bad-false");
755 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
756 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
757 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'f'");
758 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
759 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'a'");
760 : }
761 :
762 : {
763 2 : libutf8::json_tokens jt("{\"bad-false\":fa}");
764 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
765 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
766 1 : CATCH_REQUIRE(jt.string() == "bad-false");
767 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
768 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
769 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'f'");
770 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
771 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'a'");
772 : }
773 :
774 : {
775 2 : libutf8::json_tokens jt("{\"bad-false\":f}");
776 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
777 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
778 1 : CATCH_REQUIRE(jt.string() == "bad-false");
779 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
780 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
781 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'f'");
782 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_OBJECT);
783 : }
784 : }
785 : CATCH_END_SECTION()
786 :
787 40 : CATCH_START_SECTION("json_tokens_invalid: JSON null with missing characters")
788 : {
789 : {
790 2 : libutf8::json_tokens jt("{\"bad-null\":nul}");
791 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
792 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
793 1 : CATCH_REQUIRE(jt.string() == "bad-null");
794 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
795 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
796 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'n'");
797 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
798 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'u'");
799 : }
800 :
801 : {
802 2 : libutf8::json_tokens jt("{\"bad-null\":nu}");
803 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
804 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
805 1 : CATCH_REQUIRE(jt.string() == "bad-null");
806 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
807 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
808 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'n'");
809 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
810 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'u'");
811 : }
812 :
813 : {
814 2 : libutf8::json_tokens jt("{\"bad-null\":n}");
815 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
816 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
817 1 : CATCH_REQUIRE(jt.string() == "bad-null");
818 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
819 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
820 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'n'");
821 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_OBJECT);
822 : }
823 : }
824 : CATCH_END_SECTION()
825 :
826 40 : CATCH_START_SECTION("json_tokens_invalid: unexpected JSON characters")
827 : {
828 1114112 : for(char32_t c(1); c < 0x110000; ++c)
829 : {
830 1114111 : if(c >= 0xD800 && c <= 0xDFFF)
831 : {
832 2048 : continue;
833 : }
834 1112087 : switch(c)
835 : {
836 24 : case '"':
837 : case '{':
838 : case '}':
839 : case '[':
840 : case ']':
841 : case '0':
842 : case '1':
843 : case '2':
844 : case '3':
845 : case '4':
846 : case '5':
847 : case '6':
848 : case '7':
849 : case '8':
850 : case '9':
851 : case ' ':
852 : case '\t':
853 : case '\r':
854 : case '\n':
855 : case 'n':
856 : case 't':
857 : case 'f':
858 : case ',':
859 : case ':':
860 24 : continue;
861 :
862 : }
863 :
864 2224078 : std::string invalid_json(libutf8::to_u8string(c));
865 2224078 : libutf8::json_tokens jt(invalid_json);
866 :
867 1112039 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
868 1112039 : if(c < 0x20)
869 : {
870 28 : CATCH_REQUIRE(jt.error() == "found unexpected character: '^" + libutf8::to_u8string(static_cast<char32_t>(c + 0x40)) + "'");
871 : }
872 1112011 : else if(c >= 0x80 && c < 0xA0)
873 : {
874 32 : CATCH_REQUIRE(jt.error() == "found unexpected character: '@" + libutf8::to_u8string(static_cast<char32_t>(c - 0x40)) + "'");
875 : }
876 : else
877 : {
878 1111979 : CATCH_REQUIRE(jt.error() == "found unexpected character: '" + libutf8::to_u8string(c) + "'");
879 : }
880 : }
881 : }
882 : CATCH_END_SECTION()
883 :
884 40 : CATCH_START_SECTION("json_tokens_invalid: unexpected '\\0' in JSON")
885 : {
886 2 : std::string invalid_json;
887 1 : invalid_json += '\0';
888 2 : libutf8::json_tokens jt(invalid_json);
889 :
890 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
891 1 : CATCH_REQUIRE(jt.error() == "found unexpected NULL character");
892 : }
893 : CATCH_END_SECTION()
894 :
895 40 : CATCH_START_SECTION("json_tokens_invalid: unexpected '\\0' in JSON string")
896 : {
897 2 : std::string invalid_json("\"string");
898 1 : invalid_json += '\0';
899 1 : invalid_json += "with null\"";
900 2 : libutf8::json_tokens jt(invalid_json);
901 :
902 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
903 1 : CATCH_REQUIRE(jt.error() == "unexpected NULL character in string");
904 : }
905 : CATCH_END_SECTION()
906 26 : }
907 :
908 :
909 :
910 : // vim: ts=4 sw=4 et
|