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