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