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