qemu/tests/test-qobject-input-visitor.c
<<
>>
Prefs
   1/*
   2 * QObject Input Visitor unit-tests.
   3 *
   4 * Copyright (C) 2011-2016 Red Hat Inc.
   5 *
   6 * Authors:
   7 *  Luiz Capitulino <lcapitulino@redhat.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 */
  12
  13#include "qemu/osdep.h"
  14
  15#include "qemu-common.h"
  16#include "qapi/error.h"
  17#include "qapi/qobject-input-visitor.h"
  18#include "test-qapi-types.h"
  19#include "test-qapi-visit.h"
  20#include "qapi/qmp/types.h"
  21#include "qapi/qmp/qjson.h"
  22
  23typedef struct TestInputVisitorData {
  24    QObject *obj;
  25    Visitor *qiv;
  26} TestInputVisitorData;
  27
  28static void visitor_input_teardown(TestInputVisitorData *data,
  29                                   const void *unused)
  30{
  31    qobject_decref(data->obj);
  32    data->obj = NULL;
  33
  34    if (data->qiv) {
  35        visit_free(data->qiv);
  36        data->qiv = NULL;
  37    }
  38}
  39
  40/* The various test_init functions are provided instead of a test setup
  41   function so that the JSON string used by the tests are kept in the test
  42   functions (and not in main()). */
  43static Visitor *visitor_input_test_init_internal(TestInputVisitorData *data,
  44                                                 const char *json_string,
  45                                                 va_list *ap)
  46{
  47    visitor_input_teardown(data, NULL);
  48
  49    data->obj = qobject_from_jsonv(json_string, ap);
  50    g_assert(data->obj);
  51
  52    data->qiv = qobject_input_visitor_new(data->obj, false);
  53    g_assert(data->qiv);
  54    return data->qiv;
  55}
  56
  57static GCC_FMT_ATTR(2, 3)
  58Visitor *visitor_input_test_init(TestInputVisitorData *data,
  59                                 const char *json_string, ...)
  60{
  61    Visitor *v;
  62    va_list ap;
  63
  64    va_start(ap, json_string);
  65    v = visitor_input_test_init_internal(data, json_string, &ap);
  66    va_end(ap);
  67    return v;
  68}
  69
  70/* similar to visitor_input_test_init(), but does not expect a string
  71 * literal/format json_string argument and so can be used for
  72 * programatically generated strings (and we can't pass in programatically
  73 * generated strings via %s format parameters since qobject_from_jsonv()
  74 * will wrap those in double-quotes and treat the entire object as a
  75 * string)
  76 */
  77static Visitor *visitor_input_test_init_raw(TestInputVisitorData *data,
  78                                            const char *json_string)
  79{
  80    return visitor_input_test_init_internal(data, json_string, NULL);
  81}
  82
  83static void test_visitor_in_int(TestInputVisitorData *data,
  84                                const void *unused)
  85{
  86    int64_t res = 0;
  87    int value = -42;
  88    Visitor *v;
  89
  90    v = visitor_input_test_init(data, "%d", value);
  91
  92    visit_type_int(v, NULL, &res, &error_abort);
  93    g_assert_cmpint(res, ==, value);
  94}
  95
  96static void test_visitor_in_int_overflow(TestInputVisitorData *data,
  97                                         const void *unused)
  98{
  99    int64_t res = 0;
 100    Error *err = NULL;
 101    Visitor *v;
 102
 103    /* this will overflow a Qint/int64, so should be deserialized into
 104     * a QFloat/double field instead, leading to an error if we pass it
 105     * to visit_type_int. confirm this.
 106     */
 107    v = visitor_input_test_init(data, "%f", DBL_MAX);
 108
 109    visit_type_int(v, NULL, &res, &err);
 110    error_free_or_abort(&err);
 111}
 112
 113static void test_visitor_in_bool(TestInputVisitorData *data,
 114                                 const void *unused)
 115{
 116    bool res = false;
 117    Visitor *v;
 118
 119    v = visitor_input_test_init(data, "true");
 120
 121    visit_type_bool(v, NULL, &res, &error_abort);
 122    g_assert_cmpint(res, ==, true);
 123}
 124
 125static void test_visitor_in_number(TestInputVisitorData *data,
 126                                   const void *unused)
 127{
 128    double res = 0, value = 3.14;
 129    Visitor *v;
 130
 131    v = visitor_input_test_init(data, "%f", value);
 132
 133    visit_type_number(v, NULL, &res, &error_abort);
 134    g_assert_cmpfloat(res, ==, value);
 135}
 136
 137static void test_visitor_in_string(TestInputVisitorData *data,
 138                                   const void *unused)
 139{
 140    char *res = NULL, *value = (char *) "Q E M U";
 141    Visitor *v;
 142
 143    v = visitor_input_test_init(data, "%s", value);
 144
 145    visit_type_str(v, NULL, &res, &error_abort);
 146    g_assert_cmpstr(res, ==, value);
 147
 148    g_free(res);
 149}
 150
 151static void test_visitor_in_enum(TestInputVisitorData *data,
 152                                 const void *unused)
 153{
 154    Visitor *v;
 155    EnumOne i;
 156
 157    for (i = 0; EnumOne_lookup[i]; i++) {
 158        EnumOne res = -1;
 159
 160        v = visitor_input_test_init(data, "%s", EnumOne_lookup[i]);
 161
 162        visit_type_EnumOne(v, NULL, &res, &error_abort);
 163        g_assert_cmpint(i, ==, res);
 164    }
 165}
 166
 167
 168static void test_visitor_in_struct(TestInputVisitorData *data,
 169                                   const void *unused)
 170{
 171    TestStruct *p = NULL;
 172    Visitor *v;
 173
 174    v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
 175
 176    visit_type_TestStruct(v, NULL, &p, &error_abort);
 177    g_assert_cmpint(p->integer, ==, -42);
 178    g_assert(p->boolean == true);
 179    g_assert_cmpstr(p->string, ==, "foo");
 180
 181    g_free(p->string);
 182    g_free(p);
 183}
 184
 185static void test_visitor_in_struct_nested(TestInputVisitorData *data,
 186                                          const void *unused)
 187{
 188    UserDefTwo *udp = NULL;
 189    Visitor *v;
 190
 191    v = visitor_input_test_init(data, "{ 'string0': 'string0', "
 192                                "'dict1': { 'string1': 'string1', "
 193                                "'dict2': { 'userdef': { 'integer': 42, "
 194                                "'string': 'string' }, 'string': 'string2'}}}");
 195
 196    visit_type_UserDefTwo(v, NULL, &udp, &error_abort);
 197
 198    g_assert_cmpstr(udp->string0, ==, "string0");
 199    g_assert_cmpstr(udp->dict1->string1, ==, "string1");
 200    g_assert_cmpint(udp->dict1->dict2->userdef->integer, ==, 42);
 201    g_assert_cmpstr(udp->dict1->dict2->userdef->string, ==, "string");
 202    g_assert_cmpstr(udp->dict1->dict2->string, ==, "string2");
 203    g_assert(udp->dict1->has_dict3 == false);
 204
 205    qapi_free_UserDefTwo(udp);
 206}
 207
 208static void test_visitor_in_list(TestInputVisitorData *data,
 209                                 const void *unused)
 210{
 211    UserDefOneList *item, *head = NULL;
 212    Visitor *v;
 213    int i;
 214
 215    v = visitor_input_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]");
 216
 217    visit_type_UserDefOneList(v, NULL, &head, &error_abort);
 218    g_assert(head != NULL);
 219
 220    for (i = 0, item = head; item; item = item->next, i++) {
 221        char string[12];
 222
 223        snprintf(string, sizeof(string), "string%d", i);
 224        g_assert_cmpstr(item->value->string, ==, string);
 225        g_assert_cmpint(item->value->integer, ==, 42 + i);
 226    }
 227
 228    qapi_free_UserDefOneList(head);
 229    head = NULL;
 230
 231    /* An empty list is valid */
 232    v = visitor_input_test_init(data, "[]");
 233    visit_type_UserDefOneList(v, NULL, &head, &error_abort);
 234    g_assert(!head);
 235}
 236
 237static void test_visitor_in_any(TestInputVisitorData *data,
 238                                const void *unused)
 239{
 240    QObject *res = NULL;
 241    Visitor *v;
 242    QInt *qint;
 243    QBool *qbool;
 244    QString *qstring;
 245    QDict *qdict;
 246    QObject *qobj;
 247
 248    v = visitor_input_test_init(data, "-42");
 249    visit_type_any(v, NULL, &res, &error_abort);
 250    qint = qobject_to_qint(res);
 251    g_assert(qint);
 252    g_assert_cmpint(qint_get_int(qint), ==, -42);
 253    qobject_decref(res);
 254
 255    v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
 256    visit_type_any(v, NULL, &res, &error_abort);
 257    qdict = qobject_to_qdict(res);
 258    g_assert(qdict && qdict_size(qdict) == 3);
 259    qobj = qdict_get(qdict, "integer");
 260    g_assert(qobj);
 261    qint = qobject_to_qint(qobj);
 262    g_assert(qint);
 263    g_assert_cmpint(qint_get_int(qint), ==, -42);
 264    qobj = qdict_get(qdict, "boolean");
 265    g_assert(qobj);
 266    qbool = qobject_to_qbool(qobj);
 267    g_assert(qbool);
 268    g_assert(qbool_get_bool(qbool) == true);
 269    qobj = qdict_get(qdict, "string");
 270    g_assert(qobj);
 271    qstring = qobject_to_qstring(qobj);
 272    g_assert(qstring);
 273    g_assert_cmpstr(qstring_get_str(qstring), ==, "foo");
 274    qobject_decref(res);
 275}
 276
 277static void test_visitor_in_null(TestInputVisitorData *data,
 278                                 const void *unused)
 279{
 280    Visitor *v;
 281    Error *err = NULL;
 282    char *tmp;
 283
 284    /*
 285     * FIXME: Since QAPI doesn't know the 'null' type yet, we can't
 286     * test visit_type_null() by reading into a QAPI struct then
 287     * checking that it was populated correctly.  The best we can do
 288     * for now is ensure that we consumed null from the input, proven
 289     * by the fact that we can't re-read the key; and that we detect
 290     * when input is not null.
 291     */
 292
 293    v = visitor_input_test_init(data, "{ 'a': null, 'b': '' }");
 294    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 295    visit_type_null(v, "a", &error_abort);
 296    visit_type_str(v, "a", &tmp, &err);
 297    g_assert(!tmp);
 298    error_free_or_abort(&err);
 299    visit_type_null(v, "b", &err);
 300    error_free_or_abort(&err);
 301    visit_check_struct(v, &error_abort);
 302    visit_end_struct(v, NULL);
 303}
 304
 305static void test_visitor_in_union_flat(TestInputVisitorData *data,
 306                                       const void *unused)
 307{
 308    Visitor *v;
 309    UserDefFlatUnion *tmp;
 310    UserDefUnionBase *base;
 311
 312    v = visitor_input_test_init(data,
 313                                "{ 'enum1': 'value1', "
 314                                "'integer': 41, "
 315                                "'string': 'str', "
 316                                "'boolean': true }");
 317
 318    visit_type_UserDefFlatUnion(v, NULL, &tmp, &error_abort);
 319    g_assert_cmpint(tmp->enum1, ==, ENUM_ONE_VALUE1);
 320    g_assert_cmpstr(tmp->string, ==, "str");
 321    g_assert_cmpint(tmp->integer, ==, 41);
 322    g_assert_cmpint(tmp->u.value1.boolean, ==, true);
 323
 324    base = qapi_UserDefFlatUnion_base(tmp);
 325    g_assert(&base->enum1 == &tmp->enum1);
 326
 327    qapi_free_UserDefFlatUnion(tmp);
 328}
 329
 330static void test_visitor_in_alternate(TestInputVisitorData *data,
 331                                      const void *unused)
 332{
 333    Visitor *v;
 334    Error *err = NULL;
 335    UserDefAlternate *tmp;
 336    WrapAlternate *wrap;
 337
 338    v = visitor_input_test_init(data, "42");
 339    visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
 340    g_assert_cmpint(tmp->type, ==, QTYPE_QINT);
 341    g_assert_cmpint(tmp->u.i, ==, 42);
 342    qapi_free_UserDefAlternate(tmp);
 343
 344    v = visitor_input_test_init(data, "'string'");
 345    visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
 346    g_assert_cmpint(tmp->type, ==, QTYPE_QSTRING);
 347    g_assert_cmpstr(tmp->u.s, ==, "string");
 348    qapi_free_UserDefAlternate(tmp);
 349
 350    v = visitor_input_test_init(data, "{'integer':1, 'string':'str', "
 351                                "'enum1':'value1', 'boolean':true}");
 352    visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
 353    g_assert_cmpint(tmp->type, ==, QTYPE_QDICT);
 354    g_assert_cmpint(tmp->u.udfu.integer, ==, 1);
 355    g_assert_cmpstr(tmp->u.udfu.string, ==, "str");
 356    g_assert_cmpint(tmp->u.udfu.enum1, ==, ENUM_ONE_VALUE1);
 357    g_assert_cmpint(tmp->u.udfu.u.value1.boolean, ==, true);
 358    g_assert_cmpint(tmp->u.udfu.u.value1.has_a_b, ==, false);
 359    qapi_free_UserDefAlternate(tmp);
 360
 361    v = visitor_input_test_init(data, "false");
 362    visit_type_UserDefAlternate(v, NULL, &tmp, &err);
 363    error_free_or_abort(&err);
 364    qapi_free_UserDefAlternate(tmp);
 365
 366    v = visitor_input_test_init(data, "{ 'alt': 42 }");
 367    visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
 368    g_assert_cmpint(wrap->alt->type, ==, QTYPE_QINT);
 369    g_assert_cmpint(wrap->alt->u.i, ==, 42);
 370    qapi_free_WrapAlternate(wrap);
 371
 372    v = visitor_input_test_init(data, "{ 'alt': 'string' }");
 373    visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
 374    g_assert_cmpint(wrap->alt->type, ==, QTYPE_QSTRING);
 375    g_assert_cmpstr(wrap->alt->u.s, ==, "string");
 376    qapi_free_WrapAlternate(wrap);
 377
 378    v = visitor_input_test_init(data, "{ 'alt': {'integer':1, 'string':'str', "
 379                                "'enum1':'value1', 'boolean':true} }");
 380    visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
 381    g_assert_cmpint(wrap->alt->type, ==, QTYPE_QDICT);
 382    g_assert_cmpint(wrap->alt->u.udfu.integer, ==, 1);
 383    g_assert_cmpstr(wrap->alt->u.udfu.string, ==, "str");
 384    g_assert_cmpint(wrap->alt->u.udfu.enum1, ==, ENUM_ONE_VALUE1);
 385    g_assert_cmpint(wrap->alt->u.udfu.u.value1.boolean, ==, true);
 386    g_assert_cmpint(wrap->alt->u.udfu.u.value1.has_a_b, ==, false);
 387    qapi_free_WrapAlternate(wrap);
 388}
 389
 390static void test_visitor_in_alternate_number(TestInputVisitorData *data,
 391                                             const void *unused)
 392{
 393    Visitor *v;
 394    Error *err = NULL;
 395    AltStrBool *asb;
 396    AltStrNum *asn;
 397    AltNumStr *ans;
 398    AltStrInt *asi;
 399    AltIntNum *ain;
 400    AltNumInt *ani;
 401
 402    /* Parsing an int */
 403
 404    v = visitor_input_test_init(data, "42");
 405    visit_type_AltStrBool(v, NULL, &asb, &err);
 406    error_free_or_abort(&err);
 407    qapi_free_AltStrBool(asb);
 408
 409    v = visitor_input_test_init(data, "42");
 410    visit_type_AltStrNum(v, NULL, &asn, &error_abort);
 411    g_assert_cmpint(asn->type, ==, QTYPE_QFLOAT);
 412    g_assert_cmpfloat(asn->u.n, ==, 42);
 413    qapi_free_AltStrNum(asn);
 414
 415    v = visitor_input_test_init(data, "42");
 416    visit_type_AltNumStr(v, NULL, &ans, &error_abort);
 417    g_assert_cmpint(ans->type, ==, QTYPE_QFLOAT);
 418    g_assert_cmpfloat(ans->u.n, ==, 42);
 419    qapi_free_AltNumStr(ans);
 420
 421    v = visitor_input_test_init(data, "42");
 422    visit_type_AltStrInt(v, NULL, &asi, &error_abort);
 423    g_assert_cmpint(asi->type, ==, QTYPE_QINT);
 424    g_assert_cmpint(asi->u.i, ==, 42);
 425    qapi_free_AltStrInt(asi);
 426
 427    v = visitor_input_test_init(data, "42");
 428    visit_type_AltIntNum(v, NULL, &ain, &error_abort);
 429    g_assert_cmpint(ain->type, ==, QTYPE_QINT);
 430    g_assert_cmpint(ain->u.i, ==, 42);
 431    qapi_free_AltIntNum(ain);
 432
 433    v = visitor_input_test_init(data, "42");
 434    visit_type_AltNumInt(v, NULL, &ani, &error_abort);
 435    g_assert_cmpint(ani->type, ==, QTYPE_QINT);
 436    g_assert_cmpint(ani->u.i, ==, 42);
 437    qapi_free_AltNumInt(ani);
 438
 439    /* Parsing a double */
 440
 441    v = visitor_input_test_init(data, "42.5");
 442    visit_type_AltStrBool(v, NULL, &asb, &err);
 443    error_free_or_abort(&err);
 444    qapi_free_AltStrBool(asb);
 445
 446    v = visitor_input_test_init(data, "42.5");
 447    visit_type_AltStrNum(v, NULL, &asn, &error_abort);
 448    g_assert_cmpint(asn->type, ==, QTYPE_QFLOAT);
 449    g_assert_cmpfloat(asn->u.n, ==, 42.5);
 450    qapi_free_AltStrNum(asn);
 451
 452    v = visitor_input_test_init(data, "42.5");
 453    visit_type_AltNumStr(v, NULL, &ans, &error_abort);
 454    g_assert_cmpint(ans->type, ==, QTYPE_QFLOAT);
 455    g_assert_cmpfloat(ans->u.n, ==, 42.5);
 456    qapi_free_AltNumStr(ans);
 457
 458    v = visitor_input_test_init(data, "42.5");
 459    visit_type_AltStrInt(v, NULL, &asi, &err);
 460    error_free_or_abort(&err);
 461    qapi_free_AltStrInt(asi);
 462
 463    v = visitor_input_test_init(data, "42.5");
 464    visit_type_AltIntNum(v, NULL, &ain, &error_abort);
 465    g_assert_cmpint(ain->type, ==, QTYPE_QFLOAT);
 466    g_assert_cmpfloat(ain->u.n, ==, 42.5);
 467    qapi_free_AltIntNum(ain);
 468
 469    v = visitor_input_test_init(data, "42.5");
 470    visit_type_AltNumInt(v, NULL, &ani, &error_abort);
 471    g_assert_cmpint(ani->type, ==, QTYPE_QFLOAT);
 472    g_assert_cmpfloat(ani->u.n, ==, 42.5);
 473    qapi_free_AltNumInt(ani);
 474}
 475
 476static void test_native_list_integer_helper(TestInputVisitorData *data,
 477                                            const void *unused,
 478                                            UserDefNativeListUnionKind kind)
 479{
 480    UserDefNativeListUnion *cvalue = NULL;
 481    Visitor *v;
 482    GString *gstr_list = g_string_new("");
 483    GString *gstr_union = g_string_new("");
 484    int i;
 485
 486    for (i = 0; i < 32; i++) {
 487        g_string_append_printf(gstr_list, "%d", i);
 488        if (i != 31) {
 489            g_string_append(gstr_list, ", ");
 490        }
 491    }
 492    g_string_append_printf(gstr_union,  "{ 'type': '%s', 'data': [ %s ] }",
 493                           UserDefNativeListUnionKind_lookup[kind],
 494                           gstr_list->str);
 495    v = visitor_input_test_init_raw(data,  gstr_union->str);
 496
 497    visit_type_UserDefNativeListUnion(v, NULL, &cvalue, &error_abort);
 498    g_assert(cvalue != NULL);
 499    g_assert_cmpint(cvalue->type, ==, kind);
 500
 501    switch (kind) {
 502    case USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER: {
 503        intList *elem = NULL;
 504        for (i = 0, elem = cvalue->u.integer.data;
 505             elem; elem = elem->next, i++) {
 506            g_assert_cmpint(elem->value, ==, i);
 507        }
 508        break;
 509    }
 510    case USER_DEF_NATIVE_LIST_UNION_KIND_S8: {
 511        int8List *elem = NULL;
 512        for (i = 0, elem = cvalue->u.s8.data; elem; elem = elem->next, i++) {
 513            g_assert_cmpint(elem->value, ==, i);
 514        }
 515        break;
 516    }
 517    case USER_DEF_NATIVE_LIST_UNION_KIND_S16: {
 518        int16List *elem = NULL;
 519        for (i = 0, elem = cvalue->u.s16.data; elem; elem = elem->next, i++) {
 520            g_assert_cmpint(elem->value, ==, i);
 521        }
 522        break;
 523    }
 524    case USER_DEF_NATIVE_LIST_UNION_KIND_S32: {
 525        int32List *elem = NULL;
 526        for (i = 0, elem = cvalue->u.s32.data; elem; elem = elem->next, i++) {
 527            g_assert_cmpint(elem->value, ==, i);
 528        }
 529        break;
 530    }
 531    case USER_DEF_NATIVE_LIST_UNION_KIND_S64: {
 532        int64List *elem = NULL;
 533        for (i = 0, elem = cvalue->u.s64.data; elem; elem = elem->next, i++) {
 534            g_assert_cmpint(elem->value, ==, i);
 535        }
 536        break;
 537    }
 538    case USER_DEF_NATIVE_LIST_UNION_KIND_U8: {
 539        uint8List *elem = NULL;
 540        for (i = 0, elem = cvalue->u.u8.data; elem; elem = elem->next, i++) {
 541            g_assert_cmpint(elem->value, ==, i);
 542        }
 543        break;
 544    }
 545    case USER_DEF_NATIVE_LIST_UNION_KIND_U16: {
 546        uint16List *elem = NULL;
 547        for (i = 0, elem = cvalue->u.u16.data; elem; elem = elem->next, i++) {
 548            g_assert_cmpint(elem->value, ==, i);
 549        }
 550        break;
 551    }
 552    case USER_DEF_NATIVE_LIST_UNION_KIND_U32: {
 553        uint32List *elem = NULL;
 554        for (i = 0, elem = cvalue->u.u32.data; elem; elem = elem->next, i++) {
 555            g_assert_cmpint(elem->value, ==, i);
 556        }
 557        break;
 558    }
 559    case USER_DEF_NATIVE_LIST_UNION_KIND_U64: {
 560        uint64List *elem = NULL;
 561        for (i = 0, elem = cvalue->u.u64.data; elem; elem = elem->next, i++) {
 562            g_assert_cmpint(elem->value, ==, i);
 563        }
 564        break;
 565    }
 566    default:
 567        g_assert_not_reached();
 568    }
 569
 570    g_string_free(gstr_union, true);
 571    g_string_free(gstr_list, true);
 572    qapi_free_UserDefNativeListUnion(cvalue);
 573}
 574
 575static void test_visitor_in_native_list_int(TestInputVisitorData *data,
 576                                            const void *unused)
 577{
 578    test_native_list_integer_helper(data, unused,
 579                                    USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER);
 580}
 581
 582static void test_visitor_in_native_list_int8(TestInputVisitorData *data,
 583                                             const void *unused)
 584{
 585    test_native_list_integer_helper(data, unused,
 586                                    USER_DEF_NATIVE_LIST_UNION_KIND_S8);
 587}
 588
 589static void test_visitor_in_native_list_int16(TestInputVisitorData *data,
 590                                              const void *unused)
 591{
 592    test_native_list_integer_helper(data, unused,
 593                                    USER_DEF_NATIVE_LIST_UNION_KIND_S16);
 594}
 595
 596static void test_visitor_in_native_list_int32(TestInputVisitorData *data,
 597                                              const void *unused)
 598{
 599    test_native_list_integer_helper(data, unused,
 600                                    USER_DEF_NATIVE_LIST_UNION_KIND_S32);
 601}
 602
 603static void test_visitor_in_native_list_int64(TestInputVisitorData *data,
 604                                              const void *unused)
 605{
 606    test_native_list_integer_helper(data, unused,
 607                                    USER_DEF_NATIVE_LIST_UNION_KIND_S64);
 608}
 609
 610static void test_visitor_in_native_list_uint8(TestInputVisitorData *data,
 611                                             const void *unused)
 612{
 613    test_native_list_integer_helper(data, unused,
 614                                    USER_DEF_NATIVE_LIST_UNION_KIND_U8);
 615}
 616
 617static void test_visitor_in_native_list_uint16(TestInputVisitorData *data,
 618                                               const void *unused)
 619{
 620    test_native_list_integer_helper(data, unused,
 621                                    USER_DEF_NATIVE_LIST_UNION_KIND_U16);
 622}
 623
 624static void test_visitor_in_native_list_uint32(TestInputVisitorData *data,
 625                                               const void *unused)
 626{
 627    test_native_list_integer_helper(data, unused,
 628                                    USER_DEF_NATIVE_LIST_UNION_KIND_U32);
 629}
 630
 631static void test_visitor_in_native_list_uint64(TestInputVisitorData *data,
 632                                               const void *unused)
 633{
 634    test_native_list_integer_helper(data, unused,
 635                                    USER_DEF_NATIVE_LIST_UNION_KIND_U64);
 636}
 637
 638static void test_visitor_in_native_list_bool(TestInputVisitorData *data,
 639                                            const void *unused)
 640{
 641    UserDefNativeListUnion *cvalue = NULL;
 642    boolList *elem = NULL;
 643    Visitor *v;
 644    GString *gstr_list = g_string_new("");
 645    GString *gstr_union = g_string_new("");
 646    int i;
 647
 648    for (i = 0; i < 32; i++) {
 649        g_string_append_printf(gstr_list, "%s",
 650                               (i % 3 == 0) ? "true" : "false");
 651        if (i != 31) {
 652            g_string_append(gstr_list, ", ");
 653        }
 654    }
 655    g_string_append_printf(gstr_union,  "{ 'type': 'boolean', 'data': [ %s ] }",
 656                           gstr_list->str);
 657    v = visitor_input_test_init_raw(data,  gstr_union->str);
 658
 659    visit_type_UserDefNativeListUnion(v, NULL, &cvalue, &error_abort);
 660    g_assert(cvalue != NULL);
 661    g_assert_cmpint(cvalue->type, ==, USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN);
 662
 663    for (i = 0, elem = cvalue->u.boolean.data; elem; elem = elem->next, i++) {
 664        g_assert_cmpint(elem->value, ==, (i % 3 == 0) ? 1 : 0);
 665    }
 666
 667    g_string_free(gstr_union, true);
 668    g_string_free(gstr_list, true);
 669    qapi_free_UserDefNativeListUnion(cvalue);
 670}
 671
 672static void test_visitor_in_native_list_string(TestInputVisitorData *data,
 673                                               const void *unused)
 674{
 675    UserDefNativeListUnion *cvalue = NULL;
 676    strList *elem = NULL;
 677    Visitor *v;
 678    GString *gstr_list = g_string_new("");
 679    GString *gstr_union = g_string_new("");
 680    int i;
 681
 682    for (i = 0; i < 32; i++) {
 683        g_string_append_printf(gstr_list, "'%d'", i);
 684        if (i != 31) {
 685            g_string_append(gstr_list, ", ");
 686        }
 687    }
 688    g_string_append_printf(gstr_union,  "{ 'type': 'string', 'data': [ %s ] }",
 689                           gstr_list->str);
 690    v = visitor_input_test_init_raw(data,  gstr_union->str);
 691
 692    visit_type_UserDefNativeListUnion(v, NULL, &cvalue, &error_abort);
 693    g_assert(cvalue != NULL);
 694    g_assert_cmpint(cvalue->type, ==, USER_DEF_NATIVE_LIST_UNION_KIND_STRING);
 695
 696    for (i = 0, elem = cvalue->u.string.data; elem; elem = elem->next, i++) {
 697        gchar str[8];
 698        sprintf(str, "%d", i);
 699        g_assert_cmpstr(elem->value, ==, str);
 700    }
 701
 702    g_string_free(gstr_union, true);
 703    g_string_free(gstr_list, true);
 704    qapi_free_UserDefNativeListUnion(cvalue);
 705}
 706
 707#define DOUBLE_STR_MAX 16
 708
 709static void test_visitor_in_native_list_number(TestInputVisitorData *data,
 710                                               const void *unused)
 711{
 712    UserDefNativeListUnion *cvalue = NULL;
 713    numberList *elem = NULL;
 714    Visitor *v;
 715    GString *gstr_list = g_string_new("");
 716    GString *gstr_union = g_string_new("");
 717    int i;
 718
 719    for (i = 0; i < 32; i++) {
 720        g_string_append_printf(gstr_list, "%f", (double)i / 3);
 721        if (i != 31) {
 722            g_string_append(gstr_list, ", ");
 723        }
 724    }
 725    g_string_append_printf(gstr_union,  "{ 'type': 'number', 'data': [ %s ] }",
 726                           gstr_list->str);
 727    v = visitor_input_test_init_raw(data,  gstr_union->str);
 728
 729    visit_type_UserDefNativeListUnion(v, NULL, &cvalue, &error_abort);
 730    g_assert(cvalue != NULL);
 731    g_assert_cmpint(cvalue->type, ==, USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER);
 732
 733    for (i = 0, elem = cvalue->u.number.data; elem; elem = elem->next, i++) {
 734        GString *double_expected = g_string_new("");
 735        GString *double_actual = g_string_new("");
 736
 737        g_string_printf(double_expected, "%.6f", (double)i / 3);
 738        g_string_printf(double_actual, "%.6f", elem->value);
 739        g_assert_cmpstr(double_expected->str, ==, double_actual->str);
 740
 741        g_string_free(double_expected, true);
 742        g_string_free(double_actual, true);
 743    }
 744
 745    g_string_free(gstr_union, true);
 746    g_string_free(gstr_list, true);
 747    qapi_free_UserDefNativeListUnion(cvalue);
 748}
 749
 750static void input_visitor_test_add(const char *testpath,
 751                                   const void *user_data,
 752                                   void (*test_func)(TestInputVisitorData *data,
 753                                                     const void *user_data))
 754{
 755    g_test_add(testpath, TestInputVisitorData, user_data, NULL, test_func,
 756               visitor_input_teardown);
 757}
 758
 759static void test_visitor_in_errors(TestInputVisitorData *data,
 760                                   const void *unused)
 761{
 762    TestStruct *p = NULL;
 763    Error *err = NULL;
 764    Visitor *v;
 765    strList *q = NULL;
 766    UserDefTwo *r = NULL;
 767    WrapAlternate *s = NULL;
 768
 769    v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', "
 770                                "'string': -42 }");
 771
 772    visit_type_TestStruct(v, NULL, &p, &err);
 773    error_free_or_abort(&err);
 774    g_assert(!p);
 775
 776    v = visitor_input_test_init(data, "[ '1', '2', false, '3' ]");
 777    visit_type_strList(v, NULL, &q, &err);
 778    error_free_or_abort(&err);
 779    assert(!q);
 780
 781    v = visitor_input_test_init(data, "{ 'str':'hi' }");
 782    visit_type_UserDefTwo(v, NULL, &r, &err);
 783    error_free_or_abort(&err);
 784    assert(!r);
 785
 786    v = visitor_input_test_init(data, "{ }");
 787    visit_type_WrapAlternate(v, NULL, &s, &err);
 788    error_free_or_abort(&err);
 789    assert(!s);
 790}
 791
 792static void test_visitor_in_wrong_type(TestInputVisitorData *data,
 793                                       const void *unused)
 794{
 795    TestStruct *p = NULL;
 796    Visitor *v;
 797    strList *q = NULL;
 798    int64_t i;
 799    Error *err = NULL;
 800
 801    /* Make sure arrays and structs cannot be confused */
 802
 803    v = visitor_input_test_init(data, "[]");
 804    visit_type_TestStruct(v, NULL, &p, &err);
 805    error_free_or_abort(&err);
 806    g_assert(!p);
 807
 808    v = visitor_input_test_init(data, "{}");
 809    visit_type_strList(v, NULL, &q, &err);
 810    error_free_or_abort(&err);
 811    assert(!q);
 812
 813    /* Make sure primitives and struct cannot be confused */
 814
 815    v = visitor_input_test_init(data, "1");
 816    visit_type_TestStruct(v, NULL, &p, &err);
 817    error_free_or_abort(&err);
 818    g_assert(!p);
 819
 820    v = visitor_input_test_init(data, "{}");
 821    visit_type_int(v, NULL, &i, &err);
 822    error_free_or_abort(&err);
 823
 824    /* Make sure primitives and arrays cannot be confused */
 825
 826    v = visitor_input_test_init(data, "1");
 827    visit_type_strList(v, NULL, &q, &err);
 828    error_free_or_abort(&err);
 829    assert(!q);
 830
 831    v = visitor_input_test_init(data, "[]");
 832    visit_type_int(v, NULL, &i, &err);
 833    error_free_or_abort(&err);
 834}
 835
 836int main(int argc, char **argv)
 837{
 838    g_test_init(&argc, &argv, NULL);
 839
 840    input_visitor_test_add("/visitor/input/int",
 841                           NULL, test_visitor_in_int);
 842    input_visitor_test_add("/visitor/input/int_overflow",
 843                           NULL, test_visitor_in_int_overflow);
 844    input_visitor_test_add("/visitor/input/bool",
 845                           NULL, test_visitor_in_bool);
 846    input_visitor_test_add("/visitor/input/number",
 847                           NULL, test_visitor_in_number);
 848    input_visitor_test_add("/visitor/input/string",
 849                           NULL, test_visitor_in_string);
 850    input_visitor_test_add("/visitor/input/enum",
 851                           NULL, test_visitor_in_enum);
 852    input_visitor_test_add("/visitor/input/struct",
 853                           NULL, test_visitor_in_struct);
 854    input_visitor_test_add("/visitor/input/struct-nested",
 855                           NULL, test_visitor_in_struct_nested);
 856    input_visitor_test_add("/visitor/input/list",
 857                           NULL, test_visitor_in_list);
 858    input_visitor_test_add("/visitor/input/any",
 859                           NULL, test_visitor_in_any);
 860    input_visitor_test_add("/visitor/input/null",
 861                           NULL, test_visitor_in_null);
 862    input_visitor_test_add("/visitor/input/union-flat",
 863                           NULL, test_visitor_in_union_flat);
 864    input_visitor_test_add("/visitor/input/alternate",
 865                           NULL, test_visitor_in_alternate);
 866    input_visitor_test_add("/visitor/input/errors",
 867                           NULL, test_visitor_in_errors);
 868    input_visitor_test_add("/visitor/input/wrong-type",
 869                           NULL, test_visitor_in_wrong_type);
 870    input_visitor_test_add("/visitor/input/alternate-number",
 871                           NULL, test_visitor_in_alternate_number);
 872    input_visitor_test_add("/visitor/input/native_list/int",
 873                           NULL, test_visitor_in_native_list_int);
 874    input_visitor_test_add("/visitor/input/native_list/int8",
 875                           NULL, test_visitor_in_native_list_int8);
 876    input_visitor_test_add("/visitor/input/native_list/int16",
 877                           NULL, test_visitor_in_native_list_int16);
 878    input_visitor_test_add("/visitor/input/native_list/int32",
 879                           NULL, test_visitor_in_native_list_int32);
 880    input_visitor_test_add("/visitor/input/native_list/int64",
 881                           NULL, test_visitor_in_native_list_int64);
 882    input_visitor_test_add("/visitor/input/native_list/uint8",
 883                           NULL, test_visitor_in_native_list_uint8);
 884    input_visitor_test_add("/visitor/input/native_list/uint16",
 885                           NULL, test_visitor_in_native_list_uint16);
 886    input_visitor_test_add("/visitor/input/native_list/uint32",
 887                           NULL, test_visitor_in_native_list_uint32);
 888    input_visitor_test_add("/visitor/input/native_list/uint64",
 889                           NULL, test_visitor_in_native_list_uint64);
 890    input_visitor_test_add("/visitor/input/native_list/bool",
 891                           NULL, test_visitor_in_native_list_bool);
 892    input_visitor_test_add("/visitor/input/native_list/str",
 893                           NULL, test_visitor_in_native_list_string);
 894    input_visitor_test_add("/visitor/input/native_list/number",
 895                           NULL, test_visitor_in_native_list_number);
 896
 897    g_test_run();
 898
 899    return 0;
 900}
 901