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