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