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