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