]> git.proxmox.com Git - mirror_qemu.git/blame - tests/check-block-qdict.c
block-qdict: Simplify qdict_is_list() some
[mirror_qemu.git] / tests / check-block-qdict.c
CommitLineData
0bcc8e5b
MA
1/*
2 * Unit-tests for Block layer QDict extras
3 *
4 * Copyright (c) 2013-2018 Red Hat, Inc.
5 *
6 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
7 * See the COPYING.LIB file in the top-level directory.
8 */
9
10#include "qemu/osdep.h"
11#include "block/qdict.h"
12#include "qapi/qmp/qlist.h"
13#include "qapi/qmp/qnum.h"
14#include "qapi/error.h"
15
16static void qdict_defaults_test(void)
17{
18 QDict *dict, *copy;
19
20 dict = qdict_new();
21 copy = qdict_new();
22
23 qdict_set_default_str(dict, "foo", "abc");
24 qdict_set_default_str(dict, "foo", "def");
25 g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "abc");
26 qdict_set_default_str(dict, "bar", "ghi");
27
28 qdict_copy_default(copy, dict, "foo");
29 g_assert_cmpstr(qdict_get_str(copy, "foo"), ==, "abc");
30 qdict_set_default_str(copy, "bar", "xyz");
31 qdict_copy_default(copy, dict, "bar");
32 g_assert_cmpstr(qdict_get_str(copy, "bar"), ==, "xyz");
33
34 qobject_unref(copy);
35 qobject_unref(dict);
36}
37
38static void qdict_flatten_test(void)
39{
40 QList *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
113static 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
254static 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
297static 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
374static 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
434static 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
448static 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
460static 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
575static 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
636int 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}