]>
Commit | Line | Data |
---|---|---|
2d7799f2 PB |
1 | /* |
2 | * String Input Visitor unit-tests. | |
3 | * | |
4 | * Copyright (C) 2012 Red Hat Inc. | |
5 | * | |
6 | * Authors: | |
b3db211f | 7 | * Paolo Bonzini <pbonzini@redhat.com> (based on test-qobject-input-visitor) |
2d7799f2 PB |
8 | * |
9 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
10 | * See the COPYING file in the top-level directory. | |
11 | */ | |
12 | ||
681c28a3 | 13 | #include "qemu/osdep.h" |
2d7799f2 | 14 | |
79ee7df8 | 15 | #include "qemu-common.h" |
da34e65c | 16 | #include "qapi/error.h" |
2d7799f2 | 17 | #include "qapi/string-input-visitor.h" |
2d7799f2 | 18 | #include "test-qapi-visit.h" |
2d7799f2 PB |
19 | |
20 | typedef struct TestInputVisitorData { | |
7a0525c7 | 21 | Visitor *v; |
2d7799f2 PB |
22 | } TestInputVisitorData; |
23 | ||
24 | static void visitor_input_teardown(TestInputVisitorData *data, | |
25 | const void *unused) | |
26 | { | |
7a0525c7 EB |
27 | if (data->v) { |
28 | visit_free(data->v); | |
29 | data->v = NULL; | |
2d7799f2 PB |
30 | } |
31 | } | |
32 | ||
33 | /* This is provided instead of a test setup function so that the JSON | |
34 | string used by the tests are kept in the test functions (and not | |
35 | int main()) */ | |
36 | static | |
37 | Visitor *visitor_input_test_init(TestInputVisitorData *data, | |
38 | const char *string) | |
39 | { | |
0f721d16 MA |
40 | visitor_input_teardown(data, NULL); |
41 | ||
7a0525c7 EB |
42 | data->v = string_input_visitor_new(string); |
43 | g_assert(data->v); | |
44 | return data->v; | |
2d7799f2 PB |
45 | } |
46 | ||
47 | static void test_visitor_in_int(TestInputVisitorData *data, | |
48 | const void *unused) | |
49 | { | |
50 | int64_t res = 0, value = -42; | |
e940f543 | 51 | Error *err = NULL; |
2d7799f2 PB |
52 | Visitor *v; |
53 | ||
54 | v = visitor_input_test_init(data, "-42"); | |
55 | ||
d8da9e71 | 56 | visit_type_int(v, NULL, &res, &error_abort); |
2d7799f2 | 57 | g_assert_cmpint(res, ==, value); |
73374683 | 58 | |
73374683 MA |
59 | v = visitor_input_test_init(data, "not an int"); |
60 | ||
61 | visit_type_int(v, NULL, &res, &err); | |
62 | error_free_or_abort(&err); | |
d2788227 MA |
63 | |
64 | v = visitor_input_test_init(data, ""); | |
65 | ||
66 | visit_type_int(v, NULL, &res, &err); | |
67 | error_free_or_abort(&err); | |
2d7799f2 PB |
68 | } |
69 | ||
3d089cea MA |
70 | static void check_ilist(Visitor *v, int64_t *expected, size_t n) |
71 | { | |
72 | int64List *res = NULL; | |
73 | int64List *tail; | |
74 | int i; | |
75 | ||
76 | visit_type_int64List(v, NULL, &res, &error_abort); | |
77 | tail = res; | |
78 | for (i = 0; i < n; i++) { | |
79 | g_assert(tail); | |
80 | g_assert_cmpint(tail->value, ==, expected[i]); | |
81 | tail = tail->next; | |
82 | } | |
83 | g_assert(!tail); | |
84 | ||
85 | qapi_free_int64List(res); | |
86 | } | |
87 | ||
88 | static void check_ulist(Visitor *v, uint64_t *expected, size_t n) | |
89 | { | |
90 | uint64List *res = NULL; | |
91 | uint64List *tail; | |
92 | int i; | |
93 | ||
3d089cea MA |
94 | visit_type_uint64List(v, NULL, &res, &error_abort); |
95 | tail = res; | |
96 | for (i = 0; i < n; i++) { | |
97 | g_assert(tail); | |
98 | g_assert_cmpuint(tail->value, ==, expected[i]); | |
99 | tail = tail->next; | |
100 | } | |
101 | g_assert(!tail); | |
102 | ||
103 | qapi_free_uint64List(res); | |
104 | } | |
105 | ||
659268ff HT |
106 | static void test_visitor_in_intList(TestInputVisitorData *data, |
107 | const void *unused) | |
108 | { | |
c9fba9de DH |
109 | int64_t expect1[] = { 1, 2, 0, 2, 3, 4, 20, 5, 6, 7, |
110 | 8, 9, 1, 2, 3, 4, 5, 6, 7, 8 }; | |
3d089cea | 111 | int64_t expect2[] = { 32767, -32768, -32767 }; |
c9fba9de | 112 | int64_t expect3[] = { INT64_MIN, INT64_MAX }; |
eac47541 | 113 | int64_t expect4[] = { 1 }; |
345e4010 | 114 | int64_t expect5[] = { INT64_MAX - 2, INT64_MAX - 1, INT64_MAX }; |
73374683 | 115 | Error *err = NULL; |
3d089cea | 116 | int64List *res = NULL; |
659268ff | 117 | Visitor *v; |
a9416dc6 | 118 | int64_t val; |
3d089cea MA |
119 | |
120 | /* Valid lists */ | |
659268ff HT |
121 | |
122 | v = visitor_input_test_init(data, "1,2,0,2-4,20,5-9,1-8"); | |
3d089cea | 123 | check_ilist(v, expect1, ARRAY_SIZE(expect1)); |
659268ff | 124 | |
3d089cea MA |
125 | v = visitor_input_test_init(data, "32767,-32768--32767"); |
126 | check_ilist(v, expect2, ARRAY_SIZE(expect2)); | |
127 | ||
128 | v = visitor_input_test_init(data, | |
129 | "-9223372036854775808,9223372036854775807"); | |
130 | check_ilist(v, expect3, ARRAY_SIZE(expect3)); | |
131 | ||
eac47541 DH |
132 | v = visitor_input_test_init(data, "1-1"); |
133 | check_ilist(v, expect4, ARRAY_SIZE(expect4)); | |
134 | ||
345e4010 DH |
135 | v = visitor_input_test_init(data, |
136 | "9223372036854775805-9223372036854775807"); | |
137 | check_ilist(v, expect5, ARRAY_SIZE(expect5)); | |
138 | ||
eac47541 DH |
139 | /* Value too large */ |
140 | ||
141 | v = visitor_input_test_init(data, "9223372036854775808"); | |
142 | visit_type_int64List(v, NULL, &res, &err); | |
143 | error_free_or_abort(&err); | |
144 | g_assert(!res); | |
145 | ||
146 | /* Value too small */ | |
147 | ||
148 | v = visitor_input_test_init(data, "-9223372036854775809"); | |
149 | visit_type_int64List(v, NULL, &res, &err); | |
150 | error_free_or_abort(&err); | |
151 | g_assert(!res); | |
152 | ||
153 | /* Range not ascending */ | |
154 | ||
155 | v = visitor_input_test_init(data, "3-1"); | |
156 | visit_type_int64List(v, NULL, &res, &err); | |
157 | error_free_or_abort(&err); | |
158 | g_assert(!res); | |
159 | ||
160 | v = visitor_input_test_init(data, "9223372036854775807-0"); | |
161 | visit_type_int64List(v, NULL, &res, &err); | |
162 | error_free_or_abort(&err); | |
163 | g_assert(!res); | |
164 | ||
165 | /* Range too big (65536 is the limit against DOS attacks) */ | |
166 | ||
167 | v = visitor_input_test_init(data, "0-65536"); | |
168 | visit_type_int64List(v, NULL, &res, &err); | |
169 | error_free_or_abort(&err); | |
170 | g_assert(!res); | |
3d089cea | 171 | |
d2788227 | 172 | /* Empty list */ |
3d089cea MA |
173 | |
174 | v = visitor_input_test_init(data, ""); | |
d2788227 MA |
175 | visit_type_int64List(v, NULL, &res, &error_abort); |
176 | g_assert(!res); | |
659268ff | 177 | |
3d089cea | 178 | /* Not a list */ |
73374683 | 179 | |
73374683 MA |
180 | v = visitor_input_test_init(data, "not an int list"); |
181 | ||
3d089cea | 182 | visit_type_int64List(v, NULL, &res, &err); |
74f24cb6 EB |
183 | error_free_or_abort(&err); |
184 | g_assert(!res); | |
9cb8ef36 MA |
185 | |
186 | /* Unvisited list tail */ | |
187 | ||
188 | v = visitor_input_test_init(data, "0,2-3"); | |
189 | ||
13088593 DH |
190 | visit_start_list(v, NULL, NULL, 0, &error_abort); |
191 | visit_type_int64(v, NULL, &val, &error_abort); | |
192 | g_assert_cmpint(val, ==, 0); | |
193 | visit_type_int64(v, NULL, &val, &error_abort); | |
194 | g_assert_cmpint(val, ==, 2); | |
a4a1c70d MA |
195 | |
196 | visit_check_list(v, &err); | |
197 | error_free_or_abort(&err); | |
13088593 | 198 | visit_end_list(v, NULL); |
a9416dc6 MA |
199 | |
200 | /* Visit beyond end of list */ | |
13088593 | 201 | |
a9416dc6 MA |
202 | v = visitor_input_test_init(data, "0"); |
203 | ||
13088593 DH |
204 | visit_start_list(v, NULL, NULL, 0, &error_abort); |
205 | visit_type_int64(v, NULL, &val, &err); | |
206 | g_assert_cmpint(val, ==, 0); | |
a9416dc6 | 207 | visit_type_int64(v, NULL, &val, &err); |
c9fba9de | 208 | error_free_or_abort(&err); |
a9416dc6 | 209 | |
13088593 DH |
210 | visit_check_list(v, &error_abort); |
211 | visit_end_list(v, NULL); | |
659268ff HT |
212 | } |
213 | ||
cc871b1c DH |
214 | static void test_visitor_in_uintList(TestInputVisitorData *data, |
215 | const void *unused) | |
216 | { | |
217 | uint64_t expect1[] = { 1, 2, 0, 2, 3, 4, 20, 5, 6, 7, | |
218 | 8, 9, 1, 2, 3, 4, 5, 6, 7, 8 }; | |
219 | uint64_t expect2[] = { 32767, -32768, -32767 }; | |
220 | uint64_t expect3[] = { INT64_MIN, INT64_MAX }; | |
221 | uint64_t expect4[] = { 1 }; | |
222 | uint64_t expect5[] = { UINT64_MAX }; | |
345e4010 | 223 | uint64_t expect6[] = { UINT64_MAX - 2, UINT64_MAX - 1, UINT64_MAX }; |
cc871b1c DH |
224 | Error *err = NULL; |
225 | uint64List *res = NULL; | |
226 | Visitor *v; | |
227 | uint64_t val; | |
228 | ||
229 | /* Valid lists */ | |
230 | ||
231 | v = visitor_input_test_init(data, "1,2,0,2-4,20,5-9,1-8"); | |
232 | check_ulist(v, expect1, ARRAY_SIZE(expect1)); | |
233 | ||
234 | v = visitor_input_test_init(data, "32767,-32768--32767"); | |
235 | check_ulist(v, expect2, ARRAY_SIZE(expect2)); | |
236 | ||
237 | v = visitor_input_test_init(data, | |
238 | "-9223372036854775808,9223372036854775807"); | |
239 | check_ulist(v, expect3, ARRAY_SIZE(expect3)); | |
240 | ||
241 | v = visitor_input_test_init(data, "1-1"); | |
242 | check_ulist(v, expect4, ARRAY_SIZE(expect4)); | |
243 | ||
244 | v = visitor_input_test_init(data, "18446744073709551615"); | |
245 | check_ulist(v, expect5, ARRAY_SIZE(expect5)); | |
246 | ||
345e4010 DH |
247 | v = visitor_input_test_init(data, |
248 | "18446744073709551613-18446744073709551615"); | |
249 | check_ulist(v, expect6, ARRAY_SIZE(expect6)); | |
250 | ||
cc871b1c DH |
251 | /* Value too large */ |
252 | ||
253 | v = visitor_input_test_init(data, "18446744073709551616"); | |
254 | visit_type_uint64List(v, NULL, &res, &err); | |
255 | error_free_or_abort(&err); | |
256 | g_assert(!res); | |
257 | ||
258 | /* Value too small */ | |
259 | ||
260 | v = visitor_input_test_init(data, "-18446744073709551616"); | |
261 | visit_type_uint64List(v, NULL, &res, &err); | |
262 | error_free_or_abort(&err); | |
263 | g_assert(!res); | |
264 | ||
265 | /* Range not ascending */ | |
266 | ||
267 | v = visitor_input_test_init(data, "3-1"); | |
268 | visit_type_uint64List(v, NULL, &res, &err); | |
269 | error_free_or_abort(&err); | |
270 | g_assert(!res); | |
271 | ||
272 | v = visitor_input_test_init(data, "18446744073709551615-0"); | |
273 | visit_type_uint64List(v, NULL, &res, &err); | |
274 | error_free_or_abort(&err); | |
275 | g_assert(!res); | |
276 | ||
277 | /* Range too big (65536 is the limit against DOS attacks) */ | |
278 | ||
279 | v = visitor_input_test_init(data, "0-65536"); | |
280 | visit_type_uint64List(v, NULL, &res, &err); | |
281 | error_free_or_abort(&err); | |
282 | g_assert(!res); | |
283 | ||
284 | /* Empty list */ | |
285 | ||
286 | v = visitor_input_test_init(data, ""); | |
287 | visit_type_uint64List(v, NULL, &res, &error_abort); | |
288 | g_assert(!res); | |
289 | ||
290 | /* Not a list */ | |
291 | ||
292 | v = visitor_input_test_init(data, "not an uint list"); | |
293 | ||
294 | visit_type_uint64List(v, NULL, &res, &err); | |
295 | error_free_or_abort(&err); | |
296 | g_assert(!res); | |
297 | ||
298 | /* Unvisited list tail */ | |
299 | ||
300 | v = visitor_input_test_init(data, "0,2-3"); | |
301 | ||
302 | visit_start_list(v, NULL, NULL, 0, &error_abort); | |
303 | visit_type_uint64(v, NULL, &val, &error_abort); | |
304 | g_assert_cmpuint(val, ==, 0); | |
305 | visit_type_uint64(v, NULL, &val, &error_abort); | |
306 | g_assert_cmpuint(val, ==, 2); | |
307 | ||
308 | visit_check_list(v, &err); | |
309 | error_free_or_abort(&err); | |
310 | visit_end_list(v, NULL); | |
311 | ||
312 | /* Visit beyond end of list */ | |
313 | ||
314 | v = visitor_input_test_init(data, "0"); | |
315 | ||
316 | visit_start_list(v, NULL, NULL, 0, &error_abort); | |
317 | visit_type_uint64(v, NULL, &val, &err); | |
318 | g_assert_cmpuint(val, ==, 0); | |
319 | visit_type_uint64(v, NULL, &val, &err); | |
320 | error_free_or_abort(&err); | |
321 | ||
322 | visit_check_list(v, &error_abort); | |
323 | visit_end_list(v, NULL); | |
324 | } | |
325 | ||
2d7799f2 PB |
326 | static void test_visitor_in_bool(TestInputVisitorData *data, |
327 | const void *unused) | |
328 | { | |
2d7799f2 PB |
329 | bool res = false; |
330 | Visitor *v; | |
331 | ||
332 | v = visitor_input_test_init(data, "true"); | |
333 | ||
d8da9e71 | 334 | visit_type_bool(v, NULL, &res, &error_abort); |
2d7799f2 | 335 | g_assert_cmpint(res, ==, true); |
2d7799f2 PB |
336 | |
337 | v = visitor_input_test_init(data, "yes"); | |
338 | ||
d8da9e71 | 339 | visit_type_bool(v, NULL, &res, &error_abort); |
2d7799f2 | 340 | g_assert_cmpint(res, ==, true); |
2d7799f2 PB |
341 | |
342 | v = visitor_input_test_init(data, "on"); | |
343 | ||
d8da9e71 | 344 | visit_type_bool(v, NULL, &res, &error_abort); |
2d7799f2 | 345 | g_assert_cmpint(res, ==, true); |
2d7799f2 PB |
346 | |
347 | v = visitor_input_test_init(data, "false"); | |
348 | ||
d8da9e71 | 349 | visit_type_bool(v, NULL, &res, &error_abort); |
2d7799f2 | 350 | g_assert_cmpint(res, ==, false); |
2d7799f2 PB |
351 | |
352 | v = visitor_input_test_init(data, "no"); | |
353 | ||
d8da9e71 | 354 | visit_type_bool(v, NULL, &res, &error_abort); |
2d7799f2 | 355 | g_assert_cmpint(res, ==, false); |
2d7799f2 PB |
356 | |
357 | v = visitor_input_test_init(data, "off"); | |
358 | ||
d8da9e71 | 359 | visit_type_bool(v, NULL, &res, &error_abort); |
2d7799f2 PB |
360 | g_assert_cmpint(res, ==, false); |
361 | } | |
362 | ||
363 | static void test_visitor_in_number(TestInputVisitorData *data, | |
364 | const void *unused) | |
365 | { | |
366 | double res = 0, value = 3.14; | |
e940f543 | 367 | Error *err = NULL; |
2d7799f2 PB |
368 | Visitor *v; |
369 | ||
370 | v = visitor_input_test_init(data, "3.14"); | |
371 | ||
d8da9e71 | 372 | visit_type_number(v, NULL, &res, &error_abort); |
2d7799f2 | 373 | g_assert_cmpfloat(res, ==, value); |
4b69d4c3 DH |
374 | |
375 | /* NaN and infinity has to be rejected */ | |
376 | ||
377 | v = visitor_input_test_init(data, "NaN"); | |
378 | ||
379 | visit_type_number(v, NULL, &res, &err); | |
380 | error_free_or_abort(&err); | |
381 | ||
382 | v = visitor_input_test_init(data, "inf"); | |
383 | ||
384 | visit_type_number(v, NULL, &res, &err); | |
385 | error_free_or_abort(&err); | |
386 | ||
2d7799f2 PB |
387 | } |
388 | ||
389 | static void test_visitor_in_string(TestInputVisitorData *data, | |
390 | const void *unused) | |
391 | { | |
392 | char *res = NULL, *value = (char *) "Q E M U"; | |
2d7799f2 PB |
393 | Visitor *v; |
394 | ||
395 | v = visitor_input_test_init(data, value); | |
396 | ||
d8da9e71 | 397 | visit_type_str(v, NULL, &res, &error_abort); |
2d7799f2 PB |
398 | g_assert_cmpstr(res, ==, value); |
399 | ||
400 | g_free(res); | |
401 | } | |
402 | ||
403 | static void test_visitor_in_enum(TestInputVisitorData *data, | |
404 | const void *unused) | |
405 | { | |
2d7799f2 PB |
406 | Visitor *v; |
407 | EnumOne i; | |
408 | ||
1c236ba5 | 409 | for (i = 0; i < ENUM_ONE__MAX; i++) { |
2d7799f2 PB |
410 | EnumOne res = -1; |
411 | ||
977c736f | 412 | v = visitor_input_test_init(data, EnumOne_str(i)); |
2d7799f2 | 413 | |
d8da9e71 | 414 | visit_type_EnumOne(v, NULL, &res, &error_abort); |
2d7799f2 | 415 | g_assert_cmpint(i, ==, res); |
2d7799f2 | 416 | } |
2d7799f2 PB |
417 | } |
418 | ||
3f0f31a0 BS |
419 | /* Try to crash the visitors */ |
420 | static void test_visitor_in_fuzz(TestInputVisitorData *data, | |
421 | const void *unused) | |
422 | { | |
423 | int64_t ires; | |
659268ff | 424 | intList *ilres; |
3f0f31a0 BS |
425 | bool bres; |
426 | double nres; | |
427 | char *sres; | |
428 | EnumOne eres; | |
3f0f31a0 BS |
429 | Visitor *v; |
430 | unsigned int i; | |
431 | char buf[10000]; | |
432 | ||
433 | for (i = 0; i < 100; i++) { | |
f673174e | 434 | unsigned int j, k; |
3f0f31a0 BS |
435 | |
436 | j = g_test_rand_int_range(0, sizeof(buf) - 1); | |
437 | ||
438 | buf[j] = '\0'; | |
439 | ||
f673174e AS |
440 | for (k = 0; k != j; k++) { |
441 | buf[k] = (char)g_test_rand_int_range(0, 256); | |
3f0f31a0 BS |
442 | } |
443 | ||
444 | v = visitor_input_test_init(data, buf); | |
51e72bc1 | 445 | visit_type_int(v, NULL, &ires, NULL); |
3f0f31a0 | 446 | |
659268ff | 447 | v = visitor_input_test_init(data, buf); |
51e72bc1 | 448 | visit_type_intList(v, NULL, &ilres, NULL); |
bd794065 | 449 | qapi_free_intList(ilres); |
659268ff | 450 | |
3f0f31a0 | 451 | v = visitor_input_test_init(data, buf); |
51e72bc1 | 452 | visit_type_bool(v, NULL, &bres, NULL); |
3f0f31a0 BS |
453 | |
454 | v = visitor_input_test_init(data, buf); | |
51e72bc1 | 455 | visit_type_number(v, NULL, &nres, NULL); |
3f0f31a0 BS |
456 | |
457 | v = visitor_input_test_init(data, buf); | |
01845438 | 458 | sres = NULL; |
51e72bc1 | 459 | visit_type_str(v, NULL, &sres, NULL); |
3f0f31a0 BS |
460 | g_free(sres); |
461 | ||
462 | v = visitor_input_test_init(data, buf); | |
51e72bc1 | 463 | visit_type_EnumOne(v, NULL, &eres, NULL); |
3f0f31a0 BS |
464 | } |
465 | } | |
466 | ||
2d7799f2 PB |
467 | static void input_visitor_test_add(const char *testpath, |
468 | TestInputVisitorData *data, | |
469 | void (*test_func)(TestInputVisitorData *data, const void *user_data)) | |
470 | { | |
471 | g_test_add(testpath, TestInputVisitorData, data, NULL, test_func, | |
472 | visitor_input_teardown); | |
473 | } | |
474 | ||
475 | int main(int argc, char **argv) | |
476 | { | |
477 | TestInputVisitorData in_visitor_data; | |
478 | ||
479 | g_test_init(&argc, &argv, NULL); | |
480 | ||
481 | input_visitor_test_add("/string-visitor/input/int", | |
482 | &in_visitor_data, test_visitor_in_int); | |
659268ff HT |
483 | input_visitor_test_add("/string-visitor/input/intList", |
484 | &in_visitor_data, test_visitor_in_intList); | |
cc871b1c DH |
485 | input_visitor_test_add("/string-visitor/input/uintList", |
486 | &in_visitor_data, test_visitor_in_uintList); | |
2d7799f2 PB |
487 | input_visitor_test_add("/string-visitor/input/bool", |
488 | &in_visitor_data, test_visitor_in_bool); | |
489 | input_visitor_test_add("/string-visitor/input/number", | |
490 | &in_visitor_data, test_visitor_in_number); | |
491 | input_visitor_test_add("/string-visitor/input/string", | |
492 | &in_visitor_data, test_visitor_in_string); | |
493 | input_visitor_test_add("/string-visitor/input/enum", | |
494 | &in_visitor_data, test_visitor_in_enum); | |
3f0f31a0 BS |
495 | input_visitor_test_add("/string-visitor/input/fuzz", |
496 | &in_visitor_data, test_visitor_in_fuzz); | |
2d7799f2 PB |
497 | |
498 | g_test_run(); | |
499 | ||
500 | return 0; | |
501 | } |