Line data Source code
1 : // Copyright (c) 2021-2023 Made to Order Software Corp. All Rights Reserved
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 4 : CATCH_TEST_CASE("json_tokens", "[json][iterator]")
53 : {
54 4 : 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 3 : );
68 :
69 : #if 0
70 : snap::file_contents f("test.json");
71 : f.contents(valid_json);
72 : f.write_all();
73 : #endif
74 :
75 1 : 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 1 : }
158 4 : CATCH_END_SECTION()
159 :
160 4 : 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 3 : );
172 :
173 1 : 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 1 : }
197 4 : CATCH_END_SECTION()
198 :
199 4 : 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 3 : );
213 :
214 1 : 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 1 : }
268 4 : CATCH_END_SECTION()
269 :
270 4 : 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 1112063 : std::stringstream ss;
280 1112063 : 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 1112063 : 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 1112063 : 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 1112063 : }
308 : }
309 4 : CATCH_END_SECTION()
310 4 : }
311 : #pragma GCC diagnostic pop
312 :
313 :
314 20 : CATCH_TEST_CASE("json_tokens_invalid", "[json][iterator][invalid]")
315 : {
316 20 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON negative number")
317 : {
318 1 : std::string valid_json(
319 : "-a"
320 3 : );
321 :
322 1 : 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 1 : }
330 20 : CATCH_END_SECTION()
331 :
332 20 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON number with fraction")
333 : {
334 1 : std::string valid_json(
335 : "-3., 2."
336 3 : );
337 :
338 1 : 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 1 : }
346 20 : CATCH_END_SECTION()
347 :
348 20 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON number exponent")
349 : {
350 1 : std::string valid_json(
351 : "-3.0e+a, 2.1"
352 3 : );
353 :
354 1 : 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 1 : }
362 20 : CATCH_END_SECTION()
363 :
364 20 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON number with fraction")
365 : {
366 1 : std::string valid_json(
367 : "\"back\\slash\""
368 3 : );
369 :
370 1 : 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 1 : }
378 20 : CATCH_END_SECTION()
379 :
380 20 : CATCH_START_SECTION("json_tokens_invalid: unsupported JSON backslash character")
381 : {
382 : {
383 1 : std::string valid_json(
384 : "\"back\\slash\""
385 3 : );
386 :
387 1 : 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 1 : }
395 :
396 : }
397 20 : CATCH_END_SECTION()
398 :
399 20 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: too short")
400 : {
401 : {
402 1 : std::string valid_json(
403 : "\"\\u0"
404 3 : );
405 :
406 1 : 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 1 : }
414 :
415 : {
416 1 : std::string valid_json(
417 : "\"\\u20"
418 3 : );
419 :
420 1 : 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 1 : }
428 :
429 : {
430 1 : std::string valid_json(
431 : "\"\\u301"
432 3 : );
433 :
434 1 : 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 1 : }
442 :
443 : }
444 20 : CATCH_END_SECTION()
445 :
446 20 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: low surrogate missing backslash")
447 : {
448 1 : std::string valid_json(
449 : "\"\\uD91Fmissing\""
450 3 : );
451 :
452 1 : 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 1 : }
460 20 : CATCH_END_SECTION()
461 :
462 20 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: low surrogate missing 'u'")
463 : {
464 1 : std::string valid_json(
465 : "\"\\uD91F\\missing\""
466 3 : );
467 :
468 1 : 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 1 : }
476 20 : CATCH_END_SECTION()
477 :
478 20 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: low surrogate expected")
479 : {
480 : {
481 1 : std::string valid_json(
482 : "\"\\uD91F\\u0010\""
483 3 : );
484 :
485 1 : 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 1 : }
493 :
494 : {
495 1 : std::string valid_json(
496 : "\"\\uD91F\\uDBFF\""
497 3 : );
498 :
499 1 : 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 1 : }
507 :
508 : {
509 1 : std::string valid_json(
510 : "\"\\uD91F\\uE030"
511 3 : );
512 :
513 1 : 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 1 : }
521 : }
522 20 : CATCH_END_SECTION()
523 :
524 20 : 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 3 : );
530 :
531 1 : 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 1 : }
539 :
540 : {
541 1 : std::string valid_json(
542 : "\"\\uD91F\\u0f"
543 3 : );
544 :
545 1 : 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 1 : }
553 :
554 : {
555 1 : std::string valid_json(
556 : "\"\\uD91F\\u0fa"
557 3 : );
558 :
559 1 : 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 1 : }
567 : }
568 20 : CATCH_END_SECTION()
569 :
570 20 : 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 3 : );
576 :
577 1 : 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 1 : }
585 :
586 : {
587 1 : std::string valid_json(
588 : "\"\\udb31\\u3eg\""
589 3 : );
590 :
591 1 : 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 1 : }
599 :
600 : {
601 1 : std::string valid_json(
602 : "\"\\udb31\\ua3e!\""
603 3 : );
604 :
605 1 : 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 1 : }
613 : }
614 20 : CATCH_END_SECTION()
615 :
616 20 : 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 1024 : std::stringstream ss;
621 1024 : ss << "\\u" << std::hex << std::setw(4)
622 1024 : << std::setfill('0') << static_cast<int>(c);
623 :
624 : // breaking up line so it compiles on lunar
625 : //
626 : //libutf8::json_tokens jt("\"" + ss.str() + "\"");
627 3072 : std::string str("\"");
628 1024 : str += ss.str();
629 1024 : str += "\"";
630 1024 : libutf8::json_tokens jt(str);
631 :
632 1024 : CATCH_REQUIRE(jt.line() == 0);
633 1024 : CATCH_REQUIRE(jt.column() == 0);
634 1024 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
635 1024 : CATCH_REQUIRE(jt.line() == 1);
636 1024 : CATCH_REQUIRE(jt.column() == 1);
637 3072 : std::string const msg("low surrogate " + ss.str()
638 2048 : + " found before a high surrogate");
639 1024 : CATCH_REQUIRE(jt.error() == msg);
640 1024 : }
641 :
642 : }
643 20 : CATCH_END_SECTION()
644 :
645 20 : CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: invalid hexadecimal digit")
646 : {
647 : {
648 1 : std::string valid_json(
649 : "\"\\u5z"
650 3 : );
651 :
652 1 : libutf8::json_tokens jt(valid_json);
653 1 : CATCH_REQUIRE(jt.line() == 0);
654 1 : CATCH_REQUIRE(jt.column() == 0);
655 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
656 1 : CATCH_REQUIRE(jt.line() == 1);
657 1 : CATCH_REQUIRE(jt.column() == 1);
658 1 : CATCH_REQUIRE(jt.error() == "invalid unicode character: 'z'");
659 1 : }
660 :
661 : {
662 1 : std::string valid_json(
663 : "\"\\uaa$"
664 3 : );
665 :
666 1 : libutf8::json_tokens jt(valid_json);
667 1 : CATCH_REQUIRE(jt.line() == 0);
668 1 : CATCH_REQUIRE(jt.column() == 0);
669 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
670 1 : CATCH_REQUIRE(jt.line() == 1);
671 1 : CATCH_REQUIRE(jt.column() == 1);
672 1 : CATCH_REQUIRE(jt.error() == "invalid unicode character: '$'");
673 1 : }
674 :
675 : {
676 1 : std::string valid_json(
677 : "\"\\ua9a\001"
678 3 : );
679 :
680 1 : libutf8::json_tokens jt(valid_json);
681 1 : CATCH_REQUIRE(jt.line() == 0);
682 1 : CATCH_REQUIRE(jt.column() == 0);
683 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
684 1 : CATCH_REQUIRE(jt.line() == 1);
685 1 : CATCH_REQUIRE(jt.column() == 1);
686 1 : CATCH_REQUIRE(jt.error() == "invalid unicode character: '^A'");
687 1 : }
688 : }
689 20 : CATCH_END_SECTION()
690 :
691 20 : CATCH_START_SECTION("json_tokens_invalid: unterminated JSON string")
692 : {
693 3 : libutf8::json_tokens jt("\"unterminated");
694 1 : CATCH_REQUIRE(jt.line() == 0);
695 1 : CATCH_REQUIRE(jt.column() == 0);
696 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
697 1 : CATCH_REQUIRE(jt.line() == 1);
698 1 : CATCH_REQUIRE(jt.column() == 1);
699 1 : CATCH_REQUIRE(jt.error() == "unclosed string");
700 :
701 1 : }
702 20 : CATCH_END_SECTION()
703 :
704 20 : CATCH_START_SECTION("json_tokens_invalid: JSON true with missing characters")
705 : {
706 : {
707 3 : libutf8::json_tokens jt("{\"bad-true\":tru}");
708 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
709 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
710 1 : CATCH_REQUIRE(jt.string() == "bad-true");
711 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
712 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
713 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 't'");
714 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
715 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'r'");
716 1 : }
717 :
718 : {
719 3 : libutf8::json_tokens jt("{\"bad-true\":tr}");
720 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
721 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
722 1 : CATCH_REQUIRE(jt.string() == "bad-true");
723 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
724 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
725 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 't'");
726 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
727 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'r'");
728 1 : }
729 :
730 : {
731 3 : libutf8::json_tokens jt("{\"bad-true\":t}");
732 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
733 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
734 1 : CATCH_REQUIRE(jt.string() == "bad-true");
735 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
736 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
737 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 't'");
738 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_OBJECT);
739 1 : }
740 : }
741 20 : CATCH_END_SECTION()
742 :
743 20 : CATCH_START_SECTION("json_tokens_invalid: JSON false with missing characters")
744 : {
745 : {
746 3 : libutf8::json_tokens jt("{\"bad-false\":fals}");
747 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
748 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
749 1 : CATCH_REQUIRE(jt.string() == "bad-false");
750 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
751 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
752 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'f'");
753 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
754 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'a'");
755 1 : }
756 :
757 : {
758 3 : libutf8::json_tokens jt("{\"bad-false\":fal}");
759 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
760 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
761 1 : CATCH_REQUIRE(jt.string() == "bad-false");
762 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
763 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
764 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'f'");
765 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
766 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'a'");
767 1 : }
768 :
769 : {
770 3 : libutf8::json_tokens jt("{\"bad-false\":fa}");
771 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
772 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
773 1 : CATCH_REQUIRE(jt.string() == "bad-false");
774 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
775 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
776 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'f'");
777 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
778 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'a'");
779 1 : }
780 :
781 : {
782 3 : libutf8::json_tokens jt("{\"bad-false\":f}");
783 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
784 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
785 1 : CATCH_REQUIRE(jt.string() == "bad-false");
786 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
787 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
788 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'f'");
789 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_OBJECT);
790 1 : }
791 : }
792 20 : CATCH_END_SECTION()
793 :
794 20 : CATCH_START_SECTION("json_tokens_invalid: JSON null with missing characters")
795 : {
796 : {
797 3 : libutf8::json_tokens jt("{\"bad-null\":nul}");
798 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
799 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
800 1 : CATCH_REQUIRE(jt.string() == "bad-null");
801 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
802 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
803 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'n'");
804 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
805 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'u'");
806 1 : }
807 :
808 : {
809 3 : libutf8::json_tokens jt("{\"bad-null\":nu}");
810 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
811 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
812 1 : CATCH_REQUIRE(jt.string() == "bad-null");
813 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
814 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
815 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'n'");
816 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
817 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'u'");
818 1 : }
819 :
820 : {
821 3 : libutf8::json_tokens jt("{\"bad-null\":n}");
822 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
823 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
824 1 : CATCH_REQUIRE(jt.string() == "bad-null");
825 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
826 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
827 1 : CATCH_REQUIRE(jt.error() == "found unexpected character: 'n'");
828 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_OBJECT);
829 1 : }
830 : }
831 20 : CATCH_END_SECTION()
832 :
833 20 : CATCH_START_SECTION("json_tokens_invalid: unexpected JSON characters")
834 : {
835 1114112 : for(char32_t c(1); c < 0x110000; ++c)
836 : {
837 1114111 : if(c >= 0xD800 && c <= 0xDFFF)
838 : {
839 2048 : continue;
840 : }
841 1112063 : switch(c)
842 : {
843 24 : case '"':
844 : case '{':
845 : case '}':
846 : case '[':
847 : case ']':
848 : case '0':
849 : case '1':
850 : case '2':
851 : case '3':
852 : case '4':
853 : case '5':
854 : case '6':
855 : case '7':
856 : case '8':
857 : case '9':
858 : case ' ':
859 : case '\t':
860 : case '\r':
861 : case '\n':
862 : case 'n':
863 : case 't':
864 : case 'f':
865 : case ',':
866 : case ':':
867 24 : continue;
868 :
869 : }
870 :
871 2224078 : std::string invalid_json(libutf8::to_u8string(c));
872 2224078 : libutf8::json_tokens jt(invalid_json);
873 :
874 1112039 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
875 1112039 : if(c < 0x20)
876 : {
877 28 : CATCH_REQUIRE(jt.error() == "found unexpected character: '^" + libutf8::to_u8string(static_cast<char32_t>(c + 0x40)) + "'");
878 : }
879 1112011 : else if(c >= 0x80 && c < 0xA0)
880 : {
881 32 : CATCH_REQUIRE(jt.error() == "found unexpected character: '@" + libutf8::to_u8string(static_cast<char32_t>(c - 0x40)) + "'");
882 32 : }
883 : else
884 : {
885 1111979 : CATCH_REQUIRE(jt.error() == "found unexpected character: '" + libutf8::to_u8string(c) + "'");
886 : }
887 : }
888 : }
889 20 : CATCH_END_SECTION()
890 :
891 20 : CATCH_START_SECTION("json_tokens_invalid: unexpected '\\0' in JSON")
892 : {
893 1 : std::string invalid_json;
894 1 : invalid_json += '\0';
895 1 : libutf8::json_tokens jt(invalid_json);
896 :
897 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
898 1 : CATCH_REQUIRE(jt.error() == "found unexpected NULL character");
899 1 : }
900 20 : CATCH_END_SECTION()
901 :
902 20 : CATCH_START_SECTION("json_tokens_invalid: unexpected '\\0' in JSON string")
903 : {
904 3 : std::string invalid_json("\"string");
905 1 : invalid_json += '\0';
906 1 : invalid_json += "with null\"";
907 1 : libutf8::json_tokens jt(invalid_json);
908 :
909 1 : CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
910 1 : CATCH_REQUIRE(jt.error() == "unexpected NULL character in string");
911 1 : }
912 20 : CATCH_END_SECTION()
913 20 : }
914 :
915 :
916 :
917 : // vim: ts=4 sw=4 et
|