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