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