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