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