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