qemu/tests/unit/check-block-qdict.c
<<
>>
Prefs
   1/*
   2 * Unit-tests for Block layer QDict extras
   3 *
   4 * Copyright (c) 2013-2018 Red Hat, Inc.
   5 *
   6 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
   7 * See the COPYING.LIB file in the top-level directory.
   8 */
   9
  10#include "qemu/osdep.h"
  11#include "block/qdict.h"
  12#include "qapi/qmp/qlist.h"
  13#include "qapi/qmp/qnum.h"
  14#include "qapi/error.h"
  15
  16static void qdict_defaults_test(void)
  17{
  18    QDict *dict, *copy;
  19
  20    dict = qdict_new();
  21    copy = qdict_new();
  22
  23    qdict_set_default_str(dict, "foo", "abc");
  24    qdict_set_default_str(dict, "foo", "def");
  25    g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "abc");
  26    qdict_set_default_str(dict, "bar", "ghi");
  27
  28    qdict_copy_default(copy, dict, "foo");
  29    g_assert_cmpstr(qdict_get_str(copy, "foo"), ==, "abc");
  30    qdict_set_default_str(copy, "bar", "xyz");
  31    qdict_copy_default(copy, dict, "bar");
  32    g_assert_cmpstr(qdict_get_str(copy, "bar"), ==, "xyz");
  33
  34    qobject_unref(copy);
  35    qobject_unref(dict);
  36}
  37
  38static void qdict_flatten_test(void)
  39{
  40    QList *e_1 = qlist_new();
  41    QList *e = qlist_new();
  42    QDict *e_1_2 = qdict_new();
  43    QDict *f = qdict_new();
  44    QList *y = qlist_new();
  45    QDict *z = qdict_new();
  46    QDict *root = qdict_new();
  47
  48    /*
  49     * Test the flattening of
  50     *
  51     * {
  52     *     "e": [
  53     *         42,
  54     *         [
  55     *             23,
  56     *             66,
  57     *             {
  58     *                 "a": 0,
  59     *                 "b": 1
  60     *             }
  61     *         ]
  62     *     ],
  63     *     "f": {
  64     *         "c": 2,
  65     *         "d": 3,
  66     *     },
  67     *     "g": 4,
  68     *     "y": [{}],
  69     *     "z": {"a": []}
  70     * }
  71     *
  72     * to
  73     *
  74     * {
  75     *     "e.0": 42,
  76     *     "e.1.0": 23,
  77     *     "e.1.1": 66,
  78     *     "e.1.2.a": 0,
  79     *     "e.1.2.b": 1,
  80     *     "f.c": 2,
  81     *     "f.d": 3,
  82     *     "g": 4,
  83     *     "y.0": {},
  84     *     "z.a": []
  85     * }
  86     */
  87
  88    qdict_put_int(e_1_2, "a", 0);
  89    qdict_put_int(e_1_2, "b", 1);
  90
  91    qlist_append_int(e_1, 23);
  92    qlist_append_int(e_1, 66);
  93    qlist_append(e_1, e_1_2);
  94    qlist_append_int(e, 42);
  95    qlist_append(e, e_1);
  96
  97    qdict_put_int(f, "c", 2);
  98    qdict_put_int(f, "d", 3);
  99
 100    qlist_append(y, qdict_new());
 101
 102    qdict_put(z, "a", qlist_new());
 103
 104    qdict_put(root, "e", e);
 105    qdict_put(root, "f", f);
 106    qdict_put_int(root, "g", 4);
 107    qdict_put(root, "y", y);
 108    qdict_put(root, "z", z);
 109
 110    qdict_flatten(root);
 111
 112    g_assert(qdict_get_int(root, "e.0") == 42);
 113    g_assert(qdict_get_int(root, "e.1.0") == 23);
 114    g_assert(qdict_get_int(root, "e.1.1") == 66);
 115    g_assert(qdict_get_int(root, "e.1.2.a") == 0);
 116    g_assert(qdict_get_int(root, "e.1.2.b") == 1);
 117    g_assert(qdict_get_int(root, "f.c") == 2);
 118    g_assert(qdict_get_int(root, "f.d") == 3);
 119    g_assert(qdict_get_int(root, "g") == 4);
 120    g_assert(!qdict_size(qdict_get_qdict(root, "y.0")));
 121    g_assert(qlist_empty(qdict_get_qlist(root, "z.a")));
 122
 123    g_assert(qdict_size(root) == 10);
 124
 125    qobject_unref(root);
 126}
 127
 128static void qdict_clone_flatten_test(void)
 129{
 130    QDict *dict1 = qdict_new();
 131    QDict *dict2 = qdict_new();
 132    QDict *cloned_dict1;
 133
 134    /*
 135     * Test that we can clone and flatten
 136     *    { "a": { "b": 42 } }
 137     * without modifying the clone.
 138     */
 139
 140    qdict_put_int(dict2, "b", 42);
 141    qdict_put(dict1, "a", dict2);
 142
 143    cloned_dict1 = qdict_clone_shallow(dict1);
 144
 145    qdict_flatten(dict1);
 146
 147    g_assert(qdict_size(dict1) == 1);
 148    g_assert(qdict_get_int(dict1, "a.b") == 42);
 149
 150    g_assert(qdict_size(cloned_dict1) == 1);
 151    g_assert(qdict_get_qdict(cloned_dict1, "a") == dict2);
 152
 153    g_assert(qdict_size(dict2) == 1);
 154    g_assert(qdict_get_int(dict2, "b") == 42);
 155
 156    qobject_unref(dict1);
 157    qobject_unref(cloned_dict1);
 158}
 159
 160static void qdict_array_split_test(void)
 161{
 162    QDict *test_dict = qdict_new();
 163    QDict *dict1, *dict2;
 164    QNum *int1;
 165    QList *test_list;
 166
 167    /*
 168     * Test the split of
 169     *
 170     * {
 171     *     "1.x": 0,
 172     *     "4.y": 1,
 173     *     "0.a": 42,
 174     *     "o.o": 7,
 175     *     "0.b": 23,
 176     *     "2": 66
 177     * }
 178     *
 179     * to
 180     *
 181     * [
 182     *     {
 183     *         "a": 42,
 184     *         "b": 23
 185     *     },
 186     *     {
 187     *         "x": 0
 188     *     },
 189     *     66
 190     * ]
 191     *
 192     * and
 193     *
 194     * {
 195     *     "4.y": 1,
 196     *     "o.o": 7
 197     * }
 198     *
 199     * (remaining in the old QDict)
 200     *
 201     * This example is given in the comment of qdict_array_split().
 202     */
 203
 204    qdict_put_int(test_dict, "1.x", 0);
 205    qdict_put_int(test_dict, "4.y", 1);
 206    qdict_put_int(test_dict, "0.a", 42);
 207    qdict_put_int(test_dict, "o.o", 7);
 208    qdict_put_int(test_dict, "0.b", 23);
 209    qdict_put_int(test_dict, "2", 66);
 210
 211    qdict_array_split(test_dict, &test_list);
 212
 213    dict1 = qobject_to(QDict, qlist_pop(test_list));
 214    dict2 = qobject_to(QDict, qlist_pop(test_list));
 215    int1 = qobject_to(QNum, qlist_pop(test_list));
 216
 217    g_assert(dict1);
 218    g_assert(dict2);
 219    g_assert(int1);
 220    g_assert(qlist_empty(test_list));
 221
 222    qobject_unref(test_list);
 223
 224    g_assert(qdict_get_int(dict1, "a") == 42);
 225    g_assert(qdict_get_int(dict1, "b") == 23);
 226
 227    g_assert(qdict_size(dict1) == 2);
 228
 229    qobject_unref(dict1);
 230
 231    g_assert(qdict_get_int(dict2, "x") == 0);
 232
 233    g_assert(qdict_size(dict2) == 1);
 234
 235    qobject_unref(dict2);
 236
 237    g_assert_cmpint(qnum_get_int(int1), ==, 66);
 238
 239    qobject_unref(int1);
 240
 241    g_assert(qdict_get_int(test_dict, "4.y") == 1);
 242    g_assert(qdict_get_int(test_dict, "o.o") == 7);
 243
 244    g_assert(qdict_size(test_dict) == 2);
 245
 246    qobject_unref(test_dict);
 247
 248    /*
 249     * Test the split of
 250     *
 251     * {
 252     *     "0": 42,
 253     *     "1": 23,
 254     *     "1.x": 84
 255     * }
 256     *
 257     * to
 258     *
 259     * [
 260     *     42
 261     * ]
 262     *
 263     * and
 264     *
 265     * {
 266     *     "1": 23,
 267     *     "1.x": 84
 268     * }
 269     *
 270     * That is, test whether splitting stops if there is both an entry with key
 271     * of "%u" and other entries with keys prefixed "%u." for the same index.
 272     */
 273
 274    test_dict = qdict_new();
 275
 276    qdict_put_int(test_dict, "0", 42);
 277    qdict_put_int(test_dict, "1", 23);
 278    qdict_put_int(test_dict, "1.x", 84);
 279
 280    qdict_array_split(test_dict, &test_list);
 281
 282    int1 = qobject_to(QNum, qlist_pop(test_list));
 283
 284    g_assert(int1);
 285    g_assert(qlist_empty(test_list));
 286
 287    qobject_unref(test_list);
 288
 289    g_assert_cmpint(qnum_get_int(int1), ==, 42);
 290
 291    qobject_unref(int1);
 292
 293    g_assert(qdict_get_int(test_dict, "1") == 23);
 294    g_assert(qdict_get_int(test_dict, "1.x") == 84);
 295
 296    g_assert(qdict_size(test_dict) == 2);
 297
 298    qobject_unref(test_dict);
 299}
 300
 301static void qdict_array_entries_test(void)
 302{
 303    QDict *dict = qdict_new();
 304
 305    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
 306
 307    qdict_put_int(dict, "bar", 0);
 308    qdict_put_int(dict, "baz.0", 0);
 309    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
 310
 311    qdict_put_int(dict, "foo.1", 0);
 312    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
 313    qdict_put_int(dict, "foo.0", 0);
 314    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 2);
 315    qdict_put_int(dict, "foo.bar", 0);
 316    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
 317    qdict_del(dict, "foo.bar");
 318
 319    qdict_put_int(dict, "foo.2.a", 0);
 320    qdict_put_int(dict, "foo.2.b", 0);
 321    qdict_put_int(dict, "foo.2.c", 0);
 322    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 3);
 323    g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
 324
 325    qobject_unref(dict);
 326
 327    dict = qdict_new();
 328    qdict_put_int(dict, "1", 0);
 329    g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
 330    qdict_put_int(dict, "0", 0);
 331    g_assert_cmpint(qdict_array_entries(dict, ""), ==, 2);
 332    qdict_put_int(dict, "bar", 0);
 333    g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
 334    qdict_del(dict, "bar");
 335
 336    qdict_put_int(dict, "2.a", 0);
 337    qdict_put_int(dict, "2.b", 0);
 338    qdict_put_int(dict, "2.c", 0);
 339    g_assert_cmpint(qdict_array_entries(dict, ""), ==, 3);
 340
 341    qobject_unref(dict);
 342}
 343
 344static void qdict_join_test(void)
 345{
 346    QDict *dict1, *dict2;
 347    bool overwrite = false;
 348    int i;
 349
 350    dict1 = qdict_new();
 351    dict2 = qdict_new();
 352
 353    /* Test everything once without overwrite and once with */
 354    do {
 355        /* Test empty dicts */
 356        qdict_join(dict1, dict2, overwrite);
 357
 358        g_assert(qdict_size(dict1) == 0);
 359        g_assert(qdict_size(dict2) == 0);
 360
 361        /* First iteration: Test movement */
 362        /* Second iteration: Test empty source and non-empty destination */
 363        qdict_put_int(dict2, "foo", 42);
 364
 365        for (i = 0; i < 2; i++) {
 366            qdict_join(dict1, dict2, overwrite);
 367
 368            g_assert(qdict_size(dict1) == 1);
 369            g_assert(qdict_size(dict2) == 0);
 370
 371            g_assert(qdict_get_int(dict1, "foo") == 42);
 372        }
 373
 374        /* Test non-empty source and destination without conflict */
 375        qdict_put_int(dict2, "bar", 23);
 376
 377        qdict_join(dict1, dict2, overwrite);
 378
 379        g_assert(qdict_size(dict1) == 2);
 380        g_assert(qdict_size(dict2) == 0);
 381
 382        g_assert(qdict_get_int(dict1, "foo") == 42);
 383        g_assert(qdict_get_int(dict1, "bar") == 23);
 384
 385        /* Test conflict */
 386        qdict_put_int(dict2, "foo", 84);
 387
 388        qdict_join(dict1, dict2, overwrite);
 389
 390        g_assert(qdict_size(dict1) == 2);
 391        g_assert(qdict_size(dict2) == !overwrite);
 392
 393        g_assert(qdict_get_int(dict1, "foo") == (overwrite ? 84 : 42));
 394        g_assert(qdict_get_int(dict1, "bar") == 23);
 395
 396        if (!overwrite) {
 397            g_assert(qdict_get_int(dict2, "foo") == 84);
 398        }
 399
 400        /* Check the references */
 401        g_assert(qdict_get(dict1, "foo")->base.refcnt == 1);
 402        g_assert(qdict_get(dict1, "bar")->base.refcnt == 1);
 403
 404        if (!overwrite) {
 405            g_assert(qdict_get(dict2, "foo")->base.refcnt == 1);
 406        }
 407
 408        /* Clean up */
 409        qdict_del(dict1, "foo");
 410        qdict_del(dict1, "bar");
 411
 412        if (!overwrite) {
 413            qdict_del(dict2, "foo");
 414        }
 415    } while (overwrite ^= true);
 416
 417    qobject_unref(dict1);
 418    qobject_unref(dict2);
 419}
 420
 421static void qdict_crumple_test_recursive(void)
 422{
 423    QDict *src, *dst, *rule, *vnc, *acl, *listen;
 424    QDict *empty, *empty_dict, *empty_list_0;
 425    QList *rules, *empty_list, *empty_dict_a;
 426
 427    src = qdict_new();
 428    qdict_put_str(src, "vnc.listen.addr", "127.0.0.1");
 429    qdict_put_str(src, "vnc.listen.port", "5901");
 430    qdict_put_str(src, "vnc.acl.rules.0.match", "fred");
 431    qdict_put_str(src, "vnc.acl.rules.0.policy", "allow");
 432    qdict_put_str(src, "vnc.acl.rules.1.match", "bob");
 433    qdict_put_str(src, "vnc.acl.rules.1.policy", "deny");
 434    qdict_put_str(src, "vnc.acl.default", "deny");
 435    qdict_put_str(src, "vnc.acl..name", "acl0");
 436    qdict_put_str(src, "vnc.acl.rule..name", "acl0");
 437    qdict_put(src, "empty.dict.a", qlist_new());
 438    qdict_put(src, "empty.list.0", qdict_new());
 439
 440    dst = qobject_to(QDict, qdict_crumple(src, &error_abort));
 441    g_assert(dst);
 442    g_assert_cmpint(qdict_size(dst), ==, 2);
 443
 444    vnc = qdict_get_qdict(dst, "vnc");
 445    g_assert(vnc);
 446    g_assert_cmpint(qdict_size(vnc), ==, 3);
 447
 448    listen = qdict_get_qdict(vnc, "listen");
 449    g_assert(listen);
 450    g_assert_cmpint(qdict_size(listen), ==, 2);
 451    g_assert_cmpstr("127.0.0.1", ==, qdict_get_str(listen, "addr"));
 452    g_assert_cmpstr("5901", ==, qdict_get_str(listen, "port"));
 453
 454    acl = qdict_get_qdict(vnc, "acl");
 455    g_assert(acl);
 456    g_assert_cmpint(qdict_size(acl), ==, 3);
 457
 458    rules = qdict_get_qlist(acl, "rules");
 459    g_assert(rules);
 460    g_assert_cmpint(qlist_size(rules), ==, 2);
 461
 462    rule = qobject_to(QDict, qlist_pop(rules));
 463    g_assert(rule);
 464    g_assert_cmpint(qdict_size(rule), ==, 2);
 465    g_assert_cmpstr("fred", ==, qdict_get_str(rule, "match"));
 466    g_assert_cmpstr("allow", ==, qdict_get_str(rule, "policy"));
 467    qobject_unref(rule);
 468
 469    rule = qobject_to(QDict, qlist_pop(rules));
 470    g_assert(rule);
 471    g_assert_cmpint(qdict_size(rule), ==, 2);
 472    g_assert_cmpstr("bob", ==, qdict_get_str(rule, "match"));
 473    g_assert_cmpstr("deny", ==, qdict_get_str(rule, "policy"));
 474    qobject_unref(rule);
 475
 476    /* With recursive crumpling, we should see all names unescaped */
 477    g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name"));
 478    g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name"));
 479
 480    empty = qdict_get_qdict(dst, "empty");
 481    g_assert(empty);
 482    g_assert_cmpint(qdict_size(empty), ==, 2);
 483    empty_dict = qdict_get_qdict(empty, "dict");
 484    g_assert(empty_dict);
 485    g_assert_cmpint(qdict_size(empty_dict), ==, 1);
 486    empty_dict_a = qdict_get_qlist(empty_dict, "a");
 487    g_assert(empty_dict_a && qlist_empty(empty_dict_a));
 488    empty_list = qdict_get_qlist(empty, "list");
 489    g_assert(empty_list);
 490    g_assert_cmpint(qlist_size(empty_list), ==, 1);
 491    empty_list_0 = qobject_to(QDict, qlist_pop(empty_list));
 492    g_assert(empty_list_0);
 493    g_assert_cmpint(qdict_size(empty_list_0), ==, 0);
 494    qobject_unref(empty_list_0);
 495
 496    qobject_unref(src);
 497    qobject_unref(dst);
 498}
 499
 500static void qdict_crumple_test_empty(void)
 501{
 502    QDict *src, *dst;
 503
 504    src = qdict_new();
 505
 506    dst = qobject_to(QDict, qdict_crumple(src, &error_abort));
 507
 508    g_assert_cmpint(qdict_size(dst), ==, 0);
 509
 510    qobject_unref(src);
 511    qobject_unref(dst);
 512}
 513
 514static int qdict_count_entries(QDict *dict)
 515{
 516    const QDictEntry *e;
 517    int count = 0;
 518
 519    for (e = qdict_first(dict); e; e = qdict_next(dict, e)) {
 520        count++;
 521    }
 522
 523    return count;
 524}
 525
 526static void qdict_rename_keys_test(void)
 527{
 528    QDict *dict = qdict_new();
 529    QDict *copy;
 530    QDictRenames *renames;
 531    Error *local_err = NULL;
 532
 533    qdict_put_str(dict, "abc", "foo");
 534    qdict_put_str(dict, "abcdef", "bar");
 535    qdict_put_int(dict, "number", 42);
 536    qdict_put_bool(dict, "flag", true);
 537    qdict_put_null(dict, "nothing");
 538
 539    /* Empty rename list */
 540    renames = (QDictRenames[]) {
 541        { NULL, "this can be anything" }
 542    };
 543    copy = qdict_clone_shallow(dict);
 544    qdict_rename_keys(copy, renames, &error_abort);
 545
 546    g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
 547    g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
 548    g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
 549    g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
 550    g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
 551    g_assert_cmpint(qdict_count_entries(copy), ==, 5);
 552
 553    qobject_unref(copy);
 554
 555    /* Simple rename of all entries */
 556    renames = (QDictRenames[]) {
 557        { "abc",        "str1" },
 558        { "abcdef",     "str2" },
 559        { "number",     "int" },
 560        { "flag",       "bool" },
 561        { "nothing",    "null" },
 562        { NULL , NULL }
 563    };
 564    copy = qdict_clone_shallow(dict);
 565    qdict_rename_keys(copy, renames, &error_abort);
 566
 567    g_assert(!qdict_haskey(copy, "abc"));
 568    g_assert(!qdict_haskey(copy, "abcdef"));
 569    g_assert(!qdict_haskey(copy, "number"));
 570    g_assert(!qdict_haskey(copy, "flag"));
 571    g_assert(!qdict_haskey(copy, "nothing"));
 572
 573    g_assert_cmpstr(qdict_get_str(copy, "str1"), ==, "foo");
 574    g_assert_cmpstr(qdict_get_str(copy, "str2"), ==, "bar");
 575    g_assert_cmpint(qdict_get_int(copy, "int"), ==, 42);
 576    g_assert_cmpint(qdict_get_bool(copy, "bool"), ==, true);
 577    g_assert(qobject_type(qdict_get(copy, "null")) == QTYPE_QNULL);
 578    g_assert_cmpint(qdict_count_entries(copy), ==, 5);
 579
 580    qobject_unref(copy);
 581
 582    /* Renames are processed top to bottom */
 583    renames = (QDictRenames[]) {
 584        { "abc",        "tmp" },
 585        { "abcdef",     "abc" },
 586        { "number",     "abcdef" },
 587        { "flag",       "number" },
 588        { "nothing",    "flag" },
 589        { "tmp",        "nothing" },
 590        { NULL , NULL }
 591    };
 592    copy = qdict_clone_shallow(dict);
 593    qdict_rename_keys(copy, renames, &error_abort);
 594
 595    g_assert_cmpstr(qdict_get_str(copy, "nothing"), ==, "foo");
 596    g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "bar");
 597    g_assert_cmpint(qdict_get_int(copy, "abcdef"), ==, 42);
 598    g_assert_cmpint(qdict_get_bool(copy, "number"), ==, true);
 599    g_assert(qobject_type(qdict_get(copy, "flag")) == QTYPE_QNULL);
 600    g_assert(!qdict_haskey(copy, "tmp"));
 601    g_assert_cmpint(qdict_count_entries(copy), ==, 5);
 602
 603    qobject_unref(copy);
 604
 605    /* Conflicting rename */
 606    renames = (QDictRenames[]) {
 607        { "abcdef",     "abc" },
 608        { NULL , NULL }
 609    };
 610    copy = qdict_clone_shallow(dict);
 611    qdict_rename_keys(copy, renames, &local_err);
 612
 613    error_free_or_abort(&local_err);
 614
 615    g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
 616    g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
 617    g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
 618    g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
 619    g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
 620    g_assert_cmpint(qdict_count_entries(copy), ==, 5);
 621
 622    qobject_unref(copy);
 623
 624    /* Renames in an empty dict */
 625    renames = (QDictRenames[]) {
 626        { "abcdef",     "abc" },
 627        { NULL , NULL }
 628    };
 629
 630    qobject_unref(dict);
 631    dict = qdict_new();
 632
 633    qdict_rename_keys(dict, renames, &error_abort);
 634    g_assert(qdict_first(dict) == NULL);
 635
 636    qobject_unref(dict);
 637}
 638
 639static void qdict_crumple_test_bad_inputs(void)
 640{
 641    QDict *src, *nested;
 642    Error *error = NULL;
 643
 644    src = qdict_new();
 645    /* rule.0 can't be both a string and a dict */
 646    qdict_put_str(src, "rule.0", "fred");
 647    qdict_put_str(src, "rule.0.policy", "allow");
 648
 649    g_assert(qdict_crumple(src, &error) == NULL);
 650    error_free_or_abort(&error);
 651    qobject_unref(src);
 652
 653    src = qdict_new();
 654    /* rule can't be both a list and a dict */
 655    qdict_put_str(src, "rule.0", "fred");
 656    qdict_put_str(src, "rule.a", "allow");
 657
 658    g_assert(qdict_crumple(src, &error) == NULL);
 659    error_free_or_abort(&error);
 660    qobject_unref(src);
 661
 662    src = qdict_new();
 663    /* The input should be flat, ie no dicts or lists */
 664    nested = qdict_new();
 665    qdict_put(nested, "x", qdict_new());
 666    qdict_put(src, "rule.a", nested);
 667    qdict_put_str(src, "rule.b", "allow");
 668
 669    g_assert(qdict_crumple(src, &error) == NULL);
 670    error_free_or_abort(&error);
 671    qobject_unref(src);
 672
 673    src = qdict_new();
 674    /* List indexes must not have gaps */
 675    qdict_put_str(src, "rule.0", "deny");
 676    qdict_put_str(src, "rule.3", "allow");
 677
 678    g_assert(qdict_crumple(src, &error) == NULL);
 679    error_free_or_abort(&error);
 680    qobject_unref(src);
 681
 682    src = qdict_new();
 683    /* List indexes must be in %zu format */
 684    qdict_put_str(src, "rule.0", "deny");
 685    qdict_put_str(src, "rule.+1", "allow");
 686
 687    g_assert(qdict_crumple(src, &error) == NULL);
 688    error_free_or_abort(&error);
 689    qobject_unref(src);
 690}
 691
 692int main(int argc, char **argv)
 693{
 694    g_test_init(&argc, &argv, NULL);
 695
 696    g_test_add_func("/public/defaults", qdict_defaults_test);
 697    g_test_add_func("/public/flatten", qdict_flatten_test);
 698    g_test_add_func("/public/clone_flatten", qdict_clone_flatten_test);
 699    g_test_add_func("/public/array_split", qdict_array_split_test);
 700    g_test_add_func("/public/array_entries", qdict_array_entries_test);
 701    g_test_add_func("/public/join", qdict_join_test);
 702    g_test_add_func("/public/crumple/recursive",
 703                    qdict_crumple_test_recursive);
 704    g_test_add_func("/public/crumple/empty",
 705                    qdict_crumple_test_empty);
 706    g_test_add_func("/public/crumple/bad_inputs",
 707                    qdict_crumple_test_bad_inputs);
 708
 709    g_test_add_func("/public/rename_keys", qdict_rename_keys_test);
 710
 711    return g_test_run();
 712}
 713