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