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