qemu/tests/check-qdict.c
<<
>>
Prefs
   1/*
   2 * QDict unit-tests.
   3 *
   4 * Copyright (C) 2009 Red Hat Inc.
   5 *
   6 * Authors:
   7 *  Luiz Capitulino <lcapitulino@redhat.com>
   8 *
   9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  10 * See the COPYING.LIB file in the top-level directory.
  11 */
  12
  13#include "qemu/osdep.h"
  14#include "qapi/qmp/qdict.h"
  15#include "qapi/qmp/qlist.h"
  16#include "qapi/qmp/qnum.h"
  17#include "qapi/qmp/qstring.h"
  18#include "qapi/error.h"
  19#include "qemu-common.h"
  20
  21/*
  22 * Public Interface test-cases
  23 *
  24 * (with some violations to access 'private' data)
  25 */
  26
  27static void qdict_new_test(void)
  28{
  29    QDict *qdict;
  30
  31    qdict = qdict_new();
  32    g_assert(qdict != NULL);
  33    g_assert(qdict_size(qdict) == 0);
  34    g_assert(qdict->base.refcnt == 1);
  35    g_assert(qobject_type(QOBJECT(qdict)) == QTYPE_QDICT);
  36
  37    QDECREF(qdict);
  38}
  39
  40static void qdict_put_obj_test(void)
  41{
  42    QNum *qn;
  43    QDict *qdict;
  44    QDictEntry *ent;
  45    const int num = 42;
  46
  47    qdict = qdict_new();
  48
  49    // key "" will have tdb hash 12345
  50    qdict_put_int(qdict, "", num);
  51
  52    g_assert(qdict_size(qdict) == 1);
  53    ent = QLIST_FIRST(&qdict->table[12345 % QDICT_BUCKET_MAX]);
  54    qn = qobject_to(QNum, ent->value);
  55    g_assert_cmpint(qnum_get_int(qn), ==, num);
  56
  57    QDECREF(qdict);
  58}
  59
  60static void qdict_destroy_simple_test(void)
  61{
  62    QDict *qdict;
  63
  64    qdict = qdict_new();
  65    qdict_put_int(qdict, "num", 0);
  66    qdict_put_str(qdict, "str", "foo");
  67
  68    QDECREF(qdict);
  69}
  70
  71static void qdict_get_test(void)
  72{
  73    QNum *qn;
  74    QObject *obj;
  75    const int value = -42;
  76    const char *key = "test";
  77    QDict *tests_dict = qdict_new();
  78
  79    qdict_put_int(tests_dict, key, value);
  80
  81    obj = qdict_get(tests_dict, key);
  82    g_assert(obj != NULL);
  83
  84    qn = qobject_to(QNum, obj);
  85    g_assert_cmpint(qnum_get_int(qn), ==, value);
  86
  87    QDECREF(tests_dict);
  88}
  89
  90static void qdict_get_int_test(void)
  91{
  92    int ret;
  93    const int value = 100;
  94    const char *key = "int";
  95    QDict *tests_dict = qdict_new();
  96
  97    qdict_put_int(tests_dict, key, value);
  98
  99    ret = qdict_get_int(tests_dict, key);
 100    g_assert(ret == value);
 101
 102    QDECREF(tests_dict);
 103}
 104
 105static void qdict_get_try_int_test(void)
 106{
 107    int ret;
 108    const int value = 100;
 109    const char *key = "int";
 110    QDict *tests_dict = qdict_new();
 111
 112    qdict_put_int(tests_dict, key, value);
 113    qdict_put_str(tests_dict, "string", "test");
 114
 115    ret = qdict_get_try_int(tests_dict, key, 0);
 116    g_assert(ret == value);
 117
 118    ret = qdict_get_try_int(tests_dict, "missing", -42);
 119    g_assert_cmpuint(ret, ==, -42);
 120
 121    ret = qdict_get_try_int(tests_dict, "string", -42);
 122    g_assert_cmpuint(ret, ==, -42);
 123
 124    QDECREF(tests_dict);
 125}
 126
 127static void qdict_get_str_test(void)
 128{
 129    const char *p;
 130    const char *key = "key";
 131    const char *str = "string";
 132    QDict *tests_dict = qdict_new();
 133
 134    qdict_put_str(tests_dict, key, str);
 135
 136    p = qdict_get_str(tests_dict, key);
 137    g_assert(p != NULL);
 138    g_assert(strcmp(p, str) == 0);
 139
 140    QDECREF(tests_dict);
 141}
 142
 143static void qdict_get_try_str_test(void)
 144{
 145    const char *p;
 146    const char *key = "key";
 147    const char *str = "string";
 148    QDict *tests_dict = qdict_new();
 149
 150    qdict_put_str(tests_dict, key, str);
 151
 152    p = qdict_get_try_str(tests_dict, key);
 153    g_assert(p != NULL);
 154    g_assert(strcmp(p, str) == 0);
 155
 156    QDECREF(tests_dict);
 157}
 158
 159static void qdict_defaults_test(void)
 160{
 161    QDict *dict, *copy;
 162
 163    dict = qdict_new();
 164    copy = qdict_new();
 165
 166    qdict_set_default_str(dict, "foo", "abc");
 167    qdict_set_default_str(dict, "foo", "def");
 168    g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "abc");
 169    qdict_set_default_str(dict, "bar", "ghi");
 170
 171    qdict_copy_default(copy, dict, "foo");
 172    g_assert_cmpstr(qdict_get_str(copy, "foo"), ==, "abc");
 173    qdict_set_default_str(copy, "bar", "xyz");
 174    qdict_copy_default(copy, dict, "bar");
 175    g_assert_cmpstr(qdict_get_str(copy, "bar"), ==, "xyz");
 176
 177    QDECREF(copy);
 178    QDECREF(dict);
 179}
 180
 181static void qdict_haskey_not_test(void)
 182{
 183    QDict *tests_dict = qdict_new();
 184    g_assert(qdict_haskey(tests_dict, "test") == 0);
 185
 186    QDECREF(tests_dict);
 187}
 188
 189static void qdict_haskey_test(void)
 190{
 191    const char *key = "test";
 192    QDict *tests_dict = qdict_new();
 193
 194    qdict_put_int(tests_dict, key, 0);
 195    g_assert(qdict_haskey(tests_dict, key) == 1);
 196
 197    QDECREF(tests_dict);
 198}
 199
 200static void qdict_del_test(void)
 201{
 202    const char *key = "key test";
 203    QDict *tests_dict = qdict_new();
 204
 205    qdict_put_str(tests_dict, key, "foo");
 206    g_assert(qdict_size(tests_dict) == 1);
 207
 208    qdict_del(tests_dict, key);
 209
 210    g_assert(qdict_size(tests_dict) == 0);
 211    g_assert(qdict_haskey(tests_dict, key) == 0);
 212
 213    QDECREF(tests_dict);
 214}
 215
 216static void qobject_to_qdict_test(void)
 217{
 218    QDict *tests_dict = qdict_new();
 219    g_assert(qobject_to(QDict, QOBJECT(tests_dict)) == tests_dict);
 220
 221    QDECREF(tests_dict);
 222}
 223
 224static void qdict_iterapi_test(void)
 225{
 226    int count;
 227    const QDictEntry *ent;
 228    QDict *tests_dict = qdict_new();
 229
 230    g_assert(qdict_first(tests_dict) == NULL);
 231
 232    qdict_put_int(tests_dict, "key1", 1);
 233    qdict_put_int(tests_dict, "key2", 2);
 234    qdict_put_int(tests_dict, "key3", 3);
 235
 236    count = 0;
 237    for (ent = qdict_first(tests_dict); ent; ent = qdict_next(tests_dict, ent)){
 238        g_assert(qdict_haskey(tests_dict, qdict_entry_key(ent)) == 1);
 239        count++;
 240    }
 241
 242    g_assert(count == qdict_size(tests_dict));
 243
 244    /* Do it again to test restarting */
 245    count = 0;
 246    for (ent = qdict_first(tests_dict); ent; ent = qdict_next(tests_dict, ent)){
 247        g_assert(qdict_haskey(tests_dict, qdict_entry_key(ent)) == 1);
 248        count++;
 249    }
 250
 251    g_assert(count == qdict_size(tests_dict));
 252
 253    QDECREF(tests_dict);
 254}
 255
 256static void qdict_flatten_test(void)
 257{
 258    QList *list1 = qlist_new();
 259    QList *list2 = qlist_new();
 260    QDict *dict1 = qdict_new();
 261    QDict *dict2 = qdict_new();
 262    QDict *dict3 = qdict_new();
 263
 264    /*
 265     * Test the flattening of
 266     *
 267     * {
 268     *     "e": [
 269     *         42,
 270     *         [
 271     *             23,
 272     *             66,
 273     *             {
 274     *                 "a": 0,
 275     *                 "b": 1
 276     *             }
 277     *         ]
 278     *     ],
 279     *     "f": {
 280     *         "c": 2,
 281     *         "d": 3,
 282     *     },
 283     *     "g": 4
 284     * }
 285     *
 286     * to
 287     *
 288     * {
 289     *     "e.0": 42,
 290     *     "e.1.0": 23,
 291     *     "e.1.1": 66,
 292     *     "e.1.2.a": 0,
 293     *     "e.1.2.b": 1,
 294     *     "f.c": 2,
 295     *     "f.d": 3,
 296     *     "g": 4
 297     * }
 298     */
 299
 300    qdict_put_int(dict1, "a", 0);
 301    qdict_put_int(dict1, "b", 1);
 302
 303    qlist_append_int(list1, 23);
 304    qlist_append_int(list1, 66);
 305    qlist_append(list1, dict1);
 306    qlist_append_int(list2, 42);
 307    qlist_append(list2, list1);
 308
 309    qdict_put_int(dict2, "c", 2);
 310    qdict_put_int(dict2, "d", 3);
 311    qdict_put(dict3, "e", list2);
 312    qdict_put(dict3, "f", dict2);
 313    qdict_put_int(dict3, "g", 4);
 314
 315    qdict_flatten(dict3);
 316
 317    g_assert(qdict_get_int(dict3, "e.0") == 42);
 318    g_assert(qdict_get_int(dict3, "e.1.0") == 23);
 319    g_assert(qdict_get_int(dict3, "e.1.1") == 66);
 320    g_assert(qdict_get_int(dict3, "e.1.2.a") == 0);
 321    g_assert(qdict_get_int(dict3, "e.1.2.b") == 1);
 322    g_assert(qdict_get_int(dict3, "f.c") == 2);
 323    g_assert(qdict_get_int(dict3, "f.d") == 3);
 324    g_assert(qdict_get_int(dict3, "g") == 4);
 325
 326    g_assert(qdict_size(dict3) == 8);
 327
 328    QDECREF(dict3);
 329}
 330
 331static void qdict_array_split_test(void)
 332{
 333    QDict *test_dict = qdict_new();
 334    QDict *dict1, *dict2;
 335    QNum *int1;
 336    QList *test_list;
 337
 338    /*
 339     * Test the split of
 340     *
 341     * {
 342     *     "1.x": 0,
 343     *     "4.y": 1,
 344     *     "0.a": 42,
 345     *     "o.o": 7,
 346     *     "0.b": 23,
 347     *     "2": 66
 348     * }
 349     *
 350     * to
 351     *
 352     * [
 353     *     {
 354     *         "a": 42,
 355     *         "b": 23
 356     *     },
 357     *     {
 358     *         "x": 0
 359     *     },
 360     *     66
 361     * ]
 362     *
 363     * and
 364     *
 365     * {
 366     *     "4.y": 1,
 367     *     "o.o": 7
 368     * }
 369     *
 370     * (remaining in the old QDict)
 371     *
 372     * This example is given in the comment of qdict_array_split().
 373     */
 374
 375    qdict_put_int(test_dict, "1.x", 0);
 376    qdict_put_int(test_dict, "4.y", 1);
 377    qdict_put_int(test_dict, "0.a", 42);
 378    qdict_put_int(test_dict, "o.o", 7);
 379    qdict_put_int(test_dict, "0.b", 23);
 380    qdict_put_int(test_dict, "2", 66);
 381
 382    qdict_array_split(test_dict, &test_list);
 383
 384    dict1 = qobject_to(QDict, qlist_pop(test_list));
 385    dict2 = qobject_to(QDict, qlist_pop(test_list));
 386    int1 = qobject_to(QNum, qlist_pop(test_list));
 387
 388    g_assert(dict1);
 389    g_assert(dict2);
 390    g_assert(int1);
 391    g_assert(qlist_empty(test_list));
 392
 393    QDECREF(test_list);
 394
 395    g_assert(qdict_get_int(dict1, "a") == 42);
 396    g_assert(qdict_get_int(dict1, "b") == 23);
 397
 398    g_assert(qdict_size(dict1) == 2);
 399
 400    QDECREF(dict1);
 401
 402    g_assert(qdict_get_int(dict2, "x") == 0);
 403
 404    g_assert(qdict_size(dict2) == 1);
 405
 406    QDECREF(dict2);
 407
 408    g_assert_cmpint(qnum_get_int(int1), ==, 66);
 409
 410    QDECREF(int1);
 411
 412    g_assert(qdict_get_int(test_dict, "4.y") == 1);
 413    g_assert(qdict_get_int(test_dict, "o.o") == 7);
 414
 415    g_assert(qdict_size(test_dict) == 2);
 416
 417    QDECREF(test_dict);
 418
 419    /*
 420     * Test the split of
 421     *
 422     * {
 423     *     "0": 42,
 424     *     "1": 23,
 425     *     "1.x": 84
 426     * }
 427     *
 428     * to
 429     *
 430     * [
 431     *     42
 432     * ]
 433     *
 434     * and
 435     *
 436     * {
 437     *     "1": 23,
 438     *     "1.x": 84
 439     * }
 440     *
 441     * That is, test whether splitting stops if there is both an entry with key
 442     * of "%u" and other entries with keys prefixed "%u." for the same index.
 443     */
 444
 445    test_dict = qdict_new();
 446
 447    qdict_put_int(test_dict, "0", 42);
 448    qdict_put_int(test_dict, "1", 23);
 449    qdict_put_int(test_dict, "1.x", 84);
 450
 451    qdict_array_split(test_dict, &test_list);
 452
 453    int1 = qobject_to(QNum, qlist_pop(test_list));
 454
 455    g_assert(int1);
 456    g_assert(qlist_empty(test_list));
 457
 458    QDECREF(test_list);
 459
 460    g_assert_cmpint(qnum_get_int(int1), ==, 42);
 461
 462    QDECREF(int1);
 463
 464    g_assert(qdict_get_int(test_dict, "1") == 23);
 465    g_assert(qdict_get_int(test_dict, "1.x") == 84);
 466
 467    g_assert(qdict_size(test_dict) == 2);
 468
 469    QDECREF(test_dict);
 470}
 471
 472static void qdict_array_entries_test(void)
 473{
 474    QDict *dict = qdict_new();
 475
 476    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
 477
 478    qdict_put_int(dict, "bar", 0);
 479    qdict_put_int(dict, "baz.0", 0);
 480    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
 481
 482    qdict_put_int(dict, "foo.1", 0);
 483    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
 484    qdict_put_int(dict, "foo.0", 0);
 485    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 2);
 486    qdict_put_int(dict, "foo.bar", 0);
 487    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
 488    qdict_del(dict, "foo.bar");
 489
 490    qdict_put_int(dict, "foo.2.a", 0);
 491    qdict_put_int(dict, "foo.2.b", 0);
 492    qdict_put_int(dict, "foo.2.c", 0);
 493    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 3);
 494    g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
 495
 496    QDECREF(dict);
 497
 498    dict = qdict_new();
 499    qdict_put_int(dict, "1", 0);
 500    g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
 501    qdict_put_int(dict, "0", 0);
 502    g_assert_cmpint(qdict_array_entries(dict, ""), ==, 2);
 503    qdict_put_int(dict, "bar", 0);
 504    g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
 505    qdict_del(dict, "bar");
 506
 507    qdict_put_int(dict, "2.a", 0);
 508    qdict_put_int(dict, "2.b", 0);
 509    qdict_put_int(dict, "2.c", 0);
 510    g_assert_cmpint(qdict_array_entries(dict, ""), ==, 3);
 511
 512    QDECREF(dict);
 513}
 514
 515static void qdict_join_test(void)
 516{
 517    QDict *dict1, *dict2;
 518    bool overwrite = false;
 519    int i;
 520
 521    dict1 = qdict_new();
 522    dict2 = qdict_new();
 523
 524    /* Test everything once without overwrite and once with */
 525    do
 526    {
 527        /* Test empty dicts */
 528        qdict_join(dict1, dict2, overwrite);
 529
 530        g_assert(qdict_size(dict1) == 0);
 531        g_assert(qdict_size(dict2) == 0);
 532
 533        /* First iteration: Test movement */
 534        /* Second iteration: Test empty source and non-empty destination */
 535        qdict_put_int(dict2, "foo", 42);
 536
 537        for (i = 0; i < 2; i++) {
 538            qdict_join(dict1, dict2, overwrite);
 539
 540            g_assert(qdict_size(dict1) == 1);
 541            g_assert(qdict_size(dict2) == 0);
 542
 543            g_assert(qdict_get_int(dict1, "foo") == 42);
 544        }
 545
 546        /* Test non-empty source and destination without conflict */
 547        qdict_put_int(dict2, "bar", 23);
 548
 549        qdict_join(dict1, dict2, overwrite);
 550
 551        g_assert(qdict_size(dict1) == 2);
 552        g_assert(qdict_size(dict2) == 0);
 553
 554        g_assert(qdict_get_int(dict1, "foo") == 42);
 555        g_assert(qdict_get_int(dict1, "bar") == 23);
 556
 557        /* Test conflict */
 558        qdict_put_int(dict2, "foo", 84);
 559
 560        qdict_join(dict1, dict2, overwrite);
 561
 562        g_assert(qdict_size(dict1) == 2);
 563        g_assert(qdict_size(dict2) == !overwrite);
 564
 565        g_assert(qdict_get_int(dict1, "foo") == (overwrite ? 84 : 42));
 566        g_assert(qdict_get_int(dict1, "bar") == 23);
 567
 568        if (!overwrite) {
 569            g_assert(qdict_get_int(dict2, "foo") == 84);
 570        }
 571
 572        /* Check the references */
 573        g_assert(qdict_get(dict1, "foo")->refcnt == 1);
 574        g_assert(qdict_get(dict1, "bar")->refcnt == 1);
 575
 576        if (!overwrite) {
 577            g_assert(qdict_get(dict2, "foo")->refcnt == 1);
 578        }
 579
 580        /* Clean up */
 581        qdict_del(dict1, "foo");
 582        qdict_del(dict1, "bar");
 583
 584        if (!overwrite) {
 585            qdict_del(dict2, "foo");
 586        }
 587    }
 588    while (overwrite ^= true);
 589
 590    QDECREF(dict1);
 591    QDECREF(dict2);
 592}
 593
 594static void qdict_crumple_test_recursive(void)
 595{
 596    QDict *src, *dst, *rule, *vnc, *acl, *listen;
 597    QList *rules;
 598
 599    src = qdict_new();
 600    qdict_put_str(src, "vnc.listen.addr", "127.0.0.1");
 601    qdict_put_str(src, "vnc.listen.port", "5901");
 602    qdict_put_str(src, "vnc.acl.rules.0.match", "fred");
 603    qdict_put_str(src, "vnc.acl.rules.0.policy", "allow");
 604    qdict_put_str(src, "vnc.acl.rules.1.match", "bob");
 605    qdict_put_str(src, "vnc.acl.rules.1.policy", "deny");
 606    qdict_put_str(src, "vnc.acl.default", "deny");
 607    qdict_put_str(src, "vnc.acl..name", "acl0");
 608    qdict_put_str(src, "vnc.acl.rule..name", "acl0");
 609
 610    dst = qobject_to(QDict, qdict_crumple(src, &error_abort));
 611    g_assert(dst);
 612    g_assert_cmpint(qdict_size(dst), ==, 1);
 613
 614    vnc = qdict_get_qdict(dst, "vnc");
 615    g_assert(vnc);
 616    g_assert_cmpint(qdict_size(vnc), ==, 3);
 617
 618    listen = qdict_get_qdict(vnc, "listen");
 619    g_assert(listen);
 620    g_assert_cmpint(qdict_size(listen), ==, 2);
 621    g_assert_cmpstr("127.0.0.1", ==, qdict_get_str(listen, "addr"));
 622    g_assert_cmpstr("5901", ==, qdict_get_str(listen, "port"));
 623
 624    acl = qdict_get_qdict(vnc, "acl");
 625    g_assert(acl);
 626    g_assert_cmpint(qdict_size(acl), ==, 3);
 627
 628    rules = qdict_get_qlist(acl, "rules");
 629    g_assert(rules);
 630    g_assert_cmpint(qlist_size(rules), ==, 2);
 631
 632    rule = qobject_to(QDict, qlist_pop(rules));
 633    g_assert(rule);
 634    g_assert_cmpint(qdict_size(rule), ==, 2);
 635    g_assert_cmpstr("fred", ==, qdict_get_str(rule, "match"));
 636    g_assert_cmpstr("allow", ==, qdict_get_str(rule, "policy"));
 637    QDECREF(rule);
 638
 639    rule = qobject_to(QDict, qlist_pop(rules));
 640    g_assert(rule);
 641    g_assert_cmpint(qdict_size(rule), ==, 2);
 642    g_assert_cmpstr("bob", ==, qdict_get_str(rule, "match"));
 643    g_assert_cmpstr("deny", ==, qdict_get_str(rule, "policy"));
 644    QDECREF(rule);
 645
 646    /* With recursive crumpling, we should see all names unescaped */
 647    g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name"));
 648    g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name"));
 649
 650    QDECREF(src);
 651    QDECREF(dst);
 652}
 653
 654static void qdict_crumple_test_empty(void)
 655{
 656    QDict *src, *dst;
 657
 658    src = qdict_new();
 659
 660    dst = (QDict *)qdict_crumple(src, &error_abort);
 661
 662    g_assert_cmpint(qdict_size(dst), ==, 0);
 663
 664    QDECREF(src);
 665    QDECREF(dst);
 666}
 667
 668static int qdict_count_entries(QDict *dict)
 669{
 670    const QDictEntry *e;
 671    int count = 0;
 672
 673    for (e = qdict_first(dict); e; e = qdict_next(dict, e)) {
 674        count++;
 675    }
 676
 677    return count;
 678}
 679
 680static void qdict_rename_keys_test(void)
 681{
 682    QDict *dict = qdict_new();
 683    QDict *copy;
 684    QDictRenames *renames;
 685    Error *local_err = NULL;
 686
 687    qdict_put_str(dict, "abc", "foo");
 688    qdict_put_str(dict, "abcdef", "bar");
 689    qdict_put_int(dict, "number", 42);
 690    qdict_put_bool(dict, "flag", true);
 691    qdict_put_null(dict, "nothing");
 692
 693    /* Empty rename list */
 694    renames = (QDictRenames[]) {
 695        { NULL, "this can be anything" }
 696    };
 697    copy = qdict_clone_shallow(dict);
 698    qdict_rename_keys(copy, renames, &error_abort);
 699
 700    g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
 701    g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
 702    g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
 703    g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
 704    g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
 705    g_assert_cmpint(qdict_count_entries(copy), ==, 5);
 706
 707    QDECREF(copy);
 708
 709    /* Simple rename of all entries */
 710    renames = (QDictRenames[]) {
 711        { "abc",        "str1" },
 712        { "abcdef",     "str2" },
 713        { "number",     "int" },
 714        { "flag",       "bool" },
 715        { "nothing",    "null" },
 716        { NULL , NULL }
 717    };
 718    copy = qdict_clone_shallow(dict);
 719    qdict_rename_keys(copy, renames, &error_abort);
 720
 721    g_assert(!qdict_haskey(copy, "abc"));
 722    g_assert(!qdict_haskey(copy, "abcdef"));
 723    g_assert(!qdict_haskey(copy, "number"));
 724    g_assert(!qdict_haskey(copy, "flag"));
 725    g_assert(!qdict_haskey(copy, "nothing"));
 726
 727    g_assert_cmpstr(qdict_get_str(copy, "str1"), ==, "foo");
 728    g_assert_cmpstr(qdict_get_str(copy, "str2"), ==, "bar");
 729    g_assert_cmpint(qdict_get_int(copy, "int"), ==, 42);
 730    g_assert_cmpint(qdict_get_bool(copy, "bool"), ==, true);
 731    g_assert(qobject_type(qdict_get(copy, "null")) == QTYPE_QNULL);
 732    g_assert_cmpint(qdict_count_entries(copy), ==, 5);
 733
 734    QDECREF(copy);
 735
 736    /* Renames are processed top to bottom */
 737    renames = (QDictRenames[]) {
 738        { "abc",        "tmp" },
 739        { "abcdef",     "abc" },
 740        { "number",     "abcdef" },
 741        { "flag",       "number" },
 742        { "nothing",    "flag" },
 743        { "tmp",        "nothing" },
 744        { NULL , NULL }
 745    };
 746    copy = qdict_clone_shallow(dict);
 747    qdict_rename_keys(copy, renames, &error_abort);
 748
 749    g_assert_cmpstr(qdict_get_str(copy, "nothing"), ==, "foo");
 750    g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "bar");
 751    g_assert_cmpint(qdict_get_int(copy, "abcdef"), ==, 42);
 752    g_assert_cmpint(qdict_get_bool(copy, "number"), ==, true);
 753    g_assert(qobject_type(qdict_get(copy, "flag")) == QTYPE_QNULL);
 754    g_assert(!qdict_haskey(copy, "tmp"));
 755    g_assert_cmpint(qdict_count_entries(copy), ==, 5);
 756
 757    QDECREF(copy);
 758
 759    /* Conflicting rename */
 760    renames = (QDictRenames[]) {
 761        { "abcdef",     "abc" },
 762        { NULL , NULL }
 763    };
 764    copy = qdict_clone_shallow(dict);
 765    qdict_rename_keys(copy, renames, &local_err);
 766
 767    g_assert(local_err != NULL);
 768    error_free(local_err);
 769    local_err = NULL;
 770
 771    g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
 772    g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
 773    g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
 774    g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
 775    g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
 776    g_assert_cmpint(qdict_count_entries(copy), ==, 5);
 777
 778    QDECREF(copy);
 779
 780    /* Renames in an empty dict */
 781    renames = (QDictRenames[]) {
 782        { "abcdef",     "abc" },
 783        { NULL , NULL }
 784    };
 785
 786    QDECREF(dict);
 787    dict = qdict_new();
 788
 789    qdict_rename_keys(dict, renames, &error_abort);
 790    g_assert(qdict_first(dict) == NULL);
 791
 792    QDECREF(dict);
 793}
 794
 795static void qdict_crumple_test_bad_inputs(void)
 796{
 797    QDict *src;
 798    Error *error = NULL;
 799
 800    src = qdict_new();
 801    /* rule.0 can't be both a string and a dict */
 802    qdict_put_str(src, "rule.0", "fred");
 803    qdict_put_str(src, "rule.0.policy", "allow");
 804
 805    g_assert(qdict_crumple(src, &error) == NULL);
 806    g_assert(error != NULL);
 807    error_free(error);
 808    error = NULL;
 809    QDECREF(src);
 810
 811    src = qdict_new();
 812    /* rule can't be both a list and a dict */
 813    qdict_put_str(src, "rule.0", "fred");
 814    qdict_put_str(src, "rule.a", "allow");
 815
 816    g_assert(qdict_crumple(src, &error) == NULL);
 817    g_assert(error != NULL);
 818    error_free(error);
 819    error = NULL;
 820    QDECREF(src);
 821
 822    src = qdict_new();
 823    /* The input should be flat, ie no dicts or lists */
 824    qdict_put(src, "rule.a", qdict_new());
 825    qdict_put_str(src, "rule.b", "allow");
 826
 827    g_assert(qdict_crumple(src, &error) == NULL);
 828    g_assert(error != NULL);
 829    error_free(error);
 830    error = NULL;
 831    QDECREF(src);
 832
 833    src = qdict_new();
 834    /* List indexes must not have gaps */
 835    qdict_put_str(src, "rule.0", "deny");
 836    qdict_put_str(src, "rule.3", "allow");
 837
 838    g_assert(qdict_crumple(src, &error) == NULL);
 839    g_assert(error != NULL);
 840    error_free(error);
 841    error = NULL;
 842    QDECREF(src);
 843
 844    src = qdict_new();
 845    /* List indexes must be in %zu format */
 846    qdict_put_str(src, "rule.0", "deny");
 847    qdict_put_str(src, "rule.+1", "allow");
 848
 849    g_assert(qdict_crumple(src, &error) == NULL);
 850    g_assert(error != NULL);
 851    error_free(error);
 852    error = NULL;
 853    QDECREF(src);
 854}
 855
 856/*
 857 * Errors test-cases
 858 */
 859
 860static void qdict_put_exists_test(void)
 861{
 862    int value;
 863    const char *key = "exists";
 864    QDict *tests_dict = qdict_new();
 865
 866    qdict_put_int(tests_dict, key, 1);
 867    qdict_put_int(tests_dict, key, 2);
 868
 869    value = qdict_get_int(tests_dict, key);
 870    g_assert(value == 2);
 871
 872    g_assert(qdict_size(tests_dict) == 1);
 873
 874    QDECREF(tests_dict);
 875}
 876
 877static void qdict_get_not_exists_test(void)
 878{
 879    QDict *tests_dict = qdict_new();
 880    g_assert(qdict_get(tests_dict, "foo") == NULL);
 881
 882    QDECREF(tests_dict);
 883}
 884
 885/*
 886 * Stress test-case
 887 *
 888 * This is a lot big for a unit-test, but there is no other place
 889 * to have it.
 890 */
 891
 892static void remove_dots(char *string)
 893{
 894    char *p = strchr(string, ':');
 895    if (p)
 896        *p = '\0';
 897}
 898
 899static QString *read_line(FILE *file, char *key)
 900{
 901    char value[128];
 902
 903    if (fscanf(file, "%127s%127s", key, value) == EOF) {
 904        return NULL;
 905    }
 906    remove_dots(key);
 907    return qstring_from_str(value);
 908}
 909
 910#define reset_file(file)    fseek(file, 0L, SEEK_SET)
 911
 912static void qdict_stress_test(void)
 913{
 914    size_t lines;
 915    char key[128];
 916    FILE *test_file;
 917    QDict *qdict;
 918    QString *value;
 919    const char *test_file_path = "qdict-test-data.txt";
 920
 921    test_file = fopen(test_file_path, "r");
 922    g_assert(test_file != NULL);
 923
 924    // Create the dict
 925    qdict = qdict_new();
 926    g_assert(qdict != NULL);
 927
 928    // Add everything from the test file
 929    for (lines = 0;; lines++) {
 930        value = read_line(test_file, key);
 931        if (!value)
 932            break;
 933
 934        qdict_put(qdict, key, value);
 935    }
 936    g_assert(qdict_size(qdict) == lines);
 937
 938    // Check if everything is really in there
 939    reset_file(test_file);
 940    for (;;) {
 941        const char *str1, *str2;
 942
 943        value = read_line(test_file, key);
 944        if (!value)
 945            break;
 946
 947        str1 = qstring_get_str(value);
 948
 949        str2 = qdict_get_str(qdict, key);
 950        g_assert(str2 != NULL);
 951
 952        g_assert(strcmp(str1, str2) == 0);
 953
 954        QDECREF(value);
 955    }
 956
 957    // Delete everything
 958    reset_file(test_file);
 959    for (;;) {
 960        value = read_line(test_file, key);
 961        if (!value)
 962            break;
 963
 964        qdict_del(qdict, key);
 965        QDECREF(value);
 966
 967        g_assert(qdict_haskey(qdict, key) == 0);
 968    }
 969    fclose(test_file);
 970
 971    g_assert(qdict_size(qdict) == 0);
 972    QDECREF(qdict);
 973}
 974
 975int main(int argc, char **argv)
 976{
 977    g_test_init(&argc, &argv, NULL);
 978
 979    g_test_add_func("/public/new", qdict_new_test);
 980    g_test_add_func("/public/put_obj", qdict_put_obj_test);
 981    g_test_add_func("/public/destroy_simple", qdict_destroy_simple_test);
 982
 983    /* Continue, but now with fixtures */
 984    g_test_add_func("/public/get", qdict_get_test);
 985    g_test_add_func("/public/get_int", qdict_get_int_test);
 986    g_test_add_func("/public/get_try_int", qdict_get_try_int_test);
 987    g_test_add_func("/public/get_str", qdict_get_str_test);
 988    g_test_add_func("/public/get_try_str", qdict_get_try_str_test);
 989    g_test_add_func("/public/defaults", qdict_defaults_test);
 990    g_test_add_func("/public/haskey_not", qdict_haskey_not_test);
 991    g_test_add_func("/public/haskey", qdict_haskey_test);
 992    g_test_add_func("/public/del", qdict_del_test);
 993    g_test_add_func("/public/to_qdict", qobject_to_qdict_test);
 994    g_test_add_func("/public/iterapi", qdict_iterapi_test);
 995    g_test_add_func("/public/flatten", qdict_flatten_test);
 996    g_test_add_func("/public/array_split", qdict_array_split_test);
 997    g_test_add_func("/public/array_entries", qdict_array_entries_test);
 998    g_test_add_func("/public/join", qdict_join_test);
 999
1000    g_test_add_func("/errors/put_exists", qdict_put_exists_test);
1001    g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test);
1002
1003    g_test_add_func("/public/crumple/recursive",
1004                    qdict_crumple_test_recursive);
1005    g_test_add_func("/public/crumple/empty",
1006                    qdict_crumple_test_empty);
1007    g_test_add_func("/public/crumple/bad_inputs",
1008                    qdict_crumple_test_bad_inputs);
1009
1010    g_test_add_func("/public/rename_keys", qdict_rename_keys_test);
1011
1012    /* The Big one */
1013    if (g_test_slow()) {
1014        g_test_add_func("/stress/test", qdict_stress_test);
1015    }
1016
1017    return g_test_run();
1018}
1019