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