util/qht: Document memory ordering assumptions
[qemu.git] / tests / test-visitor-serialization.c
blobdba467076271296b444856aa15b014cc95c4bad0
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-types.h"
19 #include "test-qapi-visit.h"
20 #include "qapi/error.h"
21 #include "qapi/qmp/types.h"
22 #include "qapi/qmp/qjson.h"
23 #include "qapi/qmp-input-visitor.h"
24 #include "qapi/qmp-output-visitor.h"
25 #include "qapi/string-input-visitor.h"
26 #include "qapi/string-output-visitor.h"
27 #include "qapi-types.h"
28 #include "qapi-visit.h"
29 #include "qapi/dealloc-visitor.h"
31 enum PrimitiveTypeKind {
32 PTYPE_STRING = 0,
33 PTYPE_BOOLEAN,
34 PTYPE_NUMBER,
35 PTYPE_INTEGER,
36 PTYPE_U8,
37 PTYPE_U16,
38 PTYPE_U32,
39 PTYPE_U64,
40 PTYPE_S8,
41 PTYPE_S16,
42 PTYPE_S32,
43 PTYPE_S64,
44 PTYPE_EOL,
47 typedef struct PrimitiveType {
48 union {
49 const char *string;
50 bool boolean;
51 double number;
52 int64_t integer;
53 uint8_t u8;
54 uint16_t u16;
55 uint32_t u32;
56 uint64_t u64;
57 int8_t s8;
58 int16_t s16;
59 int32_t s32;
60 int64_t s64;
61 intmax_t max;
62 } value;
63 enum PrimitiveTypeKind type;
64 const char *description;
65 } PrimitiveType;
67 typedef struct PrimitiveList {
68 union {
69 strList *strings;
70 boolList *booleans;
71 numberList *numbers;
72 intList *integers;
73 int8List *s8_integers;
74 int16List *s16_integers;
75 int32List *s32_integers;
76 int64List *s64_integers;
77 uint8List *u8_integers;
78 uint16List *u16_integers;
79 uint32List *u32_integers;
80 uint64List *u64_integers;
81 } value;
82 enum PrimitiveTypeKind type;
83 const char *description;
84 } PrimitiveList;
86 /* test helpers */
88 typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp);
90 static void dealloc_helper(void *native_in, VisitorFunc visit, Error **errp)
92 Visitor *v = qapi_dealloc_visitor_new();
94 visit(v, &native_in, errp);
96 visit_free(v);
99 static void visit_primitive_type(Visitor *v, void **native, Error **errp)
101 PrimitiveType *pt = *native;
102 switch(pt->type) {
103 case PTYPE_STRING:
104 visit_type_str(v, NULL, (char **)&pt->value.string, errp);
105 break;
106 case PTYPE_BOOLEAN:
107 visit_type_bool(v, NULL, &pt->value.boolean, errp);
108 break;
109 case PTYPE_NUMBER:
110 visit_type_number(v, NULL, &pt->value.number, errp);
111 break;
112 case PTYPE_INTEGER:
113 visit_type_int(v, NULL, &pt->value.integer, errp);
114 break;
115 case PTYPE_U8:
116 visit_type_uint8(v, NULL, &pt->value.u8, errp);
117 break;
118 case PTYPE_U16:
119 visit_type_uint16(v, NULL, &pt->value.u16, errp);
120 break;
121 case PTYPE_U32:
122 visit_type_uint32(v, NULL, &pt->value.u32, errp);
123 break;
124 case PTYPE_U64:
125 visit_type_uint64(v, NULL, &pt->value.u64, errp);
126 break;
127 case PTYPE_S8:
128 visit_type_int8(v, NULL, &pt->value.s8, errp);
129 break;
130 case PTYPE_S16:
131 visit_type_int16(v, NULL, &pt->value.s16, errp);
132 break;
133 case PTYPE_S32:
134 visit_type_int32(v, NULL, &pt->value.s32, errp);
135 break;
136 case PTYPE_S64:
137 visit_type_int64(v, NULL, &pt->value.s64, errp);
138 break;
139 case PTYPE_EOL:
140 g_assert_not_reached();
144 static void visit_primitive_list(Visitor *v, void **native, Error **errp)
146 PrimitiveList *pl = *native;
147 switch (pl->type) {
148 case PTYPE_STRING:
149 visit_type_strList(v, NULL, &pl->value.strings, errp);
150 break;
151 case PTYPE_BOOLEAN:
152 visit_type_boolList(v, NULL, &pl->value.booleans, errp);
153 break;
154 case PTYPE_NUMBER:
155 visit_type_numberList(v, NULL, &pl->value.numbers, errp);
156 break;
157 case PTYPE_INTEGER:
158 visit_type_intList(v, NULL, &pl->value.integers, errp);
159 break;
160 case PTYPE_S8:
161 visit_type_int8List(v, NULL, &pl->value.s8_integers, errp);
162 break;
163 case PTYPE_S16:
164 visit_type_int16List(v, NULL, &pl->value.s16_integers, errp);
165 break;
166 case PTYPE_S32:
167 visit_type_int32List(v, NULL, &pl->value.s32_integers, errp);
168 break;
169 case PTYPE_S64:
170 visit_type_int64List(v, NULL, &pl->value.s64_integers, errp);
171 break;
172 case PTYPE_U8:
173 visit_type_uint8List(v, NULL, &pl->value.u8_integers, errp);
174 break;
175 case PTYPE_U16:
176 visit_type_uint16List(v, NULL, &pl->value.u16_integers, errp);
177 break;
178 case PTYPE_U32:
179 visit_type_uint32List(v, NULL, &pl->value.u32_integers, errp);
180 break;
181 case PTYPE_U64:
182 visit_type_uint64List(v, NULL, &pl->value.u64_integers, errp);
183 break;
184 default:
185 g_assert_not_reached();
190 static TestStruct *struct_create(void)
192 TestStruct *ts = g_malloc0(sizeof(*ts));
193 ts->integer = -42;
194 ts->boolean = true;
195 ts->string = strdup("test string");
196 return ts;
199 static void struct_compare(TestStruct *ts1, TestStruct *ts2)
201 g_assert(ts1);
202 g_assert(ts2);
203 g_assert_cmpint(ts1->integer, ==, ts2->integer);
204 g_assert(ts1->boolean == ts2->boolean);
205 g_assert_cmpstr(ts1->string, ==, ts2->string);
208 static void struct_cleanup(TestStruct *ts)
210 g_free(ts->string);
211 g_free(ts);
214 static void visit_struct(Visitor *v, void **native, Error **errp)
216 visit_type_TestStruct(v, NULL, (TestStruct **)native, errp);
219 static UserDefTwo *nested_struct_create(void)
221 UserDefTwo *udnp = g_malloc0(sizeof(*udnp));
222 udnp->string0 = strdup("test_string0");
223 udnp->dict1 = g_malloc0(sizeof(*udnp->dict1));
224 udnp->dict1->string1 = strdup("test_string1");
225 udnp->dict1->dict2 = g_malloc0(sizeof(*udnp->dict1->dict2));
226 udnp->dict1->dict2->userdef = g_new0(UserDefOne, 1);
227 udnp->dict1->dict2->userdef->integer = 42;
228 udnp->dict1->dict2->userdef->string = strdup("test_string");
229 udnp->dict1->dict2->string = strdup("test_string2");
230 udnp->dict1->dict3 = g_malloc0(sizeof(*udnp->dict1->dict3));
231 udnp->dict1->has_dict3 = true;
232 udnp->dict1->dict3->userdef = g_new0(UserDefOne, 1);
233 udnp->dict1->dict3->userdef->integer = 43;
234 udnp->dict1->dict3->userdef->string = strdup("test_string");
235 udnp->dict1->dict3->string = strdup("test_string3");
236 return udnp;
239 static void nested_struct_compare(UserDefTwo *udnp1, UserDefTwo *udnp2)
241 g_assert(udnp1);
242 g_assert(udnp2);
243 g_assert_cmpstr(udnp1->string0, ==, udnp2->string0);
244 g_assert_cmpstr(udnp1->dict1->string1, ==, udnp2->dict1->string1);
245 g_assert_cmpint(udnp1->dict1->dict2->userdef->integer, ==,
246 udnp2->dict1->dict2->userdef->integer);
247 g_assert_cmpstr(udnp1->dict1->dict2->userdef->string, ==,
248 udnp2->dict1->dict2->userdef->string);
249 g_assert_cmpstr(udnp1->dict1->dict2->string, ==,
250 udnp2->dict1->dict2->string);
251 g_assert(udnp1->dict1->has_dict3 == udnp2->dict1->has_dict3);
252 g_assert_cmpint(udnp1->dict1->dict3->userdef->integer, ==,
253 udnp2->dict1->dict3->userdef->integer);
254 g_assert_cmpstr(udnp1->dict1->dict3->userdef->string, ==,
255 udnp2->dict1->dict3->userdef->string);
256 g_assert_cmpstr(udnp1->dict1->dict3->string, ==,
257 udnp2->dict1->dict3->string);
260 static void nested_struct_cleanup(UserDefTwo *udnp)
262 qapi_free_UserDefTwo(udnp);
265 static void visit_nested_struct(Visitor *v, void **native, Error **errp)
267 visit_type_UserDefTwo(v, NULL, (UserDefTwo **)native, errp);
270 static void visit_nested_struct_list(Visitor *v, void **native, Error **errp)
272 visit_type_UserDefTwoList(v, NULL, (UserDefTwoList **)native, errp);
275 /* test cases */
277 typedef enum VisitorCapabilities {
278 VCAP_PRIMITIVES = 1,
279 VCAP_STRUCTURES = 2,
280 VCAP_LISTS = 4,
281 VCAP_PRIMITIVE_LISTS = 8,
282 } VisitorCapabilities;
284 typedef struct SerializeOps {
285 void (*serialize)(void *native_in, void **datap,
286 VisitorFunc visit, Error **errp);
287 void (*deserialize)(void **native_out, void *datap,
288 VisitorFunc visit, Error **errp);
289 void (*cleanup)(void *datap);
290 const char *type;
291 VisitorCapabilities caps;
292 } SerializeOps;
294 typedef struct TestArgs {
295 const SerializeOps *ops;
296 void *test_data;
297 } TestArgs;
299 static void test_primitives(gconstpointer opaque)
301 TestArgs *args = (TestArgs *) opaque;
302 const SerializeOps *ops = args->ops;
303 PrimitiveType *pt = args->test_data;
304 PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy));
305 void *serialize_data;
307 pt_copy->type = pt->type;
308 ops->serialize(pt, &serialize_data, visit_primitive_type, &error_abort);
309 ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type,
310 &error_abort);
312 g_assert(pt_copy != NULL);
313 if (pt->type == PTYPE_STRING) {
314 g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string);
315 g_free((char *)pt_copy->value.string);
316 } else if (pt->type == PTYPE_NUMBER) {
317 GString *double_expected = g_string_new("");
318 GString *double_actual = g_string_new("");
319 /* we serialize with %f for our reference visitors, so rather than fuzzy
320 * floating math to test "equality", just compare the formatted values
322 g_string_printf(double_expected, "%.6f", pt->value.number);
323 g_string_printf(double_actual, "%.6f", pt_copy->value.number);
324 g_assert_cmpstr(double_actual->str, ==, double_expected->str);
326 g_string_free(double_expected, true);
327 g_string_free(double_actual, true);
328 } else if (pt->type == PTYPE_BOOLEAN) {
329 g_assert_cmpint(!!pt->value.max, ==, !!pt->value.max);
330 } else {
331 g_assert_cmpint(pt->value.max, ==, pt_copy->value.max);
334 ops->cleanup(serialize_data);
335 g_free(args);
336 g_free(pt_copy);
339 static void test_primitive_lists(gconstpointer opaque)
341 TestArgs *args = (TestArgs *) opaque;
342 const SerializeOps *ops = args->ops;
343 PrimitiveType *pt = args->test_data;
344 PrimitiveList pl = { .value = { NULL } };
345 PrimitiveList pl_copy = { .value = { NULL } };
346 PrimitiveList *pl_copy_ptr = &pl_copy;
347 void *serialize_data;
348 void *cur_head = NULL;
349 int i;
351 pl.type = pl_copy.type = pt->type;
353 /* build up our list of primitive types */
354 for (i = 0; i < 32; i++) {
355 switch (pl.type) {
356 case PTYPE_STRING: {
357 strList *tmp = g_new0(strList, 1);
358 tmp->value = g_strdup(pt->value.string);
359 if (pl.value.strings == NULL) {
360 pl.value.strings = tmp;
361 } else {
362 tmp->next = pl.value.strings;
363 pl.value.strings = tmp;
365 break;
367 case PTYPE_INTEGER: {
368 intList *tmp = g_new0(intList, 1);
369 tmp->value = pt->value.integer;
370 if (pl.value.integers == NULL) {
371 pl.value.integers = tmp;
372 } else {
373 tmp->next = pl.value.integers;
374 pl.value.integers = tmp;
376 break;
378 case PTYPE_S8: {
379 int8List *tmp = g_new0(int8List, 1);
380 tmp->value = pt->value.s8;
381 if (pl.value.s8_integers == NULL) {
382 pl.value.s8_integers = tmp;
383 } else {
384 tmp->next = pl.value.s8_integers;
385 pl.value.s8_integers = tmp;
387 break;
389 case PTYPE_S16: {
390 int16List *tmp = g_new0(int16List, 1);
391 tmp->value = pt->value.s16;
392 if (pl.value.s16_integers == NULL) {
393 pl.value.s16_integers = tmp;
394 } else {
395 tmp->next = pl.value.s16_integers;
396 pl.value.s16_integers = tmp;
398 break;
400 case PTYPE_S32: {
401 int32List *tmp = g_new0(int32List, 1);
402 tmp->value = pt->value.s32;
403 if (pl.value.s32_integers == NULL) {
404 pl.value.s32_integers = tmp;
405 } else {
406 tmp->next = pl.value.s32_integers;
407 pl.value.s32_integers = tmp;
409 break;
411 case PTYPE_S64: {
412 int64List *tmp = g_new0(int64List, 1);
413 tmp->value = pt->value.s64;
414 if (pl.value.s64_integers == NULL) {
415 pl.value.s64_integers = tmp;
416 } else {
417 tmp->next = pl.value.s64_integers;
418 pl.value.s64_integers = tmp;
420 break;
422 case PTYPE_U8: {
423 uint8List *tmp = g_new0(uint8List, 1);
424 tmp->value = pt->value.u8;
425 if (pl.value.u8_integers == NULL) {
426 pl.value.u8_integers = tmp;
427 } else {
428 tmp->next = pl.value.u8_integers;
429 pl.value.u8_integers = tmp;
431 break;
433 case PTYPE_U16: {
434 uint16List *tmp = g_new0(uint16List, 1);
435 tmp->value = pt->value.u16;
436 if (pl.value.u16_integers == NULL) {
437 pl.value.u16_integers = tmp;
438 } else {
439 tmp->next = pl.value.u16_integers;
440 pl.value.u16_integers = tmp;
442 break;
444 case PTYPE_U32: {
445 uint32List *tmp = g_new0(uint32List, 1);
446 tmp->value = pt->value.u32;
447 if (pl.value.u32_integers == NULL) {
448 pl.value.u32_integers = tmp;
449 } else {
450 tmp->next = pl.value.u32_integers;
451 pl.value.u32_integers = tmp;
453 break;
455 case PTYPE_U64: {
456 uint64List *tmp = g_new0(uint64List, 1);
457 tmp->value = pt->value.u64;
458 if (pl.value.u64_integers == NULL) {
459 pl.value.u64_integers = tmp;
460 } else {
461 tmp->next = pl.value.u64_integers;
462 pl.value.u64_integers = tmp;
464 break;
466 case PTYPE_NUMBER: {
467 numberList *tmp = g_new0(numberList, 1);
468 tmp->value = pt->value.number;
469 if (pl.value.numbers == NULL) {
470 pl.value.numbers = tmp;
471 } else {
472 tmp->next = pl.value.numbers;
473 pl.value.numbers = tmp;
475 break;
477 case PTYPE_BOOLEAN: {
478 boolList *tmp = g_new0(boolList, 1);
479 tmp->value = pt->value.boolean;
480 if (pl.value.booleans == NULL) {
481 pl.value.booleans = tmp;
482 } else {
483 tmp->next = pl.value.booleans;
484 pl.value.booleans = tmp;
486 break;
488 default:
489 g_assert_not_reached();
493 ops->serialize((void **)&pl, &serialize_data, visit_primitive_list,
494 &error_abort);
495 ops->deserialize((void **)&pl_copy_ptr, serialize_data,
496 visit_primitive_list, &error_abort);
498 i = 0;
500 /* compare our deserialized list of primitives to the original */
501 do {
502 switch (pl_copy.type) {
503 case PTYPE_STRING: {
504 strList *ptr;
505 if (cur_head) {
506 ptr = cur_head;
507 cur_head = ptr->next;
508 } else {
509 cur_head = ptr = pl_copy.value.strings;
511 g_assert_cmpstr(pt->value.string, ==, ptr->value);
512 break;
514 case PTYPE_INTEGER: {
515 intList *ptr;
516 if (cur_head) {
517 ptr = cur_head;
518 cur_head = ptr->next;
519 } else {
520 cur_head = ptr = pl_copy.value.integers;
522 g_assert_cmpint(pt->value.integer, ==, ptr->value);
523 break;
525 case PTYPE_S8: {
526 int8List *ptr;
527 if (cur_head) {
528 ptr = cur_head;
529 cur_head = ptr->next;
530 } else {
531 cur_head = ptr = pl_copy.value.s8_integers;
533 g_assert_cmpint(pt->value.s8, ==, ptr->value);
534 break;
536 case PTYPE_S16: {
537 int16List *ptr;
538 if (cur_head) {
539 ptr = cur_head;
540 cur_head = ptr->next;
541 } else {
542 cur_head = ptr = pl_copy.value.s16_integers;
544 g_assert_cmpint(pt->value.s16, ==, ptr->value);
545 break;
547 case PTYPE_S32: {
548 int32List *ptr;
549 if (cur_head) {
550 ptr = cur_head;
551 cur_head = ptr->next;
552 } else {
553 cur_head = ptr = pl_copy.value.s32_integers;
555 g_assert_cmpint(pt->value.s32, ==, ptr->value);
556 break;
558 case PTYPE_S64: {
559 int64List *ptr;
560 if (cur_head) {
561 ptr = cur_head;
562 cur_head = ptr->next;
563 } else {
564 cur_head = ptr = pl_copy.value.s64_integers;
566 g_assert_cmpint(pt->value.s64, ==, ptr->value);
567 break;
569 case PTYPE_U8: {
570 uint8List *ptr;
571 if (cur_head) {
572 ptr = cur_head;
573 cur_head = ptr->next;
574 } else {
575 cur_head = ptr = pl_copy.value.u8_integers;
577 g_assert_cmpint(pt->value.u8, ==, ptr->value);
578 break;
580 case PTYPE_U16: {
581 uint16List *ptr;
582 if (cur_head) {
583 ptr = cur_head;
584 cur_head = ptr->next;
585 } else {
586 cur_head = ptr = pl_copy.value.u16_integers;
588 g_assert_cmpint(pt->value.u16, ==, ptr->value);
589 break;
591 case PTYPE_U32: {
592 uint32List *ptr;
593 if (cur_head) {
594 ptr = cur_head;
595 cur_head = ptr->next;
596 } else {
597 cur_head = ptr = pl_copy.value.u32_integers;
599 g_assert_cmpint(pt->value.u32, ==, ptr->value);
600 break;
602 case PTYPE_U64: {
603 uint64List *ptr;
604 if (cur_head) {
605 ptr = cur_head;
606 cur_head = ptr->next;
607 } else {
608 cur_head = ptr = pl_copy.value.u64_integers;
610 g_assert_cmpint(pt->value.u64, ==, ptr->value);
611 break;
613 case PTYPE_NUMBER: {
614 numberList *ptr;
615 GString *double_expected = g_string_new("");
616 GString *double_actual = g_string_new("");
617 if (cur_head) {
618 ptr = cur_head;
619 cur_head = ptr->next;
620 } else {
621 cur_head = ptr = pl_copy.value.numbers;
623 /* we serialize with %f for our reference visitors, so rather than
624 * fuzzy floating math to test "equality", just compare the
625 * formatted values
627 g_string_printf(double_expected, "%.6f", pt->value.number);
628 g_string_printf(double_actual, "%.6f", ptr->value);
629 g_assert_cmpstr(double_actual->str, ==, double_expected->str);
630 g_string_free(double_expected, true);
631 g_string_free(double_actual, true);
632 break;
634 case PTYPE_BOOLEAN: {
635 boolList *ptr;
636 if (cur_head) {
637 ptr = cur_head;
638 cur_head = ptr->next;
639 } else {
640 cur_head = ptr = pl_copy.value.booleans;
642 g_assert_cmpint(!!pt->value.boolean, ==, !!ptr->value);
643 break;
645 default:
646 g_assert_not_reached();
648 i++;
649 } while (cur_head);
651 g_assert_cmpint(i, ==, 33);
653 ops->cleanup(serialize_data);
654 dealloc_helper(&pl, visit_primitive_list, &error_abort);
655 dealloc_helper(&pl_copy, visit_primitive_list, &error_abort);
656 g_free(args);
659 static void test_struct(gconstpointer opaque)
661 TestArgs *args = (TestArgs *) opaque;
662 const SerializeOps *ops = args->ops;
663 TestStruct *ts = struct_create();
664 TestStruct *ts_copy = NULL;
665 void *serialize_data;
667 ops->serialize(ts, &serialize_data, visit_struct, &error_abort);
668 ops->deserialize((void **)&ts_copy, serialize_data, visit_struct,
669 &error_abort);
671 struct_compare(ts, ts_copy);
673 struct_cleanup(ts);
674 struct_cleanup(ts_copy);
676 ops->cleanup(serialize_data);
677 g_free(args);
680 static void test_nested_struct(gconstpointer opaque)
682 TestArgs *args = (TestArgs *) opaque;
683 const SerializeOps *ops = args->ops;
684 UserDefTwo *udnp = nested_struct_create();
685 UserDefTwo *udnp_copy = NULL;
686 void *serialize_data;
688 ops->serialize(udnp, &serialize_data, visit_nested_struct, &error_abort);
689 ops->deserialize((void **)&udnp_copy, serialize_data, visit_nested_struct,
690 &error_abort);
692 nested_struct_compare(udnp, udnp_copy);
694 nested_struct_cleanup(udnp);
695 nested_struct_cleanup(udnp_copy);
697 ops->cleanup(serialize_data);
698 g_free(args);
701 static void test_nested_struct_list(gconstpointer opaque)
703 TestArgs *args = (TestArgs *) opaque;
704 const SerializeOps *ops = args->ops;
705 UserDefTwoList *listp = NULL, *tmp, *tmp_copy, *listp_copy = NULL;
706 void *serialize_data;
707 int i = 0;
709 for (i = 0; i < 8; i++) {
710 tmp = g_new0(UserDefTwoList, 1);
711 tmp->value = nested_struct_create();
712 tmp->next = listp;
713 listp = tmp;
716 ops->serialize(listp, &serialize_data, visit_nested_struct_list,
717 &error_abort);
718 ops->deserialize((void **)&listp_copy, serialize_data,
719 visit_nested_struct_list, &error_abort);
721 tmp = listp;
722 tmp_copy = listp_copy;
723 while (listp_copy) {
724 g_assert(listp);
725 nested_struct_compare(listp->value, listp_copy->value);
726 listp = listp->next;
727 listp_copy = listp_copy->next;
730 qapi_free_UserDefTwoList(tmp);
731 qapi_free_UserDefTwoList(tmp_copy);
733 ops->cleanup(serialize_data);
734 g_free(args);
737 static PrimitiveType pt_values[] = {
738 /* string tests */
740 .description = "string_empty",
741 .type = PTYPE_STRING,
742 .value.string = "",
745 .description = "string_whitespace",
746 .type = PTYPE_STRING,
747 .value.string = "a b c\td",
750 .description = "string_newlines",
751 .type = PTYPE_STRING,
752 .value.string = "a\nb\n",
755 .description = "string_commas",
756 .type = PTYPE_STRING,
757 .value.string = "a,b, c,d",
760 .description = "string_single_quoted",
761 .type = PTYPE_STRING,
762 .value.string = "'a b',cd",
765 .description = "string_double_quoted",
766 .type = PTYPE_STRING,
767 .value.string = "\"a b\",cd",
769 /* boolean tests */
771 .description = "boolean_true1",
772 .type = PTYPE_BOOLEAN,
773 .value.boolean = true,
776 .description = "boolean_true2",
777 .type = PTYPE_BOOLEAN,
778 .value.boolean = 8,
781 .description = "boolean_true3",
782 .type = PTYPE_BOOLEAN,
783 .value.boolean = -1,
786 .description = "boolean_false1",
787 .type = PTYPE_BOOLEAN,
788 .value.boolean = false,
791 .description = "boolean_false2",
792 .type = PTYPE_BOOLEAN,
793 .value.boolean = 0,
795 /* number tests (double) */
796 /* note: we format these to %.6f before comparing, since that's how
797 * we serialize them and it doesn't make sense to check precision
798 * beyond that.
801 .description = "number_sanity1",
802 .type = PTYPE_NUMBER,
803 .value.number = -1,
806 .description = "number_sanity2",
807 .type = PTYPE_NUMBER,
808 .value.number = 3.14159265,
811 .description = "number_min",
812 .type = PTYPE_NUMBER,
813 .value.number = DBL_MIN,
816 .description = "number_max",
817 .type = PTYPE_NUMBER,
818 .value.number = DBL_MAX,
820 /* integer tests (int64) */
822 .description = "integer_sanity1",
823 .type = PTYPE_INTEGER,
824 .value.integer = -1,
827 .description = "integer_sanity2",
828 .type = PTYPE_INTEGER,
829 .value.integer = INT64_MAX / 2 + 1,
832 .description = "integer_min",
833 .type = PTYPE_INTEGER,
834 .value.integer = INT64_MIN,
837 .description = "integer_max",
838 .type = PTYPE_INTEGER,
839 .value.integer = INT64_MAX,
841 /* uint8 tests */
843 .description = "uint8_sanity1",
844 .type = PTYPE_U8,
845 .value.u8 = 1,
848 .description = "uint8_sanity2",
849 .type = PTYPE_U8,
850 .value.u8 = UINT8_MAX / 2 + 1,
853 .description = "uint8_min",
854 .type = PTYPE_U8,
855 .value.u8 = 0,
858 .description = "uint8_max",
859 .type = PTYPE_U8,
860 .value.u8 = UINT8_MAX,
862 /* uint16 tests */
864 .description = "uint16_sanity1",
865 .type = PTYPE_U16,
866 .value.u16 = 1,
869 .description = "uint16_sanity2",
870 .type = PTYPE_U16,
871 .value.u16 = UINT16_MAX / 2 + 1,
874 .description = "uint16_min",
875 .type = PTYPE_U16,
876 .value.u16 = 0,
879 .description = "uint16_max",
880 .type = PTYPE_U16,
881 .value.u16 = UINT16_MAX,
883 /* uint32 tests */
885 .description = "uint32_sanity1",
886 .type = PTYPE_U32,
887 .value.u32 = 1,
890 .description = "uint32_sanity2",
891 .type = PTYPE_U32,
892 .value.u32 = UINT32_MAX / 2 + 1,
895 .description = "uint32_min",
896 .type = PTYPE_U32,
897 .value.u32 = 0,
900 .description = "uint32_max",
901 .type = PTYPE_U32,
902 .value.u32 = UINT32_MAX,
904 /* uint64 tests */
906 .description = "uint64_sanity1",
907 .type = PTYPE_U64,
908 .value.u64 = 1,
911 .description = "uint64_sanity2",
912 .type = PTYPE_U64,
913 .value.u64 = UINT64_MAX / 2 + 1,
916 .description = "uint64_min",
917 .type = PTYPE_U64,
918 .value.u64 = 0,
921 .description = "uint64_max",
922 .type = PTYPE_U64,
923 .value.u64 = UINT64_MAX,
925 /* int8 tests */
927 .description = "int8_sanity1",
928 .type = PTYPE_S8,
929 .value.s8 = -1,
932 .description = "int8_sanity2",
933 .type = PTYPE_S8,
934 .value.s8 = INT8_MAX / 2 + 1,
937 .description = "int8_min",
938 .type = PTYPE_S8,
939 .value.s8 = INT8_MIN,
942 .description = "int8_max",
943 .type = PTYPE_S8,
944 .value.s8 = INT8_MAX,
946 /* int16 tests */
948 .description = "int16_sanity1",
949 .type = PTYPE_S16,
950 .value.s16 = -1,
953 .description = "int16_sanity2",
954 .type = PTYPE_S16,
955 .value.s16 = INT16_MAX / 2 + 1,
958 .description = "int16_min",
959 .type = PTYPE_S16,
960 .value.s16 = INT16_MIN,
963 .description = "int16_max",
964 .type = PTYPE_S16,
965 .value.s16 = INT16_MAX,
967 /* int32 tests */
969 .description = "int32_sanity1",
970 .type = PTYPE_S32,
971 .value.s32 = -1,
974 .description = "int32_sanity2",
975 .type = PTYPE_S32,
976 .value.s32 = INT32_MAX / 2 + 1,
979 .description = "int32_min",
980 .type = PTYPE_S32,
981 .value.s32 = INT32_MIN,
984 .description = "int32_max",
985 .type = PTYPE_S32,
986 .value.s32 = INT32_MAX,
988 /* int64 tests */
990 .description = "int64_sanity1",
991 .type = PTYPE_S64,
992 .value.s64 = -1,
995 .description = "int64_sanity2",
996 .type = PTYPE_S64,
997 .value.s64 = INT64_MAX / 2 + 1,
1000 .description = "int64_min",
1001 .type = PTYPE_S64,
1002 .value.s64 = INT64_MIN,
1005 .description = "int64_max",
1006 .type = PTYPE_S64,
1007 .value.s64 = INT64_MAX,
1009 { .type = PTYPE_EOL }
1012 /* visitor-specific op implementations */
1014 typedef struct QmpSerializeData {
1015 Visitor *qov;
1016 QObject *obj;
1017 Visitor *qiv;
1018 } QmpSerializeData;
1020 static void qmp_serialize(void *native_in, void **datap,
1021 VisitorFunc visit, Error **errp)
1023 QmpSerializeData *d = g_malloc0(sizeof(*d));
1025 d->qov = qmp_output_visitor_new(&d->obj);
1026 visit(d->qov, &native_in, errp);
1027 *datap = d;
1030 static void qmp_deserialize(void **native_out, void *datap,
1031 VisitorFunc visit, Error **errp)
1033 QmpSerializeData *d = datap;
1034 QString *output_json;
1035 QObject *obj_orig, *obj;
1037 visit_complete(d->qov, &d->obj);
1038 obj_orig = d->obj;
1039 output_json = qobject_to_json(obj_orig);
1040 obj = qobject_from_json(qstring_get_str(output_json));
1042 QDECREF(output_json);
1043 d->qiv = qmp_input_visitor_new(obj, true);
1044 qobject_decref(obj_orig);
1045 qobject_decref(obj);
1046 visit(d->qiv, native_out, errp);
1049 static void qmp_cleanup(void *datap)
1051 QmpSerializeData *d = datap;
1052 visit_free(d->qov);
1053 visit_free(d->qiv);
1055 g_free(d);
1058 typedef struct StringSerializeData {
1059 char *string;
1060 Visitor *sov;
1061 Visitor *siv;
1062 } StringSerializeData;
1064 static void string_serialize(void *native_in, void **datap,
1065 VisitorFunc visit, Error **errp)
1067 StringSerializeData *d = g_malloc0(sizeof(*d));
1069 d->sov = string_output_visitor_new(false, &d->string);
1070 visit(d->sov, &native_in, errp);
1071 *datap = d;
1074 static void string_deserialize(void **native_out, void *datap,
1075 VisitorFunc visit, Error **errp)
1077 StringSerializeData *d = datap;
1079 visit_complete(d->sov, &d->string);
1080 d->siv = string_input_visitor_new(d->string);
1081 visit(d->siv, native_out, errp);
1084 static void string_cleanup(void *datap)
1086 StringSerializeData *d = datap;
1088 visit_free(d->sov);
1089 visit_free(d->siv);
1090 g_free(d->string);
1091 g_free(d);
1094 /* visitor registration, test harness */
1096 /* note: to function interchangeably as a serialization mechanism your
1097 * visitor test implementation should pass the test cases for all visitor
1098 * capabilities: primitives, structures, and lists
1100 static const SerializeOps visitors[] = {
1102 .type = "QMP",
1103 .serialize = qmp_serialize,
1104 .deserialize = qmp_deserialize,
1105 .cleanup = qmp_cleanup,
1106 .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS |
1107 VCAP_PRIMITIVE_LISTS
1110 .type = "String",
1111 .serialize = string_serialize,
1112 .deserialize = string_deserialize,
1113 .cleanup = string_cleanup,
1114 .caps = VCAP_PRIMITIVES
1116 { NULL }
1119 static void add_visitor_type(const SerializeOps *ops)
1121 char testname_prefix[128];
1122 char testname[128];
1123 TestArgs *args;
1124 int i = 0;
1126 sprintf(testname_prefix, "/visitor/serialization/%s", ops->type);
1128 if (ops->caps & VCAP_PRIMITIVES) {
1129 while (pt_values[i].type != PTYPE_EOL) {
1130 sprintf(testname, "%s/primitives/%s", testname_prefix,
1131 pt_values[i].description);
1132 args = g_malloc0(sizeof(*args));
1133 args->ops = ops;
1134 args->test_data = &pt_values[i];
1135 g_test_add_data_func(testname, args, test_primitives);
1136 i++;
1140 if (ops->caps & VCAP_STRUCTURES) {
1141 sprintf(testname, "%s/struct", testname_prefix);
1142 args = g_malloc0(sizeof(*args));
1143 args->ops = ops;
1144 args->test_data = NULL;
1145 g_test_add_data_func(testname, args, test_struct);
1147 sprintf(testname, "%s/nested_struct", testname_prefix);
1148 args = g_malloc0(sizeof(*args));
1149 args->ops = ops;
1150 args->test_data = NULL;
1151 g_test_add_data_func(testname, args, test_nested_struct);
1154 if (ops->caps & VCAP_LISTS) {
1155 sprintf(testname, "%s/nested_struct_list", testname_prefix);
1156 args = g_malloc0(sizeof(*args));
1157 args->ops = ops;
1158 args->test_data = NULL;
1159 g_test_add_data_func(testname, args, test_nested_struct_list);
1162 if (ops->caps & VCAP_PRIMITIVE_LISTS) {
1163 i = 0;
1164 while (pt_values[i].type != PTYPE_EOL) {
1165 sprintf(testname, "%s/primitive_list/%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_primitive_lists);
1171 i++;
1176 int main(int argc, char **argv)
1178 int i = 0;
1180 g_test_init(&argc, &argv, NULL);
1182 while (visitors[i].type != NULL) {
1183 add_visitor_type(&visitors[i]);
1184 i++;
1187 g_test_run();
1189 return 0;