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