1 /*
2  * Unit-tests for visitor-based serialization
3  *
4  * Copyright (C) 2014-2015 Red Hat, Inc.
5  * Copyright IBM, Corp. 2012
6  *
7  * Authors:
8  *  Michael Roth <mdroth@linux.vnet.ibm.com>
9  *
10  * This work is licensed under the terms of the GNU GPL, version 2 or later.
11  * See the COPYING file in the top-level directory.
12  */
13 
14 #include "qemu/osdep.h"
15 #include <float.h>
16 
17 #include "qemu-common.h"
18 #include "test-qapi-visit.h"
19 #include "qapi/error.h"
20 #include "qapi/qmp/qjson.h"
21 #include "qapi/qmp/qstring.h"
22 #include "qapi/qobject-input-visitor.h"
23 #include "qapi/qobject-output-visitor.h"
24 #include "qapi/string-input-visitor.h"
25 #include "qapi/string-output-visitor.h"
26 #include "qapi/dealloc-visitor.h"
27 
28 enum PrimitiveTypeKind {
29     PTYPE_STRING = 0,
30     PTYPE_BOOLEAN,
31     PTYPE_NUMBER,
32     PTYPE_INTEGER,
33     PTYPE_U8,
34     PTYPE_U16,
35     PTYPE_U32,
36     PTYPE_U64,
37     PTYPE_S8,
38     PTYPE_S16,
39     PTYPE_S32,
40     PTYPE_S64,
41     PTYPE_EOL,
42 };
43 
44 typedef struct PrimitiveType {
45     union {
46         const char *string;
47         bool boolean;
48         double number;
49         int64_t integer;
50         uint8_t u8;
51         uint16_t u16;
52         uint32_t u32;
53         uint64_t u64;
54         int8_t s8;
55         int16_t s16;
56         int32_t s32;
57         int64_t s64;
58     } value;
59     enum PrimitiveTypeKind type;
60     const char *description;
61 } PrimitiveType;
62 
63 typedef struct PrimitiveList {
64     union {
65         strList *strings;
66         boolList *booleans;
67         numberList *numbers;
68         intList *integers;
69         int8List *s8_integers;
70         int16List *s16_integers;
71         int32List *s32_integers;
72         int64List *s64_integers;
73         uint8List *u8_integers;
74         uint16List *u16_integers;
75         uint32List *u32_integers;
76         uint64List *u64_integers;
77     } value;
78     enum PrimitiveTypeKind type;
79     const char *description;
80 } PrimitiveList;
81 
82 /* test helpers */
83 
84 typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp);
85 
86 static void dealloc_helper(void *native_in, VisitorFunc visit, Error **errp)
87 {
88     Visitor *v = qapi_dealloc_visitor_new();
89 
90     visit(v, &native_in, errp);
91 
92     visit_free(v);
93 }
94 
95 static void visit_primitive_type(Visitor *v, void **native, Error **errp)
96 {
97     PrimitiveType *pt = *native;
98     switch(pt->type) {
99     case PTYPE_STRING:
100         visit_type_str(v, NULL, (char **)&pt->value.string, errp);
101         break;
102     case PTYPE_BOOLEAN:
103         visit_type_bool(v, NULL, &pt->value.boolean, errp);
104         break;
105     case PTYPE_NUMBER:
106         visit_type_number(v, NULL, &pt->value.number, errp);
107         break;
108     case PTYPE_INTEGER:
109         visit_type_int(v, NULL, &pt->value.integer, errp);
110         break;
111     case PTYPE_U8:
112         visit_type_uint8(v, NULL, &pt->value.u8, errp);
113         break;
114     case PTYPE_U16:
115         visit_type_uint16(v, NULL, &pt->value.u16, errp);
116         break;
117     case PTYPE_U32:
118         visit_type_uint32(v, NULL, &pt->value.u32, errp);
119         break;
120     case PTYPE_U64:
121         visit_type_uint64(v, NULL, &pt->value.u64, errp);
122         break;
123     case PTYPE_S8:
124         visit_type_int8(v, NULL, &pt->value.s8, errp);
125         break;
126     case PTYPE_S16:
127         visit_type_int16(v, NULL, &pt->value.s16, errp);
128         break;
129     case PTYPE_S32:
130         visit_type_int32(v, NULL, &pt->value.s32, errp);
131         break;
132     case PTYPE_S64:
133         visit_type_int64(v, NULL, &pt->value.s64, errp);
134         break;
135     case PTYPE_EOL:
136         g_assert_not_reached();
137     }
138 }
139 
140 static void visit_primitive_list(Visitor *v, void **native, Error **errp)
141 {
142     PrimitiveList *pl = *native;
143     switch (pl->type) {
144     case PTYPE_STRING:
145         visit_type_strList(v, NULL, &pl->value.strings, errp);
146         break;
147     case PTYPE_BOOLEAN:
148         visit_type_boolList(v, NULL, &pl->value.booleans, errp);
149         break;
150     case PTYPE_NUMBER:
151         visit_type_numberList(v, NULL, &pl->value.numbers, errp);
152         break;
153     case PTYPE_INTEGER:
154         visit_type_intList(v, NULL, &pl->value.integers, errp);
155         break;
156     case PTYPE_S8:
157         visit_type_int8List(v, NULL, &pl->value.s8_integers, errp);
158         break;
159     case PTYPE_S16:
160         visit_type_int16List(v, NULL, &pl->value.s16_integers, errp);
161         break;
162     case PTYPE_S32:
163         visit_type_int32List(v, NULL, &pl->value.s32_integers, errp);
164         break;
165     case PTYPE_S64:
166         visit_type_int64List(v, NULL, &pl->value.s64_integers, errp);
167         break;
168     case PTYPE_U8:
169         visit_type_uint8List(v, NULL, &pl->value.u8_integers, errp);
170         break;
171     case PTYPE_U16:
172         visit_type_uint16List(v, NULL, &pl->value.u16_integers, errp);
173         break;
174     case PTYPE_U32:
175         visit_type_uint32List(v, NULL, &pl->value.u32_integers, errp);
176         break;
177     case PTYPE_U64:
178         visit_type_uint64List(v, NULL, &pl->value.u64_integers, errp);
179         break;
180     default:
181         g_assert_not_reached();
182     }
183 }
184 
185 
186 static TestStruct *struct_create(void)
187 {
188     TestStruct *ts = g_malloc0(sizeof(*ts));
189     ts->integer = -42;
190     ts->boolean = true;
191     ts->string = strdup("test string");
192     return ts;
193 }
194 
195 static void struct_compare(TestStruct *ts1, TestStruct *ts2)
196 {
197     g_assert(ts1);
198     g_assert(ts2);
199     g_assert_cmpint(ts1->integer, ==, ts2->integer);
200     g_assert(ts1->boolean == ts2->boolean);
201     g_assert_cmpstr(ts1->string, ==, ts2->string);
202 }
203 
204 static void struct_cleanup(TestStruct *ts)
205 {
206     g_free(ts->string);
207     g_free(ts);
208 }
209 
210 static void visit_struct(Visitor *v, void **native, Error **errp)
211 {
212     visit_type_TestStruct(v, NULL, (TestStruct **)native, errp);
213 }
214 
215 static UserDefTwo *nested_struct_create(void)
216 {
217     UserDefTwo *udnp = g_malloc0(sizeof(*udnp));
218     udnp->string0 = strdup("test_string0");
219     udnp->dict1 = g_malloc0(sizeof(*udnp->dict1));
220     udnp->dict1->string1 = strdup("test_string1");
221     udnp->dict1->dict2 = g_malloc0(sizeof(*udnp->dict1->dict2));
222     udnp->dict1->dict2->userdef = g_new0(UserDefOne, 1);
223     udnp->dict1->dict2->userdef->integer = 42;
224     udnp->dict1->dict2->userdef->string = strdup("test_string");
225     udnp->dict1->dict2->string = strdup("test_string2");
226     udnp->dict1->dict3 = g_malloc0(sizeof(*udnp->dict1->dict3));
227     udnp->dict1->has_dict3 = true;
228     udnp->dict1->dict3->userdef = g_new0(UserDefOne, 1);
229     udnp->dict1->dict3->userdef->integer = 43;
230     udnp->dict1->dict3->userdef->string = strdup("test_string");
231     udnp->dict1->dict3->string = strdup("test_string3");
232     return udnp;
233 }
234 
235 static void nested_struct_compare(UserDefTwo *udnp1, UserDefTwo *udnp2)
236 {
237     g_assert(udnp1);
238     g_assert(udnp2);
239     g_assert_cmpstr(udnp1->string0, ==, udnp2->string0);
240     g_assert_cmpstr(udnp1->dict1->string1, ==, udnp2->dict1->string1);
241     g_assert_cmpint(udnp1->dict1->dict2->userdef->integer, ==,
242                     udnp2->dict1->dict2->userdef->integer);
243     g_assert_cmpstr(udnp1->dict1->dict2->userdef->string, ==,
244                     udnp2->dict1->dict2->userdef->string);
245     g_assert_cmpstr(udnp1->dict1->dict2->string, ==,
246                     udnp2->dict1->dict2->string);
247     g_assert(udnp1->dict1->has_dict3 == udnp2->dict1->has_dict3);
248     g_assert_cmpint(udnp1->dict1->dict3->userdef->integer, ==,
249                     udnp2->dict1->dict3->userdef->integer);
250     g_assert_cmpstr(udnp1->dict1->dict3->userdef->string, ==,
251                     udnp2->dict1->dict3->userdef->string);
252     g_assert_cmpstr(udnp1->dict1->dict3->string, ==,
253                     udnp2->dict1->dict3->string);
254 }
255 
256 static void nested_struct_cleanup(UserDefTwo *udnp)
257 {
258     qapi_free_UserDefTwo(udnp);
259 }
260 
261 static void visit_nested_struct(Visitor *v, void **native, Error **errp)
262 {
263     visit_type_UserDefTwo(v, NULL, (UserDefTwo **)native, errp);
264 }
265 
266 static void visit_nested_struct_list(Visitor *v, void **native, Error **errp)
267 {
268     visit_type_UserDefTwoList(v, NULL, (UserDefTwoList **)native, errp);
269 }
270 
271 /* test cases */
272 
273 typedef enum VisitorCapabilities {
274     VCAP_PRIMITIVES = 1,
275     VCAP_STRUCTURES = 2,
276     VCAP_LISTS = 4,
277     VCAP_PRIMITIVE_LISTS = 8,
278 } VisitorCapabilities;
279 
280 typedef struct SerializeOps {
281     void (*serialize)(void *native_in, void **datap,
282                       VisitorFunc visit, Error **errp);
283     void (*deserialize)(void **native_out, void *datap,
284                             VisitorFunc visit, Error **errp);
285     void (*cleanup)(void *datap);
286     const char *type;
287     VisitorCapabilities caps;
288 } SerializeOps;
289 
290 typedef struct TestArgs {
291     const SerializeOps *ops;
292     void *test_data;
293 } TestArgs;
294 
295 static void test_primitives(gconstpointer opaque)
296 {
297     TestArgs *args = (TestArgs *) opaque;
298     const SerializeOps *ops = args->ops;
299     PrimitiveType *pt = args->test_data;
300     PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy));
301     void *serialize_data;
302 
303     pt_copy->type = pt->type;
304     ops->serialize(pt, &serialize_data, visit_primitive_type, &error_abort);
305     ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type,
306                      &error_abort);
307 
308     g_assert(pt_copy != NULL);
309     switch (pt->type) {
310     case PTYPE_STRING:
311         g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string);
312         g_free((char *)pt_copy->value.string);
313         break;
314     case PTYPE_BOOLEAN:
315         g_assert_cmpint(pt->value.boolean, ==, pt->value.boolean);
316         break;
317     case PTYPE_NUMBER:
318         g_assert_cmpfloat(pt->value.number, ==, pt_copy->value.number);
319         break;
320     case PTYPE_INTEGER:
321         g_assert_cmpint(pt->value.integer, ==, pt_copy->value.integer);
322         break;
323     case PTYPE_U8:
324         g_assert_cmpuint(pt->value.u8, ==, pt_copy->value.u8);
325         break;
326     case PTYPE_U16:
327         g_assert_cmpuint(pt->value.u16, ==, pt_copy->value.u16);
328         break;
329     case PTYPE_U32:
330         g_assert_cmpuint(pt->value.u32, ==, pt_copy->value.u32);
331         break;
332     case PTYPE_U64:
333         g_assert_cmpuint(pt->value.u64, ==, pt_copy->value.u64);
334         break;
335     case PTYPE_S8:
336         g_assert_cmpint(pt->value.s8, ==, pt_copy->value.s8);
337         break;
338     case PTYPE_S16:
339         g_assert_cmpint(pt->value.s16, ==, pt_copy->value.s16);
340         break;
341     case PTYPE_S32:
342         g_assert_cmpint(pt->value.s32, ==, pt_copy->value.s32);
343         break;
344     case PTYPE_S64:
345         g_assert_cmpint(pt->value.s64, ==, pt_copy->value.s64);
346         break;
347     case PTYPE_EOL:
348         g_assert_not_reached();
349     }
350 
351     ops->cleanup(serialize_data);
352     g_free(args);
353     g_free(pt_copy);
354 }
355 
356 static void test_primitive_lists(gconstpointer opaque)
357 {
358     TestArgs *args = (TestArgs *) opaque;
359     const SerializeOps *ops = args->ops;
360     PrimitiveType *pt = args->test_data;
361     PrimitiveList pl = { .value = { NULL } };
362     PrimitiveList pl_copy = { .value = { NULL } };
363     PrimitiveList *pl_copy_ptr = &pl_copy;
364     void *serialize_data;
365     void *cur_head = NULL;
366     int i;
367 
368     pl.type = pl_copy.type = pt->type;
369 
370     /* build up our list of primitive types */
371     for (i = 0; i < 32; i++) {
372         switch (pl.type) {
373         case PTYPE_STRING: {
374             QAPI_LIST_PREPEND(pl.value.strings, g_strdup(pt->value.string));
375             break;
376         }
377         case PTYPE_INTEGER: {
378             QAPI_LIST_PREPEND(pl.value.integers, pt->value.integer);
379             break;
380         }
381         case PTYPE_S8: {
382             QAPI_LIST_PREPEND(pl.value.s8_integers, pt->value.s8);
383             break;
384         }
385         case PTYPE_S16: {
386             QAPI_LIST_PREPEND(pl.value.s16_integers, pt->value.s16);
387             break;
388         }
389         case PTYPE_S32: {
390             QAPI_LIST_PREPEND(pl.value.s32_integers, pt->value.s32);
391             break;
392         }
393         case PTYPE_S64: {
394             QAPI_LIST_PREPEND(pl.value.s64_integers, pt->value.s64);
395             break;
396         }
397         case PTYPE_U8: {
398             QAPI_LIST_PREPEND(pl.value.u8_integers, pt->value.u8);
399             break;
400         }
401         case PTYPE_U16: {
402             QAPI_LIST_PREPEND(pl.value.u16_integers, pt->value.u16);
403             break;
404         }
405         case PTYPE_U32: {
406             QAPI_LIST_PREPEND(pl.value.u32_integers, pt->value.u32);
407             break;
408         }
409         case PTYPE_U64: {
410             QAPI_LIST_PREPEND(pl.value.u64_integers, pt->value.u64);
411             break;
412         }
413         case PTYPE_NUMBER: {
414             QAPI_LIST_PREPEND(pl.value.numbers, pt->value.number);
415             break;
416         }
417         case PTYPE_BOOLEAN: {
418             QAPI_LIST_PREPEND(pl.value.booleans, pt->value.boolean);
419             break;
420         }
421         default:
422             g_assert_not_reached();
423         }
424     }
425 
426     ops->serialize((void **)&pl, &serialize_data, visit_primitive_list,
427                    &error_abort);
428     ops->deserialize((void **)&pl_copy_ptr, serialize_data,
429                      visit_primitive_list, &error_abort);
430 
431     i = 0;
432 
433     /* compare our deserialized list of primitives to the original */
434     do {
435         switch (pl_copy.type) {
436         case PTYPE_STRING: {
437             strList *ptr;
438             if (cur_head) {
439                 ptr = cur_head;
440                 cur_head = ptr->next;
441             } else {
442                 cur_head = ptr = pl_copy.value.strings;
443             }
444             g_assert_cmpstr(pt->value.string, ==, ptr->value);
445             break;
446         }
447         case PTYPE_INTEGER: {
448             intList *ptr;
449             if (cur_head) {
450                 ptr = cur_head;
451                 cur_head = ptr->next;
452             } else {
453                 cur_head = ptr = pl_copy.value.integers;
454             }
455             g_assert_cmpint(pt->value.integer, ==, ptr->value);
456             break;
457         }
458         case PTYPE_S8: {
459             int8List *ptr;
460             if (cur_head) {
461                 ptr = cur_head;
462                 cur_head = ptr->next;
463             } else {
464                 cur_head = ptr = pl_copy.value.s8_integers;
465             }
466             g_assert_cmpint(pt->value.s8, ==, ptr->value);
467             break;
468         }
469         case PTYPE_S16: {
470             int16List *ptr;
471             if (cur_head) {
472                 ptr = cur_head;
473                 cur_head = ptr->next;
474             } else {
475                 cur_head = ptr = pl_copy.value.s16_integers;
476             }
477             g_assert_cmpint(pt->value.s16, ==, ptr->value);
478             break;
479         }
480         case PTYPE_S32: {
481             int32List *ptr;
482             if (cur_head) {
483                 ptr = cur_head;
484                 cur_head = ptr->next;
485             } else {
486                 cur_head = ptr = pl_copy.value.s32_integers;
487             }
488             g_assert_cmpint(pt->value.s32, ==, ptr->value);
489             break;
490         }
491         case PTYPE_S64: {
492             int64List *ptr;
493             if (cur_head) {
494                 ptr = cur_head;
495                 cur_head = ptr->next;
496             } else {
497                 cur_head = ptr = pl_copy.value.s64_integers;
498             }
499             g_assert_cmpint(pt->value.s64, ==, ptr->value);
500             break;
501         }
502         case PTYPE_U8: {
503             uint8List *ptr;
504             if (cur_head) {
505                 ptr = cur_head;
506                 cur_head = ptr->next;
507             } else {
508                 cur_head = ptr = pl_copy.value.u8_integers;
509             }
510             g_assert_cmpint(pt->value.u8, ==, ptr->value);
511             break;
512         }
513         case PTYPE_U16: {
514             uint16List *ptr;
515             if (cur_head) {
516                 ptr = cur_head;
517                 cur_head = ptr->next;
518             } else {
519                 cur_head = ptr = pl_copy.value.u16_integers;
520             }
521             g_assert_cmpint(pt->value.u16, ==, ptr->value);
522             break;
523         }
524         case PTYPE_U32: {
525             uint32List *ptr;
526             if (cur_head) {
527                 ptr = cur_head;
528                 cur_head = ptr->next;
529             } else {
530                 cur_head = ptr = pl_copy.value.u32_integers;
531             }
532             g_assert_cmpint(pt->value.u32, ==, ptr->value);
533             break;
534         }
535         case PTYPE_U64: {
536             uint64List *ptr;
537             if (cur_head) {
538                 ptr = cur_head;
539                 cur_head = ptr->next;
540             } else {
541                 cur_head = ptr = pl_copy.value.u64_integers;
542             }
543             g_assert_cmpint(pt->value.u64, ==, ptr->value);
544             break;
545         }
546         case PTYPE_NUMBER: {
547             numberList *ptr;
548             GString *double_expected = g_string_new("");
549             GString *double_actual = g_string_new("");
550             if (cur_head) {
551                 ptr = cur_head;
552                 cur_head = ptr->next;
553             } else {
554                 cur_head = ptr = pl_copy.value.numbers;
555             }
556             /* we serialize with %f for our reference visitors, so rather than
557              * fuzzy floating math to test "equality", just compare the
558              * formatted values
559              */
560             g_string_printf(double_expected, "%.6f", pt->value.number);
561             g_string_printf(double_actual, "%.6f", ptr->value);
562             g_assert_cmpstr(double_actual->str, ==, double_expected->str);
563             g_string_free(double_expected, true);
564             g_string_free(double_actual, true);
565             break;
566         }
567         case PTYPE_BOOLEAN: {
568             boolList *ptr;
569             if (cur_head) {
570                 ptr = cur_head;
571                 cur_head = ptr->next;
572             } else {
573                 cur_head = ptr = pl_copy.value.booleans;
574             }
575             g_assert_cmpint(!!pt->value.boolean, ==, !!ptr->value);
576             break;
577         }
578         default:
579             g_assert_not_reached();
580         }
581         i++;
582     } while (cur_head);
583 
584     g_assert_cmpint(i, ==, 33);
585 
586     ops->cleanup(serialize_data);
587     dealloc_helper(&pl, visit_primitive_list, &error_abort);
588     dealloc_helper(&pl_copy, visit_primitive_list, &error_abort);
589     g_free(args);
590 }
591 
592 static void test_struct(gconstpointer opaque)
593 {
594     TestArgs *args = (TestArgs *) opaque;
595     const SerializeOps *ops = args->ops;
596     TestStruct *ts = struct_create();
597     TestStruct *ts_copy = NULL;
598     void *serialize_data;
599 
600     ops->serialize(ts, &serialize_data, visit_struct, &error_abort);
601     ops->deserialize((void **)&ts_copy, serialize_data, visit_struct,
602                      &error_abort);
603 
604     struct_compare(ts, ts_copy);
605 
606     struct_cleanup(ts);
607     struct_cleanup(ts_copy);
608 
609     ops->cleanup(serialize_data);
610     g_free(args);
611 }
612 
613 static void test_nested_struct(gconstpointer opaque)
614 {
615     TestArgs *args = (TestArgs *) opaque;
616     const SerializeOps *ops = args->ops;
617     UserDefTwo *udnp = nested_struct_create();
618     UserDefTwo *udnp_copy = NULL;
619     void *serialize_data;
620 
621     ops->serialize(udnp, &serialize_data, visit_nested_struct, &error_abort);
622     ops->deserialize((void **)&udnp_copy, serialize_data, visit_nested_struct,
623                      &error_abort);
624 
625     nested_struct_compare(udnp, udnp_copy);
626 
627     nested_struct_cleanup(udnp);
628     nested_struct_cleanup(udnp_copy);
629 
630     ops->cleanup(serialize_data);
631     g_free(args);
632 }
633 
634 static void test_nested_struct_list(gconstpointer opaque)
635 {
636     TestArgs *args = (TestArgs *) opaque;
637     const SerializeOps *ops = args->ops;
638     UserDefTwoList *listp = NULL, *tmp, *tmp_copy, *listp_copy = NULL;
639     void *serialize_data;
640     int i = 0;
641 
642     for (i = 0; i < 8; i++) {
643         QAPI_LIST_PREPEND(listp, nested_struct_create());
644     }
645 
646     ops->serialize(listp, &serialize_data, visit_nested_struct_list,
647                    &error_abort);
648     ops->deserialize((void **)&listp_copy, serialize_data,
649                      visit_nested_struct_list, &error_abort);
650 
651     tmp = listp;
652     tmp_copy = listp_copy;
653     while (listp_copy) {
654         g_assert(listp);
655         nested_struct_compare(listp->value, listp_copy->value);
656         listp = listp->next;
657         listp_copy = listp_copy->next;
658     }
659 
660     qapi_free_UserDefTwoList(tmp);
661     qapi_free_UserDefTwoList(tmp_copy);
662 
663     ops->cleanup(serialize_data);
664     g_free(args);
665 }
666 
667 static PrimitiveType pt_values[] = {
668     /* string tests */
669     {
670         .description = "string_empty",
671         .type = PTYPE_STRING,
672         .value.string = "",
673     },
674     {
675         .description = "string_whitespace",
676         .type = PTYPE_STRING,
677         .value.string = "a b  c\td",
678     },
679     {
680         .description = "string_newlines",
681         .type = PTYPE_STRING,
682         .value.string = "a\nb\n",
683     },
684     {
685         .description = "string_commas",
686         .type = PTYPE_STRING,
687         .value.string = "a,b, c,d",
688     },
689     {
690         .description = "string_single_quoted",
691         .type = PTYPE_STRING,
692         .value.string = "'a b',cd",
693     },
694     {
695         .description = "string_double_quoted",
696         .type = PTYPE_STRING,
697         .value.string = "\"a b\",cd",
698     },
699     /* boolean tests */
700     {
701         .description = "boolean_true1",
702         .type = PTYPE_BOOLEAN,
703         .value.boolean = true,
704     },
705     {
706         .description = "boolean_true2",
707         .type = PTYPE_BOOLEAN,
708         .value.boolean = 8,
709     },
710     {
711         .description = "boolean_true3",
712         .type = PTYPE_BOOLEAN,
713         .value.boolean = -1,
714     },
715     {
716         .description = "boolean_false1",
717         .type = PTYPE_BOOLEAN,
718         .value.boolean = false,
719     },
720     {
721         .description = "boolean_false2",
722         .type = PTYPE_BOOLEAN,
723         .value.boolean = 0,
724     },
725     /* number tests (double) */
726     {
727         .description = "number_sanity1",
728         .type = PTYPE_NUMBER,
729         .value.number = -1,
730     },
731     {
732         .description = "number_sanity2",
733         .type = PTYPE_NUMBER,
734         .value.number = 3.141593,
735     },
736     {
737         .description = "number_min",
738         .type = PTYPE_NUMBER,
739         .value.number = DBL_MIN,
740     },
741     {
742         .description = "number_max",
743         .type = PTYPE_NUMBER,
744         .value.number = DBL_MAX,
745     },
746     /* integer tests (int64) */
747     {
748         .description = "integer_sanity1",
749         .type = PTYPE_INTEGER,
750         .value.integer = -1,
751     },
752     {
753         .description = "integer_sanity2",
754         .type = PTYPE_INTEGER,
755         .value.integer = INT64_MAX / 2 + 1,
756     },
757     {
758         .description = "integer_min",
759         .type = PTYPE_INTEGER,
760         .value.integer = INT64_MIN,
761     },
762     {
763         .description = "integer_max",
764         .type = PTYPE_INTEGER,
765         .value.integer = INT64_MAX,
766     },
767     /* uint8 tests */
768     {
769         .description = "uint8_sanity1",
770         .type = PTYPE_U8,
771         .value.u8 = 1,
772     },
773     {
774         .description = "uint8_sanity2",
775         .type = PTYPE_U8,
776         .value.u8 = UINT8_MAX / 2 + 1,
777     },
778     {
779         .description = "uint8_min",
780         .type = PTYPE_U8,
781         .value.u8 = 0,
782     },
783     {
784         .description = "uint8_max",
785         .type = PTYPE_U8,
786         .value.u8 = UINT8_MAX,
787     },
788     /* uint16 tests */
789     {
790         .description = "uint16_sanity1",
791         .type = PTYPE_U16,
792         .value.u16 = 1,
793     },
794     {
795         .description = "uint16_sanity2",
796         .type = PTYPE_U16,
797         .value.u16 = UINT16_MAX / 2 + 1,
798     },
799     {
800         .description = "uint16_min",
801         .type = PTYPE_U16,
802         .value.u16 = 0,
803     },
804     {
805         .description = "uint16_max",
806         .type = PTYPE_U16,
807         .value.u16 = UINT16_MAX,
808     },
809     /* uint32 tests */
810     {
811         .description = "uint32_sanity1",
812         .type = PTYPE_U32,
813         .value.u32 = 1,
814     },
815     {
816         .description = "uint32_sanity2",
817         .type = PTYPE_U32,
818         .value.u32 = UINT32_MAX / 2 + 1,
819     },
820     {
821         .description = "uint32_min",
822         .type = PTYPE_U32,
823         .value.u32 = 0,
824     },
825     {
826         .description = "uint32_max",
827         .type = PTYPE_U32,
828         .value.u32 = UINT32_MAX,
829     },
830     /* uint64 tests */
831     {
832         .description = "uint64_sanity1",
833         .type = PTYPE_U64,
834         .value.u64 = 1,
835     },
836     {
837         .description = "uint64_sanity2",
838         .type = PTYPE_U64,
839         .value.u64 = UINT64_MAX / 2 + 1,
840     },
841     {
842         .description = "uint64_min",
843         .type = PTYPE_U64,
844         .value.u64 = 0,
845     },
846     {
847         .description = "uint64_max",
848         .type = PTYPE_U64,
849         .value.u64 = UINT64_MAX,
850     },
851     /* int8 tests */
852     {
853         .description = "int8_sanity1",
854         .type = PTYPE_S8,
855         .value.s8 = -1,
856     },
857     {
858         .description = "int8_sanity2",
859         .type = PTYPE_S8,
860         .value.s8 = INT8_MAX / 2 + 1,
861     },
862     {
863         .description = "int8_min",
864         .type = PTYPE_S8,
865         .value.s8 = INT8_MIN,
866     },
867     {
868         .description = "int8_max",
869         .type = PTYPE_S8,
870         .value.s8 = INT8_MAX,
871     },
872     /* int16 tests */
873     {
874         .description = "int16_sanity1",
875         .type = PTYPE_S16,
876         .value.s16 = -1,
877     },
878     {
879         .description = "int16_sanity2",
880         .type = PTYPE_S16,
881         .value.s16 = INT16_MAX / 2 + 1,
882     },
883     {
884         .description = "int16_min",
885         .type = PTYPE_S16,
886         .value.s16 = INT16_MIN,
887     },
888     {
889         .description = "int16_max",
890         .type = PTYPE_S16,
891         .value.s16 = INT16_MAX,
892     },
893     /* int32 tests */
894     {
895         .description = "int32_sanity1",
896         .type = PTYPE_S32,
897         .value.s32 = -1,
898     },
899     {
900         .description = "int32_sanity2",
901         .type = PTYPE_S32,
902         .value.s32 = INT32_MAX / 2 + 1,
903     },
904     {
905         .description = "int32_min",
906         .type = PTYPE_S32,
907         .value.s32 = INT32_MIN,
908     },
909     {
910         .description = "int32_max",
911         .type = PTYPE_S32,
912         .value.s32 = INT32_MAX,
913     },
914     /* int64 tests */
915     {
916         .description = "int64_sanity1",
917         .type = PTYPE_S64,
918         .value.s64 = -1,
919     },
920     {
921         .description = "int64_sanity2",
922         .type = PTYPE_S64,
923         .value.s64 = INT64_MAX / 2 + 1,
924     },
925     {
926         .description = "int64_min",
927         .type = PTYPE_S64,
928         .value.s64 = INT64_MIN,
929     },
930     {
931         .description = "int64_max",
932         .type = PTYPE_S64,
933         .value.s64 = INT64_MAX,
934     },
935     { .type = PTYPE_EOL }
936 };
937 
938 /* visitor-specific op implementations */
939 
940 typedef struct QmpSerializeData {
941     Visitor *qov;
942     QObject *obj;
943     Visitor *qiv;
944 } QmpSerializeData;
945 
946 static void qmp_serialize(void *native_in, void **datap,
947                           VisitorFunc visit, Error **errp)
948 {
949     QmpSerializeData *d = g_malloc0(sizeof(*d));
950 
951     d->qov = qobject_output_visitor_new(&d->obj);
952     visit(d->qov, &native_in, errp);
953     *datap = d;
954 }
955 
956 static void qmp_deserialize(void **native_out, void *datap,
957                             VisitorFunc visit, Error **errp)
958 {
959     QmpSerializeData *d = datap;
960     GString *output_json;
961     QObject *obj_orig, *obj;
962 
963     visit_complete(d->qov, &d->obj);
964     obj_orig = d->obj;
965     output_json = qobject_to_json(obj_orig);
966     obj = qobject_from_json(output_json->str, &error_abort);
967 
968     g_string_free(output_json, true);
969     d->qiv = qobject_input_visitor_new(obj);
970     qobject_unref(obj_orig);
971     qobject_unref(obj);
972     visit(d->qiv, native_out, errp);
973 }
974 
975 static void qmp_cleanup(void *datap)
976 {
977     QmpSerializeData *d = datap;
978     visit_free(d->qov);
979     visit_free(d->qiv);
980 
981     g_free(d);
982 }
983 
984 typedef struct StringSerializeData {
985     char *string;
986     Visitor *sov;
987     Visitor *siv;
988 } StringSerializeData;
989 
990 static void string_serialize(void *native_in, void **datap,
991                              VisitorFunc visit, Error **errp)
992 {
993     StringSerializeData *d = g_malloc0(sizeof(*d));
994 
995     d->sov = string_output_visitor_new(false, &d->string);
996     visit(d->sov, &native_in, errp);
997     *datap = d;
998 }
999 
1000 static void string_deserialize(void **native_out, void *datap,
1001                                VisitorFunc visit, Error **errp)
1002 {
1003     StringSerializeData *d = datap;
1004 
1005     visit_complete(d->sov, &d->string);
1006     d->siv = string_input_visitor_new(d->string);
1007     visit(d->siv, native_out, errp);
1008 }
1009 
1010 static void string_cleanup(void *datap)
1011 {
1012     StringSerializeData *d = datap;
1013 
1014     visit_free(d->sov);
1015     visit_free(d->siv);
1016     g_free(d->string);
1017     g_free(d);
1018 }
1019 
1020 /* visitor registration, test harness */
1021 
1022 /* note: to function interchangeably as a serialization mechanism your
1023  * visitor test implementation should pass the test cases for all visitor
1024  * capabilities: primitives, structures, and lists
1025  */
1026 static const SerializeOps visitors[] = {
1027     {
1028         .type = "QMP",
1029         .serialize = qmp_serialize,
1030         .deserialize = qmp_deserialize,
1031         .cleanup = qmp_cleanup,
1032         .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS |
1033                 VCAP_PRIMITIVE_LISTS
1034     },
1035     {
1036         .type = "String",
1037         .serialize = string_serialize,
1038         .deserialize = string_deserialize,
1039         .cleanup = string_cleanup,
1040         .caps = VCAP_PRIMITIVES
1041     },
1042     { NULL }
1043 };
1044 
1045 static void add_visitor_type(const SerializeOps *ops)
1046 {
1047     char testname_prefix[32];
1048     char testname[128];
1049     TestArgs *args;
1050     int i = 0;
1051 
1052     sprintf(testname_prefix, "/visitor/serialization/%s", ops->type);
1053 
1054     if (ops->caps & VCAP_PRIMITIVES) {
1055         while (pt_values[i].type != PTYPE_EOL) {
1056             sprintf(testname, "%s/primitives/%s", testname_prefix,
1057                     pt_values[i].description);
1058             args = g_malloc0(sizeof(*args));
1059             args->ops = ops;
1060             args->test_data = &pt_values[i];
1061             g_test_add_data_func(testname, args, test_primitives);
1062             i++;
1063         }
1064     }
1065 
1066     if (ops->caps & VCAP_STRUCTURES) {
1067         sprintf(testname, "%s/struct", testname_prefix);
1068         args = g_malloc0(sizeof(*args));
1069         args->ops = ops;
1070         args->test_data = NULL;
1071         g_test_add_data_func(testname, args, test_struct);
1072 
1073         sprintf(testname, "%s/nested_struct", testname_prefix);
1074         args = g_malloc0(sizeof(*args));
1075         args->ops = ops;
1076         args->test_data = NULL;
1077         g_test_add_data_func(testname, args, test_nested_struct);
1078     }
1079 
1080     if (ops->caps & VCAP_LISTS) {
1081         sprintf(testname, "%s/nested_struct_list", testname_prefix);
1082         args = g_malloc0(sizeof(*args));
1083         args->ops = ops;
1084         args->test_data = NULL;
1085         g_test_add_data_func(testname, args, test_nested_struct_list);
1086     }
1087 
1088     if (ops->caps & VCAP_PRIMITIVE_LISTS) {
1089         i = 0;
1090         while (pt_values[i].type != PTYPE_EOL) {
1091             sprintf(testname, "%s/primitive_list/%s", testname_prefix,
1092                     pt_values[i].description);
1093             args = g_malloc0(sizeof(*args));
1094             args->ops = ops;
1095             args->test_data = &pt_values[i];
1096             g_test_add_data_func(testname, args, test_primitive_lists);
1097             i++;
1098         }
1099     }
1100 }
1101 
1102 int main(int argc, char **argv)
1103 {
1104     int i = 0;
1105 
1106     g_test_init(&argc, &argv, NULL);
1107 
1108     while (visitors[i].type != NULL) {
1109         add_visitor_type(&visitors[i]);
1110         i++;
1111     }
1112 
1113     g_test_run();
1114 
1115     return 0;
1116 }
1117