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