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