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