qemu/tests/test-keyval.c
<<
>>
Prefs
   1/*
   2 * Unit tests for parsing of KEY=VALUE,... strings
   3 *
   4 * Copyright (C) 2017 Red Hat Inc.
   5 *
   6 * Authors:
   7 *  Markus Armbruster <armbru@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#include "qemu/units.h"
  15#include "qapi/error.h"
  16#include "qapi/qmp/qdict.h"
  17#include "qapi/qmp/qlist.h"
  18#include "qapi/qmp/qstring.h"
  19#include "qapi/qobject-input-visitor.h"
  20#include "test-qapi-visit.h"
  21#include "qemu/cutils.h"
  22#include "qemu/option.h"
  23
  24static void test_keyval_parse(void)
  25{
  26    Error *err = NULL;
  27    QDict *qdict, *sub_qdict;
  28    char long_key[129];
  29    char *params;
  30
  31    /* Nothing */
  32    qdict = keyval_parse("", NULL, &error_abort);
  33    g_assert_cmpuint(qdict_size(qdict), ==, 0);
  34    qobject_unref(qdict);
  35
  36    /* Empty key (qemu_opts_parse() accepts this) */
  37    qdict = keyval_parse("=val", NULL, &err);
  38    error_free_or_abort(&err);
  39    g_assert(!qdict);
  40
  41    /* Empty key fragment */
  42    qdict = keyval_parse(".", NULL, &err);
  43    error_free_or_abort(&err);
  44    g_assert(!qdict);
  45    qdict = keyval_parse("key.", NULL, &err);
  46    error_free_or_abort(&err);
  47    g_assert(!qdict);
  48
  49    /* Invalid non-empty key (qemu_opts_parse() doesn't care) */
  50    qdict = keyval_parse("7up=val", NULL, &err);
  51    error_free_or_abort(&err);
  52    g_assert(!qdict);
  53
  54    /* Overlong key */
  55    memset(long_key, 'a', 127);
  56    long_key[127] = 'z';
  57    long_key[128] = 0;
  58    params = g_strdup_printf("k.%s=v", long_key);
  59    qdict = keyval_parse(params + 2, NULL, &err);
  60    error_free_or_abort(&err);
  61    g_assert(!qdict);
  62
  63    /* Overlong key fragment */
  64    qdict = keyval_parse(params, NULL, &err);
  65    error_free_or_abort(&err);
  66    g_assert(!qdict);
  67    g_free(params);
  68
  69    /* Long key (qemu_opts_parse() accepts and truncates silently) */
  70    params = g_strdup_printf("k.%s=v", long_key + 1);
  71    qdict = keyval_parse(params + 2, NULL, &error_abort);
  72    g_assert_cmpuint(qdict_size(qdict), ==, 1);
  73    g_assert_cmpstr(qdict_get_try_str(qdict, long_key + 1), ==, "v");
  74    qobject_unref(qdict);
  75
  76    /* Long key fragment */
  77    qdict = keyval_parse(params, NULL, &error_abort);
  78    g_assert_cmpuint(qdict_size(qdict), ==, 1);
  79    sub_qdict = qdict_get_qdict(qdict, "k");
  80    g_assert(sub_qdict);
  81    g_assert_cmpuint(qdict_size(sub_qdict), ==, 1);
  82    g_assert_cmpstr(qdict_get_try_str(sub_qdict, long_key + 1), ==, "v");
  83    qobject_unref(qdict);
  84    g_free(params);
  85
  86    /* Crap after valid key */
  87    qdict = keyval_parse("key[0]=val", NULL, &err);
  88    error_free_or_abort(&err);
  89    g_assert(!qdict);
  90
  91    /* Multiple keys, last one wins */
  92    qdict = keyval_parse("a=1,b=2,,x,a=3", NULL, &error_abort);
  93    g_assert_cmpuint(qdict_size(qdict), ==, 2);
  94    g_assert_cmpstr(qdict_get_try_str(qdict, "a"), ==, "3");
  95    g_assert_cmpstr(qdict_get_try_str(qdict, "b"), ==, "2,x");
  96    qobject_unref(qdict);
  97
  98    /* Even when it doesn't in qemu_opts_parse() */
  99    qdict = keyval_parse("id=foo,id=bar", NULL, &error_abort);
 100    g_assert_cmpuint(qdict_size(qdict), ==, 1);
 101    g_assert_cmpstr(qdict_get_try_str(qdict, "id"), ==, "bar");
 102    qobject_unref(qdict);
 103
 104    /* Dotted keys */
 105    qdict = keyval_parse("a.b.c=1,a.b.c=2,d=3", NULL, &error_abort);
 106    g_assert_cmpuint(qdict_size(qdict), ==, 2);
 107    sub_qdict = qdict_get_qdict(qdict, "a");
 108    g_assert(sub_qdict);
 109    g_assert_cmpuint(qdict_size(sub_qdict), ==, 1);
 110    sub_qdict = qdict_get_qdict(sub_qdict, "b");
 111    g_assert(sub_qdict);
 112    g_assert_cmpuint(qdict_size(sub_qdict), ==, 1);
 113    g_assert_cmpstr(qdict_get_try_str(sub_qdict, "c"), ==, "2");
 114    g_assert_cmpstr(qdict_get_try_str(qdict, "d"), ==, "3");
 115    qobject_unref(qdict);
 116
 117    /* Inconsistent dotted keys */
 118    qdict = keyval_parse("a.b=1,a=2", NULL, &err);
 119    error_free_or_abort(&err);
 120    g_assert(!qdict);
 121    qdict = keyval_parse("a.b=1,a.b.c=2", NULL, &err);
 122    error_free_or_abort(&err);
 123    g_assert(!qdict);
 124
 125    /* Trailing comma is ignored */
 126    qdict = keyval_parse("x=y,", NULL, &error_abort);
 127    g_assert_cmpuint(qdict_size(qdict), ==, 1);
 128    g_assert_cmpstr(qdict_get_try_str(qdict, "x"), ==, "y");
 129    qobject_unref(qdict);
 130
 131    /* Except when it isn't */
 132    qdict = keyval_parse(",", NULL, &err);
 133    error_free_or_abort(&err);
 134    g_assert(!qdict);
 135
 136    /* Value containing ,id= not misinterpreted as qemu_opts_parse() does */
 137    qdict = keyval_parse("x=,,id=bar", NULL, &error_abort);
 138    g_assert_cmpuint(qdict_size(qdict), ==, 1);
 139    g_assert_cmpstr(qdict_get_try_str(qdict, "x"), ==, ",id=bar");
 140    qobject_unref(qdict);
 141
 142    /* Anti-social ID is left to caller (qemu_opts_parse() rejects it) */
 143    qdict = keyval_parse("id=666", NULL, &error_abort);
 144    g_assert_cmpuint(qdict_size(qdict), ==, 1);
 145    g_assert_cmpstr(qdict_get_try_str(qdict, "id"), ==, "666");
 146    qobject_unref(qdict);
 147
 148    /* Implied value not supported (unlike qemu_opts_parse()) */
 149    qdict = keyval_parse("an,noaus,noaus=", NULL, &err);
 150    error_free_or_abort(&err);
 151    g_assert(!qdict);
 152
 153    /* Implied value, key "no" (qemu_opts_parse(): negated empty key) */
 154    qdict = keyval_parse("no", NULL, &err);
 155    error_free_or_abort(&err);
 156    g_assert(!qdict);
 157
 158    /* Implied key */
 159    qdict = keyval_parse("an,aus=off,noaus=", "implied", &error_abort);
 160    g_assert_cmpuint(qdict_size(qdict), ==, 3);
 161    g_assert_cmpstr(qdict_get_try_str(qdict, "implied"), ==, "an");
 162    g_assert_cmpstr(qdict_get_try_str(qdict, "aus"), ==, "off");
 163    g_assert_cmpstr(qdict_get_try_str(qdict, "noaus"), ==, "");
 164    qobject_unref(qdict);
 165
 166    /* Implied dotted key */
 167    qdict = keyval_parse("val", "eins.zwei", &error_abort);
 168    g_assert_cmpuint(qdict_size(qdict), ==, 1);
 169    sub_qdict = qdict_get_qdict(qdict, "eins");
 170    g_assert(sub_qdict);
 171    g_assert_cmpuint(qdict_size(sub_qdict), ==, 1);
 172    g_assert_cmpstr(qdict_get_try_str(sub_qdict, "zwei"), ==, "val");
 173    qobject_unref(qdict);
 174
 175    /* Implied key with empty value (qemu_opts_parse() accepts this) */
 176    qdict = keyval_parse(",", "implied", &err);
 177    error_free_or_abort(&err);
 178    g_assert(!qdict);
 179
 180    /* Likewise (qemu_opts_parse(): implied key with comma value) */
 181    qdict = keyval_parse(",,,a=1", "implied", &err);
 182    error_free_or_abort(&err);
 183    g_assert(!qdict);
 184
 185    /* Empty key is not an implied key */
 186    qdict = keyval_parse("=val", "implied", &err);
 187    error_free_or_abort(&err);
 188    g_assert(!qdict);
 189}
 190
 191static void check_list012(QList *qlist)
 192{
 193    static const char *expected[] = { "null", "eins", "zwei" };
 194    int i;
 195    QString *qstr;
 196
 197    g_assert(qlist);
 198    for (i = 0; i < ARRAY_SIZE(expected); i++) {
 199        qstr = qobject_to(QString, qlist_pop(qlist));
 200        g_assert(qstr);
 201        g_assert_cmpstr(qstring_get_str(qstr), ==, expected[i]);
 202        qobject_unref(qstr);
 203    }
 204    g_assert(qlist_empty(qlist));
 205}
 206
 207static void test_keyval_parse_list(void)
 208{
 209    Error *err = NULL;
 210    QDict *qdict, *sub_qdict;
 211
 212    /* Root can't be a list */
 213    qdict = keyval_parse("0=1", NULL, &err);
 214    error_free_or_abort(&err);
 215    g_assert(!qdict);
 216
 217    /* List elements need not be in order */
 218    qdict = keyval_parse("list.0=null,list.2=zwei,list.1=eins",
 219                         NULL, &error_abort);
 220    g_assert_cmpint(qdict_size(qdict), ==, 1);
 221    check_list012(qdict_get_qlist(qdict, "list"));
 222    qobject_unref(qdict);
 223
 224    /* Multiple indexes, last one wins */
 225    qdict = keyval_parse("list.1=goner,list.0=null,list.01=eins,list.2=zwei",
 226                         NULL, &error_abort);
 227    g_assert_cmpint(qdict_size(qdict), ==, 1);
 228    check_list012(qdict_get_qlist(qdict, "list"));
 229    qobject_unref(qdict);
 230
 231    /* List at deeper nesting */
 232    qdict = keyval_parse("a.list.1=eins,a.list.00=null,a.list.2=zwei",
 233                         NULL, &error_abort);
 234    g_assert_cmpint(qdict_size(qdict), ==, 1);
 235    sub_qdict = qdict_get_qdict(qdict, "a");
 236    g_assert_cmpint(qdict_size(sub_qdict), ==, 1);
 237    check_list012(qdict_get_qlist(sub_qdict, "list"));
 238    qobject_unref(qdict);
 239
 240    /* Inconsistent dotted keys: both list and dictionary */
 241    qdict = keyval_parse("a.b.c=1,a.b.0=2", NULL, &err);
 242    error_free_or_abort(&err);
 243    g_assert(!qdict);
 244    qdict = keyval_parse("a.0.c=1,a.b.c=2", NULL, &err);
 245    error_free_or_abort(&err);
 246    g_assert(!qdict);
 247
 248    /* Missing list indexes */
 249    qdict = keyval_parse("list.1=lonely", NULL, &err);
 250    error_free_or_abort(&err);
 251    g_assert(!qdict);
 252    qdict = keyval_parse("list.0=null,list.2=eins,list.02=zwei", NULL, &err);
 253    error_free_or_abort(&err);
 254    g_assert(!qdict);
 255}
 256
 257static void test_keyval_visit_bool(void)
 258{
 259    Error *err = NULL;
 260    Visitor *v;
 261    QDict *qdict;
 262    bool b;
 263
 264    qdict = keyval_parse("bool1=on,bool2=off", NULL, &error_abort);
 265    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 266    qobject_unref(qdict);
 267    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 268    visit_type_bool(v, "bool1", &b, &error_abort);
 269    g_assert(b);
 270    visit_type_bool(v, "bool2", &b, &error_abort);
 271    g_assert(!b);
 272    visit_check_struct(v, &error_abort);
 273    visit_end_struct(v, NULL);
 274    visit_free(v);
 275
 276    qdict = keyval_parse("bool1=offer", NULL, &error_abort);
 277    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 278    qobject_unref(qdict);
 279    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 280    visit_type_bool(v, "bool1", &b, &err);
 281    error_free_or_abort(&err);
 282    visit_end_struct(v, NULL);
 283    visit_free(v);
 284}
 285
 286static void test_keyval_visit_number(void)
 287{
 288    Error *err = NULL;
 289    Visitor *v;
 290    QDict *qdict;
 291    uint64_t u;
 292
 293    /* Lower limit zero */
 294    qdict = keyval_parse("number1=0", NULL, &error_abort);
 295    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 296    qobject_unref(qdict);
 297    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 298    visit_type_uint64(v, "number1", &u, &error_abort);
 299    g_assert_cmpuint(u, ==, 0);
 300    visit_check_struct(v, &error_abort);
 301    visit_end_struct(v, NULL);
 302    visit_free(v);
 303
 304    /* Upper limit 2^64-1 */
 305    qdict = keyval_parse("number1=18446744073709551615,number2=-1",
 306                         NULL, &error_abort);
 307    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 308    qobject_unref(qdict);
 309    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 310    visit_type_uint64(v, "number1", &u, &error_abort);
 311    g_assert_cmphex(u, ==, UINT64_MAX);
 312    visit_type_uint64(v, "number2", &u, &error_abort);
 313    g_assert_cmphex(u, ==, UINT64_MAX);
 314    visit_check_struct(v, &error_abort);
 315    visit_end_struct(v, NULL);
 316    visit_free(v);
 317
 318    /* Above upper limit */
 319    qdict = keyval_parse("number1=18446744073709551616",
 320                         NULL, &error_abort);
 321    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 322    qobject_unref(qdict);
 323    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 324    visit_type_uint64(v, "number1", &u, &err);
 325    error_free_or_abort(&err);
 326    visit_end_struct(v, NULL);
 327    visit_free(v);
 328
 329    /* Below lower limit */
 330    qdict = keyval_parse("number1=-18446744073709551616",
 331                         NULL, &error_abort);
 332    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 333    qobject_unref(qdict);
 334    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 335    visit_type_uint64(v, "number1", &u, &err);
 336    error_free_or_abort(&err);
 337    visit_end_struct(v, NULL);
 338    visit_free(v);
 339
 340    /* Hex and octal */
 341    qdict = keyval_parse("number1=0x2a,number2=052",
 342                         NULL, &error_abort);
 343    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 344    qobject_unref(qdict);
 345    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 346    visit_type_uint64(v, "number1", &u, &error_abort);
 347    g_assert_cmpuint(u, ==, 42);
 348    visit_type_uint64(v, "number2", &u, &error_abort);
 349    g_assert_cmpuint(u, ==, 42);
 350    visit_check_struct(v, &error_abort);
 351    visit_end_struct(v, NULL);
 352    visit_free(v);
 353
 354    /* Trailing crap */
 355    qdict = keyval_parse("number1=3.14,number2=08",
 356                         NULL, &error_abort);
 357    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 358    qobject_unref(qdict);
 359    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 360    visit_type_uint64(v, "number1", &u, &err);
 361    error_free_or_abort(&err);
 362    visit_type_uint64(v, "number2", &u, &err);
 363    error_free_or_abort(&err);
 364    visit_end_struct(v, NULL);
 365    visit_free(v);
 366}
 367
 368static void test_keyval_visit_size(void)
 369{
 370    Error *err = NULL;
 371    Visitor *v;
 372    QDict *qdict;
 373    uint64_t sz;
 374
 375    /* Lower limit zero */
 376    qdict = keyval_parse("sz1=0", NULL, &error_abort);
 377    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 378    qobject_unref(qdict);
 379    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 380    visit_type_size(v, "sz1", &sz, &error_abort);
 381    g_assert_cmpuint(sz, ==, 0);
 382    visit_check_struct(v, &error_abort);
 383    visit_end_struct(v, NULL);
 384    visit_free(v);
 385
 386    /* Note: precision is 53 bits since we're parsing with strtod() */
 387
 388    /* Around limit of precision: 2^53-1, 2^53, 2^53+1 */
 389    qdict = keyval_parse("sz1=9007199254740991,"
 390                         "sz2=9007199254740992,"
 391                         "sz3=9007199254740993",
 392                         NULL, &error_abort);
 393    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 394    qobject_unref(qdict);
 395    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 396    visit_type_size(v, "sz1", &sz, &error_abort);
 397    g_assert_cmphex(sz, ==, 0x1fffffffffffff);
 398    visit_type_size(v, "sz2", &sz, &error_abort);
 399    g_assert_cmphex(sz, ==, 0x20000000000000);
 400    visit_type_size(v, "sz3", &sz, &error_abort);
 401    g_assert_cmphex(sz, ==, 0x20000000000000);
 402    visit_check_struct(v, &error_abort);
 403    visit_end_struct(v, NULL);
 404    visit_free(v);
 405
 406    /* Close to signed upper limit 0x7ffffffffffffc00 (53 msbs set) */
 407    qdict = keyval_parse("sz1=9223372036854774784," /* 7ffffffffffffc00 */
 408                         "sz2=9223372036854775295", /* 7ffffffffffffdff */
 409                         NULL, &error_abort);
 410    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 411    qobject_unref(qdict);
 412    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 413    visit_type_size(v, "sz1", &sz, &error_abort);
 414    g_assert_cmphex(sz, ==, 0x7ffffffffffffc00);
 415    visit_type_size(v, "sz2", &sz, &error_abort);
 416    g_assert_cmphex(sz, ==, 0x7ffffffffffffc00);
 417    visit_check_struct(v, &error_abort);
 418    visit_end_struct(v, NULL);
 419    visit_free(v);
 420
 421    /* Close to actual upper limit 0xfffffffffffff800 (53 msbs set) */
 422    qdict = keyval_parse("sz1=18446744073709549568," /* fffffffffffff800 */
 423                         "sz2=18446744073709550591", /* fffffffffffffbff */
 424                         NULL, &error_abort);
 425    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 426    qobject_unref(qdict);
 427    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 428    visit_type_size(v, "sz1", &sz, &error_abort);
 429    g_assert_cmphex(sz, ==, 0xfffffffffffff800);
 430    visit_type_size(v, "sz2", &sz, &error_abort);
 431    g_assert_cmphex(sz, ==, 0xfffffffffffff800);
 432    visit_check_struct(v, &error_abort);
 433    visit_end_struct(v, NULL);
 434    visit_free(v);
 435
 436    /* Beyond limits */
 437    qdict = keyval_parse("sz1=-1,"
 438                         "sz2=18446744073709550592", /* fffffffffffffc00 */
 439                         NULL, &error_abort);
 440    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 441    qobject_unref(qdict);
 442    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 443    visit_type_size(v, "sz1", &sz, &err);
 444    error_free_or_abort(&err);
 445    visit_type_size(v, "sz2", &sz, &err);
 446    error_free_or_abort(&err);
 447    visit_end_struct(v, NULL);
 448    visit_free(v);
 449
 450    /* Suffixes */
 451    qdict = keyval_parse("sz1=8b,sz2=1.5k,sz3=2M,sz4=0.1G,sz5=16777215T",
 452                         NULL, &error_abort);
 453    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 454    qobject_unref(qdict);
 455    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 456    visit_type_size(v, "sz1", &sz, &error_abort);
 457    g_assert_cmpuint(sz, ==, 8);
 458    visit_type_size(v, "sz2", &sz, &error_abort);
 459    g_assert_cmpuint(sz, ==, 1536);
 460    visit_type_size(v, "sz3", &sz, &error_abort);
 461    g_assert_cmphex(sz, ==, 2 * MiB);
 462    visit_type_size(v, "sz4", &sz, &error_abort);
 463    g_assert_cmphex(sz, ==, GiB / 10);
 464    visit_type_size(v, "sz5", &sz, &error_abort);
 465    g_assert_cmphex(sz, ==, 16777215ULL * TiB);
 466    visit_check_struct(v, &error_abort);
 467    visit_end_struct(v, NULL);
 468    visit_free(v);
 469
 470    /* Beyond limit with suffix */
 471    qdict = keyval_parse("sz1=16777216T", NULL, &error_abort);
 472    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 473    qobject_unref(qdict);
 474    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 475    visit_type_size(v, "sz1", &sz, &err);
 476    error_free_or_abort(&err);
 477    visit_end_struct(v, NULL);
 478    visit_free(v);
 479
 480    /* Trailing crap */
 481    qdict = keyval_parse("sz1=16E,sz2=16Gi", NULL, &error_abort);
 482    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 483    qobject_unref(qdict);
 484    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 485    visit_type_size(v, "sz1", &sz, &err);
 486    error_free_or_abort(&err);
 487    visit_type_size(v, "sz2", &sz, &err);
 488    error_free_or_abort(&err);
 489    visit_end_struct(v, NULL);
 490    visit_free(v);
 491}
 492
 493static void test_keyval_visit_dict(void)
 494{
 495    Error *err = NULL;
 496    Visitor *v;
 497    QDict *qdict;
 498    int64_t i;
 499
 500    qdict = keyval_parse("a.b.c=1,a.b.c=2,d=3", NULL, &error_abort);
 501    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 502    qobject_unref(qdict);
 503    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 504    visit_start_struct(v, "a", NULL, 0, &error_abort);
 505    visit_start_struct(v, "b", NULL, 0, &error_abort);
 506    visit_type_int(v, "c", &i, &error_abort);
 507    g_assert_cmpint(i, ==, 2);
 508    visit_check_struct(v, &error_abort);
 509    visit_end_struct(v, NULL);
 510    visit_check_struct(v, &error_abort);
 511    visit_end_struct(v, NULL);
 512    visit_type_int(v, "d", &i, &error_abort);
 513    g_assert_cmpint(i, ==, 3);
 514    visit_check_struct(v, &error_abort);
 515    visit_end_struct(v, NULL);
 516    visit_free(v);
 517
 518    qdict = keyval_parse("a.b=", NULL, &error_abort);
 519    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 520    qobject_unref(qdict);
 521    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 522    visit_start_struct(v, "a", NULL, 0, &error_abort);
 523    visit_type_int(v, "c", &i, &err);   /* a.c missing */
 524    error_free_or_abort(&err);
 525    visit_check_struct(v, &err);
 526    error_free_or_abort(&err);          /* a.b unexpected */
 527    visit_end_struct(v, NULL);
 528    visit_check_struct(v, &error_abort);
 529    visit_end_struct(v, NULL);
 530    visit_free(v);
 531}
 532
 533static void test_keyval_visit_list(void)
 534{
 535    Error *err = NULL;
 536    Visitor *v;
 537    QDict *qdict;
 538    char *s;
 539
 540    qdict = keyval_parse("a.0=,a.1=I,a.2.0=II", NULL, &error_abort);
 541    /* TODO empty list */
 542    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 543    qobject_unref(qdict);
 544    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 545    visit_start_list(v, "a", NULL, 0, &error_abort);
 546    visit_type_str(v, NULL, &s, &error_abort);
 547    g_assert_cmpstr(s, ==, "");
 548    g_free(s);
 549    visit_type_str(v, NULL, &s, &error_abort);
 550    g_assert_cmpstr(s, ==, "I");
 551    g_free(s);
 552    visit_start_list(v, NULL, NULL, 0, &error_abort);
 553    visit_type_str(v, NULL, &s, &error_abort);
 554    g_assert_cmpstr(s, ==, "II");
 555    g_free(s);
 556    visit_check_list(v, &error_abort);
 557    visit_end_list(v, NULL);
 558    visit_check_list(v, &error_abort);
 559    visit_end_list(v, NULL);
 560    visit_check_struct(v, &error_abort);
 561    visit_end_struct(v, NULL);
 562    visit_free(v);
 563
 564    qdict = keyval_parse("a.0=,b.0.0=head", NULL, &error_abort);
 565    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 566    qobject_unref(qdict);
 567    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 568    visit_start_list(v, "a", NULL, 0, &error_abort);
 569    visit_check_list(v, &err);  /* a[0] unexpected */
 570    error_free_or_abort(&err);
 571    visit_end_list(v, NULL);
 572    visit_start_list(v, "b", NULL, 0, &error_abort);
 573    visit_start_list(v, NULL, NULL, 0, &error_abort);
 574    visit_type_str(v, NULL, &s, &error_abort);
 575    g_assert_cmpstr(s, ==, "head");
 576    g_free(s);
 577    visit_type_str(v, NULL, &s, &err); /* b[0][1] missing */
 578    error_free_or_abort(&err);
 579    visit_end_list(v, NULL);
 580    visit_end_list(v, NULL);
 581    visit_check_struct(v, &error_abort);
 582    visit_end_struct(v, NULL);
 583    visit_free(v);
 584}
 585
 586static void test_keyval_visit_optional(void)
 587{
 588    Visitor *v;
 589    QDict *qdict;
 590    bool present;
 591    int64_t i;
 592
 593    qdict = keyval_parse("a.b=1", NULL, &error_abort);
 594    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 595    qobject_unref(qdict);
 596    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 597    visit_optional(v, "b", &present);
 598    g_assert(!present);         /* b missing */
 599    visit_optional(v, "a", &present);
 600    g_assert(present);          /* a present */
 601    visit_start_struct(v, "a", NULL, 0, &error_abort);
 602    visit_optional(v, "b", &present);
 603    g_assert(present);          /* a.b present */
 604    visit_type_int(v, "b", &i, &error_abort);
 605    g_assert_cmpint(i, ==, 1);
 606    visit_optional(v, "a", &present);
 607    g_assert(!present);         /* a.a missing */
 608    visit_check_struct(v, &error_abort);
 609    visit_end_struct(v, NULL);
 610    visit_check_struct(v, &error_abort);
 611    visit_end_struct(v, NULL);
 612    visit_free(v);
 613}
 614
 615static void test_keyval_visit_alternate(void)
 616{
 617    Error *err = NULL;
 618    Visitor *v;
 619    QDict *qdict;
 620    AltStrObj *aso;
 621    AltNumEnum *ane;
 622    AltEnumBool *aeb;
 623
 624    /*
 625     * Can't do scalar alternate variants other than string.  You get
 626     * the string variant if there is one, else an error.
 627     * TODO make it work for unambiguous cases like AltEnumBool below
 628     */
 629    qdict = keyval_parse("a=1,b=2,c=on", NULL, &error_abort);
 630    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 631    qobject_unref(qdict);
 632    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 633    visit_type_AltStrObj(v, "a", &aso, &error_abort);
 634    g_assert_cmpint(aso->type, ==, QTYPE_QSTRING);
 635    g_assert_cmpstr(aso->u.s, ==, "1");
 636    qapi_free_AltStrObj(aso);
 637    visit_type_AltNumEnum(v, "b", &ane, &err);
 638    error_free_or_abort(&err);
 639    visit_type_AltEnumBool(v, "c", &aeb, &err);
 640    error_free_or_abort(&err);
 641    visit_end_struct(v, NULL);
 642    visit_free(v);
 643}
 644
 645static void test_keyval_visit_any(void)
 646{
 647    Visitor *v;
 648    QDict *qdict;
 649    QObject *any;
 650    QList *qlist;
 651    QString *qstr;
 652
 653    qdict = keyval_parse("a.0=null,a.1=1", NULL, &error_abort);
 654    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
 655    qobject_unref(qdict);
 656    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 657    visit_type_any(v, "a", &any, &error_abort);
 658    qlist = qobject_to(QList, any);
 659    g_assert(qlist);
 660    qstr = qobject_to(QString, qlist_pop(qlist));
 661    g_assert_cmpstr(qstring_get_str(qstr), ==, "null");
 662    qobject_unref(qstr);
 663    qstr = qobject_to(QString, qlist_pop(qlist));
 664    g_assert_cmpstr(qstring_get_str(qstr), ==, "1");
 665    g_assert(qlist_empty(qlist));
 666    qobject_unref(qstr);
 667    qobject_unref(any);
 668    visit_check_struct(v, &error_abort);
 669    visit_end_struct(v, NULL);
 670    visit_free(v);
 671}
 672
 673int main(int argc, char *argv[])
 674{
 675    g_test_init(&argc, &argv, NULL);
 676    g_test_add_func("/keyval/keyval_parse", test_keyval_parse);
 677    g_test_add_func("/keyval/keyval_parse/list", test_keyval_parse_list);
 678    g_test_add_func("/keyval/visit/bool", test_keyval_visit_bool);
 679    g_test_add_func("/keyval/visit/number", test_keyval_visit_number);
 680    g_test_add_func("/keyval/visit/size", test_keyval_visit_size);
 681    g_test_add_func("/keyval/visit/dict", test_keyval_visit_dict);
 682    g_test_add_func("/keyval/visit/list", test_keyval_visit_list);
 683    g_test_add_func("/keyval/visit/optional", test_keyval_visit_optional);
 684    g_test_add_func("/keyval/visit/alternate", test_keyval_visit_alternate);
 685    g_test_add_func("/keyval/visit/any", test_keyval_visit_any);
 686    g_test_run();
 687    return 0;
 688}
 689