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