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