qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

qobject: Move block-specific qdict code to block-qdict.c

Pure code motion, except for two brace placements and a comment
tweaked to appease checkpatch.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>

authored by

Markus Armbruster and committed by
Kevin Wolf
0bcc8e5b 609f45ea

+1302 -1271
+2
MAINTAINERS
··· 1369 1369 F: qemu-io* 1370 1370 F: tests/qemu-iotests/ 1371 1371 F: util/qemu-progress.c 1372 + F: qobject/block-qdict.c 1373 + F: test/check-block-qdict.c 1372 1374 T: git git://repo.or.cz/qemu/kevin.git block 1373 1375 1374 1376 Block I/O path
+1
qobject/Makefile.objs
··· 1 1 util-obj-y = qnull.o qnum.o qstring.o qdict.o qlist.o qbool.o qlit.o 2 2 util-obj-y += qjson.o qobject.o json-lexer.o json-streamer.o json-parser.o 3 + util-obj-y += block-qdict.o
+640
qobject/block-qdict.c
··· 1 + /* 2 + * Special QDict functions used by the block layer 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 "qemu/cutils.h" 14 + #include "qapi/error.h" 15 + 16 + /** 17 + * qdict_copy_default(): If no entry mapped by 'key' exists in 'dst' yet, the 18 + * value of 'key' in 'src' is copied there (and the refcount increased 19 + * accordingly). 20 + */ 21 + void qdict_copy_default(QDict *dst, QDict *src, const char *key) 22 + { 23 + QObject *val; 24 + 25 + if (qdict_haskey(dst, key)) { 26 + return; 27 + } 28 + 29 + val = qdict_get(src, key); 30 + if (val) { 31 + qdict_put_obj(dst, key, qobject_ref(val)); 32 + } 33 + } 34 + 35 + /** 36 + * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet, a 37 + * new QString initialised by 'val' is put there. 38 + */ 39 + void qdict_set_default_str(QDict *dst, const char *key, const char *val) 40 + { 41 + if (qdict_haskey(dst, key)) { 42 + return; 43 + } 44 + 45 + qdict_put_str(dst, key, val); 46 + } 47 + 48 + static void qdict_flatten_qdict(QDict *qdict, QDict *target, 49 + const char *prefix); 50 + 51 + static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix) 52 + { 53 + QObject *value; 54 + const QListEntry *entry; 55 + char *new_key; 56 + int i; 57 + 58 + /* This function is never called with prefix == NULL, i.e., it is always 59 + * called from within qdict_flatten_q(list|dict)(). Therefore, it does not 60 + * need to remove list entries during the iteration (the whole list will be 61 + * deleted eventually anyway from qdict_flatten_qdict()). */ 62 + assert(prefix); 63 + 64 + entry = qlist_first(qlist); 65 + 66 + for (i = 0; entry; entry = qlist_next(entry), i++) { 67 + value = qlist_entry_obj(entry); 68 + new_key = g_strdup_printf("%s.%i", prefix, i); 69 + 70 + if (qobject_type(value) == QTYPE_QDICT) { 71 + qdict_flatten_qdict(qobject_to(QDict, value), target, new_key); 72 + } else if (qobject_type(value) == QTYPE_QLIST) { 73 + qdict_flatten_qlist(qobject_to(QList, value), target, new_key); 74 + } else { 75 + /* All other types are moved to the target unchanged. */ 76 + qdict_put_obj(target, new_key, qobject_ref(value)); 77 + } 78 + 79 + g_free(new_key); 80 + } 81 + } 82 + 83 + static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix) 84 + { 85 + QObject *value; 86 + const QDictEntry *entry, *next; 87 + char *new_key; 88 + bool delete; 89 + 90 + entry = qdict_first(qdict); 91 + 92 + while (entry != NULL) { 93 + 94 + next = qdict_next(qdict, entry); 95 + value = qdict_entry_value(entry); 96 + new_key = NULL; 97 + delete = false; 98 + 99 + if (prefix) { 100 + new_key = g_strdup_printf("%s.%s", prefix, entry->key); 101 + } 102 + 103 + if (qobject_type(value) == QTYPE_QDICT) { 104 + /* Entries of QDicts are processed recursively, the QDict object 105 + * itself disappears. */ 106 + qdict_flatten_qdict(qobject_to(QDict, value), target, 107 + new_key ? new_key : entry->key); 108 + delete = true; 109 + } else if (qobject_type(value) == QTYPE_QLIST) { 110 + qdict_flatten_qlist(qobject_to(QList, value), target, 111 + new_key ? new_key : entry->key); 112 + delete = true; 113 + } else if (prefix) { 114 + /* All other objects are moved to the target unchanged. */ 115 + qdict_put_obj(target, new_key, qobject_ref(value)); 116 + delete = true; 117 + } 118 + 119 + g_free(new_key); 120 + 121 + if (delete) { 122 + qdict_del(qdict, entry->key); 123 + 124 + /* Restart loop after modifying the iterated QDict */ 125 + entry = qdict_first(qdict); 126 + continue; 127 + } 128 + 129 + entry = next; 130 + } 131 + } 132 + 133 + /** 134 + * qdict_flatten(): For each nested QDict with key x, all fields with key y 135 + * are moved to this QDict and their key is renamed to "x.y". For each nested 136 + * QList with key x, the field at index y is moved to this QDict with the key 137 + * "x.y" (i.e., the reverse of what qdict_array_split() does). 138 + * This operation is applied recursively for nested QDicts and QLists. 139 + */ 140 + void qdict_flatten(QDict *qdict) 141 + { 142 + qdict_flatten_qdict(qdict, qdict, NULL); 143 + } 144 + 145 + /* extract all the src QDict entries starting by start into dst */ 146 + void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start) 147 + 148 + { 149 + const QDictEntry *entry, *next; 150 + const char *p; 151 + 152 + *dst = qdict_new(); 153 + entry = qdict_first(src); 154 + 155 + while (entry != NULL) { 156 + next = qdict_next(src, entry); 157 + if (strstart(entry->key, start, &p)) { 158 + qdict_put_obj(*dst, p, qobject_ref(entry->value)); 159 + qdict_del(src, entry->key); 160 + } 161 + entry = next; 162 + } 163 + } 164 + 165 + static int qdict_count_prefixed_entries(const QDict *src, const char *start) 166 + { 167 + const QDictEntry *entry; 168 + int count = 0; 169 + 170 + for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) { 171 + if (strstart(entry->key, start, NULL)) { 172 + if (count == INT_MAX) { 173 + return -ERANGE; 174 + } 175 + count++; 176 + } 177 + } 178 + 179 + return count; 180 + } 181 + 182 + /** 183 + * qdict_array_split(): This function moves array-like elements of a QDict into 184 + * a new QList. Every entry in the original QDict with a key "%u" or one 185 + * prefixed "%u.", where %u designates an unsigned integer starting at 0 and 186 + * incrementally counting up, will be moved to a new QDict at index %u in the 187 + * output QList with the key prefix removed, if that prefix is "%u.". If the 188 + * whole key is just "%u", the whole QObject will be moved unchanged without 189 + * creating a new QDict. The function terminates when there is no entry in the 190 + * QDict with a prefix directly (incrementally) following the last one; it also 191 + * returns if there are both entries with "%u" and "%u." for the same index %u. 192 + * Example: {"0.a": 42, "0.b": 23, "1.x": 0, "4.y": 1, "o.o": 7, "2": 66} 193 + * (or {"1.x": 0, "4.y": 1, "0.a": 42, "o.o": 7, "0.b": 23, "2": 66}) 194 + * => [{"a": 42, "b": 23}, {"x": 0}, 66] 195 + * and {"4.y": 1, "o.o": 7} (remainder of the old QDict) 196 + */ 197 + void qdict_array_split(QDict *src, QList **dst) 198 + { 199 + unsigned i; 200 + 201 + *dst = qlist_new(); 202 + 203 + for (i = 0; i < UINT_MAX; i++) { 204 + QObject *subqobj; 205 + bool is_subqdict; 206 + QDict *subqdict; 207 + char indexstr[32], prefix[32]; 208 + size_t snprintf_ret; 209 + 210 + snprintf_ret = snprintf(indexstr, 32, "%u", i); 211 + assert(snprintf_ret < 32); 212 + 213 + subqobj = qdict_get(src, indexstr); 214 + 215 + snprintf_ret = snprintf(prefix, 32, "%u.", i); 216 + assert(snprintf_ret < 32); 217 + 218 + /* Overflow is the same as positive non-zero results */ 219 + is_subqdict = qdict_count_prefixed_entries(src, prefix); 220 + 221 + /* 222 + * There may be either a single subordinate object (named 223 + * "%u") or multiple objects (each with a key prefixed "%u."), 224 + * but not both. 225 + */ 226 + if (!subqobj == !is_subqdict) { 227 + break; 228 + } 229 + 230 + if (is_subqdict) { 231 + qdict_extract_subqdict(src, &subqdict, prefix); 232 + assert(qdict_size(subqdict) > 0); 233 + } else { 234 + qobject_ref(subqobj); 235 + qdict_del(src, indexstr); 236 + } 237 + 238 + qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict)); 239 + } 240 + } 241 + 242 + /** 243 + * qdict_split_flat_key: 244 + * @key: the key string to split 245 + * @prefix: non-NULL pointer to hold extracted prefix 246 + * @suffix: non-NULL pointer to remaining suffix 247 + * 248 + * Given a flattened key such as 'foo.0.bar', split it into two parts 249 + * at the first '.' separator. Allows double dot ('..') to escape the 250 + * normal separator. 251 + * 252 + * e.g. 253 + * 'foo.0.bar' -> prefix='foo' and suffix='0.bar' 254 + * 'foo..0.bar' -> prefix='foo.0' and suffix='bar' 255 + * 256 + * The '..' sequence will be unescaped in the returned 'prefix' 257 + * string. The 'suffix' string will be left in escaped format, so it 258 + * can be fed back into the qdict_split_flat_key() key as the input 259 + * later. 260 + * 261 + * The caller is responsible for freeing the string returned in @prefix 262 + * using g_free(). 263 + */ 264 + static void qdict_split_flat_key(const char *key, char **prefix, 265 + const char **suffix) 266 + { 267 + const char *separator; 268 + size_t i, j; 269 + 270 + /* Find first '.' separator, but if there is a pair '..' 271 + * that acts as an escape, so skip over '..' */ 272 + separator = NULL; 273 + do { 274 + if (separator) { 275 + separator += 2; 276 + } else { 277 + separator = key; 278 + } 279 + separator = strchr(separator, '.'); 280 + } while (separator && separator[1] == '.'); 281 + 282 + if (separator) { 283 + *prefix = g_strndup(key, separator - key); 284 + *suffix = separator + 1; 285 + } else { 286 + *prefix = g_strdup(key); 287 + *suffix = NULL; 288 + } 289 + 290 + /* Unescape the '..' sequence into '.' */ 291 + for (i = 0, j = 0; (*prefix)[i] != '\0'; i++, j++) { 292 + if ((*prefix)[i] == '.') { 293 + assert((*prefix)[i + 1] == '.'); 294 + i++; 295 + } 296 + (*prefix)[j] = (*prefix)[i]; 297 + } 298 + (*prefix)[j] = '\0'; 299 + } 300 + 301 + /** 302 + * qdict_is_list: 303 + * @maybe_list: dict to check if keys represent list elements. 304 + * 305 + * Determine whether all keys in @maybe_list are valid list elements. 306 + * If @maybe_list is non-zero in length and all the keys look like 307 + * valid list indexes, this will return 1. If @maybe_list is zero 308 + * length or all keys are non-numeric then it will return 0 to indicate 309 + * it is a normal qdict. If there is a mix of numeric and non-numeric 310 + * keys, or the list indexes are non-contiguous, an error is reported. 311 + * 312 + * Returns: 1 if a valid list, 0 if a dict, -1 on error 313 + */ 314 + static int qdict_is_list(QDict *maybe_list, Error **errp) 315 + { 316 + const QDictEntry *ent; 317 + ssize_t len = 0; 318 + ssize_t max = -1; 319 + int is_list = -1; 320 + int64_t val; 321 + 322 + for (ent = qdict_first(maybe_list); ent != NULL; 323 + ent = qdict_next(maybe_list, ent)) { 324 + 325 + if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) { 326 + if (is_list == -1) { 327 + is_list = 1; 328 + } else if (!is_list) { 329 + error_setg(errp, 330 + "Cannot mix list and non-list keys"); 331 + return -1; 332 + } 333 + len++; 334 + if (val > max) { 335 + max = val; 336 + } 337 + } else { 338 + if (is_list == -1) { 339 + is_list = 0; 340 + } else if (is_list) { 341 + error_setg(errp, 342 + "Cannot mix list and non-list keys"); 343 + return -1; 344 + } 345 + } 346 + } 347 + 348 + if (is_list == -1) { 349 + assert(!qdict_size(maybe_list)); 350 + is_list = 0; 351 + } 352 + 353 + /* NB this isn't a perfect check - e.g. it won't catch 354 + * a list containing '1', '+1', '01', '3', but that 355 + * does not matter - we've still proved that the 356 + * input is a list. It is up the caller to do a 357 + * stricter check if desired */ 358 + if (len != (max + 1)) { 359 + error_setg(errp, "List indices are not contiguous, " 360 + "saw %zd elements but %zd largest index", 361 + len, max); 362 + return -1; 363 + } 364 + 365 + return is_list; 366 + } 367 + 368 + /** 369 + * qdict_crumple: 370 + * @src: the original flat dictionary (only scalar values) to crumple 371 + * 372 + * Takes a flat dictionary whose keys use '.' separator to indicate 373 + * nesting, and values are scalars, and crumples it into a nested 374 + * structure. 375 + * 376 + * To include a literal '.' in a key name, it must be escaped as '..' 377 + * 378 + * For example, an input of: 379 + * 380 + * { 'foo.0.bar': 'one', 'foo.0.wizz': '1', 381 + * 'foo.1.bar': 'two', 'foo.1.wizz': '2' } 382 + * 383 + * will result in an output of: 384 + * 385 + * { 386 + * 'foo': [ 387 + * { 'bar': 'one', 'wizz': '1' }, 388 + * { 'bar': 'two', 'wizz': '2' } 389 + * ], 390 + * } 391 + * 392 + * The following scenarios in the input dict will result in an 393 + * error being returned: 394 + * 395 + * - Any values in @src are non-scalar types 396 + * - If keys in @src imply that a particular level is both a 397 + * list and a dict. e.g., "foo.0.bar" and "foo.eek.bar". 398 + * - If keys in @src imply that a particular level is a list, 399 + * but the indices are non-contiguous. e.g. "foo.0.bar" and 400 + * "foo.2.bar" without any "foo.1.bar" present. 401 + * - If keys in @src represent list indexes, but are not in 402 + * the "%zu" format. e.g. "foo.+0.bar" 403 + * 404 + * Returns: either a QDict or QList for the nested data structure, or NULL 405 + * on error 406 + */ 407 + QObject *qdict_crumple(const QDict *src, Error **errp) 408 + { 409 + const QDictEntry *ent; 410 + QDict *two_level, *multi_level = NULL; 411 + QObject *dst = NULL, *child; 412 + size_t i; 413 + char *prefix = NULL; 414 + const char *suffix = NULL; 415 + int is_list; 416 + 417 + two_level = qdict_new(); 418 + 419 + /* Step 1: split our totally flat dict into a two level dict */ 420 + for (ent = qdict_first(src); ent != NULL; ent = qdict_next(src, ent)) { 421 + if (qobject_type(ent->value) == QTYPE_QDICT || 422 + qobject_type(ent->value) == QTYPE_QLIST) { 423 + error_setg(errp, "Value %s is not a scalar", 424 + ent->key); 425 + goto error; 426 + } 427 + 428 + qdict_split_flat_key(ent->key, &prefix, &suffix); 429 + 430 + child = qdict_get(two_level, prefix); 431 + if (suffix) { 432 + QDict *child_dict = qobject_to(QDict, child); 433 + if (!child_dict) { 434 + if (child) { 435 + error_setg(errp, "Key %s prefix is already set as a scalar", 436 + prefix); 437 + goto error; 438 + } 439 + 440 + child_dict = qdict_new(); 441 + qdict_put_obj(two_level, prefix, QOBJECT(child_dict)); 442 + } 443 + 444 + qdict_put_obj(child_dict, suffix, qobject_ref(ent->value)); 445 + } else { 446 + if (child) { 447 + error_setg(errp, "Key %s prefix is already set as a dict", 448 + prefix); 449 + goto error; 450 + } 451 + qdict_put_obj(two_level, prefix, qobject_ref(ent->value)); 452 + } 453 + 454 + g_free(prefix); 455 + prefix = NULL; 456 + } 457 + 458 + /* Step 2: optionally process the two level dict recursively 459 + * into a multi-level dict */ 460 + multi_level = qdict_new(); 461 + for (ent = qdict_first(two_level); ent != NULL; 462 + ent = qdict_next(two_level, ent)) { 463 + QDict *dict = qobject_to(QDict, ent->value); 464 + if (dict) { 465 + child = qdict_crumple(dict, errp); 466 + if (!child) { 467 + goto error; 468 + } 469 + 470 + qdict_put_obj(multi_level, ent->key, child); 471 + } else { 472 + qdict_put_obj(multi_level, ent->key, qobject_ref(ent->value)); 473 + } 474 + } 475 + qobject_unref(two_level); 476 + two_level = NULL; 477 + 478 + /* Step 3: detect if we need to turn our dict into list */ 479 + is_list = qdict_is_list(multi_level, errp); 480 + if (is_list < 0) { 481 + goto error; 482 + } 483 + 484 + if (is_list) { 485 + dst = QOBJECT(qlist_new()); 486 + 487 + for (i = 0; i < qdict_size(multi_level); i++) { 488 + char *key = g_strdup_printf("%zu", i); 489 + 490 + child = qdict_get(multi_level, key); 491 + g_free(key); 492 + 493 + if (!child) { 494 + error_setg(errp, "Missing list index %zu", i); 495 + goto error; 496 + } 497 + 498 + qlist_append_obj(qobject_to(QList, dst), qobject_ref(child)); 499 + } 500 + qobject_unref(multi_level); 501 + multi_level = NULL; 502 + } else { 503 + dst = QOBJECT(multi_level); 504 + } 505 + 506 + return dst; 507 + 508 + error: 509 + g_free(prefix); 510 + qobject_unref(multi_level); 511 + qobject_unref(two_level); 512 + qobject_unref(dst); 513 + return NULL; 514 + } 515 + 516 + /** 517 + * qdict_array_entries(): Returns the number of direct array entries if the 518 + * sub-QDict of src specified by the prefix in subqdict (or src itself for 519 + * prefix == "") is valid as an array, i.e. the length of the created list if 520 + * the sub-QDict would become empty after calling qdict_array_split() on it. If 521 + * the array is not valid, -EINVAL is returned. 522 + */ 523 + int qdict_array_entries(QDict *src, const char *subqdict) 524 + { 525 + const QDictEntry *entry; 526 + unsigned i; 527 + unsigned entries = 0; 528 + size_t subqdict_len = strlen(subqdict); 529 + 530 + assert(!subqdict_len || subqdict[subqdict_len - 1] == '.'); 531 + 532 + /* qdict_array_split() loops until UINT_MAX, but as we want to return 533 + * negative errors, we only have a signed return value here. Any additional 534 + * entries will lead to -EINVAL. */ 535 + for (i = 0; i < INT_MAX; i++) { 536 + QObject *subqobj; 537 + int subqdict_entries; 538 + char *prefix = g_strdup_printf("%s%u.", subqdict, i); 539 + 540 + subqdict_entries = qdict_count_prefixed_entries(src, prefix); 541 + 542 + /* Remove ending "." */ 543 + prefix[strlen(prefix) - 1] = 0; 544 + subqobj = qdict_get(src, prefix); 545 + 546 + g_free(prefix); 547 + 548 + if (subqdict_entries < 0) { 549 + return subqdict_entries; 550 + } 551 + 552 + /* There may be either a single subordinate object (named "%u") or 553 + * multiple objects (each with a key prefixed "%u."), but not both. */ 554 + if (subqobj && subqdict_entries) { 555 + return -EINVAL; 556 + } else if (!subqobj && !subqdict_entries) { 557 + break; 558 + } 559 + 560 + entries += subqdict_entries ? subqdict_entries : 1; 561 + } 562 + 563 + /* Consider everything handled that isn't part of the given sub-QDict */ 564 + for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) { 565 + if (!strstart(qdict_entry_key(entry), subqdict, NULL)) { 566 + entries++; 567 + } 568 + } 569 + 570 + /* Anything left in the sub-QDict that wasn't handled? */ 571 + if (qdict_size(src) != entries) { 572 + return -EINVAL; 573 + } 574 + 575 + return i; 576 + } 577 + 578 + /** 579 + * qdict_join(): Absorb the src QDict into the dest QDict, that is, move all 580 + * elements from src to dest. 581 + * 582 + * If an element from src has a key already present in dest, it will not be 583 + * moved unless overwrite is true. 584 + * 585 + * If overwrite is true, the conflicting values in dest will be discarded and 586 + * replaced by the corresponding values from src. 587 + * 588 + * Therefore, with overwrite being true, the src QDict will always be empty when 589 + * this function returns. If overwrite is false, the src QDict will be empty 590 + * iff there were no conflicts. 591 + */ 592 + void qdict_join(QDict *dest, QDict *src, bool overwrite) 593 + { 594 + const QDictEntry *entry, *next; 595 + 596 + entry = qdict_first(src); 597 + while (entry) { 598 + next = qdict_next(src, entry); 599 + 600 + if (overwrite || !qdict_haskey(dest, entry->key)) { 601 + qdict_put_obj(dest, entry->key, qobject_ref(entry->value)); 602 + qdict_del(src, entry->key); 603 + } 604 + 605 + entry = next; 606 + } 607 + } 608 + 609 + /** 610 + * qdict_rename_keys(): Rename keys in qdict according to the replacements 611 + * specified in the array renames. The array must be terminated by an entry 612 + * with from = NULL. 613 + * 614 + * The renames are performed individually in the order of the array, so entries 615 + * may be renamed multiple times and may or may not conflict depending on the 616 + * order of the renames array. 617 + * 618 + * Returns true for success, false in error cases. 619 + */ 620 + bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp) 621 + { 622 + QObject *qobj; 623 + 624 + while (renames->from) { 625 + if (qdict_haskey(qdict, renames->from)) { 626 + if (qdict_haskey(qdict, renames->to)) { 627 + error_setg(errp, "'%s' and its alias '%s' can't be used at the " 628 + "same time", renames->to, renames->from); 629 + return false; 630 + } 631 + 632 + qobj = qdict_get(qdict, renames->from); 633 + qdict_put_obj(qdict, renames->to, qobject_ref(qobj)); 634 + qdict_del(qdict, renames->from); 635 + } 636 + 637 + renames++; 638 + } 639 + return true; 640 + }
-629
qobject/qdict.c
··· 11 11 */ 12 12 13 13 #include "qemu/osdep.h" 14 - #include "block/qdict.h" 15 14 #include "qapi/qmp/qnum.h" 16 15 #include "qapi/qmp/qdict.h" 17 16 #include "qapi/qmp/qbool.h" 18 - #include "qapi/qmp/qlist.h" 19 17 #include "qapi/qmp/qnull.h" 20 18 #include "qapi/qmp/qstring.h" 21 - #include "qapi/error.h" 22 - #include "qemu/queue.h" 23 - #include "qemu-common.h" 24 - #include "qemu/cutils.h" 25 19 26 20 /** 27 21 * qdict_new(): Create a new QDict ··· 464 458 465 459 g_free(qdict); 466 460 } 467 - 468 - /** 469 - * qdict_copy_default(): If no entry mapped by 'key' exists in 'dst' yet, the 470 - * value of 'key' in 'src' is copied there (and the refcount increased 471 - * accordingly). 472 - */ 473 - void qdict_copy_default(QDict *dst, QDict *src, const char *key) 474 - { 475 - QObject *val; 476 - 477 - if (qdict_haskey(dst, key)) { 478 - return; 479 - } 480 - 481 - val = qdict_get(src, key); 482 - if (val) { 483 - qdict_put_obj(dst, key, qobject_ref(val)); 484 - } 485 - } 486 - 487 - /** 488 - * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet, a 489 - * new QString initialised by 'val' is put there. 490 - */ 491 - void qdict_set_default_str(QDict *dst, const char *key, const char *val) 492 - { 493 - if (qdict_haskey(dst, key)) { 494 - return; 495 - } 496 - 497 - qdict_put_str(dst, key, val); 498 - } 499 - 500 - static void qdict_flatten_qdict(QDict *qdict, QDict *target, 501 - const char *prefix); 502 - 503 - static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix) 504 - { 505 - QObject *value; 506 - const QListEntry *entry; 507 - char *new_key; 508 - int i; 509 - 510 - /* This function is never called with prefix == NULL, i.e., it is always 511 - * called from within qdict_flatten_q(list|dict)(). Therefore, it does not 512 - * need to remove list entries during the iteration (the whole list will be 513 - * deleted eventually anyway from qdict_flatten_qdict()). */ 514 - assert(prefix); 515 - 516 - entry = qlist_first(qlist); 517 - 518 - for (i = 0; entry; entry = qlist_next(entry), i++) { 519 - value = qlist_entry_obj(entry); 520 - new_key = g_strdup_printf("%s.%i", prefix, i); 521 - 522 - if (qobject_type(value) == QTYPE_QDICT) { 523 - qdict_flatten_qdict(qobject_to(QDict, value), target, new_key); 524 - } else if (qobject_type(value) == QTYPE_QLIST) { 525 - qdict_flatten_qlist(qobject_to(QList, value), target, new_key); 526 - } else { 527 - /* All other types are moved to the target unchanged. */ 528 - qdict_put_obj(target, new_key, qobject_ref(value)); 529 - } 530 - 531 - g_free(new_key); 532 - } 533 - } 534 - 535 - static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix) 536 - { 537 - QObject *value; 538 - const QDictEntry *entry, *next; 539 - char *new_key; 540 - bool delete; 541 - 542 - entry = qdict_first(qdict); 543 - 544 - while (entry != NULL) { 545 - 546 - next = qdict_next(qdict, entry); 547 - value = qdict_entry_value(entry); 548 - new_key = NULL; 549 - delete = false; 550 - 551 - if (prefix) { 552 - new_key = g_strdup_printf("%s.%s", prefix, entry->key); 553 - } 554 - 555 - if (qobject_type(value) == QTYPE_QDICT) { 556 - /* Entries of QDicts are processed recursively, the QDict object 557 - * itself disappears. */ 558 - qdict_flatten_qdict(qobject_to(QDict, value), target, 559 - new_key ? new_key : entry->key); 560 - delete = true; 561 - } else if (qobject_type(value) == QTYPE_QLIST) { 562 - qdict_flatten_qlist(qobject_to(QList, value), target, 563 - new_key ? new_key : entry->key); 564 - delete = true; 565 - } else if (prefix) { 566 - /* All other objects are moved to the target unchanged. */ 567 - qdict_put_obj(target, new_key, qobject_ref(value)); 568 - delete = true; 569 - } 570 - 571 - g_free(new_key); 572 - 573 - if (delete) { 574 - qdict_del(qdict, entry->key); 575 - 576 - /* Restart loop after modifying the iterated QDict */ 577 - entry = qdict_first(qdict); 578 - continue; 579 - } 580 - 581 - entry = next; 582 - } 583 - } 584 - 585 - /** 586 - * qdict_flatten(): For each nested QDict with key x, all fields with key y 587 - * are moved to this QDict and their key is renamed to "x.y". For each nested 588 - * QList with key x, the field at index y is moved to this QDict with the key 589 - * "x.y" (i.e., the reverse of what qdict_array_split() does). 590 - * This operation is applied recursively for nested QDicts and QLists. 591 - */ 592 - void qdict_flatten(QDict *qdict) 593 - { 594 - qdict_flatten_qdict(qdict, qdict, NULL); 595 - } 596 - 597 - /* extract all the src QDict entries starting by start into dst */ 598 - void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start) 599 - 600 - { 601 - const QDictEntry *entry, *next; 602 - const char *p; 603 - 604 - *dst = qdict_new(); 605 - entry = qdict_first(src); 606 - 607 - while (entry != NULL) { 608 - next = qdict_next(src, entry); 609 - if (strstart(entry->key, start, &p)) { 610 - qdict_put_obj(*dst, p, qobject_ref(entry->value)); 611 - qdict_del(src, entry->key); 612 - } 613 - entry = next; 614 - } 615 - } 616 - 617 - static int qdict_count_prefixed_entries(const QDict *src, const char *start) 618 - { 619 - const QDictEntry *entry; 620 - int count = 0; 621 - 622 - for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) { 623 - if (strstart(entry->key, start, NULL)) { 624 - if (count == INT_MAX) { 625 - return -ERANGE; 626 - } 627 - count++; 628 - } 629 - } 630 - 631 - return count; 632 - } 633 - 634 - /** 635 - * qdict_array_split(): This function moves array-like elements of a QDict into 636 - * a new QList. Every entry in the original QDict with a key "%u" or one 637 - * prefixed "%u.", where %u designates an unsigned integer starting at 0 and 638 - * incrementally counting up, will be moved to a new QDict at index %u in the 639 - * output QList with the key prefix removed, if that prefix is "%u.". If the 640 - * whole key is just "%u", the whole QObject will be moved unchanged without 641 - * creating a new QDict. The function terminates when there is no entry in the 642 - * QDict with a prefix directly (incrementally) following the last one; it also 643 - * returns if there are both entries with "%u" and "%u." for the same index %u. 644 - * Example: {"0.a": 42, "0.b": 23, "1.x": 0, "4.y": 1, "o.o": 7, "2": 66} 645 - * (or {"1.x": 0, "4.y": 1, "0.a": 42, "o.o": 7, "0.b": 23, "2": 66}) 646 - * => [{"a": 42, "b": 23}, {"x": 0}, 66] 647 - * and {"4.y": 1, "o.o": 7} (remainder of the old QDict) 648 - */ 649 - void qdict_array_split(QDict *src, QList **dst) 650 - { 651 - unsigned i; 652 - 653 - *dst = qlist_new(); 654 - 655 - for (i = 0; i < UINT_MAX; i++) { 656 - QObject *subqobj; 657 - bool is_subqdict; 658 - QDict *subqdict; 659 - char indexstr[32], prefix[32]; 660 - size_t snprintf_ret; 661 - 662 - snprintf_ret = snprintf(indexstr, 32, "%u", i); 663 - assert(snprintf_ret < 32); 664 - 665 - subqobj = qdict_get(src, indexstr); 666 - 667 - snprintf_ret = snprintf(prefix, 32, "%u.", i); 668 - assert(snprintf_ret < 32); 669 - 670 - /* Overflow is the same as positive non-zero results */ 671 - is_subqdict = qdict_count_prefixed_entries(src, prefix); 672 - 673 - // There may be either a single subordinate object (named "%u") or 674 - // multiple objects (each with a key prefixed "%u."), but not both. 675 - if (!subqobj == !is_subqdict) { 676 - break; 677 - } 678 - 679 - if (is_subqdict) { 680 - qdict_extract_subqdict(src, &subqdict, prefix); 681 - assert(qdict_size(subqdict) > 0); 682 - } else { 683 - qobject_ref(subqobj); 684 - qdict_del(src, indexstr); 685 - } 686 - 687 - qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict)); 688 - } 689 - } 690 - 691 - /** 692 - * qdict_split_flat_key: 693 - * @key: the key string to split 694 - * @prefix: non-NULL pointer to hold extracted prefix 695 - * @suffix: non-NULL pointer to remaining suffix 696 - * 697 - * Given a flattened key such as 'foo.0.bar', split it into two parts 698 - * at the first '.' separator. Allows double dot ('..') to escape the 699 - * normal separator. 700 - * 701 - * e.g. 702 - * 'foo.0.bar' -> prefix='foo' and suffix='0.bar' 703 - * 'foo..0.bar' -> prefix='foo.0' and suffix='bar' 704 - * 705 - * The '..' sequence will be unescaped in the returned 'prefix' 706 - * string. The 'suffix' string will be left in escaped format, so it 707 - * can be fed back into the qdict_split_flat_key() key as the input 708 - * later. 709 - * 710 - * The caller is responsible for freeing the string returned in @prefix 711 - * using g_free(). 712 - */ 713 - static void qdict_split_flat_key(const char *key, char **prefix, 714 - const char **suffix) 715 - { 716 - const char *separator; 717 - size_t i, j; 718 - 719 - /* Find first '.' separator, but if there is a pair '..' 720 - * that acts as an escape, so skip over '..' */ 721 - separator = NULL; 722 - do { 723 - if (separator) { 724 - separator += 2; 725 - } else { 726 - separator = key; 727 - } 728 - separator = strchr(separator, '.'); 729 - } while (separator && separator[1] == '.'); 730 - 731 - if (separator) { 732 - *prefix = g_strndup(key, separator - key); 733 - *suffix = separator + 1; 734 - } else { 735 - *prefix = g_strdup(key); 736 - *suffix = NULL; 737 - } 738 - 739 - /* Unescape the '..' sequence into '.' */ 740 - for (i = 0, j = 0; (*prefix)[i] != '\0'; i++, j++) { 741 - if ((*prefix)[i] == '.') { 742 - assert((*prefix)[i + 1] == '.'); 743 - i++; 744 - } 745 - (*prefix)[j] = (*prefix)[i]; 746 - } 747 - (*prefix)[j] = '\0'; 748 - } 749 - 750 - /** 751 - * qdict_is_list: 752 - * @maybe_list: dict to check if keys represent list elements. 753 - * 754 - * Determine whether all keys in @maybe_list are valid list elements. 755 - * If @maybe_list is non-zero in length and all the keys look like 756 - * valid list indexes, this will return 1. If @maybe_list is zero 757 - * length or all keys are non-numeric then it will return 0 to indicate 758 - * it is a normal qdict. If there is a mix of numeric and non-numeric 759 - * keys, or the list indexes are non-contiguous, an error is reported. 760 - * 761 - * Returns: 1 if a valid list, 0 if a dict, -1 on error 762 - */ 763 - static int qdict_is_list(QDict *maybe_list, Error **errp) 764 - { 765 - const QDictEntry *ent; 766 - ssize_t len = 0; 767 - ssize_t max = -1; 768 - int is_list = -1; 769 - int64_t val; 770 - 771 - for (ent = qdict_first(maybe_list); ent != NULL; 772 - ent = qdict_next(maybe_list, ent)) { 773 - 774 - if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) { 775 - if (is_list == -1) { 776 - is_list = 1; 777 - } else if (!is_list) { 778 - error_setg(errp, 779 - "Cannot mix list and non-list keys"); 780 - return -1; 781 - } 782 - len++; 783 - if (val > max) { 784 - max = val; 785 - } 786 - } else { 787 - if (is_list == -1) { 788 - is_list = 0; 789 - } else if (is_list) { 790 - error_setg(errp, 791 - "Cannot mix list and non-list keys"); 792 - return -1; 793 - } 794 - } 795 - } 796 - 797 - if (is_list == -1) { 798 - assert(!qdict_size(maybe_list)); 799 - is_list = 0; 800 - } 801 - 802 - /* NB this isn't a perfect check - e.g. it won't catch 803 - * a list containing '1', '+1', '01', '3', but that 804 - * does not matter - we've still proved that the 805 - * input is a list. It is up the caller to do a 806 - * stricter check if desired */ 807 - if (len != (max + 1)) { 808 - error_setg(errp, "List indices are not contiguous, " 809 - "saw %zd elements but %zd largest index", 810 - len, max); 811 - return -1; 812 - } 813 - 814 - return is_list; 815 - } 816 - 817 - /** 818 - * qdict_crumple: 819 - * @src: the original flat dictionary (only scalar values) to crumple 820 - * 821 - * Takes a flat dictionary whose keys use '.' separator to indicate 822 - * nesting, and values are scalars, and crumples it into a nested 823 - * structure. 824 - * 825 - * To include a literal '.' in a key name, it must be escaped as '..' 826 - * 827 - * For example, an input of: 828 - * 829 - * { 'foo.0.bar': 'one', 'foo.0.wizz': '1', 830 - * 'foo.1.bar': 'two', 'foo.1.wizz': '2' } 831 - * 832 - * will result in an output of: 833 - * 834 - * { 835 - * 'foo': [ 836 - * { 'bar': 'one', 'wizz': '1' }, 837 - * { 'bar': 'two', 'wizz': '2' } 838 - * ], 839 - * } 840 - * 841 - * The following scenarios in the input dict will result in an 842 - * error being returned: 843 - * 844 - * - Any values in @src are non-scalar types 845 - * - If keys in @src imply that a particular level is both a 846 - * list and a dict. e.g., "foo.0.bar" and "foo.eek.bar". 847 - * - If keys in @src imply that a particular level is a list, 848 - * but the indices are non-contiguous. e.g. "foo.0.bar" and 849 - * "foo.2.bar" without any "foo.1.bar" present. 850 - * - If keys in @src represent list indexes, but are not in 851 - * the "%zu" format. e.g. "foo.+0.bar" 852 - * 853 - * Returns: either a QDict or QList for the nested data structure, or NULL 854 - * on error 855 - */ 856 - QObject *qdict_crumple(const QDict *src, Error **errp) 857 - { 858 - const QDictEntry *ent; 859 - QDict *two_level, *multi_level = NULL; 860 - QObject *dst = NULL, *child; 861 - size_t i; 862 - char *prefix = NULL; 863 - const char *suffix = NULL; 864 - int is_list; 865 - 866 - two_level = qdict_new(); 867 - 868 - /* Step 1: split our totally flat dict into a two level dict */ 869 - for (ent = qdict_first(src); ent != NULL; ent = qdict_next(src, ent)) { 870 - if (qobject_type(ent->value) == QTYPE_QDICT || 871 - qobject_type(ent->value) == QTYPE_QLIST) { 872 - error_setg(errp, "Value %s is not a scalar", 873 - ent->key); 874 - goto error; 875 - } 876 - 877 - qdict_split_flat_key(ent->key, &prefix, &suffix); 878 - 879 - child = qdict_get(two_level, prefix); 880 - if (suffix) { 881 - QDict *child_dict = qobject_to(QDict, child); 882 - if (!child_dict) { 883 - if (child) { 884 - error_setg(errp, "Key %s prefix is already set as a scalar", 885 - prefix); 886 - goto error; 887 - } 888 - 889 - child_dict = qdict_new(); 890 - qdict_put_obj(two_level, prefix, QOBJECT(child_dict)); 891 - } 892 - 893 - qdict_put_obj(child_dict, suffix, qobject_ref(ent->value)); 894 - } else { 895 - if (child) { 896 - error_setg(errp, "Key %s prefix is already set as a dict", 897 - prefix); 898 - goto error; 899 - } 900 - qdict_put_obj(two_level, prefix, qobject_ref(ent->value)); 901 - } 902 - 903 - g_free(prefix); 904 - prefix = NULL; 905 - } 906 - 907 - /* Step 2: optionally process the two level dict recursively 908 - * into a multi-level dict */ 909 - multi_level = qdict_new(); 910 - for (ent = qdict_first(two_level); ent != NULL; 911 - ent = qdict_next(two_level, ent)) { 912 - QDict *dict = qobject_to(QDict, ent->value); 913 - if (dict) { 914 - child = qdict_crumple(dict, errp); 915 - if (!child) { 916 - goto error; 917 - } 918 - 919 - qdict_put_obj(multi_level, ent->key, child); 920 - } else { 921 - qdict_put_obj(multi_level, ent->key, qobject_ref(ent->value)); 922 - } 923 - } 924 - qobject_unref(two_level); 925 - two_level = NULL; 926 - 927 - /* Step 3: detect if we need to turn our dict into list */ 928 - is_list = qdict_is_list(multi_level, errp); 929 - if (is_list < 0) { 930 - goto error; 931 - } 932 - 933 - if (is_list) { 934 - dst = QOBJECT(qlist_new()); 935 - 936 - for (i = 0; i < qdict_size(multi_level); i++) { 937 - char *key = g_strdup_printf("%zu", i); 938 - 939 - child = qdict_get(multi_level, key); 940 - g_free(key); 941 - 942 - if (!child) { 943 - error_setg(errp, "Missing list index %zu", i); 944 - goto error; 945 - } 946 - 947 - qlist_append_obj(qobject_to(QList, dst), qobject_ref(child)); 948 - } 949 - qobject_unref(multi_level); 950 - multi_level = NULL; 951 - } else { 952 - dst = QOBJECT(multi_level); 953 - } 954 - 955 - return dst; 956 - 957 - error: 958 - g_free(prefix); 959 - qobject_unref(multi_level); 960 - qobject_unref(two_level); 961 - qobject_unref(dst); 962 - return NULL; 963 - } 964 - 965 - /** 966 - * qdict_array_entries(): Returns the number of direct array entries if the 967 - * sub-QDict of src specified by the prefix in subqdict (or src itself for 968 - * prefix == "") is valid as an array, i.e. the length of the created list if 969 - * the sub-QDict would become empty after calling qdict_array_split() on it. If 970 - * the array is not valid, -EINVAL is returned. 971 - */ 972 - int qdict_array_entries(QDict *src, const char *subqdict) 973 - { 974 - const QDictEntry *entry; 975 - unsigned i; 976 - unsigned entries = 0; 977 - size_t subqdict_len = strlen(subqdict); 978 - 979 - assert(!subqdict_len || subqdict[subqdict_len - 1] == '.'); 980 - 981 - /* qdict_array_split() loops until UINT_MAX, but as we want to return 982 - * negative errors, we only have a signed return value here. Any additional 983 - * entries will lead to -EINVAL. */ 984 - for (i = 0; i < INT_MAX; i++) { 985 - QObject *subqobj; 986 - int subqdict_entries; 987 - char *prefix = g_strdup_printf("%s%u.", subqdict, i); 988 - 989 - subqdict_entries = qdict_count_prefixed_entries(src, prefix); 990 - 991 - /* Remove ending "." */ 992 - prefix[strlen(prefix) - 1] = 0; 993 - subqobj = qdict_get(src, prefix); 994 - 995 - g_free(prefix); 996 - 997 - if (subqdict_entries < 0) { 998 - return subqdict_entries; 999 - } 1000 - 1001 - /* There may be either a single subordinate object (named "%u") or 1002 - * multiple objects (each with a key prefixed "%u."), but not both. */ 1003 - if (subqobj && subqdict_entries) { 1004 - return -EINVAL; 1005 - } else if (!subqobj && !subqdict_entries) { 1006 - break; 1007 - } 1008 - 1009 - entries += subqdict_entries ? subqdict_entries : 1; 1010 - } 1011 - 1012 - /* Consider everything handled that isn't part of the given sub-QDict */ 1013 - for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) { 1014 - if (!strstart(qdict_entry_key(entry), subqdict, NULL)) { 1015 - entries++; 1016 - } 1017 - } 1018 - 1019 - /* Anything left in the sub-QDict that wasn't handled? */ 1020 - if (qdict_size(src) != entries) { 1021 - return -EINVAL; 1022 - } 1023 - 1024 - return i; 1025 - } 1026 - 1027 - /** 1028 - * qdict_join(): Absorb the src QDict into the dest QDict, that is, move all 1029 - * elements from src to dest. 1030 - * 1031 - * If an element from src has a key already present in dest, it will not be 1032 - * moved unless overwrite is true. 1033 - * 1034 - * If overwrite is true, the conflicting values in dest will be discarded and 1035 - * replaced by the corresponding values from src. 1036 - * 1037 - * Therefore, with overwrite being true, the src QDict will always be empty when 1038 - * this function returns. If overwrite is false, the src QDict will be empty 1039 - * iff there were no conflicts. 1040 - */ 1041 - void qdict_join(QDict *dest, QDict *src, bool overwrite) 1042 - { 1043 - const QDictEntry *entry, *next; 1044 - 1045 - entry = qdict_first(src); 1046 - while (entry) { 1047 - next = qdict_next(src, entry); 1048 - 1049 - if (overwrite || !qdict_haskey(dest, entry->key)) { 1050 - qdict_put_obj(dest, entry->key, qobject_ref(entry->value)); 1051 - qdict_del(src, entry->key); 1052 - } 1053 - 1054 - entry = next; 1055 - } 1056 - } 1057 - 1058 - /** 1059 - * qdict_rename_keys(): Rename keys in qdict according to the replacements 1060 - * specified in the array renames. The array must be terminated by an entry 1061 - * with from = NULL. 1062 - * 1063 - * The renames are performed individually in the order of the array, so entries 1064 - * may be renamed multiple times and may or may not conflict depending on the 1065 - * order of the renames array. 1066 - * 1067 - * Returns true for success, false in error cases. 1068 - */ 1069 - bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp) 1070 - { 1071 - QObject *qobj; 1072 - 1073 - while (renames->from) { 1074 - if (qdict_haskey(qdict, renames->from)) { 1075 - if (qdict_haskey(qdict, renames->to)) { 1076 - error_setg(errp, "'%s' and its alias '%s' can't be used at the " 1077 - "same time", renames->to, renames->from); 1078 - return false; 1079 - } 1080 - 1081 - qobj = qdict_get(qdict, renames->from); 1082 - qdict_put_obj(qdict, renames->to, qobject_ref(qobj)); 1083 - qdict_del(qdict, renames->from); 1084 - } 1085 - 1086 - renames++; 1087 - } 1088 - return true; 1089 - }
+4
tests/Makefile.include
··· 39 39 40 40 check-unit-y = tests/check-qdict$(EXESUF) 41 41 gcov-files-check-qdict-y = qobject/qdict.c 42 + check-unit-y = tests/check-block-qdict$(EXESUF) 43 + gcov-files-check-block-qdict-y = qobject/block-qdict.c 42 44 check-unit-y += tests/test-char$(EXESUF) 43 45 gcov-files-check-qdict-y = chardev/char.c 44 46 check-unit-y += tests/check-qnum$(EXESUF) ··· 584 586 test-obj-y = tests/check-qnum.o tests/check-qstring.o tests/check-qdict.o \ 585 587 tests/check-qlist.o tests/check-qnull.o tests/check-qobject.o \ 586 588 tests/check-qjson.o tests/check-qlit.o \ 589 + tests/check-block-qtest.o \ 587 590 tests/test-coroutine.o tests/test-string-output-visitor.o \ 588 591 tests/test-string-input-visitor.o tests/test-qobject-output-visitor.o \ 589 592 tests/test-clone-visitor.o \ ··· 614 617 tests/check-qnum$(EXESUF): tests/check-qnum.o $(test-util-obj-y) 615 618 tests/check-qstring$(EXESUF): tests/check-qstring.o $(test-util-obj-y) 616 619 tests/check-qdict$(EXESUF): tests/check-qdict.o $(test-util-obj-y) 620 + tests/check-block-qdict$(EXESUF): tests/check-block-qdict.o $(test-util-obj-y) 617 621 tests/check-qlist$(EXESUF): tests/check-qlist.o $(test-util-obj-y) 618 622 tests/check-qnull$(EXESUF): tests/check-qnull.o $(test-util-obj-y) 619 623 tests/check-qobject$(EXESUF): tests/check-qobject.o $(test-util-obj-y)
+655
tests/check-block-qdict.c
··· 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 + 16 + static 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 + 38 + static void qdict_flatten_test(void) 39 + { 40 + QList *list1 = qlist_new(); 41 + QList *list2 = qlist_new(); 42 + QDict *dict1 = qdict_new(); 43 + QDict *dict2 = qdict_new(); 44 + QDict *dict3 = qdict_new(); 45 + 46 + /* 47 + * Test the flattening of 48 + * 49 + * { 50 + * "e": [ 51 + * 42, 52 + * [ 53 + * 23, 54 + * 66, 55 + * { 56 + * "a": 0, 57 + * "b": 1 58 + * } 59 + * ] 60 + * ], 61 + * "f": { 62 + * "c": 2, 63 + * "d": 3, 64 + * }, 65 + * "g": 4 66 + * } 67 + * 68 + * to 69 + * 70 + * { 71 + * "e.0": 42, 72 + * "e.1.0": 23, 73 + * "e.1.1": 66, 74 + * "e.1.2.a": 0, 75 + * "e.1.2.b": 1, 76 + * "f.c": 2, 77 + * "f.d": 3, 78 + * "g": 4 79 + * } 80 + */ 81 + 82 + qdict_put_int(dict1, "a", 0); 83 + qdict_put_int(dict1, "b", 1); 84 + 85 + qlist_append_int(list1, 23); 86 + qlist_append_int(list1, 66); 87 + qlist_append(list1, dict1); 88 + qlist_append_int(list2, 42); 89 + qlist_append(list2, list1); 90 + 91 + qdict_put_int(dict2, "c", 2); 92 + qdict_put_int(dict2, "d", 3); 93 + qdict_put(dict3, "e", list2); 94 + qdict_put(dict3, "f", dict2); 95 + qdict_put_int(dict3, "g", 4); 96 + 97 + qdict_flatten(dict3); 98 + 99 + g_assert(qdict_get_int(dict3, "e.0") == 42); 100 + g_assert(qdict_get_int(dict3, "e.1.0") == 23); 101 + g_assert(qdict_get_int(dict3, "e.1.1") == 66); 102 + g_assert(qdict_get_int(dict3, "e.1.2.a") == 0); 103 + g_assert(qdict_get_int(dict3, "e.1.2.b") == 1); 104 + g_assert(qdict_get_int(dict3, "f.c") == 2); 105 + g_assert(qdict_get_int(dict3, "f.d") == 3); 106 + g_assert(qdict_get_int(dict3, "g") == 4); 107 + 108 + g_assert(qdict_size(dict3) == 8); 109 + 110 + qobject_unref(dict3); 111 + } 112 + 113 + static void qdict_array_split_test(void) 114 + { 115 + QDict *test_dict = qdict_new(); 116 + QDict *dict1, *dict2; 117 + QNum *int1; 118 + QList *test_list; 119 + 120 + /* 121 + * Test the split of 122 + * 123 + * { 124 + * "1.x": 0, 125 + * "4.y": 1, 126 + * "0.a": 42, 127 + * "o.o": 7, 128 + * "0.b": 23, 129 + * "2": 66 130 + * } 131 + * 132 + * to 133 + * 134 + * [ 135 + * { 136 + * "a": 42, 137 + * "b": 23 138 + * }, 139 + * { 140 + * "x": 0 141 + * }, 142 + * 66 143 + * ] 144 + * 145 + * and 146 + * 147 + * { 148 + * "4.y": 1, 149 + * "o.o": 7 150 + * } 151 + * 152 + * (remaining in the old QDict) 153 + * 154 + * This example is given in the comment of qdict_array_split(). 155 + */ 156 + 157 + qdict_put_int(test_dict, "1.x", 0); 158 + qdict_put_int(test_dict, "4.y", 1); 159 + qdict_put_int(test_dict, "0.a", 42); 160 + qdict_put_int(test_dict, "o.o", 7); 161 + qdict_put_int(test_dict, "0.b", 23); 162 + qdict_put_int(test_dict, "2", 66); 163 + 164 + qdict_array_split(test_dict, &test_list); 165 + 166 + dict1 = qobject_to(QDict, qlist_pop(test_list)); 167 + dict2 = qobject_to(QDict, qlist_pop(test_list)); 168 + int1 = qobject_to(QNum, qlist_pop(test_list)); 169 + 170 + g_assert(dict1); 171 + g_assert(dict2); 172 + g_assert(int1); 173 + g_assert(qlist_empty(test_list)); 174 + 175 + qobject_unref(test_list); 176 + 177 + g_assert(qdict_get_int(dict1, "a") == 42); 178 + g_assert(qdict_get_int(dict1, "b") == 23); 179 + 180 + g_assert(qdict_size(dict1) == 2); 181 + 182 + qobject_unref(dict1); 183 + 184 + g_assert(qdict_get_int(dict2, "x") == 0); 185 + 186 + g_assert(qdict_size(dict2) == 1); 187 + 188 + qobject_unref(dict2); 189 + 190 + g_assert_cmpint(qnum_get_int(int1), ==, 66); 191 + 192 + qobject_unref(int1); 193 + 194 + g_assert(qdict_get_int(test_dict, "4.y") == 1); 195 + g_assert(qdict_get_int(test_dict, "o.o") == 7); 196 + 197 + g_assert(qdict_size(test_dict) == 2); 198 + 199 + qobject_unref(test_dict); 200 + 201 + /* 202 + * Test the split of 203 + * 204 + * { 205 + * "0": 42, 206 + * "1": 23, 207 + * "1.x": 84 208 + * } 209 + * 210 + * to 211 + * 212 + * [ 213 + * 42 214 + * ] 215 + * 216 + * and 217 + * 218 + * { 219 + * "1": 23, 220 + * "1.x": 84 221 + * } 222 + * 223 + * That is, test whether splitting stops if there is both an entry with key 224 + * of "%u" and other entries with keys prefixed "%u." for the same index. 225 + */ 226 + 227 + test_dict = qdict_new(); 228 + 229 + qdict_put_int(test_dict, "0", 42); 230 + qdict_put_int(test_dict, "1", 23); 231 + qdict_put_int(test_dict, "1.x", 84); 232 + 233 + qdict_array_split(test_dict, &test_list); 234 + 235 + int1 = qobject_to(QNum, qlist_pop(test_list)); 236 + 237 + g_assert(int1); 238 + g_assert(qlist_empty(test_list)); 239 + 240 + qobject_unref(test_list); 241 + 242 + g_assert_cmpint(qnum_get_int(int1), ==, 42); 243 + 244 + qobject_unref(int1); 245 + 246 + g_assert(qdict_get_int(test_dict, "1") == 23); 247 + g_assert(qdict_get_int(test_dict, "1.x") == 84); 248 + 249 + g_assert(qdict_size(test_dict) == 2); 250 + 251 + qobject_unref(test_dict); 252 + } 253 + 254 + static void qdict_array_entries_test(void) 255 + { 256 + QDict *dict = qdict_new(); 257 + 258 + g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0); 259 + 260 + qdict_put_int(dict, "bar", 0); 261 + qdict_put_int(dict, "baz.0", 0); 262 + g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0); 263 + 264 + qdict_put_int(dict, "foo.1", 0); 265 + g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL); 266 + qdict_put_int(dict, "foo.0", 0); 267 + g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 2); 268 + qdict_put_int(dict, "foo.bar", 0); 269 + g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL); 270 + qdict_del(dict, "foo.bar"); 271 + 272 + qdict_put_int(dict, "foo.2.a", 0); 273 + qdict_put_int(dict, "foo.2.b", 0); 274 + qdict_put_int(dict, "foo.2.c", 0); 275 + g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 3); 276 + g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL); 277 + 278 + qobject_unref(dict); 279 + 280 + dict = qdict_new(); 281 + qdict_put_int(dict, "1", 0); 282 + g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL); 283 + qdict_put_int(dict, "0", 0); 284 + g_assert_cmpint(qdict_array_entries(dict, ""), ==, 2); 285 + qdict_put_int(dict, "bar", 0); 286 + g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL); 287 + qdict_del(dict, "bar"); 288 + 289 + qdict_put_int(dict, "2.a", 0); 290 + qdict_put_int(dict, "2.b", 0); 291 + qdict_put_int(dict, "2.c", 0); 292 + g_assert_cmpint(qdict_array_entries(dict, ""), ==, 3); 293 + 294 + qobject_unref(dict); 295 + } 296 + 297 + static void qdict_join_test(void) 298 + { 299 + QDict *dict1, *dict2; 300 + bool overwrite = false; 301 + int i; 302 + 303 + dict1 = qdict_new(); 304 + dict2 = qdict_new(); 305 + 306 + /* Test everything once without overwrite and once with */ 307 + do { 308 + /* Test empty dicts */ 309 + qdict_join(dict1, dict2, overwrite); 310 + 311 + g_assert(qdict_size(dict1) == 0); 312 + g_assert(qdict_size(dict2) == 0); 313 + 314 + /* First iteration: Test movement */ 315 + /* Second iteration: Test empty source and non-empty destination */ 316 + qdict_put_int(dict2, "foo", 42); 317 + 318 + for (i = 0; i < 2; i++) { 319 + qdict_join(dict1, dict2, overwrite); 320 + 321 + g_assert(qdict_size(dict1) == 1); 322 + g_assert(qdict_size(dict2) == 0); 323 + 324 + g_assert(qdict_get_int(dict1, "foo") == 42); 325 + } 326 + 327 + /* Test non-empty source and destination without conflict */ 328 + qdict_put_int(dict2, "bar", 23); 329 + 330 + qdict_join(dict1, dict2, overwrite); 331 + 332 + g_assert(qdict_size(dict1) == 2); 333 + g_assert(qdict_size(dict2) == 0); 334 + 335 + g_assert(qdict_get_int(dict1, "foo") == 42); 336 + g_assert(qdict_get_int(dict1, "bar") == 23); 337 + 338 + /* Test conflict */ 339 + qdict_put_int(dict2, "foo", 84); 340 + 341 + qdict_join(dict1, dict2, overwrite); 342 + 343 + g_assert(qdict_size(dict1) == 2); 344 + g_assert(qdict_size(dict2) == !overwrite); 345 + 346 + g_assert(qdict_get_int(dict1, "foo") == (overwrite ? 84 : 42)); 347 + g_assert(qdict_get_int(dict1, "bar") == 23); 348 + 349 + if (!overwrite) { 350 + g_assert(qdict_get_int(dict2, "foo") == 84); 351 + } 352 + 353 + /* Check the references */ 354 + g_assert(qdict_get(dict1, "foo")->base.refcnt == 1); 355 + g_assert(qdict_get(dict1, "bar")->base.refcnt == 1); 356 + 357 + if (!overwrite) { 358 + g_assert(qdict_get(dict2, "foo")->base.refcnt == 1); 359 + } 360 + 361 + /* Clean up */ 362 + qdict_del(dict1, "foo"); 363 + qdict_del(dict1, "bar"); 364 + 365 + if (!overwrite) { 366 + qdict_del(dict2, "foo"); 367 + } 368 + } while (overwrite ^= true); 369 + 370 + qobject_unref(dict1); 371 + qobject_unref(dict2); 372 + } 373 + 374 + static void qdict_crumple_test_recursive(void) 375 + { 376 + QDict *src, *dst, *rule, *vnc, *acl, *listen; 377 + QList *rules; 378 + 379 + src = qdict_new(); 380 + qdict_put_str(src, "vnc.listen.addr", "127.0.0.1"); 381 + qdict_put_str(src, "vnc.listen.port", "5901"); 382 + qdict_put_str(src, "vnc.acl.rules.0.match", "fred"); 383 + qdict_put_str(src, "vnc.acl.rules.0.policy", "allow"); 384 + qdict_put_str(src, "vnc.acl.rules.1.match", "bob"); 385 + qdict_put_str(src, "vnc.acl.rules.1.policy", "deny"); 386 + qdict_put_str(src, "vnc.acl.default", "deny"); 387 + qdict_put_str(src, "vnc.acl..name", "acl0"); 388 + qdict_put_str(src, "vnc.acl.rule..name", "acl0"); 389 + 390 + dst = qobject_to(QDict, qdict_crumple(src, &error_abort)); 391 + g_assert(dst); 392 + g_assert_cmpint(qdict_size(dst), ==, 1); 393 + 394 + vnc = qdict_get_qdict(dst, "vnc"); 395 + g_assert(vnc); 396 + g_assert_cmpint(qdict_size(vnc), ==, 3); 397 + 398 + listen = qdict_get_qdict(vnc, "listen"); 399 + g_assert(listen); 400 + g_assert_cmpint(qdict_size(listen), ==, 2); 401 + g_assert_cmpstr("127.0.0.1", ==, qdict_get_str(listen, "addr")); 402 + g_assert_cmpstr("5901", ==, qdict_get_str(listen, "port")); 403 + 404 + acl = qdict_get_qdict(vnc, "acl"); 405 + g_assert(acl); 406 + g_assert_cmpint(qdict_size(acl), ==, 3); 407 + 408 + rules = qdict_get_qlist(acl, "rules"); 409 + g_assert(rules); 410 + g_assert_cmpint(qlist_size(rules), ==, 2); 411 + 412 + rule = qobject_to(QDict, qlist_pop(rules)); 413 + g_assert(rule); 414 + g_assert_cmpint(qdict_size(rule), ==, 2); 415 + g_assert_cmpstr("fred", ==, qdict_get_str(rule, "match")); 416 + g_assert_cmpstr("allow", ==, qdict_get_str(rule, "policy")); 417 + qobject_unref(rule); 418 + 419 + rule = qobject_to(QDict, qlist_pop(rules)); 420 + g_assert(rule); 421 + g_assert_cmpint(qdict_size(rule), ==, 2); 422 + g_assert_cmpstr("bob", ==, qdict_get_str(rule, "match")); 423 + g_assert_cmpstr("deny", ==, qdict_get_str(rule, "policy")); 424 + qobject_unref(rule); 425 + 426 + /* With recursive crumpling, we should see all names unescaped */ 427 + g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name")); 428 + g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name")); 429 + 430 + qobject_unref(src); 431 + qobject_unref(dst); 432 + } 433 + 434 + static void qdict_crumple_test_empty(void) 435 + { 436 + QDict *src, *dst; 437 + 438 + src = qdict_new(); 439 + 440 + dst = qobject_to(QDict, qdict_crumple(src, &error_abort)); 441 + 442 + g_assert_cmpint(qdict_size(dst), ==, 0); 443 + 444 + qobject_unref(src); 445 + qobject_unref(dst); 446 + } 447 + 448 + static int qdict_count_entries(QDict *dict) 449 + { 450 + const QDictEntry *e; 451 + int count = 0; 452 + 453 + for (e = qdict_first(dict); e; e = qdict_next(dict, e)) { 454 + count++; 455 + } 456 + 457 + return count; 458 + } 459 + 460 + static void qdict_rename_keys_test(void) 461 + { 462 + QDict *dict = qdict_new(); 463 + QDict *copy; 464 + QDictRenames *renames; 465 + Error *local_err = NULL; 466 + 467 + qdict_put_str(dict, "abc", "foo"); 468 + qdict_put_str(dict, "abcdef", "bar"); 469 + qdict_put_int(dict, "number", 42); 470 + qdict_put_bool(dict, "flag", true); 471 + qdict_put_null(dict, "nothing"); 472 + 473 + /* Empty rename list */ 474 + renames = (QDictRenames[]) { 475 + { NULL, "this can be anything" } 476 + }; 477 + copy = qdict_clone_shallow(dict); 478 + qdict_rename_keys(copy, renames, &error_abort); 479 + 480 + g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo"); 481 + g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar"); 482 + g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42); 483 + g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true); 484 + g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL); 485 + g_assert_cmpint(qdict_count_entries(copy), ==, 5); 486 + 487 + qobject_unref(copy); 488 + 489 + /* Simple rename of all entries */ 490 + renames = (QDictRenames[]) { 491 + { "abc", "str1" }, 492 + { "abcdef", "str2" }, 493 + { "number", "int" }, 494 + { "flag", "bool" }, 495 + { "nothing", "null" }, 496 + { NULL , NULL } 497 + }; 498 + copy = qdict_clone_shallow(dict); 499 + qdict_rename_keys(copy, renames, &error_abort); 500 + 501 + g_assert(!qdict_haskey(copy, "abc")); 502 + g_assert(!qdict_haskey(copy, "abcdef")); 503 + g_assert(!qdict_haskey(copy, "number")); 504 + g_assert(!qdict_haskey(copy, "flag")); 505 + g_assert(!qdict_haskey(copy, "nothing")); 506 + 507 + g_assert_cmpstr(qdict_get_str(copy, "str1"), ==, "foo"); 508 + g_assert_cmpstr(qdict_get_str(copy, "str2"), ==, "bar"); 509 + g_assert_cmpint(qdict_get_int(copy, "int"), ==, 42); 510 + g_assert_cmpint(qdict_get_bool(copy, "bool"), ==, true); 511 + g_assert(qobject_type(qdict_get(copy, "null")) == QTYPE_QNULL); 512 + g_assert_cmpint(qdict_count_entries(copy), ==, 5); 513 + 514 + qobject_unref(copy); 515 + 516 + /* Renames are processed top to bottom */ 517 + renames = (QDictRenames[]) { 518 + { "abc", "tmp" }, 519 + { "abcdef", "abc" }, 520 + { "number", "abcdef" }, 521 + { "flag", "number" }, 522 + { "nothing", "flag" }, 523 + { "tmp", "nothing" }, 524 + { NULL , NULL } 525 + }; 526 + copy = qdict_clone_shallow(dict); 527 + qdict_rename_keys(copy, renames, &error_abort); 528 + 529 + g_assert_cmpstr(qdict_get_str(copy, "nothing"), ==, "foo"); 530 + g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "bar"); 531 + g_assert_cmpint(qdict_get_int(copy, "abcdef"), ==, 42); 532 + g_assert_cmpint(qdict_get_bool(copy, "number"), ==, true); 533 + g_assert(qobject_type(qdict_get(copy, "flag")) == QTYPE_QNULL); 534 + g_assert(!qdict_haskey(copy, "tmp")); 535 + g_assert_cmpint(qdict_count_entries(copy), ==, 5); 536 + 537 + qobject_unref(copy); 538 + 539 + /* Conflicting rename */ 540 + renames = (QDictRenames[]) { 541 + { "abcdef", "abc" }, 542 + { NULL , NULL } 543 + }; 544 + copy = qdict_clone_shallow(dict); 545 + qdict_rename_keys(copy, renames, &local_err); 546 + 547 + g_assert(local_err != NULL); 548 + error_free(local_err); 549 + local_err = NULL; 550 + 551 + g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo"); 552 + g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar"); 553 + g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42); 554 + g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true); 555 + g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL); 556 + g_assert_cmpint(qdict_count_entries(copy), ==, 5); 557 + 558 + qobject_unref(copy); 559 + 560 + /* Renames in an empty dict */ 561 + renames = (QDictRenames[]) { 562 + { "abcdef", "abc" }, 563 + { NULL , NULL } 564 + }; 565 + 566 + qobject_unref(dict); 567 + dict = qdict_new(); 568 + 569 + qdict_rename_keys(dict, renames, &error_abort); 570 + g_assert(qdict_first(dict) == NULL); 571 + 572 + qobject_unref(dict); 573 + } 574 + 575 + static void qdict_crumple_test_bad_inputs(void) 576 + { 577 + QDict *src; 578 + Error *error = NULL; 579 + 580 + src = qdict_new(); 581 + /* rule.0 can't be both a string and a dict */ 582 + qdict_put_str(src, "rule.0", "fred"); 583 + qdict_put_str(src, "rule.0.policy", "allow"); 584 + 585 + g_assert(qdict_crumple(src, &error) == NULL); 586 + g_assert(error != NULL); 587 + error_free(error); 588 + error = NULL; 589 + qobject_unref(src); 590 + 591 + src = qdict_new(); 592 + /* rule can't be both a list and a dict */ 593 + qdict_put_str(src, "rule.0", "fred"); 594 + qdict_put_str(src, "rule.a", "allow"); 595 + 596 + g_assert(qdict_crumple(src, &error) == NULL); 597 + g_assert(error != NULL); 598 + error_free(error); 599 + error = NULL; 600 + qobject_unref(src); 601 + 602 + src = qdict_new(); 603 + /* The input should be flat, ie no dicts or lists */ 604 + qdict_put(src, "rule.a", qdict_new()); 605 + qdict_put_str(src, "rule.b", "allow"); 606 + 607 + g_assert(qdict_crumple(src, &error) == NULL); 608 + g_assert(error != NULL); 609 + error_free(error); 610 + error = NULL; 611 + qobject_unref(src); 612 + 613 + src = qdict_new(); 614 + /* List indexes must not have gaps */ 615 + qdict_put_str(src, "rule.0", "deny"); 616 + qdict_put_str(src, "rule.3", "allow"); 617 + 618 + g_assert(qdict_crumple(src, &error) == NULL); 619 + g_assert(error != NULL); 620 + error_free(error); 621 + error = NULL; 622 + qobject_unref(src); 623 + 624 + src = qdict_new(); 625 + /* List indexes must be in %zu format */ 626 + qdict_put_str(src, "rule.0", "deny"); 627 + qdict_put_str(src, "rule.+1", "allow"); 628 + 629 + g_assert(qdict_crumple(src, &error) == NULL); 630 + g_assert(error != NULL); 631 + error_free(error); 632 + error = NULL; 633 + qobject_unref(src); 634 + } 635 + 636 + int main(int argc, char **argv) 637 + { 638 + g_test_init(&argc, &argv, NULL); 639 + 640 + g_test_add_func("/public/defaults", qdict_defaults_test); 641 + g_test_add_func("/public/flatten", qdict_flatten_test); 642 + g_test_add_func("/public/array_split", qdict_array_split_test); 643 + g_test_add_func("/public/array_entries", qdict_array_entries_test); 644 + g_test_add_func("/public/join", qdict_join_test); 645 + g_test_add_func("/public/crumple/recursive", 646 + qdict_crumple_test_recursive); 647 + g_test_add_func("/public/crumple/empty", 648 + qdict_crumple_test_empty); 649 + g_test_add_func("/public/crumple/bad_inputs", 650 + qdict_crumple_test_bad_inputs); 651 + 652 + g_test_add_func("/public/rename_keys", qdict_rename_keys_test); 653 + 654 + return g_test_run(); 655 + }
-642
tests/check-qdict.c
··· 11 11 */ 12 12 13 13 #include "qemu/osdep.h" 14 - #include "block/qdict.h" 15 14 #include "qapi/qmp/qdict.h" 16 - #include "qapi/qmp/qlist.h" 17 - #include "qapi/qmp/qnum.h" 18 - #include "qapi/qmp/qstring.h" 19 - #include "qapi/error.h" 20 - #include "qemu-common.h" 21 15 22 16 /* 23 17 * Public Interface test-cases ··· 157 151 qobject_unref(tests_dict); 158 152 } 159 153 160 - static void qdict_defaults_test(void) 161 - { 162 - QDict *dict, *copy; 163 - 164 - dict = qdict_new(); 165 - copy = qdict_new(); 166 - 167 - qdict_set_default_str(dict, "foo", "abc"); 168 - qdict_set_default_str(dict, "foo", "def"); 169 - g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "abc"); 170 - qdict_set_default_str(dict, "bar", "ghi"); 171 - 172 - qdict_copy_default(copy, dict, "foo"); 173 - g_assert_cmpstr(qdict_get_str(copy, "foo"), ==, "abc"); 174 - qdict_set_default_str(copy, "bar", "xyz"); 175 - qdict_copy_default(copy, dict, "bar"); 176 - g_assert_cmpstr(qdict_get_str(copy, "bar"), ==, "xyz"); 177 - 178 - qobject_unref(copy); 179 - qobject_unref(dict); 180 - } 181 - 182 154 static void qdict_haskey_not_test(void) 183 155 { 184 156 QDict *tests_dict = qdict_new(); ··· 254 226 qobject_unref(tests_dict); 255 227 } 256 228 257 - static void qdict_flatten_test(void) 258 - { 259 - QList *list1 = qlist_new(); 260 - QList *list2 = qlist_new(); 261 - QDict *dict1 = qdict_new(); 262 - QDict *dict2 = qdict_new(); 263 - QDict *dict3 = qdict_new(); 264 - 265 - /* 266 - * Test the flattening of 267 - * 268 - * { 269 - * "e": [ 270 - * 42, 271 - * [ 272 - * 23, 273 - * 66, 274 - * { 275 - * "a": 0, 276 - * "b": 1 277 - * } 278 - * ] 279 - * ], 280 - * "f": { 281 - * "c": 2, 282 - * "d": 3, 283 - * }, 284 - * "g": 4 285 - * } 286 - * 287 - * to 288 - * 289 - * { 290 - * "e.0": 42, 291 - * "e.1.0": 23, 292 - * "e.1.1": 66, 293 - * "e.1.2.a": 0, 294 - * "e.1.2.b": 1, 295 - * "f.c": 2, 296 - * "f.d": 3, 297 - * "g": 4 298 - * } 299 - */ 300 - 301 - qdict_put_int(dict1, "a", 0); 302 - qdict_put_int(dict1, "b", 1); 303 - 304 - qlist_append_int(list1, 23); 305 - qlist_append_int(list1, 66); 306 - qlist_append(list1, dict1); 307 - qlist_append_int(list2, 42); 308 - qlist_append(list2, list1); 309 - 310 - qdict_put_int(dict2, "c", 2); 311 - qdict_put_int(dict2, "d", 3); 312 - qdict_put(dict3, "e", list2); 313 - qdict_put(dict3, "f", dict2); 314 - qdict_put_int(dict3, "g", 4); 315 - 316 - qdict_flatten(dict3); 317 - 318 - g_assert(qdict_get_int(dict3, "e.0") == 42); 319 - g_assert(qdict_get_int(dict3, "e.1.0") == 23); 320 - g_assert(qdict_get_int(dict3, "e.1.1") == 66); 321 - g_assert(qdict_get_int(dict3, "e.1.2.a") == 0); 322 - g_assert(qdict_get_int(dict3, "e.1.2.b") == 1); 323 - g_assert(qdict_get_int(dict3, "f.c") == 2); 324 - g_assert(qdict_get_int(dict3, "f.d") == 3); 325 - g_assert(qdict_get_int(dict3, "g") == 4); 326 - 327 - g_assert(qdict_size(dict3) == 8); 328 - 329 - qobject_unref(dict3); 330 - } 331 - 332 - static void qdict_array_split_test(void) 333 - { 334 - QDict *test_dict = qdict_new(); 335 - QDict *dict1, *dict2; 336 - QNum *int1; 337 - QList *test_list; 338 - 339 - /* 340 - * Test the split of 341 - * 342 - * { 343 - * "1.x": 0, 344 - * "4.y": 1, 345 - * "0.a": 42, 346 - * "o.o": 7, 347 - * "0.b": 23, 348 - * "2": 66 349 - * } 350 - * 351 - * to 352 - * 353 - * [ 354 - * { 355 - * "a": 42, 356 - * "b": 23 357 - * }, 358 - * { 359 - * "x": 0 360 - * }, 361 - * 66 362 - * ] 363 - * 364 - * and 365 - * 366 - * { 367 - * "4.y": 1, 368 - * "o.o": 7 369 - * } 370 - * 371 - * (remaining in the old QDict) 372 - * 373 - * This example is given in the comment of qdict_array_split(). 374 - */ 375 - 376 - qdict_put_int(test_dict, "1.x", 0); 377 - qdict_put_int(test_dict, "4.y", 1); 378 - qdict_put_int(test_dict, "0.a", 42); 379 - qdict_put_int(test_dict, "o.o", 7); 380 - qdict_put_int(test_dict, "0.b", 23); 381 - qdict_put_int(test_dict, "2", 66); 382 - 383 - qdict_array_split(test_dict, &test_list); 384 - 385 - dict1 = qobject_to(QDict, qlist_pop(test_list)); 386 - dict2 = qobject_to(QDict, qlist_pop(test_list)); 387 - int1 = qobject_to(QNum, qlist_pop(test_list)); 388 - 389 - g_assert(dict1); 390 - g_assert(dict2); 391 - g_assert(int1); 392 - g_assert(qlist_empty(test_list)); 393 - 394 - qobject_unref(test_list); 395 - 396 - g_assert(qdict_get_int(dict1, "a") == 42); 397 - g_assert(qdict_get_int(dict1, "b") == 23); 398 - 399 - g_assert(qdict_size(dict1) == 2); 400 - 401 - qobject_unref(dict1); 402 - 403 - g_assert(qdict_get_int(dict2, "x") == 0); 404 - 405 - g_assert(qdict_size(dict2) == 1); 406 - 407 - qobject_unref(dict2); 408 - 409 - g_assert_cmpint(qnum_get_int(int1), ==, 66); 410 - 411 - qobject_unref(int1); 412 - 413 - g_assert(qdict_get_int(test_dict, "4.y") == 1); 414 - g_assert(qdict_get_int(test_dict, "o.o") == 7); 415 - 416 - g_assert(qdict_size(test_dict) == 2); 417 - 418 - qobject_unref(test_dict); 419 - 420 - /* 421 - * Test the split of 422 - * 423 - * { 424 - * "0": 42, 425 - * "1": 23, 426 - * "1.x": 84 427 - * } 428 - * 429 - * to 430 - * 431 - * [ 432 - * 42 433 - * ] 434 - * 435 - * and 436 - * 437 - * { 438 - * "1": 23, 439 - * "1.x": 84 440 - * } 441 - * 442 - * That is, test whether splitting stops if there is both an entry with key 443 - * of "%u" and other entries with keys prefixed "%u." for the same index. 444 - */ 445 - 446 - test_dict = qdict_new(); 447 - 448 - qdict_put_int(test_dict, "0", 42); 449 - qdict_put_int(test_dict, "1", 23); 450 - qdict_put_int(test_dict, "1.x", 84); 451 - 452 - qdict_array_split(test_dict, &test_list); 453 - 454 - int1 = qobject_to(QNum, qlist_pop(test_list)); 455 - 456 - g_assert(int1); 457 - g_assert(qlist_empty(test_list)); 458 - 459 - qobject_unref(test_list); 460 - 461 - g_assert_cmpint(qnum_get_int(int1), ==, 42); 462 - 463 - qobject_unref(int1); 464 - 465 - g_assert(qdict_get_int(test_dict, "1") == 23); 466 - g_assert(qdict_get_int(test_dict, "1.x") == 84); 467 - 468 - g_assert(qdict_size(test_dict) == 2); 469 - 470 - qobject_unref(test_dict); 471 - } 472 - 473 - static void qdict_array_entries_test(void) 474 - { 475 - QDict *dict = qdict_new(); 476 - 477 - g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0); 478 - 479 - qdict_put_int(dict, "bar", 0); 480 - qdict_put_int(dict, "baz.0", 0); 481 - g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0); 482 - 483 - qdict_put_int(dict, "foo.1", 0); 484 - g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL); 485 - qdict_put_int(dict, "foo.0", 0); 486 - g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 2); 487 - qdict_put_int(dict, "foo.bar", 0); 488 - g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL); 489 - qdict_del(dict, "foo.bar"); 490 - 491 - qdict_put_int(dict, "foo.2.a", 0); 492 - qdict_put_int(dict, "foo.2.b", 0); 493 - qdict_put_int(dict, "foo.2.c", 0); 494 - g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 3); 495 - g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL); 496 - 497 - qobject_unref(dict); 498 - 499 - dict = qdict_new(); 500 - qdict_put_int(dict, "1", 0); 501 - g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL); 502 - qdict_put_int(dict, "0", 0); 503 - g_assert_cmpint(qdict_array_entries(dict, ""), ==, 2); 504 - qdict_put_int(dict, "bar", 0); 505 - g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL); 506 - qdict_del(dict, "bar"); 507 - 508 - qdict_put_int(dict, "2.a", 0); 509 - qdict_put_int(dict, "2.b", 0); 510 - qdict_put_int(dict, "2.c", 0); 511 - g_assert_cmpint(qdict_array_entries(dict, ""), ==, 3); 512 - 513 - qobject_unref(dict); 514 - } 515 - 516 - static void qdict_join_test(void) 517 - { 518 - QDict *dict1, *dict2; 519 - bool overwrite = false; 520 - int i; 521 - 522 - dict1 = qdict_new(); 523 - dict2 = qdict_new(); 524 - 525 - /* Test everything once without overwrite and once with */ 526 - do 527 - { 528 - /* Test empty dicts */ 529 - qdict_join(dict1, dict2, overwrite); 530 - 531 - g_assert(qdict_size(dict1) == 0); 532 - g_assert(qdict_size(dict2) == 0); 533 - 534 - /* First iteration: Test movement */ 535 - /* Second iteration: Test empty source and non-empty destination */ 536 - qdict_put_int(dict2, "foo", 42); 537 - 538 - for (i = 0; i < 2; i++) { 539 - qdict_join(dict1, dict2, overwrite); 540 - 541 - g_assert(qdict_size(dict1) == 1); 542 - g_assert(qdict_size(dict2) == 0); 543 - 544 - g_assert(qdict_get_int(dict1, "foo") == 42); 545 - } 546 - 547 - /* Test non-empty source and destination without conflict */ 548 - qdict_put_int(dict2, "bar", 23); 549 - 550 - qdict_join(dict1, dict2, overwrite); 551 - 552 - g_assert(qdict_size(dict1) == 2); 553 - g_assert(qdict_size(dict2) == 0); 554 - 555 - g_assert(qdict_get_int(dict1, "foo") == 42); 556 - g_assert(qdict_get_int(dict1, "bar") == 23); 557 - 558 - /* Test conflict */ 559 - qdict_put_int(dict2, "foo", 84); 560 - 561 - qdict_join(dict1, dict2, overwrite); 562 - 563 - g_assert(qdict_size(dict1) == 2); 564 - g_assert(qdict_size(dict2) == !overwrite); 565 - 566 - g_assert(qdict_get_int(dict1, "foo") == (overwrite ? 84 : 42)); 567 - g_assert(qdict_get_int(dict1, "bar") == 23); 568 - 569 - if (!overwrite) { 570 - g_assert(qdict_get_int(dict2, "foo") == 84); 571 - } 572 - 573 - /* Check the references */ 574 - g_assert(qdict_get(dict1, "foo")->base.refcnt == 1); 575 - g_assert(qdict_get(dict1, "bar")->base.refcnt == 1); 576 - 577 - if (!overwrite) { 578 - g_assert(qdict_get(dict2, "foo")->base.refcnt == 1); 579 - } 580 - 581 - /* Clean up */ 582 - qdict_del(dict1, "foo"); 583 - qdict_del(dict1, "bar"); 584 - 585 - if (!overwrite) { 586 - qdict_del(dict2, "foo"); 587 - } 588 - } 589 - while (overwrite ^= true); 590 - 591 - qobject_unref(dict1); 592 - qobject_unref(dict2); 593 - } 594 - 595 - static void qdict_crumple_test_recursive(void) 596 - { 597 - QDict *src, *dst, *rule, *vnc, *acl, *listen; 598 - QList *rules; 599 - 600 - src = qdict_new(); 601 - qdict_put_str(src, "vnc.listen.addr", "127.0.0.1"); 602 - qdict_put_str(src, "vnc.listen.port", "5901"); 603 - qdict_put_str(src, "vnc.acl.rules.0.match", "fred"); 604 - qdict_put_str(src, "vnc.acl.rules.0.policy", "allow"); 605 - qdict_put_str(src, "vnc.acl.rules.1.match", "bob"); 606 - qdict_put_str(src, "vnc.acl.rules.1.policy", "deny"); 607 - qdict_put_str(src, "vnc.acl.default", "deny"); 608 - qdict_put_str(src, "vnc.acl..name", "acl0"); 609 - qdict_put_str(src, "vnc.acl.rule..name", "acl0"); 610 - 611 - dst = qobject_to(QDict, qdict_crumple(src, &error_abort)); 612 - g_assert(dst); 613 - g_assert_cmpint(qdict_size(dst), ==, 1); 614 - 615 - vnc = qdict_get_qdict(dst, "vnc"); 616 - g_assert(vnc); 617 - g_assert_cmpint(qdict_size(vnc), ==, 3); 618 - 619 - listen = qdict_get_qdict(vnc, "listen"); 620 - g_assert(listen); 621 - g_assert_cmpint(qdict_size(listen), ==, 2); 622 - g_assert_cmpstr("127.0.0.1", ==, qdict_get_str(listen, "addr")); 623 - g_assert_cmpstr("5901", ==, qdict_get_str(listen, "port")); 624 - 625 - acl = qdict_get_qdict(vnc, "acl"); 626 - g_assert(acl); 627 - g_assert_cmpint(qdict_size(acl), ==, 3); 628 - 629 - rules = qdict_get_qlist(acl, "rules"); 630 - g_assert(rules); 631 - g_assert_cmpint(qlist_size(rules), ==, 2); 632 - 633 - rule = qobject_to(QDict, qlist_pop(rules)); 634 - g_assert(rule); 635 - g_assert_cmpint(qdict_size(rule), ==, 2); 636 - g_assert_cmpstr("fred", ==, qdict_get_str(rule, "match")); 637 - g_assert_cmpstr("allow", ==, qdict_get_str(rule, "policy")); 638 - qobject_unref(rule); 639 - 640 - rule = qobject_to(QDict, qlist_pop(rules)); 641 - g_assert(rule); 642 - g_assert_cmpint(qdict_size(rule), ==, 2); 643 - g_assert_cmpstr("bob", ==, qdict_get_str(rule, "match")); 644 - g_assert_cmpstr("deny", ==, qdict_get_str(rule, "policy")); 645 - qobject_unref(rule); 646 - 647 - /* With recursive crumpling, we should see all names unescaped */ 648 - g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name")); 649 - g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name")); 650 - 651 - qobject_unref(src); 652 - qobject_unref(dst); 653 - } 654 - 655 - static void qdict_crumple_test_empty(void) 656 - { 657 - QDict *src, *dst; 658 - 659 - src = qdict_new(); 660 - 661 - dst = qobject_to(QDict, qdict_crumple(src, &error_abort)); 662 - 663 - g_assert_cmpint(qdict_size(dst), ==, 0); 664 - 665 - qobject_unref(src); 666 - qobject_unref(dst); 667 - } 668 - 669 - static int qdict_count_entries(QDict *dict) 670 - { 671 - const QDictEntry *e; 672 - int count = 0; 673 - 674 - for (e = qdict_first(dict); e; e = qdict_next(dict, e)) { 675 - count++; 676 - } 677 - 678 - return count; 679 - } 680 - 681 - static void qdict_rename_keys_test(void) 682 - { 683 - QDict *dict = qdict_new(); 684 - QDict *copy; 685 - QDictRenames *renames; 686 - Error *local_err = NULL; 687 - 688 - qdict_put_str(dict, "abc", "foo"); 689 - qdict_put_str(dict, "abcdef", "bar"); 690 - qdict_put_int(dict, "number", 42); 691 - qdict_put_bool(dict, "flag", true); 692 - qdict_put_null(dict, "nothing"); 693 - 694 - /* Empty rename list */ 695 - renames = (QDictRenames[]) { 696 - { NULL, "this can be anything" } 697 - }; 698 - copy = qdict_clone_shallow(dict); 699 - qdict_rename_keys(copy, renames, &error_abort); 700 - 701 - g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo"); 702 - g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar"); 703 - g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42); 704 - g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true); 705 - g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL); 706 - g_assert_cmpint(qdict_count_entries(copy), ==, 5); 707 - 708 - qobject_unref(copy); 709 - 710 - /* Simple rename of all entries */ 711 - renames = (QDictRenames[]) { 712 - { "abc", "str1" }, 713 - { "abcdef", "str2" }, 714 - { "number", "int" }, 715 - { "flag", "bool" }, 716 - { "nothing", "null" }, 717 - { NULL , NULL } 718 - }; 719 - copy = qdict_clone_shallow(dict); 720 - qdict_rename_keys(copy, renames, &error_abort); 721 - 722 - g_assert(!qdict_haskey(copy, "abc")); 723 - g_assert(!qdict_haskey(copy, "abcdef")); 724 - g_assert(!qdict_haskey(copy, "number")); 725 - g_assert(!qdict_haskey(copy, "flag")); 726 - g_assert(!qdict_haskey(copy, "nothing")); 727 - 728 - g_assert_cmpstr(qdict_get_str(copy, "str1"), ==, "foo"); 729 - g_assert_cmpstr(qdict_get_str(copy, "str2"), ==, "bar"); 730 - g_assert_cmpint(qdict_get_int(copy, "int"), ==, 42); 731 - g_assert_cmpint(qdict_get_bool(copy, "bool"), ==, true); 732 - g_assert(qobject_type(qdict_get(copy, "null")) == QTYPE_QNULL); 733 - g_assert_cmpint(qdict_count_entries(copy), ==, 5); 734 - 735 - qobject_unref(copy); 736 - 737 - /* Renames are processed top to bottom */ 738 - renames = (QDictRenames[]) { 739 - { "abc", "tmp" }, 740 - { "abcdef", "abc" }, 741 - { "number", "abcdef" }, 742 - { "flag", "number" }, 743 - { "nothing", "flag" }, 744 - { "tmp", "nothing" }, 745 - { NULL , NULL } 746 - }; 747 - copy = qdict_clone_shallow(dict); 748 - qdict_rename_keys(copy, renames, &error_abort); 749 - 750 - g_assert_cmpstr(qdict_get_str(copy, "nothing"), ==, "foo"); 751 - g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "bar"); 752 - g_assert_cmpint(qdict_get_int(copy, "abcdef"), ==, 42); 753 - g_assert_cmpint(qdict_get_bool(copy, "number"), ==, true); 754 - g_assert(qobject_type(qdict_get(copy, "flag")) == QTYPE_QNULL); 755 - g_assert(!qdict_haskey(copy, "tmp")); 756 - g_assert_cmpint(qdict_count_entries(copy), ==, 5); 757 - 758 - qobject_unref(copy); 759 - 760 - /* Conflicting rename */ 761 - renames = (QDictRenames[]) { 762 - { "abcdef", "abc" }, 763 - { NULL , NULL } 764 - }; 765 - copy = qdict_clone_shallow(dict); 766 - qdict_rename_keys(copy, renames, &local_err); 767 - 768 - g_assert(local_err != NULL); 769 - error_free(local_err); 770 - local_err = NULL; 771 - 772 - g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo"); 773 - g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar"); 774 - g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42); 775 - g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true); 776 - g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL); 777 - g_assert_cmpint(qdict_count_entries(copy), ==, 5); 778 - 779 - qobject_unref(copy); 780 - 781 - /* Renames in an empty dict */ 782 - renames = (QDictRenames[]) { 783 - { "abcdef", "abc" }, 784 - { NULL , NULL } 785 - }; 786 - 787 - qobject_unref(dict); 788 - dict = qdict_new(); 789 - 790 - qdict_rename_keys(dict, renames, &error_abort); 791 - g_assert(qdict_first(dict) == NULL); 792 - 793 - qobject_unref(dict); 794 - } 795 - 796 - static void qdict_crumple_test_bad_inputs(void) 797 - { 798 - QDict *src; 799 - Error *error = NULL; 800 - 801 - src = qdict_new(); 802 - /* rule.0 can't be both a string and a dict */ 803 - qdict_put_str(src, "rule.0", "fred"); 804 - qdict_put_str(src, "rule.0.policy", "allow"); 805 - 806 - g_assert(qdict_crumple(src, &error) == NULL); 807 - g_assert(error != NULL); 808 - error_free(error); 809 - error = NULL; 810 - qobject_unref(src); 811 - 812 - src = qdict_new(); 813 - /* rule can't be both a list and a dict */ 814 - qdict_put_str(src, "rule.0", "fred"); 815 - qdict_put_str(src, "rule.a", "allow"); 816 - 817 - g_assert(qdict_crumple(src, &error) == NULL); 818 - g_assert(error != NULL); 819 - error_free(error); 820 - error = NULL; 821 - qobject_unref(src); 822 - 823 - src = qdict_new(); 824 - /* The input should be flat, ie no dicts or lists */ 825 - qdict_put(src, "rule.a", qdict_new()); 826 - qdict_put_str(src, "rule.b", "allow"); 827 - 828 - g_assert(qdict_crumple(src, &error) == NULL); 829 - g_assert(error != NULL); 830 - error_free(error); 831 - error = NULL; 832 - qobject_unref(src); 833 - 834 - src = qdict_new(); 835 - /* List indexes must not have gaps */ 836 - qdict_put_str(src, "rule.0", "deny"); 837 - qdict_put_str(src, "rule.3", "allow"); 838 - 839 - g_assert(qdict_crumple(src, &error) == NULL); 840 - g_assert(error != NULL); 841 - error_free(error); 842 - error = NULL; 843 - qobject_unref(src); 844 - 845 - src = qdict_new(); 846 - /* List indexes must be in %zu format */ 847 - qdict_put_str(src, "rule.0", "deny"); 848 - qdict_put_str(src, "rule.+1", "allow"); 849 - 850 - g_assert(qdict_crumple(src, &error) == NULL); 851 - g_assert(error != NULL); 852 - error_free(error); 853 - error = NULL; 854 - qobject_unref(src); 855 - } 856 - 857 229 /* 858 230 * Errors test-cases 859 231 */ ··· 987 359 g_test_add_func("/public/get_try_int", qdict_get_try_int_test); 988 360 g_test_add_func("/public/get_str", qdict_get_str_test); 989 361 g_test_add_func("/public/get_try_str", qdict_get_try_str_test); 990 - g_test_add_func("/public/defaults", qdict_defaults_test); 991 362 g_test_add_func("/public/haskey_not", qdict_haskey_not_test); 992 363 g_test_add_func("/public/haskey", qdict_haskey_test); 993 364 g_test_add_func("/public/del", qdict_del_test); 994 365 g_test_add_func("/public/to_qdict", qobject_to_qdict_test); 995 366 g_test_add_func("/public/iterapi", qdict_iterapi_test); 996 - g_test_add_func("/public/flatten", qdict_flatten_test); 997 - g_test_add_func("/public/array_split", qdict_array_split_test); 998 - g_test_add_func("/public/array_entries", qdict_array_entries_test); 999 - g_test_add_func("/public/join", qdict_join_test); 1000 367 1001 368 g_test_add_func("/errors/put_exists", qdict_put_exists_test); 1002 369 g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test); 1003 - 1004 - g_test_add_func("/public/crumple/recursive", 1005 - qdict_crumple_test_recursive); 1006 - g_test_add_func("/public/crumple/empty", 1007 - qdict_crumple_test_empty); 1008 - g_test_add_func("/public/crumple/bad_inputs", 1009 - qdict_crumple_test_bad_inputs); 1010 - 1011 - g_test_add_func("/public/rename_keys", qdict_rename_keys_test); 1012 370 1013 371 /* The Big one */ 1014 372 if (g_test_slow()) {