]> git.proxmox.com Git - qemu.git/blame - tests/check-qjson.c
check-qjson: Test noncharacters other than U+FFFE, U+FFFF in strings
[qemu.git] / tests / check-qjson.c
CommitLineData
422c46a8
AL
1/*
2 * Copyright IBM, Corp. 2009
3960c41f 3 * Copyright (c) 2013 Red Hat Inc.
422c46a8
AL
4 *
5 * Authors:
6 * Anthony Liguori <aliguori@us.ibm.com>
d6244e2c 7 * Markus Armbruster <armbru@redhat.com>
422c46a8
AL
8 *
9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10 * See the COPYING.LIB file in the top-level directory.
11 *
12 */
ef76dc59 13#include <glib.h>
422c46a8 14
7b1b5d19
PB
15#include "qapi/qmp/qstring.h"
16#include "qapi/qmp/qint.h"
17#include "qapi/qmp/qdict.h"
18#include "qapi/qmp/qlist.h"
19#include "qapi/qmp/qfloat.h"
20#include "qapi/qmp/qbool.h"
21#include "qapi/qmp/qjson.h"
422c46a8
AL
22
23#include "qemu-common.h"
24
ef76dc59 25static void escaped_string(void)
422c46a8
AL
26{
27 int i;
28 struct {
29 const char *encoded;
30 const char *decoded;
6ee59202 31 int skip;
422c46a8 32 } test_cases[] = {
d22b0bd7
LC
33 { "\"\\b\"", "\b" },
34 { "\"\\f\"", "\f" },
35 { "\"\\n\"", "\n" },
36 { "\"\\r\"", "\r" },
37 { "\"\\t\"", "\t" },
69faeee1
JK
38 { "\"/\"", "/" },
39 { "\"\\/\"", "/", .skip = 1 },
d22b0bd7 40 { "\"\\\\\"", "\\" },
422c46a8
AL
41 { "\"\\\"\"", "\"" },
42 { "\"hello world \\\"embedded string\\\"\"",
43 "hello world \"embedded string\"" },
44 { "\"hello world\\nwith new line\"", "hello world\nwith new line" },
6ee59202 45 { "\"single byte utf-8 \\u0020\"", "single byte utf-8 ", .skip = 1 },
422c46a8
AL
46 { "\"double byte utf-8 \\u00A2\"", "double byte utf-8 \xc2\xa2" },
47 { "\"triple byte utf-8 \\u20AC\"", "triple byte utf-8 \xe2\x82\xac" },
48 {}
49 };
50
51 for (i = 0; test_cases[i].encoded; i++) {
52 QObject *obj;
53 QString *str;
54
55 obj = qobject_from_json(test_cases[i].encoded);
56
ef76dc59
AL
57 g_assert(obj != NULL);
58 g_assert(qobject_type(obj) == QTYPE_QSTRING);
422c46a8
AL
59
60 str = qobject_to_qstring(obj);
ef76dc59 61 g_assert_cmpstr(qstring_get_str(str), ==, test_cases[i].decoded);
422c46a8 62
6ee59202
AL
63 if (test_cases[i].skip == 0) {
64 str = qobject_to_json(obj);
ef76dc59 65 g_assert_cmpstr(qstring_get_str(str), ==, test_cases[i].encoded);
6ee59202
AL
66 qobject_decref(obj);
67 }
68
422c46a8
AL
69 QDECREF(str);
70 }
71}
422c46a8 72
ef76dc59 73static void simple_string(void)
422c46a8
AL
74{
75 int i;
76 struct {
77 const char *encoded;
78 const char *decoded;
79 } test_cases[] = {
80 { "\"hello world\"", "hello world" },
81 { "\"the quick brown fox jumped over the fence\"",
82 "the quick brown fox jumped over the fence" },
83 {}
84 };
85
86 for (i = 0; test_cases[i].encoded; i++) {
87 QObject *obj;
88 QString *str;
89
90 obj = qobject_from_json(test_cases[i].encoded);
91
ef76dc59
AL
92 g_assert(obj != NULL);
93 g_assert(qobject_type(obj) == QTYPE_QSTRING);
422c46a8
AL
94
95 str = qobject_to_qstring(obj);
ef76dc59 96 g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
422c46a8 97
6ee59202 98 str = qobject_to_json(obj);
ef76dc59 99 g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
6ee59202
AL
100
101 qobject_decref(obj);
102
422c46a8
AL
103 QDECREF(str);
104 }
105}
422c46a8 106
ef76dc59 107static void single_quote_string(void)
422c46a8
AL
108{
109 int i;
110 struct {
111 const char *encoded;
112 const char *decoded;
113 } test_cases[] = {
114 { "'hello world'", "hello world" },
115 { "'the quick brown fox \\' jumped over the fence'",
116 "the quick brown fox ' jumped over the fence" },
117 {}
118 };
119
120 for (i = 0; test_cases[i].encoded; i++) {
121 QObject *obj;
122 QString *str;
123
124 obj = qobject_from_json(test_cases[i].encoded);
125
ef76dc59
AL
126 g_assert(obj != NULL);
127 g_assert(qobject_type(obj) == QTYPE_QSTRING);
422c46a8
AL
128
129 str = qobject_to_qstring(obj);
ef76dc59 130 g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
422c46a8
AL
131
132 QDECREF(str);
133 }
134}
422c46a8 135
3960c41f
MA
136static void utf8_string(void)
137{
138 /*
139 * FIXME Current behavior for invalid UTF-8 sequences is
140 * incorrect. This test expects current, incorrect results.
141 * They're all marked "bug:" below, and are to be replaced by
142 * correct ones as the bugs get fixed.
143 *
144 * The JSON parser rejects some invalid sequences, but accepts
145 * others without correcting the problem.
146 *
147 * The JSON formatter replaces some invalid sequences by U+FFFF (a
148 * noncharacter), and goes wonky for others.
149 *
150 * For both directions, we should either reject all invalid
151 * sequences, or minimize overlong sequences and replace all other
152 * invalid sequences by a suitable replacement character. A
153 * common choice for replacement is U+FFFD.
154 *
155 * Problem: we can't easily deal with embedded U+0000. Parsing
156 * the JSON string "this \\u0000" is fun" yields "this \0 is fun",
157 * which gets misinterpreted as NUL-terminated "this ". We should
158 * consider using overlong encoding \xC0\x80 for U+0000 ("modified
159 * UTF-8").
160 *
1d50c8e9 161 * Most test cases are scraped from Markus Kuhn's UTF-8 decoder
3960c41f
MA
162 * capability and stress test at
163 * http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
164 */
165 static const struct {
166 const char *json_in;
167 const char *utf8_out;
168 const char *json_out; /* defaults to @json_in */
169 const char *utf8_in; /* defaults to @utf8_out */
170 } test_cases[] = {
171 /*
172 * Bug markers used here:
173 * - bug: not corrected
174 * JSON parser fails to correct invalid sequence(s)
175 * - bug: rejected
176 * JSON parser rejects invalid sequence(s)
177 * We may choose to define this as feature
178 * - bug: want "\"...\""
179 * JSON formatter produces incorrect result, this is the
180 * correct one, assuming replacement character U+FFFF
181 * - bug: want "..." (no \")
182 * JSON parser produces incorrect result, this is the
183 * correct one, assuming replacement character U+FFFF
184 * We may choose to reject instead of replace
185 * Not marked explicitly, but trivial to find:
186 * - JSON formatter replacing invalid sequence by \\uFFFF is a
187 * bug if we want it to fail for invalid sequences.
188 */
189
190 /* 1 Some correct UTF-8 text */
191 {
192 /* a bit of German */
193 "\"Falsches \xC3\x9C" "ben von Xylophonmusik qu\xC3\xA4lt"
194 " jeden gr\xC3\xB6\xC3\x9F" "eren Zwerg.\"",
195 "Falsches \xC3\x9C" "ben von Xylophonmusik qu\xC3\xA4lt"
196 " jeden gr\xC3\xB6\xC3\x9F" "eren Zwerg.",
197 "\"Falsches \\u00DCben von Xylophonmusik qu\\u00E4lt"
198 " jeden gr\\u00F6\\u00DFeren Zwerg.\"",
199 },
200 {
201 /* a bit of Greek */
202 "\"\xCE\xBA\xE1\xBD\xB9\xCF\x83\xCE\xBC\xCE\xB5\"",
203 "\xCE\xBA\xE1\xBD\xB9\xCF\x83\xCE\xBC\xCE\xB5",
204 "\"\\u03BA\\u1F79\\u03C3\\u03BC\\u03B5\"",
205 },
206 /* 2 Boundary condition test cases */
207 /* 2.1 First possible sequence of a certain length */
208 /* 2.1.1 1 byte U+0000 */
209 {
210 "\"\\u0000\"",
211 "", /* bug: want overlong "\xC0\x80" */
212 "\"\"", /* bug: want "\"\\u0000\"" */
213 },
214 /* 2.1.2 2 bytes U+0080 */
215 {
216 "\"\xC2\x80\"",
217 "\xC2\x80",
218 "\"\\u0080\"",
219 },
220 /* 2.1.3 3 bytes U+0800 */
221 {
222 "\"\xE0\xA0\x80\"",
223 "\xE0\xA0\x80",
224 "\"\\u0800\"",
225 },
226 /* 2.1.4 4 bytes U+10000 */
227 {
228 "\"\xF0\x90\x80\x80\"",
229 "\xF0\x90\x80\x80",
230 "\"\\u0400\\uFFFF\"", /* bug: want "\"\\uD800\\uDC00\"" */
231 },
232 /* 2.1.5 5 bytes U+200000 */
233 {
234 "\"\xF8\x88\x80\x80\x80\"",
235 NULL, /* bug: rejected */
236 "\"\\u8200\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
237 "\xF8\x88\x80\x80\x80",
238 },
239 /* 2.1.6 6 bytes U+4000000 */
240 {
241 "\"\xFC\x84\x80\x80\x80\x80\"",
242 NULL, /* bug: rejected */
243 "\"\\uC100\\uFFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
244 "\xFC\x84\x80\x80\x80\x80",
245 },
246 /* 2.2 Last possible sequence of a certain length */
247 /* 2.2.1 1 byte U+007F */
248 {
249 "\"\x7F\"",
250 "\x7F",
251 "\"\177\"",
252 },
253 /* 2.2.2 2 bytes U+07FF */
254 {
255 "\"\xDF\xBF\"",
256 "\xDF\xBF",
257 "\"\\u07FF\"",
258 },
1d50c8e9
MA
259 /*
260 * 2.2.3 3 bytes U+FFFC
261 * The last possible sequence is actually U+FFFF. But that's
262 * a noncharacter, and already covered by its own test case
263 * under 5.3. Same for U+FFFE. U+FFFD is the last character
264 * in the BMP, and covered under 2.3. Because of U+FFFD's
265 * special role as replacement character, it's worth testing
266 * U+FFFC here.
267 */
3960c41f 268 {
1d50c8e9
MA
269 "\"\xEF\xBF\xBC\"",
270 "\xEF\xBF\xBC",
271 "\"\\uFFFC\"",
3960c41f
MA
272 },
273 /* 2.2.4 4 bytes U+1FFFFF */
274 {
275 "\"\xF7\xBF\xBF\xBF\"",
276 NULL, /* bug: rejected */
277 "\"\\u7FFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
278 "\xF7\xBF\xBF\xBF",
279 },
280 /* 2.2.5 5 bytes U+3FFFFFF */
281 {
282 "\"\xFB\xBF\xBF\xBF\xBF\"",
283 NULL, /* bug: rejected */
284 "\"\\uBFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
285 "\xFB\xBF\xBF\xBF\xBF",
286 },
287 /* 2.2.6 6 bytes U+7FFFFFFF */
288 {
289 "\"\xFD\xBF\xBF\xBF\xBF\xBF\"",
290 NULL, /* bug: rejected */
291 "\"\\uDFFF\\uFFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
292 "\xFD\xBF\xBF\xBF\xBF\xBF",
293 },
294 /* 2.3 Other boundary conditions */
295 {
d6244e2c 296 /* last one before surrogate range: U+D7FF */
3960c41f
MA
297 "\"\xED\x9F\xBF\"",
298 "\xED\x9F\xBF",
299 "\"\\uD7FF\"",
300 },
301 {
d6244e2c 302 /* first one after surrogate range: U+E000 */
3960c41f
MA
303 "\"\xEE\x80\x80\"",
304 "\xEE\x80\x80",
305 "\"\\uE000\"",
306 },
307 {
d6244e2c 308 /* last one in BMP: U+FFFD */
3960c41f
MA
309 "\"\xEF\xBF\xBD\"",
310 "\xEF\xBF\xBD",
311 "\"\\uFFFD\"",
312 },
313 {
1d50c8e9
MA
314 /* last one in last plane: U+10FFFD */
315 "\"\xF4\x8F\xBF\xBD\"",
316 "\xF4\x8F\xBF\xBD",
317 "\"\\u43FF\\uFFFF\"", /* bug: want "\"\\uDBFF\\uDFFD\"" */
3960c41f
MA
318 },
319 {
d6244e2c 320 /* first one beyond Unicode range: U+110000 */
3960c41f
MA
321 "\"\xF4\x90\x80\x80\"",
322 "\xF4\x90\x80\x80",
323 "\"\\u4400\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
324 },
325 /* 3 Malformed sequences */
326 /* 3.1 Unexpected continuation bytes */
327 /* 3.1.1 First continuation byte */
328 {
329 "\"\x80\"",
330 "\x80", /* bug: not corrected */
331 "\"\\uFFFF\"",
332 },
333 /* 3.1.2 Last continuation byte */
334 {
335 "\"\xBF\"",
336 "\xBF", /* bug: not corrected */
337 "\"\\uFFFF\"",
338 },
339 /* 3.1.3 2 continuation bytes */
340 {
341 "\"\x80\xBF\"",
342 "\x80\xBF", /* bug: not corrected */
343 "\"\\uFFFF\\uFFFF\"",
344 },
345 /* 3.1.4 3 continuation bytes */
346 {
347 "\"\x80\xBF\x80\"",
348 "\x80\xBF\x80", /* bug: not corrected */
349 "\"\\uFFFF\\uFFFF\\uFFFF\"",
350 },
351 /* 3.1.5 4 continuation bytes */
352 {
353 "\"\x80\xBF\x80\xBF\"",
354 "\x80\xBF\x80\xBF", /* bug: not corrected */
355 "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"",
356 },
357 /* 3.1.6 5 continuation bytes */
358 {
359 "\"\x80\xBF\x80\xBF\x80\"",
360 "\x80\xBF\x80\xBF\x80", /* bug: not corrected */
361 "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"",
362 },
363 /* 3.1.7 6 continuation bytes */
364 {
365 "\"\x80\xBF\x80\xBF\x80\xBF\"",
366 "\x80\xBF\x80\xBF\x80\xBF", /* bug: not corrected */
367 "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"",
368 },
369 /* 3.1.8 7 continuation bytes */
370 {
371 "\"\x80\xBF\x80\xBF\x80\xBF\x80\"",
372 "\x80\xBF\x80\xBF\x80\xBF\x80", /* bug: not corrected */
373 "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"",
374 },
375 /* 3.1.9 Sequence of all 64 possible continuation bytes */
376 {
377 "\"\x80\x81\x82\x83\x84\x85\x86\x87"
378 "\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F"
379 "\x90\x91\x92\x93\x94\x95\x96\x97"
380 "\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F"
381 "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7"
382 "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF"
383 "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7"
384 "\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\"",
385 /* bug: not corrected */
386 "\x80\x81\x82\x83\x84\x85\x86\x87"
387 "\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F"
388 "\x90\x91\x92\x93\x94\x95\x96\x97"
389 "\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F"
390 "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7"
391 "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF"
392 "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7"
393 "\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF",
394 "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
395 "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
396 "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
397 "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
398 "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
399 "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
400 "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
401 "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\""
402 },
403 /* 3.2 Lonely start characters */
404 /* 3.2.1 All 32 first bytes of 2-byte sequences, followed by space */
405 {
406 "\"\xC0 \xC1 \xC2 \xC3 \xC4 \xC5 \xC6 \xC7 "
407 "\xC8 \xC9 \xCA \xCB \xCC \xCD \xCE \xCF "
408 "\xD0 \xD1 \xD2 \xD3 \xD4 \xD5 \xD6 \xD7 "
409 "\xD8 \xD9 \xDA \xDB \xDC \xDD \xDE \xDF \"",
410 NULL, /* bug: rejected */
411 "\"\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF "
412 "\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF "
413 "\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF "
414 "\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \"",
415 "\xC0 \xC1 \xC2 \xC3 \xC4 \xC5 \xC6 \xC7 "
416 "\xC8 \xC9 \xCA \xCB \xCC \xCD \xCE \xCF "
417 "\xD0 \xD1 \xD2 \xD3 \xD4 \xD5 \xD6 \xD7 "
418 "\xD8 \xD9 \xDA \xDB \xDC \xDD \xDE \xDF ",
419 },
420 /* 3.2.2 All 16 first bytes of 3-byte sequences, followed by space */
421 {
422 "\"\xE0 \xE1 \xE2 \xE3 \xE4 \xE5 \xE6 \xE7 "
423 "\xE8 \xE9 \xEA \xEB \xEC \xED \xEE \xEF \"",
424 /* bug: not corrected */
425 "\xE0 \xE1 \xE2 \xE3 \xE4 \xE5 \xE6 \xE7 "
426 "\xE8 \xE9 \xEA \xEB \xEC \xED \xEE \xEF ",
427 "\"\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF "
428 "\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \"",
429 },
430 /* 3.2.3 All 8 first bytes of 4-byte sequences, followed by space */
431 {
432 "\"\xF0 \xF1 \xF2 \xF3 \xF4 \xF5 \xF6 \xF7 \"",
433 NULL, /* bug: rejected */
434 "\"\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \"",
435 "\xF0 \xF1 \xF2 \xF3 \xF4 \xF5 \xF6 \xF7 ",
436 },
437 /* 3.2.4 All 4 first bytes of 5-byte sequences, followed by space */
438 {
439 "\"\xF8 \xF9 \xFA \xFB \"",
440 NULL, /* bug: rejected */
441 "\"\\uFFFF \\uFFFF \\uFFFF \\uFFFF \"",
442 "\xF8 \xF9 \xFA \xFB ",
443 },
444 /* 3.2.5 All 2 first bytes of 6-byte sequences, followed by space */
445 {
446 "\"\xFC \xFD \"",
447 NULL, /* bug: rejected */
448 "\"\\uFFFF \\uFFFF \"",
449 "\xFC \xFD ",
450 },
451 /* 3.3 Sequences with last continuation byte missing */
452 /* 3.3.1 2-byte sequence with last byte missing (U+0000) */
453 {
454 "\"\xC0\"",
455 NULL, /* bug: rejected */
456 "\"\\uFFFF\"",
457 "\xC0",
458 },
459 /* 3.3.2 3-byte sequence with last byte missing (U+0000) */
460 {
461 "\"\xE0\x80\"",
462 "\xE0\x80", /* bug: not corrected */
463 "\"\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
464 },
465 /* 3.3.3 4-byte sequence with last byte missing (U+0000) */
466 {
467 "\"\xF0\x80\x80\"",
468 "\xF0\x80\x80", /* bug: not corrected */
469 "\"\\u0000\"", /* bug: want "\"\\uFFFF\"" */
470 },
471 /* 3.3.4 5-byte sequence with last byte missing (U+0000) */
472 {
d6244e2c 473 "\"\xF8\x80\x80\x80\"",
3960c41f
MA
474 NULL, /* bug: rejected */
475 "\"\\u8000\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
476 "\xF8\x80\x80\x80",
477 },
478 /* 3.3.5 6-byte sequence with last byte missing (U+0000) */
479 {
480 "\"\xFC\x80\x80\x80\x80\"",
481 NULL, /* bug: rejected */
482 "\"\\uC000\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
483 "\xFC\x80\x80\x80\x80",
484 },
485 /* 3.3.6 2-byte sequence with last byte missing (U+07FF) */
486 {
487 "\"\xDF\"",
488 "\xDF", /* bug: not corrected */
489 "\"\\uFFFF\"",
490 },
491 /* 3.3.7 3-byte sequence with last byte missing (U+FFFF) */
492 {
493 "\"\xEF\xBF\"",
494 "\xEF\xBF", /* bug: not corrected */
495 "\"\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
496 },
497 /* 3.3.8 4-byte sequence with last byte missing (U+1FFFFF) */
498 {
499 "\"\xF7\xBF\xBF\"",
500 NULL, /* bug: rejected */
501 "\"\\u7FFF\"", /* bug: want "\"\\uFFFF\"" */
502 "\xF7\xBF\xBF",
503 },
504 /* 3.3.9 5-byte sequence with last byte missing (U+3FFFFFF) */
505 {
506 "\"\xFB\xBF\xBF\xBF\"",
507 NULL, /* bug: rejected */
508 "\"\\uBFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
509 "\xFB\xBF\xBF\xBF",
510 },
511 /* 3.3.10 6-byte sequence with last byte missing (U+7FFFFFFF) */
512 {
513 "\"\xFD\xBF\xBF\xBF\xBF\"",
514 NULL, /* bug: rejected */
515 "\"\\uDFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"", */
516 "\xFD\xBF\xBF\xBF\xBF",
517 },
518 /* 3.4 Concatenation of incomplete sequences */
519 {
520 "\"\xC0\xE0\x80\xF0\x80\x80\xF8\x80\x80\x80\xFC\x80\x80\x80\x80"
521 "\xDF\xEF\xBF\xF7\xBF\xBF\xFB\xBF\xBF\xBF\xFD\xBF\xBF\xBF\xBF\"",
522 NULL, /* bug: rejected */
523 /* bug: want "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF"
524 "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"" */
525 "\"\\u0020\\uFFFF\\u0000\\u8000\\uFFFF\\uC000\\uFFFF\\uFFFF"
526 "\\u07EF\\uFFFF\\u7FFF\\uBFFF\\uFFFF\\uDFFF\\uFFFF\\uFFFF\"",
527 "\xC0\xE0\x80\xF0\x80\x80\xF8\x80\x80\x80\xFC\x80\x80\x80\x80"
528 "\xDF\xEF\xBF\xF7\xBF\xBF\xFB\xBF\xBF\xBF\xFD\xBF\xBF\xBF\xBF",
529 },
530 /* 3.5 Impossible bytes */
531 {
532 "\"\xFE\"",
533 NULL, /* bug: rejected */
534 "\"\\uFFFF\"",
535 "\xFE",
536 },
537 {
538 "\"\xFF\"",
539 NULL, /* bug: rejected */
540 "\"\\uFFFF\"",
541 "\xFF",
542 },
543 {
544 "\"\xFE\xFE\xFF\xFF\"",
545 NULL, /* bug: rejected */
546 /* bug: want "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"" */
547 "\"\\uEFBF\\uFFFF\"",
548 "\xFE\xFE\xFF\xFF",
549 },
550 /* 4 Overlong sequences */
551 /* 4.1 Overlong '/' */
552 {
553 "\"\xC0\xAF\"",
554 NULL, /* bug: rejected */
555 "\"\\u002F\"", /* bug: want "\"/\"" */
556 "\xC0\xAF",
557 },
558 {
559 "\"\xE0\x80\xAF\"",
560 "\xE0\x80\xAF", /* bug: not corrected */
561 "\"\\u002F\"", /* bug: want "\"/\"" */
562 },
563 {
564 "\"\xF0\x80\x80\xAF\"",
565 "\xF0\x80\x80\xAF", /* bug: not corrected */
566 "\"\\u0000\\uFFFF\"" /* bug: want "\"/\"" */
567 },
568 {
569 "\"\xF8\x80\x80\x80\xAF\"",
570 NULL, /* bug: rejected */
571 "\"\\u8000\\uFFFF\\uFFFF\"", /* bug: want "\"/\"" */
572 "\xF8\x80\x80\x80\xAF",
573 },
574 {
575 "\"\xFC\x80\x80\x80\x80\xAF\"",
576 NULL, /* bug: rejected */
577 "\"\\uC000\\uFFFF\\uFFFF\\uFFFF\"", /* bug: want "\"/\"" */
578 "\xFC\x80\x80\x80\x80\xAF",
579 },
d6244e2c
MA
580 /*
581 * 4.2 Maximum overlong sequences
582 * Highest Unicode value that is still resulting in an
583 * overlong sequence if represented with the given number of
584 * bytes. This is a boundary test for safe UTF-8 decoders.
585 */
3960c41f
MA
586 {
587 /* \U+007F */
588 "\"\xC1\xBF\"",
589 NULL, /* bug: rejected */
590 "\"\\u007F\"", /* bug: want "\"\177\"" */
591 "\xC1\xBF",
592 },
593 {
594 /* \U+07FF */
595 "\"\xE0\x9F\xBF\"",
596 "\xE0\x9F\xBF", /* bug: not corrected */
597 "\"\\u07FF\"",
598 },
599 {
1d50c8e9
MA
600 /*
601 * \U+FFFC
602 * The actual maximum would be U+FFFF, but that's a
603 * noncharacter. Testing U+FFFC seems more useful. See
604 * also 2.2.3
605 */
606 "\"\xF0\x8F\xBF\xBC\"",
607 "\xF0\x8F\xBF\xBC", /* bug: not corrected */
3960c41f
MA
608 "\"\\u03FF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
609 },
610 {
611 /* \U+1FFFFF */
612 "\"\xF8\x87\xBF\xBF\xBF\"",
613 NULL, /* bug: rejected */
614 "\"\\u81FF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
615 "\xF8\x87\xBF\xBF\xBF",
616 },
617 {
618 /* \U+3FFFFFF */
619 "\"\xFC\x83\xBF\xBF\xBF\xBF\"",
620 NULL, /* bug: rejected */
621 "\"\\uC0FF\\uFFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */
622 "\xFC\x83\xBF\xBF\xBF\xBF",
623 },
624 /* 4.3 Overlong representation of the NUL character */
625 {
626 /* \U+0000 */
627 "\"\xC0\x80\"",
628 NULL, /* bug: rejected */
629 "\"\\u0000\"",
630 "\xC0\x80",
631 },
632 {
633 /* \U+0000 */
634 "\"\xE0\x80\x80\"",
635 "\xE0\x80\x80", /* bug: not corrected */
636 "\"\\u0000\"",
637 },
638 {
639 /* \U+0000 */
640 "\"\xF0\x80\x80\x80\"",
641 "\xF0\x80\x80\x80", /* bug: not corrected */
642 "\"\\u0000\\uFFFF\"", /* bug: want "\"\\u0000\"" */
643 },
644 {
645 /* \U+0000 */
646 "\"\xF8\x80\x80\x80\x80\"",
647 NULL, /* bug: rejected */
648 "\"\\u8000\\uFFFF\\uFFFF\"", /* bug: want "\"\\u0000\"" */
649 "\xF8\x80\x80\x80\x80",
650 },
651 {
652 /* \U+0000 */
653 "\"\xFC\x80\x80\x80\x80\x80\"",
654 NULL, /* bug: rejected */
655 "\"\\uC000\\uFFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\u0000\"" */
656 "\xFC\x80\x80\x80\x80\x80",
657 },
658 /* 5 Illegal code positions */
659 /* 5.1 Single UTF-16 surrogates */
660 {
661 /* \U+D800 */
662 "\"\xED\xA0\x80\"",
663 "\xED\xA0\x80", /* bug: not corrected */
664 "\"\\uD800\"", /* bug: want "\"\\uFFFF\"" */
665 },
666 {
667 /* \U+DB7F */
668 "\"\xED\xAD\xBF\"",
669 "\xED\xAD\xBF", /* bug: not corrected */
670 "\"\\uDB7F\"", /* bug: want "\"\\uFFFF\"" */
671 },
672 {
673 /* \U+DB80 */
674 "\"\xED\xAE\x80\"",
675 "\xED\xAE\x80", /* bug: not corrected */
676 "\"\\uDB80\"", /* bug: want "\"\\uFFFF\"" */
677 },
678 {
679 /* \U+DBFF */
680 "\"\xED\xAF\xBF\"",
681 "\xED\xAF\xBF", /* bug: not corrected */
682 "\"\\uDBFF\"", /* bug: want "\"\\uFFFF\"" */
683 },
684 {
685 /* \U+DC00 */
686 "\"\xED\xB0\x80\"",
687 "\xED\xB0\x80", /* bug: not corrected */
688 "\"\\uDC00\"", /* bug: want "\"\\uFFFF\"" */
689 },
690 {
691 /* \U+DF80 */
692 "\"\xED\xBE\x80\"",
693 "\xED\xBE\x80", /* bug: not corrected */
694 "\"\\uDF80\"", /* bug: want "\"\\uFFFF\"" */
695 },
696 {
697 /* \U+DFFF */
698 "\"\xED\xBF\xBF\"",
699 "\xED\xBF\xBF", /* bug: not corrected */
700 "\"\\uDFFF\"", /* bug: want "\"\\uFFFF\"" */
701 },
702 /* 5.2 Paired UTF-16 surrogates */
703 {
704 /* \U+D800\U+DC00 */
705 "\"\xED\xA0\x80\xED\xB0\x80\"",
706 "\xED\xA0\x80\xED\xB0\x80", /* bug: not corrected */
707 "\"\\uD800\\uDC00\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
708 },
709 {
710 /* \U+D800\U+DFFF */
711 "\"\xED\xA0\x80\xED\xBF\xBF\"",
712 "\xED\xA0\x80\xED\xBF\xBF", /* bug: not corrected */
713 "\"\\uD800\\uDFFF\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
714 },
715 {
716 /* \U+DB7F\U+DC00 */
717 "\"\xED\xAD\xBF\xED\xB0\x80\"",
718 "\xED\xAD\xBF\xED\xB0\x80", /* bug: not corrected */
719 "\"\\uDB7F\\uDC00\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
720 },
721 {
722 /* \U+DB7F\U+DFFF */
723 "\"\xED\xAD\xBF\xED\xBF\xBF\"",
724 "\xED\xAD\xBF\xED\xBF\xBF", /* bug: not corrected */
725 "\"\\uDB7F\\uDFFF\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
726 },
727 {
728 /* \U+DB80\U+DC00 */
729 "\"\xED\xAE\x80\xED\xB0\x80\"",
730 "\xED\xAE\x80\xED\xB0\x80", /* bug: not corrected */
731 "\"\\uDB80\\uDC00\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
732 },
733 {
734 /* \U+DB80\U+DFFF */
735 "\"\xED\xAE\x80\xED\xBF\xBF\"",
736 "\xED\xAE\x80\xED\xBF\xBF", /* bug: not corrected */
737 "\"\\uDB80\\uDFFF\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
738 },
739 {
740 /* \U+DBFF\U+DC00 */
741 "\"\xED\xAF\xBF\xED\xB0\x80\"",
742 "\xED\xAF\xBF\xED\xB0\x80", /* bug: not corrected */
743 "\"\\uDBFF\\uDC00\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
744 },
745 {
746 /* \U+DBFF\U+DFFF */
747 "\"\xED\xAF\xBF\xED\xBF\xBF\"",
748 "\xED\xAF\xBF\xED\xBF\xBF", /* bug: not corrected */
749 "\"\\uDBFF\\uDFFF\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */
750 },
751 /* 5.3 Other illegal code positions */
1d50c8e9 752 /* BMP noncharacters */
3960c41f
MA
753 {
754 /* \U+FFFE */
755 "\"\xEF\xBF\xBE\"",
756 "\xEF\xBF\xBE", /* bug: not corrected */
757 "\"\\uFFFE\"", /* bug: not corrected */
758 },
759 {
760 /* \U+FFFF */
761 "\"\xEF\xBF\xBF\"",
762 "\xEF\xBF\xBF", /* bug: not corrected */
763 "\"\\uFFFF\"", /* bug: not corrected */
764 },
1d50c8e9
MA
765 {
766 /* U+FDD0 */
767 "\"\xEF\xB7\x90\"",
768 "\xEF\xB7\x90", /* bug: not corrected */
769 "\"\\uFDD0\"", /* bug: not corrected */
770 },
771 {
772 /* U+FDEF */
773 "\"\xEF\xB7\xAF\"",
774 "\xEF\xB7\xAF", /* bug: not corrected */
775 "\"\\uFDEF\"", /* bug: not corrected */
776 },
777 /* Plane 1 .. 16 noncharacters */
778 {
779 /* U+1FFFE U+1FFFF U+2FFFE U+2FFFF ... U+10FFFE U+10FFFF */
780 "\"\xF0\x9F\xBF\xBE\xF0\x9F\xBF\xBF"
781 "\xF0\xAF\xBF\xBE\xF0\xAF\xBF\xBF"
782 "\xF0\xBF\xBF\xBE\xF0\xBF\xBF\xBF"
783 "\xF1\x8F\xBF\xBE\xF1\x8F\xBF\xBF"
784 "\xF1\x9F\xBF\xBE\xF1\x9F\xBF\xBF"
785 "\xF1\xAF\xBF\xBE\xF1\xAF\xBF\xBF"
786 "\xF1\xBF\xBF\xBE\xF1\xBF\xBF\xBF"
787 "\xF2\x8F\xBF\xBE\xF2\x8F\xBF\xBF"
788 "\xF2\x9F\xBF\xBE\xF2\x9F\xBF\xBF"
789 "\xF2\xAF\xBF\xBE\xF2\xAF\xBF\xBF"
790 "\xF2\xBF\xBF\xBE\xF2\xBF\xBF\xBF"
791 "\xF3\x8F\xBF\xBE\xF3\x8F\xBF\xBF"
792 "\xF3\x9F\xBF\xBE\xF3\x9F\xBF\xBF"
793 "\xF3\xAF\xBF\xBE\xF3\xAF\xBF\xBF"
794 "\xF3\xBF\xBF\xBE\xF3\xBF\xBF\xBF"
795 "\xF4\x8F\xBF\xBE\xF4\x8F\xBF\xBF\"",
796 /* bug: not corrected */
797 "\xF0\x9F\xBF\xBE\xF0\x9F\xBF\xBF"
798 "\xF0\xAF\xBF\xBE\xF0\xAF\xBF\xBF"
799 "\xF0\xBF\xBF\xBE\xF0\xBF\xBF\xBF"
800 "\xF1\x8F\xBF\xBE\xF1\x8F\xBF\xBF"
801 "\xF1\x9F\xBF\xBE\xF1\x9F\xBF\xBF"
802 "\xF1\xAF\xBF\xBE\xF1\xAF\xBF\xBF"
803 "\xF1\xBF\xBF\xBE\xF1\xBF\xBF\xBF"
804 "\xF2\x8F\xBF\xBE\xF2\x8F\xBF\xBF"
805 "\xF2\x9F\xBF\xBE\xF2\x9F\xBF\xBF"
806 "\xF2\xAF\xBF\xBE\xF2\xAF\xBF\xBF"
807 "\xF2\xBF\xBF\xBE\xF2\xBF\xBF\xBF"
808 "\xF3\x8F\xBF\xBE\xF3\x8F\xBF\xBF"
809 "\xF3\x9F\xBF\xBE\xF3\x9F\xBF\xBF"
810 "\xF3\xAF\xBF\xBE\xF3\xAF\xBF\xBF"
811 "\xF3\xBF\xBF\xBE\xF3\xBF\xBF\xBF"
812 "\xF4\x8F\xBF\xBE\xF4\x8F\xBF\xBF",
813 /* bug: not corrected */
814 "\"\\u07FF\\uFFFF\\u07FF\\uFFFF\\u0BFF\\uFFFF\\u0BFF\\uFFFF"
815 "\\u0FFF\\uFFFF\\u0FFF\\uFFFF\\u13FF\\uFFFF\\u13FF\\uFFFF"
816 "\\u17FF\\uFFFF\\u17FF\\uFFFF\\u1BFF\\uFFFF\\u1BFF\\uFFFF"
817 "\\u1FFF\\uFFFF\\u1FFF\\uFFFF\\u23FF\\uFFFF\\u23FF\\uFFFF"
818 "\\u27FF\\uFFFF\\u27FF\\uFFFF\\u2BFF\\uFFFF\\u2BFF\\uFFFF"
819 "\\u2FFF\\uFFFF\\u2FFF\\uFFFF\\u33FF\\uFFFF\\u33FF\\uFFFF"
820 "\\u37FF\\uFFFF\\u37FF\\uFFFF\\u3BFF\\uFFFF\\u3BFF\\uFFFF"
821 "\\u3FFF\\uFFFF\\u3FFF\\uFFFF\\u43FF\\uFFFF\\u43FF\\uFFFF\"",
822 },
3960c41f
MA
823 {}
824 };
825 int i;
826 QObject *obj;
827 QString *str;
828 const char *json_in, *utf8_out, *utf8_in, *json_out;
829
830 for (i = 0; test_cases[i].json_in; i++) {
831 json_in = test_cases[i].json_in;
832 utf8_out = test_cases[i].utf8_out;
833 utf8_in = test_cases[i].utf8_in ?: test_cases[i].utf8_out;
834 json_out = test_cases[i].json_out ?: test_cases[i].json_in;
835
836 obj = qobject_from_json(json_in);
837 if (utf8_out) {
838 g_assert(obj);
839 g_assert(qobject_type(obj) == QTYPE_QSTRING);
840 str = qobject_to_qstring(obj);
841 g_assert_cmpstr(qstring_get_str(str), ==, utf8_out);
842 } else {
843 g_assert(!obj);
844 }
845 qobject_decref(obj);
846
847 obj = QOBJECT(qstring_from_str(utf8_in));
848 str = qobject_to_json(obj);
849 if (json_out) {
850 g_assert(str);
851 g_assert_cmpstr(qstring_get_str(str), ==, json_out);
852 } else {
853 g_assert(!str);
854 }
855 QDECREF(str);
856 qobject_decref(obj);
857
858 /*
859 * Disabled, because json_out currently contains the crap
860 * qobject_to_json() produces.
861 * FIXME Enable once these bugs have been fixed.
862 */
863 if (0 && json_out != json_in) {
864 obj = qobject_from_json(json_out);
865 g_assert(obj);
866 g_assert(qobject_type(obj) == QTYPE_QSTRING);
867 str = qobject_to_qstring(obj);
868 g_assert_cmpstr(qstring_get_str(str), ==, utf8_out);
869 }
870 }
871}
872
ef76dc59 873static void vararg_string(void)
422c46a8
AL
874{
875 int i;
876 struct {
877 const char *decoded;
878 } test_cases[] = {
879 { "hello world" },
880 { "the quick brown fox jumped over the fence" },
881 {}
882 };
883
884 for (i = 0; test_cases[i].decoded; i++) {
885 QObject *obj;
886 QString *str;
887
888 obj = qobject_from_jsonf("%s", test_cases[i].decoded);
889
ef76dc59
AL
890 g_assert(obj != NULL);
891 g_assert(qobject_type(obj) == QTYPE_QSTRING);
422c46a8
AL
892
893 str = qobject_to_qstring(obj);
ef76dc59 894 g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
422c46a8
AL
895
896 QDECREF(str);
897 }
898}
422c46a8 899
ef76dc59 900static void simple_number(void)
422c46a8
AL
901{
902 int i;
903 struct {
904 const char *encoded;
905 int64_t decoded;
6ee59202 906 int skip;
422c46a8
AL
907 } test_cases[] = {
908 { "0", 0 },
909 { "1234", 1234 },
910 { "1", 1 },
911 { "-32", -32 },
6ee59202 912 { "-0", 0, .skip = 1 },
422c46a8
AL
913 { },
914 };
915
916 for (i = 0; test_cases[i].encoded; i++) {
917 QObject *obj;
918 QInt *qint;
919
920 obj = qobject_from_json(test_cases[i].encoded);
ef76dc59
AL
921 g_assert(obj != NULL);
922 g_assert(qobject_type(obj) == QTYPE_QINT);
422c46a8
AL
923
924 qint = qobject_to_qint(obj);
ef76dc59 925 g_assert(qint_get_int(qint) == test_cases[i].decoded);
6ee59202
AL
926 if (test_cases[i].skip == 0) {
927 QString *str;
928
929 str = qobject_to_json(obj);
ef76dc59 930 g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
6ee59202
AL
931 QDECREF(str);
932 }
422c46a8
AL
933
934 QDECREF(qint);
935 }
936}
422c46a8 937
ef76dc59 938static void float_number(void)
422c46a8
AL
939{
940 int i;
941 struct {
942 const char *encoded;
943 double decoded;
6ee59202 944 int skip;
422c46a8
AL
945 } test_cases[] = {
946 { "32.43", 32.43 },
947 { "0.222", 0.222 },
948 { "-32.12313", -32.12313 },
6ee59202 949 { "-32.20e-10", -32.20e-10, .skip = 1 },
422c46a8
AL
950 { },
951 };
952
953 for (i = 0; test_cases[i].encoded; i++) {
954 QObject *obj;
955 QFloat *qfloat;
956
957 obj = qobject_from_json(test_cases[i].encoded);
ef76dc59
AL
958 g_assert(obj != NULL);
959 g_assert(qobject_type(obj) == QTYPE_QFLOAT);
422c46a8
AL
960
961 qfloat = qobject_to_qfloat(obj);
ef76dc59 962 g_assert(qfloat_get_double(qfloat) == test_cases[i].decoded);
422c46a8 963
6ee59202
AL
964 if (test_cases[i].skip == 0) {
965 QString *str;
966
967 str = qobject_to_json(obj);
ef76dc59 968 g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
6ee59202
AL
969 QDECREF(str);
970 }
971
422c46a8
AL
972 QDECREF(qfloat);
973 }
974}
422c46a8 975
ef76dc59 976static void vararg_number(void)
422c46a8
AL
977{
978 QObject *obj;
979 QInt *qint;
980 QFloat *qfloat;
981 int value = 0x2342;
982 int64_t value64 = 0x2342342343LL;
983 double valuef = 2.323423423;
984
985 obj = qobject_from_jsonf("%d", value);
ef76dc59
AL
986 g_assert(obj != NULL);
987 g_assert(qobject_type(obj) == QTYPE_QINT);
422c46a8
AL
988
989 qint = qobject_to_qint(obj);
ef76dc59 990 g_assert(qint_get_int(qint) == value);
422c46a8
AL
991
992 QDECREF(qint);
993
994 obj = qobject_from_jsonf("%" PRId64, value64);
ef76dc59
AL
995 g_assert(obj != NULL);
996 g_assert(qobject_type(obj) == QTYPE_QINT);
422c46a8
AL
997
998 qint = qobject_to_qint(obj);
ef76dc59 999 g_assert(qint_get_int(qint) == value64);
422c46a8
AL
1000
1001 QDECREF(qint);
1002
1003 obj = qobject_from_jsonf("%f", valuef);
ef76dc59
AL
1004 g_assert(obj != NULL);
1005 g_assert(qobject_type(obj) == QTYPE_QFLOAT);
422c46a8
AL
1006
1007 qfloat = qobject_to_qfloat(obj);
ef76dc59 1008 g_assert(qfloat_get_double(qfloat) == valuef);
422c46a8
AL
1009
1010 QDECREF(qfloat);
1011}
422c46a8 1012
ef76dc59 1013static void keyword_literal(void)
422c46a8
AL
1014{
1015 QObject *obj;
1016 QBool *qbool;
6ee59202 1017 QString *str;
422c46a8
AL
1018
1019 obj = qobject_from_json("true");
ef76dc59
AL
1020 g_assert(obj != NULL);
1021 g_assert(qobject_type(obj) == QTYPE_QBOOL);
422c46a8
AL
1022
1023 qbool = qobject_to_qbool(obj);
ef76dc59 1024 g_assert(qbool_get_int(qbool) != 0);
422c46a8 1025
6ee59202 1026 str = qobject_to_json(obj);
ef76dc59 1027 g_assert(strcmp(qstring_get_str(str), "true") == 0);
6ee59202
AL
1028 QDECREF(str);
1029
422c46a8
AL
1030 QDECREF(qbool);
1031
1032 obj = qobject_from_json("false");
ef76dc59
AL
1033 g_assert(obj != NULL);
1034 g_assert(qobject_type(obj) == QTYPE_QBOOL);
422c46a8
AL
1035
1036 qbool = qobject_to_qbool(obj);
ef76dc59 1037 g_assert(qbool_get_int(qbool) == 0);
422c46a8 1038
6ee59202 1039 str = qobject_to_json(obj);
ef76dc59 1040 g_assert(strcmp(qstring_get_str(str), "false") == 0);
6ee59202
AL
1041 QDECREF(str);
1042
422c46a8
AL
1043 QDECREF(qbool);
1044
1045 obj = qobject_from_jsonf("%i", false);
ef76dc59
AL
1046 g_assert(obj != NULL);
1047 g_assert(qobject_type(obj) == QTYPE_QBOOL);
422c46a8
AL
1048
1049 qbool = qobject_to_qbool(obj);
ef76dc59 1050 g_assert(qbool_get_int(qbool) == 0);
422c46a8
AL
1051
1052 QDECREF(qbool);
1053
1054 obj = qobject_from_jsonf("%i", true);
ef76dc59
AL
1055 g_assert(obj != NULL);
1056 g_assert(qobject_type(obj) == QTYPE_QBOOL);
422c46a8
AL
1057
1058 qbool = qobject_to_qbool(obj);
ef76dc59 1059 g_assert(qbool_get_int(qbool) != 0);
422c46a8
AL
1060
1061 QDECREF(qbool);
1062}
422c46a8
AL
1063
1064typedef struct LiteralQDictEntry LiteralQDictEntry;
1065typedef struct LiteralQObject LiteralQObject;
1066
1067struct LiteralQObject
1068{
1069 int type;
1070 union {
1071 int64_t qint;
1072 const char *qstr;
1073 LiteralQDictEntry *qdict;
1074 LiteralQObject *qlist;
1075 } value;
1076};
1077
1078struct LiteralQDictEntry
1079{
1080 const char *key;
1081 LiteralQObject value;
1082};
1083
1084#define QLIT_QINT(val) (LiteralQObject){.type = QTYPE_QINT, .value.qint = (val)}
1085#define QLIT_QSTR(val) (LiteralQObject){.type = QTYPE_QSTRING, .value.qstr = (val)}
1086#define QLIT_QDICT(val) (LiteralQObject){.type = QTYPE_QDICT, .value.qdict = (val)}
1087#define QLIT_QLIST(val) (LiteralQObject){.type = QTYPE_QLIST, .value.qlist = (val)}
1088
1089typedef struct QListCompareHelper
1090{
1091 int index;
1092 LiteralQObject *objs;
1093 int result;
1094} QListCompareHelper;
1095
1096static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
1097
1098static void compare_helper(QObject *obj, void *opaque)
1099{
1100 QListCompareHelper *helper = opaque;
1101
1102 if (helper->result == 0) {
1103 return;
1104 }
1105
1106 if (helper->objs[helper->index].type == QTYPE_NONE) {
1107 helper->result = 0;
1108 return;
1109 }
1110
1111 helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++], obj);
1112}
1113
1114static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
1115{
1116 if (lhs->type != qobject_type(rhs)) {
1117 return 0;
1118 }
1119
1120 switch (lhs->type) {
1121 case QTYPE_QINT:
1122 return lhs->value.qint == qint_get_int(qobject_to_qint(rhs));
1123 case QTYPE_QSTRING:
1124 return (strcmp(lhs->value.qstr, qstring_get_str(qobject_to_qstring(rhs))) == 0);
1125 case QTYPE_QDICT: {
1126 int i;
1127
1128 for (i = 0; lhs->value.qdict[i].key; i++) {
1129 QObject *obj = qdict_get(qobject_to_qdict(rhs), lhs->value.qdict[i].key);
1130
1131 if (!compare_litqobj_to_qobj(&lhs->value.qdict[i].value, obj)) {
1132 return 0;
1133 }
1134 }
1135
1136 return 1;
1137 }
1138 case QTYPE_QLIST: {
1139 QListCompareHelper helper;
1140
1141 helper.index = 0;
1142 helper.objs = lhs->value.qlist;
1143 helper.result = 1;
1144
1145 qlist_iter(qobject_to_qlist(rhs), compare_helper, &helper);
1146
1147 return helper.result;
1148 }
1149 default:
1150 break;
1151 }
1152
1153 return 0;
1154}
1155
ef76dc59 1156static void simple_dict(void)
422c46a8
AL
1157{
1158 int i;
1159 struct {
1160 const char *encoded;
1161 LiteralQObject decoded;
1162 } test_cases[] = {
1163 {
6ee59202 1164 .encoded = "{\"foo\": 42, \"bar\": \"hello world\"}",
422c46a8
AL
1165 .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
1166 { "foo", QLIT_QINT(42) },
1167 { "bar", QLIT_QSTR("hello world") },
1168 { }
1169 })),
1170 }, {
1171 .encoded = "{}",
1172 .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
1173 { }
1174 })),
1175 }, {
6ee59202 1176 .encoded = "{\"foo\": 43}",
422c46a8
AL
1177 .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
1178 { "foo", QLIT_QINT(43) },
1179 { }
1180 })),
1181 },
1182 { }
1183 };
1184
1185 for (i = 0; test_cases[i].encoded; i++) {
1186 QObject *obj;
6ee59202 1187 QString *str;
422c46a8
AL
1188
1189 obj = qobject_from_json(test_cases[i].encoded);
ef76dc59
AL
1190 g_assert(obj != NULL);
1191 g_assert(qobject_type(obj) == QTYPE_QDICT);
422c46a8 1192
ef76dc59 1193 g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
422c46a8 1194
6ee59202
AL
1195 str = qobject_to_json(obj);
1196 qobject_decref(obj);
1197
1198 obj = qobject_from_json(qstring_get_str(str));
ef76dc59
AL
1199 g_assert(obj != NULL);
1200 g_assert(qobject_type(obj) == QTYPE_QDICT);
6ee59202 1201
ef76dc59 1202 g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
422c46a8 1203 qobject_decref(obj);
6ee59202 1204 QDECREF(str);
422c46a8
AL
1205 }
1206}
422c46a8 1207
7109edfe
MR
1208/*
1209 * this generates json of the form:
1210 * a(0,m) = [0, 1, ..., m-1]
1211 * a(n,m) = {
1212 * 'key0': a(0,m),
1213 * 'key1': a(1,m),
1214 * ...
1215 * 'key(n-1)': a(n-1,m)
1216 * }
1217 */
1218static void gen_test_json(GString *gstr, int nest_level_max,
1219 int elem_count)
1220{
1221 int i;
1222
1223 g_assert(gstr);
1224 if (nest_level_max == 0) {
1225 g_string_append(gstr, "[");
1226 for (i = 0; i < elem_count; i++) {
1227 g_string_append_printf(gstr, "%d", i);
1228 if (i < elem_count - 1) {
1229 g_string_append_printf(gstr, ", ");
1230 }
1231 }
1232 g_string_append(gstr, "]");
1233 return;
1234 }
1235
1236 g_string_append(gstr, "{");
1237 for (i = 0; i < nest_level_max; i++) {
1238 g_string_append_printf(gstr, "'key%d': ", i);
1239 gen_test_json(gstr, i, elem_count);
1240 if (i < nest_level_max - 1) {
1241 g_string_append(gstr, ",");
1242 }
1243 }
1244 g_string_append(gstr, "}");
1245}
1246
1247static void large_dict(void)
1248{
1249 GString *gstr = g_string_new("");
1250 QObject *obj;
1251
1252 gen_test_json(gstr, 10, 100);
1253 obj = qobject_from_json(gstr->str);
1254 g_assert(obj != NULL);
1255
1256 qobject_decref(obj);
1257 g_string_free(gstr, true);
1258}
1259
ef76dc59 1260static void simple_list(void)
422c46a8
AL
1261{
1262 int i;
1263 struct {
1264 const char *encoded;
1265 LiteralQObject decoded;
1266 } test_cases[] = {
1267 {
1268 .encoded = "[43,42]",
1269 .decoded = QLIT_QLIST(((LiteralQObject[]){
1270 QLIT_QINT(43),
1271 QLIT_QINT(42),
1272 { }
1273 })),
1274 },
1275 {
1276 .encoded = "[43]",
1277 .decoded = QLIT_QLIST(((LiteralQObject[]){
1278 QLIT_QINT(43),
1279 { }
1280 })),
1281 },
1282 {
1283 .encoded = "[]",
1284 .decoded = QLIT_QLIST(((LiteralQObject[]){
1285 { }
1286 })),
1287 },
1288 {
1289 .encoded = "[{}]",
1290 .decoded = QLIT_QLIST(((LiteralQObject[]){
1291 QLIT_QDICT(((LiteralQDictEntry[]){
1292 {},
1293 })),
1294 {},
1295 })),
1296 },
1297 { }
1298 };
1299
1300 for (i = 0; test_cases[i].encoded; i++) {
1301 QObject *obj;
6ee59202 1302 QString *str;
422c46a8
AL
1303
1304 obj = qobject_from_json(test_cases[i].encoded);
ef76dc59
AL
1305 g_assert(obj != NULL);
1306 g_assert(qobject_type(obj) == QTYPE_QLIST);
422c46a8 1307
ef76dc59 1308 g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
422c46a8 1309
6ee59202
AL
1310 str = qobject_to_json(obj);
1311 qobject_decref(obj);
1312
1313 obj = qobject_from_json(qstring_get_str(str));
ef76dc59
AL
1314 g_assert(obj != NULL);
1315 g_assert(qobject_type(obj) == QTYPE_QLIST);
6ee59202 1316
ef76dc59 1317 g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
422c46a8 1318 qobject_decref(obj);
6ee59202 1319 QDECREF(str);
422c46a8
AL
1320 }
1321}
422c46a8 1322
ef76dc59 1323static void simple_whitespace(void)
422c46a8
AL
1324{
1325 int i;
1326 struct {
1327 const char *encoded;
1328 LiteralQObject decoded;
1329 } test_cases[] = {
1330 {
1331 .encoded = " [ 43 , 42 ]",
1332 .decoded = QLIT_QLIST(((LiteralQObject[]){
1333 QLIT_QINT(43),
1334 QLIT_QINT(42),
1335 { }
1336 })),
1337 },
1338 {
1339 .encoded = " [ 43 , { 'h' : 'b' }, [ ], 42 ]",
1340 .decoded = QLIT_QLIST(((LiteralQObject[]){
1341 QLIT_QINT(43),
1342 QLIT_QDICT(((LiteralQDictEntry[]){
1343 { "h", QLIT_QSTR("b") },
1344 { }})),
1345 QLIT_QLIST(((LiteralQObject[]){
1346 { }})),
1347 QLIT_QINT(42),
1348 { }
1349 })),
1350 },
1351 {
1352 .encoded = " [ 43 , { 'h' : 'b' , 'a' : 32 }, [ ], 42 ]",
1353 .decoded = QLIT_QLIST(((LiteralQObject[]){
1354 QLIT_QINT(43),
1355 QLIT_QDICT(((LiteralQDictEntry[]){
1356 { "h", QLIT_QSTR("b") },
1357 { "a", QLIT_QINT(32) },
1358 { }})),
1359 QLIT_QLIST(((LiteralQObject[]){
1360 { }})),
1361 QLIT_QINT(42),
1362 { }
1363 })),
1364 },
1365 { }
1366 };
1367
1368 for (i = 0; test_cases[i].encoded; i++) {
1369 QObject *obj;
6ee59202 1370 QString *str;
422c46a8
AL
1371
1372 obj = qobject_from_json(test_cases[i].encoded);
ef76dc59
AL
1373 g_assert(obj != NULL);
1374 g_assert(qobject_type(obj) == QTYPE_QLIST);
422c46a8 1375
ef76dc59 1376 g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
422c46a8 1377
6ee59202 1378 str = qobject_to_json(obj);
422c46a8 1379 qobject_decref(obj);
6ee59202
AL
1380
1381 obj = qobject_from_json(qstring_get_str(str));
ef76dc59
AL
1382 g_assert(obj != NULL);
1383 g_assert(qobject_type(obj) == QTYPE_QLIST);
6ee59202 1384
ef76dc59 1385 g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
6ee59202
AL
1386
1387 qobject_decref(obj);
1388 QDECREF(str);
422c46a8
AL
1389 }
1390}
422c46a8 1391
ef76dc59 1392static void simple_varargs(void)
422c46a8
AL
1393{
1394 QObject *embedded_obj;
1395 QObject *obj;
1396 LiteralQObject decoded = QLIT_QLIST(((LiteralQObject[]){
1397 QLIT_QINT(1),
1398 QLIT_QINT(2),
1399 QLIT_QLIST(((LiteralQObject[]){
1400 QLIT_QINT(32),
1401 QLIT_QINT(42),
1402 {}})),
1403 {}}));
1404
1405 embedded_obj = qobject_from_json("[32, 42]");
ef76dc59 1406 g_assert(embedded_obj != NULL);
422c46a8
AL
1407
1408 obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj);
ef76dc59 1409 g_assert(obj != NULL);
422c46a8 1410
ef76dc59 1411 g_assert(compare_litqobj_to_qobj(&decoded, obj) == 1);
422c46a8
AL
1412
1413 qobject_decref(obj);
1414}
422c46a8 1415
ef76dc59 1416static void empty_input(void)
7f8fca7c 1417{
e7a06af8
JK
1418 const char *empty = "";
1419
1420 QObject *obj = qobject_from_json(empty);
ef76dc59 1421 g_assert(obj == NULL);
7f8fca7c 1422}
7f8fca7c 1423
ef76dc59 1424static void unterminated_string(void)
7f8fca7c
PB
1425{
1426 QObject *obj = qobject_from_json("\"abc");
ef76dc59 1427 g_assert(obj == NULL);
7f8fca7c 1428}
7f8fca7c 1429
ef76dc59 1430static void unterminated_sq_string(void)
7f8fca7c
PB
1431{
1432 QObject *obj = qobject_from_json("'abc");
ef76dc59 1433 g_assert(obj == NULL);
7f8fca7c 1434}
7f8fca7c 1435
ef76dc59 1436static void unterminated_escape(void)
7f8fca7c
PB
1437{
1438 QObject *obj = qobject_from_json("\"abc\\\"");
ef76dc59 1439 g_assert(obj == NULL);
7f8fca7c 1440}
7f8fca7c 1441
ef76dc59 1442static void unterminated_array(void)
7f8fca7c
PB
1443{
1444 QObject *obj = qobject_from_json("[32");
ef76dc59 1445 g_assert(obj == NULL);
7f8fca7c 1446}
7f8fca7c 1447
ef76dc59 1448static void unterminated_array_comma(void)
7f8fca7c
PB
1449{
1450 QObject *obj = qobject_from_json("[32,");
ef76dc59 1451 g_assert(obj == NULL);
7f8fca7c 1452}
7f8fca7c 1453
ef76dc59 1454static void invalid_array_comma(void)
7f8fca7c
PB
1455{
1456 QObject *obj = qobject_from_json("[32,}");
ef76dc59 1457 g_assert(obj == NULL);
7f8fca7c 1458}
7f8fca7c 1459
ef76dc59 1460static void unterminated_dict(void)
7f8fca7c
PB
1461{
1462 QObject *obj = qobject_from_json("{'abc':32");
ef76dc59 1463 g_assert(obj == NULL);
7f8fca7c 1464}
7f8fca7c 1465
ef76dc59 1466static void unterminated_dict_comma(void)
7f8fca7c
PB
1467{
1468 QObject *obj = qobject_from_json("{'abc':32,");
ef76dc59 1469 g_assert(obj == NULL);
7f8fca7c 1470}
7f8fca7c 1471
ef76dc59 1472static void invalid_dict_comma(void)
7f8fca7c
PB
1473{
1474 QObject *obj = qobject_from_json("{'abc':32,}");
ef76dc59 1475 g_assert(obj == NULL);
7f8fca7c 1476}
7f8fca7c 1477
ef76dc59 1478static void unterminated_literal(void)
7f8fca7c
PB
1479{
1480 QObject *obj = qobject_from_json("nul");
ef76dc59 1481 g_assert(obj == NULL);
7f8fca7c 1482}
7f8fca7c 1483
ef76dc59 1484int main(int argc, char **argv)
422c46a8 1485{
ef76dc59
AL
1486 g_test_init(&argc, &argv, NULL);
1487
1488 g_test_add_func("/literals/string/simple", simple_string);
1489 g_test_add_func("/literals/string/escaped", escaped_string);
3960c41f 1490 g_test_add_func("/literals/string/utf8", utf8_string);
ef76dc59
AL
1491 g_test_add_func("/literals/string/single_quote", single_quote_string);
1492 g_test_add_func("/literals/string/vararg", vararg_string);
1493
1494 g_test_add_func("/literals/number/simple", simple_number);
1495 g_test_add_func("/literals/number/float", float_number);
1496 g_test_add_func("/literals/number/vararg", vararg_number);
1497
1498 g_test_add_func("/literals/keyword", keyword_literal);
1499
1500 g_test_add_func("/dicts/simple_dict", simple_dict);
7109edfe 1501 g_test_add_func("/dicts/large_dict", large_dict);
ef76dc59
AL
1502 g_test_add_func("/lists/simple_list", simple_list);
1503
1504 g_test_add_func("/whitespace/simple_whitespace", simple_whitespace);
1505
1506 g_test_add_func("/varargs/simple_varargs", simple_varargs);
1507
1508 g_test_add_func("/errors/empty_input", empty_input);
1509 g_test_add_func("/errors/unterminated/string", unterminated_string);
1510 g_test_add_func("/errors/unterminated/escape", unterminated_escape);
1511 g_test_add_func("/errors/unterminated/sq_string", unterminated_sq_string);
1512 g_test_add_func("/errors/unterminated/array", unterminated_array);
1513 g_test_add_func("/errors/unterminated/array_comma", unterminated_array_comma);
1514 g_test_add_func("/errors/unterminated/dict", unterminated_dict);
1515 g_test_add_func("/errors/unterminated/dict_comma", unterminated_dict_comma);
1516 g_test_add_func("/errors/invalid_array_comma", invalid_array_comma);
ef76dc59
AL
1517 g_test_add_func("/errors/invalid_dict_comma", invalid_dict_comma);
1518 g_test_add_func("/errors/unterminated/literal", unterminated_literal);
7f8fca7c 1519
ef76dc59 1520 return g_test_run();
422c46a8 1521}