target/arm: Define an IDAU interface
[qemu.git] / tests / test-visitor-serialization.c
blobdd7e51d4f5d0ac8150302c4d7879ad06dfab06ee
1 /*
2 * Unit-tests for visitor-based serialization
4 * Copyright (C) 2014-2015 Red Hat, Inc.
5 * Copyright IBM, Corp. 2012
7 * Authors:
8 * Michael Roth <mdroth@linux.vnet.ibm.com>
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.
14 #include "qemu/osdep.h"
15 #include <float.h>
17 #include "qemu-common.h"
18 #include "test-qapi-visit.h"
19 #include "qapi/error.h"
20 #include "qapi/qmp/qjson.h"
21 #include "qapi/qmp/qstring.h"
22 #include "qapi/qobject-input-visitor.h"
23 #include "qapi/qobject-output-visitor.h"
24 #include "qapi/string-input-visitor.h"
25 #include "qapi/string-output-visitor.h"
26 #include "qapi-visit.h"
27 #include "qapi/dealloc-visitor.h"
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,
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;
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;
84 /* test helpers */
86 typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp);
88 static void dealloc_helper(void *native_in, VisitorFunc visit, Error **errp)
90 Visitor *v = qapi_dealloc_visitor_new();
92 visit(v, &native_in, errp);
94 visit_free(v);
97 static void visit_primitive_type(Visitor *v, void **native, Error **errp)
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();
142 static void visit_primitive_list(Visitor *v, void **native, Error **errp)
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();
188 static TestStruct *struct_create(void)
190 TestStruct *ts = g_malloc0(sizeof(*ts));
191 ts->integer = -42;
192 ts->boolean = true;
193 ts->string = strdup("test string");
194 return ts;
197 static void struct_compare(TestStruct *ts1, TestStruct *ts2)
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);
206 static void struct_cleanup(TestStruct *ts)
208 g_free(ts->string);
209 g_free(ts);
212 static void visit_struct(Visitor *v, void **native, Error **errp)
214 visit_type_TestStruct(v, NULL, (TestStruct **)native, errp);
217 static UserDefTwo *nested_struct_create(void)
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;
237 static void nested_struct_compare(UserDefTwo *udnp1, UserDefTwo *udnp2)
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);
258 static void nested_struct_cleanup(UserDefTwo *udnp)
260 qapi_free_UserDefTwo(udnp);
263 static void visit_nested_struct(Visitor *v, void **native, Error **errp)
265 visit_type_UserDefTwo(v, NULL, (UserDefTwo **)native, errp);
268 static void visit_nested_struct_list(Visitor *v, void **native, Error **errp)
270 visit_type_UserDefTwoList(v, NULL, (UserDefTwoList **)native, errp);
273 /* test cases */
275 typedef enum VisitorCapabilities {
276 VCAP_PRIMITIVES = 1,
277 VCAP_STRUCTURES = 2,
278 VCAP_LISTS = 4,
279 VCAP_PRIMITIVE_LISTS = 8,
280 } VisitorCapabilities;
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;
292 typedef struct TestArgs {
293 const SerializeOps *ops;
294 void *test_data;
295 } TestArgs;
297 static void test_primitives(gconstpointer opaque)
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;
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);
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
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);
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);
332 ops->cleanup(serialize_data);
333 g_free(args);
334 g_free(pt_copy);
337 static void test_primitive_lists(gconstpointer opaque)
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;
349 pl.type = pl_copy.type = pt->type;
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;
363 break;
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;
374 break;
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;
385 break;
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;
396 break;
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;
407 break;
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;
418 break;
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;
429 break;
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;
440 break;
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;
451 break;
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;
462 break;
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;
473 break;
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;
484 break;
486 default:
487 g_assert_not_reached();
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);
496 i = 0;
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;
509 g_assert_cmpstr(pt->value.string, ==, ptr->value);
510 break;
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;
520 g_assert_cmpint(pt->value.integer, ==, ptr->value);
521 break;
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;
531 g_assert_cmpint(pt->value.s8, ==, ptr->value);
532 break;
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;
542 g_assert_cmpint(pt->value.s16, ==, ptr->value);
543 break;
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;
553 g_assert_cmpint(pt->value.s32, ==, ptr->value);
554 break;
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;
564 g_assert_cmpint(pt->value.s64, ==, ptr->value);
565 break;
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;
575 g_assert_cmpint(pt->value.u8, ==, ptr->value);
576 break;
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;
586 g_assert_cmpint(pt->value.u16, ==, ptr->value);
587 break;
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;
597 g_assert_cmpint(pt->value.u32, ==, ptr->value);
598 break;
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;
608 g_assert_cmpint(pt->value.u64, ==, ptr->value);
609 break;
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;
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
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;
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;
640 g_assert_cmpint(!!pt->value.boolean, ==, !!ptr->value);
641 break;
643 default:
644 g_assert_not_reached();
646 i++;
647 } while (cur_head);
649 g_assert_cmpint(i, ==, 33);
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);
657 static void test_struct(gconstpointer opaque)
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;
665 ops->serialize(ts, &serialize_data, visit_struct, &error_abort);
666 ops->deserialize((void **)&ts_copy, serialize_data, visit_struct,
667 &error_abort);
669 struct_compare(ts, ts_copy);
671 struct_cleanup(ts);
672 struct_cleanup(ts_copy);
674 ops->cleanup(serialize_data);
675 g_free(args);
678 static void test_nested_struct(gconstpointer opaque)
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;
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);
690 nested_struct_compare(udnp, udnp_copy);
692 nested_struct_cleanup(udnp);
693 nested_struct_cleanup(udnp_copy);
695 ops->cleanup(serialize_data);
696 g_free(args);
699 static void test_nested_struct_list(gconstpointer opaque)
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;
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;
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);
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;
728 qapi_free_UserDefTwoList(tmp);
729 qapi_free_UserDefTwoList(tmp_copy);
731 ops->cleanup(serialize_data);
732 g_free(args);
735 static PrimitiveType pt_values[] = {
736 /* string tests */
738 .description = "string_empty",
739 .type = PTYPE_STRING,
740 .value.string = "",
743 .description = "string_whitespace",
744 .type = PTYPE_STRING,
745 .value.string = "a b c\td",
748 .description = "string_newlines",
749 .type = PTYPE_STRING,
750 .value.string = "a\nb\n",
753 .description = "string_commas",
754 .type = PTYPE_STRING,
755 .value.string = "a,b, c,d",
758 .description = "string_single_quoted",
759 .type = PTYPE_STRING,
760 .value.string = "'a b',cd",
763 .description = "string_double_quoted",
764 .type = PTYPE_STRING,
765 .value.string = "\"a b\",cd",
767 /* boolean tests */
769 .description = "boolean_true1",
770 .type = PTYPE_BOOLEAN,
771 .value.boolean = true,
774 .description = "boolean_true2",
775 .type = PTYPE_BOOLEAN,
776 .value.boolean = 8,
779 .description = "boolean_true3",
780 .type = PTYPE_BOOLEAN,
781 .value.boolean = -1,
784 .description = "boolean_false1",
785 .type = PTYPE_BOOLEAN,
786 .value.boolean = false,
789 .description = "boolean_false2",
790 .type = PTYPE_BOOLEAN,
791 .value.boolean = 0,
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.
799 .description = "number_sanity1",
800 .type = PTYPE_NUMBER,
801 .value.number = -1,
804 .description = "number_sanity2",
805 .type = PTYPE_NUMBER,
806 .value.number = 3.14159265,
809 .description = "number_min",
810 .type = PTYPE_NUMBER,
811 .value.number = DBL_MIN,
814 .description = "number_max",
815 .type = PTYPE_NUMBER,
816 .value.number = DBL_MAX,
818 /* integer tests (int64) */
820 .description = "integer_sanity1",
821 .type = PTYPE_INTEGER,
822 .value.integer = -1,
825 .description = "integer_sanity2",
826 .type = PTYPE_INTEGER,
827 .value.integer = INT64_MAX / 2 + 1,
830 .description = "integer_min",
831 .type = PTYPE_INTEGER,
832 .value.integer = INT64_MIN,
835 .description = "integer_max",
836 .type = PTYPE_INTEGER,
837 .value.integer = INT64_MAX,
839 /* uint8 tests */
841 .description = "uint8_sanity1",
842 .type = PTYPE_U8,
843 .value.u8 = 1,
846 .description = "uint8_sanity2",
847 .type = PTYPE_U8,
848 .value.u8 = UINT8_MAX / 2 + 1,
851 .description = "uint8_min",
852 .type = PTYPE_U8,
853 .value.u8 = 0,
856 .description = "uint8_max",
857 .type = PTYPE_U8,
858 .value.u8 = UINT8_MAX,
860 /* uint16 tests */
862 .description = "uint16_sanity1",
863 .type = PTYPE_U16,
864 .value.u16 = 1,
867 .description = "uint16_sanity2",
868 .type = PTYPE_U16,
869 .value.u16 = UINT16_MAX / 2 + 1,
872 .description = "uint16_min",
873 .type = PTYPE_U16,
874 .value.u16 = 0,
877 .description = "uint16_max",
878 .type = PTYPE_U16,
879 .value.u16 = UINT16_MAX,
881 /* uint32 tests */
883 .description = "uint32_sanity1",
884 .type = PTYPE_U32,
885 .value.u32 = 1,
888 .description = "uint32_sanity2",
889 .type = PTYPE_U32,
890 .value.u32 = UINT32_MAX / 2 + 1,
893 .description = "uint32_min",
894 .type = PTYPE_U32,
895 .value.u32 = 0,
898 .description = "uint32_max",
899 .type = PTYPE_U32,
900 .value.u32 = UINT32_MAX,
902 /* uint64 tests */
904 .description = "uint64_sanity1",
905 .type = PTYPE_U64,
906 .value.u64 = 1,
909 .description = "uint64_sanity2",
910 .type = PTYPE_U64,
911 .value.u64 = UINT64_MAX / 2 + 1,
914 .description = "uint64_min",
915 .type = PTYPE_U64,
916 .value.u64 = 0,
919 .description = "uint64_max",
920 .type = PTYPE_U64,
921 .value.u64 = UINT64_MAX,
923 /* int8 tests */
925 .description = "int8_sanity1",
926 .type = PTYPE_S8,
927 .value.s8 = -1,
930 .description = "int8_sanity2",
931 .type = PTYPE_S8,
932 .value.s8 = INT8_MAX / 2 + 1,
935 .description = "int8_min",
936 .type = PTYPE_S8,
937 .value.s8 = INT8_MIN,
940 .description = "int8_max",
941 .type = PTYPE_S8,
942 .value.s8 = INT8_MAX,
944 /* int16 tests */
946 .description = "int16_sanity1",
947 .type = PTYPE_S16,
948 .value.s16 = -1,
951 .description = "int16_sanity2",
952 .type = PTYPE_S16,
953 .value.s16 = INT16_MAX / 2 + 1,
956 .description = "int16_min",
957 .type = PTYPE_S16,
958 .value.s16 = INT16_MIN,
961 .description = "int16_max",
962 .type = PTYPE_S16,
963 .value.s16 = INT16_MAX,
965 /* int32 tests */
967 .description = "int32_sanity1",
968 .type = PTYPE_S32,
969 .value.s32 = -1,
972 .description = "int32_sanity2",
973 .type = PTYPE_S32,
974 .value.s32 = INT32_MAX / 2 + 1,
977 .description = "int32_min",
978 .type = PTYPE_S32,
979 .value.s32 = INT32_MIN,
982 .description = "int32_max",
983 .type = PTYPE_S32,
984 .value.s32 = INT32_MAX,
986 /* int64 tests */
988 .description = "int64_sanity1",
989 .type = PTYPE_S64,
990 .value.s64 = -1,
993 .description = "int64_sanity2",
994 .type = PTYPE_S64,
995 .value.s64 = INT64_MAX / 2 + 1,
998 .description = "int64_min",
999 .type = PTYPE_S64,
1000 .value.s64 = INT64_MIN,
1003 .description = "int64_max",
1004 .type = PTYPE_S64,
1005 .value.s64 = INT64_MAX,
1007 { .type = PTYPE_EOL }
1010 /* visitor-specific op implementations */
1012 typedef struct QmpSerializeData {
1013 Visitor *qov;
1014 QObject *obj;
1015 Visitor *qiv;
1016 } QmpSerializeData;
1018 static void qmp_serialize(void *native_in, void **datap,
1019 VisitorFunc visit, Error **errp)
1021 QmpSerializeData *d = g_malloc0(sizeof(*d));
1023 d->qov = qobject_output_visitor_new(&d->obj);
1024 visit(d->qov, &native_in, errp);
1025 *datap = d;
1028 static void qmp_deserialize(void **native_out, void *datap,
1029 VisitorFunc visit, Error **errp)
1031 QmpSerializeData *d = datap;
1032 QString *output_json;
1033 QObject *obj_orig, *obj;
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);
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);
1047 static void qmp_cleanup(void *datap)
1049 QmpSerializeData *d = datap;
1050 visit_free(d->qov);
1051 visit_free(d->qiv);
1053 g_free(d);
1056 typedef struct StringSerializeData {
1057 char *string;
1058 Visitor *sov;
1059 Visitor *siv;
1060 } StringSerializeData;
1062 static void string_serialize(void *native_in, void **datap,
1063 VisitorFunc visit, Error **errp)
1065 StringSerializeData *d = g_malloc0(sizeof(*d));
1067 d->sov = string_output_visitor_new(false, &d->string);
1068 visit(d->sov, &native_in, errp);
1069 *datap = d;
1072 static void string_deserialize(void **native_out, void *datap,
1073 VisitorFunc visit, Error **errp)
1075 StringSerializeData *d = datap;
1077 visit_complete(d->sov, &d->string);
1078 d->siv = string_input_visitor_new(d->string);
1079 visit(d->siv, native_out, errp);
1082 static void string_cleanup(void *datap)
1084 StringSerializeData *d = datap;
1086 visit_free(d->sov);
1087 visit_free(d->siv);
1088 g_free(d->string);
1089 g_free(d);
1092 /* visitor registration, test harness */
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
1098 static const SerializeOps visitors[] = {
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
1108 .type = "String",
1109 .serialize = string_serialize,
1110 .deserialize = string_deserialize,
1111 .cleanup = string_cleanup,
1112 .caps = VCAP_PRIMITIVES
1114 { NULL }
1117 static void add_visitor_type(const SerializeOps *ops)
1119 char testname_prefix[128];
1120 char testname[128];
1121 TestArgs *args;
1122 int i = 0;
1124 sprintf(testname_prefix, "/visitor/serialization/%s", ops->type);
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++;
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);
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);
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);
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++;
1174 int main(int argc, char **argv)
1176 int i = 0;
1178 g_test_init(&argc, &argv, NULL);
1180 while (visitors[i].type != NULL) {
1181 add_visitor_type(&visitors[i]);
1182 i++;
1185 g_test_run();
1187 return 0;