xref: /qemu/tests/unit/test-keyval.c (revision 9ca9c893b617c0c182f16331021c5ff8c64c5c00)
1d454dbe0SMarkus Armbruster /*
2d454dbe0SMarkus Armbruster  * Unit tests for parsing of KEY=VALUE,... strings
3d454dbe0SMarkus Armbruster  *
4d454dbe0SMarkus Armbruster  * Copyright (C) 2017 Red Hat Inc.
5d454dbe0SMarkus Armbruster  *
6d454dbe0SMarkus Armbruster  * Authors:
7d454dbe0SMarkus Armbruster  *  Markus Armbruster <armbru@redhat.com>,
8d454dbe0SMarkus Armbruster  *
9d454dbe0SMarkus Armbruster  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10d454dbe0SMarkus Armbruster  * See the COPYING file in the top-level directory.
11d454dbe0SMarkus Armbruster  */
12d454dbe0SMarkus Armbruster 
13d454dbe0SMarkus Armbruster #include "qemu/osdep.h"
14d23b6caaSPhilippe Mathieu-Daudé #include "qemu/units.h"
15d454dbe0SMarkus Armbruster #include "qapi/error.h"
16452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h"
1747e6b297SMarkus Armbruster #include "qapi/qmp/qlist.h"
180b2c1beeSMarkus Armbruster #include "qapi/qmp/qstring.h"
199e3943f8SMarkus Armbruster #include "qapi/qobject-input-visitor.h"
20599c156bSMarkus Armbruster #include "test-qapi-visit.h"
219e3943f8SMarkus Armbruster #include "qemu/cutils.h"
22*9ca9c893SMarc-André Lureau #include "qemu/keyval.h"
23d454dbe0SMarkus Armbruster 
24d454dbe0SMarkus Armbruster static void test_keyval_parse(void)
25d454dbe0SMarkus Armbruster {
26d454dbe0SMarkus Armbruster     Error *err = NULL;
27d454dbe0SMarkus Armbruster     QDict *qdict, *sub_qdict;
28d454dbe0SMarkus Armbruster     char long_key[129];
29d454dbe0SMarkus Armbruster     char *params;
308bf12c4fSKevin Wolf     bool help;
31d454dbe0SMarkus Armbruster 
32d454dbe0SMarkus Armbruster     /* Nothing */
338bf12c4fSKevin Wolf     qdict = keyval_parse("", NULL, NULL, &error_abort);
34d454dbe0SMarkus Armbruster     g_assert_cmpuint(qdict_size(qdict), ==, 0);
35cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
36d454dbe0SMarkus Armbruster 
37d454dbe0SMarkus Armbruster     /* Empty key (qemu_opts_parse() accepts this) */
388bf12c4fSKevin Wolf     qdict = keyval_parse("=val", NULL, NULL, &err);
39d454dbe0SMarkus Armbruster     error_free_or_abort(&err);
40d454dbe0SMarkus Armbruster     g_assert(!qdict);
41d454dbe0SMarkus Armbruster 
42d454dbe0SMarkus Armbruster     /* Empty key fragment */
438bf12c4fSKevin Wolf     qdict = keyval_parse(".", NULL, NULL, &err);
44d454dbe0SMarkus Armbruster     error_free_or_abort(&err);
45d454dbe0SMarkus Armbruster     g_assert(!qdict);
468bf12c4fSKevin Wolf     qdict = keyval_parse("key.", NULL, NULL, &err);
47d454dbe0SMarkus Armbruster     error_free_or_abort(&err);
48d454dbe0SMarkus Armbruster     g_assert(!qdict);
49d454dbe0SMarkus Armbruster 
50f7400483SMarkus Armbruster     /* Invalid non-empty key (qemu_opts_parse() doesn't care) */
518bf12c4fSKevin Wolf     qdict = keyval_parse("7up=val", NULL, NULL, &err);
52f7400483SMarkus Armbruster     error_free_or_abort(&err);
53f7400483SMarkus Armbruster     g_assert(!qdict);
54f7400483SMarkus Armbruster 
55d454dbe0SMarkus Armbruster     /* Overlong key */
56d454dbe0SMarkus Armbruster     memset(long_key, 'a', 127);
57d454dbe0SMarkus Armbruster     long_key[127] = 'z';
58d454dbe0SMarkus Armbruster     long_key[128] = 0;
59d454dbe0SMarkus Armbruster     params = g_strdup_printf("k.%s=v", long_key);
608bf12c4fSKevin Wolf     qdict = keyval_parse(params + 2, NULL, NULL, &err);
61d454dbe0SMarkus Armbruster     error_free_or_abort(&err);
62d454dbe0SMarkus Armbruster     g_assert(!qdict);
63d454dbe0SMarkus Armbruster 
64d454dbe0SMarkus Armbruster     /* Overlong key fragment */
658bf12c4fSKevin Wolf     qdict = keyval_parse(params, NULL, NULL, &err);
66d454dbe0SMarkus Armbruster     error_free_or_abort(&err);
67d454dbe0SMarkus Armbruster     g_assert(!qdict);
68d454dbe0SMarkus Armbruster     g_free(params);
69d454dbe0SMarkus Armbruster 
70d454dbe0SMarkus Armbruster     /* Long key (qemu_opts_parse() accepts and truncates silently) */
71d454dbe0SMarkus Armbruster     params = g_strdup_printf("k.%s=v", long_key + 1);
728bf12c4fSKevin Wolf     qdict = keyval_parse(params + 2, NULL, NULL, &error_abort);
73d454dbe0SMarkus Armbruster     g_assert_cmpuint(qdict_size(qdict), ==, 1);
74d454dbe0SMarkus Armbruster     g_assert_cmpstr(qdict_get_try_str(qdict, long_key + 1), ==, "v");
75cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
76d454dbe0SMarkus Armbruster 
77d454dbe0SMarkus Armbruster     /* Long key fragment */
788bf12c4fSKevin Wolf     qdict = keyval_parse(params, NULL, NULL, &error_abort);
79d454dbe0SMarkus Armbruster     g_assert_cmpuint(qdict_size(qdict), ==, 1);
80d454dbe0SMarkus Armbruster     sub_qdict = qdict_get_qdict(qdict, "k");
81d454dbe0SMarkus Armbruster     g_assert(sub_qdict);
82d454dbe0SMarkus Armbruster     g_assert_cmpuint(qdict_size(sub_qdict), ==, 1);
83d454dbe0SMarkus Armbruster     g_assert_cmpstr(qdict_get_try_str(sub_qdict, long_key + 1), ==, "v");
84cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
85d454dbe0SMarkus Armbruster     g_free(params);
86d454dbe0SMarkus Armbruster 
87f7400483SMarkus Armbruster     /* Crap after valid key */
888bf12c4fSKevin Wolf     qdict = keyval_parse("key[0]=val", NULL, NULL, &err);
89f7400483SMarkus Armbruster     error_free_or_abort(&err);
90f7400483SMarkus Armbruster     g_assert(!qdict);
91f7400483SMarkus Armbruster 
92d454dbe0SMarkus Armbruster     /* Multiple keys, last one wins */
938bf12c4fSKevin Wolf     qdict = keyval_parse("a=1,b=2,,x,a=3", NULL, NULL, &error_abort);
94d454dbe0SMarkus Armbruster     g_assert_cmpuint(qdict_size(qdict), ==, 2);
95d454dbe0SMarkus Armbruster     g_assert_cmpstr(qdict_get_try_str(qdict, "a"), ==, "3");
96d454dbe0SMarkus Armbruster     g_assert_cmpstr(qdict_get_try_str(qdict, "b"), ==, "2,x");
97cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
98d454dbe0SMarkus Armbruster 
99d454dbe0SMarkus Armbruster     /* Even when it doesn't in qemu_opts_parse() */
1008bf12c4fSKevin Wolf     qdict = keyval_parse("id=foo,id=bar", NULL, NULL, &error_abort);
101d454dbe0SMarkus Armbruster     g_assert_cmpuint(qdict_size(qdict), ==, 1);
102d454dbe0SMarkus Armbruster     g_assert_cmpstr(qdict_get_try_str(qdict, "id"), ==, "bar");
103cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
104d454dbe0SMarkus Armbruster 
105d454dbe0SMarkus Armbruster     /* Dotted keys */
1068bf12c4fSKevin Wolf     qdict = keyval_parse("a.b.c=1,a.b.c=2,d=3", NULL, NULL, &error_abort);
107d454dbe0SMarkus Armbruster     g_assert_cmpuint(qdict_size(qdict), ==, 2);
108d454dbe0SMarkus Armbruster     sub_qdict = qdict_get_qdict(qdict, "a");
109d454dbe0SMarkus Armbruster     g_assert(sub_qdict);
110d454dbe0SMarkus Armbruster     g_assert_cmpuint(qdict_size(sub_qdict), ==, 1);
111d454dbe0SMarkus Armbruster     sub_qdict = qdict_get_qdict(sub_qdict, "b");
112d454dbe0SMarkus Armbruster     g_assert(sub_qdict);
113d454dbe0SMarkus Armbruster     g_assert_cmpuint(qdict_size(sub_qdict), ==, 1);
114d454dbe0SMarkus Armbruster     g_assert_cmpstr(qdict_get_try_str(sub_qdict, "c"), ==, "2");
115d454dbe0SMarkus Armbruster     g_assert_cmpstr(qdict_get_try_str(qdict, "d"), ==, "3");
116cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
117d454dbe0SMarkus Armbruster 
118d454dbe0SMarkus Armbruster     /* Inconsistent dotted keys */
1198bf12c4fSKevin Wolf     qdict = keyval_parse("a.b=1,a=2", NULL, NULL, &err);
120d454dbe0SMarkus Armbruster     error_free_or_abort(&err);
121d454dbe0SMarkus Armbruster     g_assert(!qdict);
1228bf12c4fSKevin Wolf     qdict = keyval_parse("a.b=1,a.b.c=2", NULL, NULL, &err);
123d454dbe0SMarkus Armbruster     error_free_or_abort(&err);
124d454dbe0SMarkus Armbruster     g_assert(!qdict);
125d454dbe0SMarkus Armbruster 
126d454dbe0SMarkus Armbruster     /* Trailing comma is ignored */
1278bf12c4fSKevin Wolf     qdict = keyval_parse("x=y,", NULL, NULL, &error_abort);
128d454dbe0SMarkus Armbruster     g_assert_cmpuint(qdict_size(qdict), ==, 1);
129d454dbe0SMarkus Armbruster     g_assert_cmpstr(qdict_get_try_str(qdict, "x"), ==, "y");
130cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
131d454dbe0SMarkus Armbruster 
132d454dbe0SMarkus Armbruster     /* Except when it isn't */
1338bf12c4fSKevin Wolf     qdict = keyval_parse(",", NULL, NULL, &err);
134d454dbe0SMarkus Armbruster     error_free_or_abort(&err);
135d454dbe0SMarkus Armbruster     g_assert(!qdict);
136d454dbe0SMarkus Armbruster 
137d454dbe0SMarkus Armbruster     /* Value containing ,id= not misinterpreted as qemu_opts_parse() does */
1388bf12c4fSKevin Wolf     qdict = keyval_parse("x=,,id=bar", NULL, NULL, &error_abort);
139d454dbe0SMarkus Armbruster     g_assert_cmpuint(qdict_size(qdict), ==, 1);
140d454dbe0SMarkus Armbruster     g_assert_cmpstr(qdict_get_try_str(qdict, "x"), ==, ",id=bar");
141cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
142d454dbe0SMarkus Armbruster 
143d454dbe0SMarkus Armbruster     /* Anti-social ID is left to caller (qemu_opts_parse() rejects it) */
1448bf12c4fSKevin Wolf     qdict = keyval_parse("id=666", NULL, NULL, &error_abort);
145d454dbe0SMarkus Armbruster     g_assert_cmpuint(qdict_size(qdict), ==, 1);
146d454dbe0SMarkus Armbruster     g_assert_cmpstr(qdict_get_try_str(qdict, "id"), ==, "666");
147cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
148d454dbe0SMarkus Armbruster 
149d454dbe0SMarkus Armbruster     /* Implied value not supported (unlike qemu_opts_parse()) */
1508bf12c4fSKevin Wolf     qdict = keyval_parse("an,noaus,noaus=", NULL, NULL, &err);
151d454dbe0SMarkus Armbruster     error_free_or_abort(&err);
152d454dbe0SMarkus Armbruster     g_assert(!qdict);
153d454dbe0SMarkus Armbruster 
154d454dbe0SMarkus Armbruster     /* Implied value, key "no" (qemu_opts_parse(): negated empty key) */
1558bf12c4fSKevin Wolf     qdict = keyval_parse("no", NULL, NULL, &err);
156d454dbe0SMarkus Armbruster     error_free_or_abort(&err);
157d454dbe0SMarkus Armbruster     g_assert(!qdict);
158d454dbe0SMarkus Armbruster 
159d454dbe0SMarkus Armbruster     /* Implied key */
1608bf12c4fSKevin Wolf     qdict = keyval_parse("an,aus=off,noaus=", "implied", NULL, &error_abort);
161d454dbe0SMarkus Armbruster     g_assert_cmpuint(qdict_size(qdict), ==, 3);
162d454dbe0SMarkus Armbruster     g_assert_cmpstr(qdict_get_try_str(qdict, "implied"), ==, "an");
163d454dbe0SMarkus Armbruster     g_assert_cmpstr(qdict_get_try_str(qdict, "aus"), ==, "off");
164d454dbe0SMarkus Armbruster     g_assert_cmpstr(qdict_get_try_str(qdict, "noaus"), ==, "");
165cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
166d454dbe0SMarkus Armbruster 
167d454dbe0SMarkus Armbruster     /* Implied dotted key */
1688bf12c4fSKevin Wolf     qdict = keyval_parse("val", "eins.zwei", NULL, &error_abort);
169d454dbe0SMarkus Armbruster     g_assert_cmpuint(qdict_size(qdict), ==, 1);
170d454dbe0SMarkus Armbruster     sub_qdict = qdict_get_qdict(qdict, "eins");
171d454dbe0SMarkus Armbruster     g_assert(sub_qdict);
172d454dbe0SMarkus Armbruster     g_assert_cmpuint(qdict_size(sub_qdict), ==, 1);
173d454dbe0SMarkus Armbruster     g_assert_cmpstr(qdict_get_try_str(sub_qdict, "zwei"), ==, "val");
174cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
175d454dbe0SMarkus Armbruster 
176d454dbe0SMarkus Armbruster     /* Implied key with empty value (qemu_opts_parse() accepts this) */
1778bf12c4fSKevin Wolf     qdict = keyval_parse(",", "implied", NULL, &err);
178d454dbe0SMarkus Armbruster     error_free_or_abort(&err);
179d454dbe0SMarkus Armbruster     g_assert(!qdict);
180d454dbe0SMarkus Armbruster 
181d454dbe0SMarkus Armbruster     /* Likewise (qemu_opts_parse(): implied key with comma value) */
1828bf12c4fSKevin Wolf     qdict = keyval_parse(",,,a=1", "implied", NULL, &err);
183d454dbe0SMarkus Armbruster     error_free_or_abort(&err);
184d454dbe0SMarkus Armbruster     g_assert(!qdict);
185d454dbe0SMarkus Armbruster 
186ce40cbf1SMarkus Armbruster     /* Implied key's value can't have comma (qemu_opts_parse(): it can) */
1878bf12c4fSKevin Wolf     qdict = keyval_parse("val,,ue", "implied", NULL, &err);
1887051ae6cSMarkus Armbruster     error_free_or_abort(&err);
1897051ae6cSMarkus Armbruster     g_assert(!qdict);
190ce40cbf1SMarkus Armbruster 
191d454dbe0SMarkus Armbruster     /* Empty key is not an implied key */
1928bf12c4fSKevin Wolf     qdict = keyval_parse("=val", "implied", NULL, &err);
193d454dbe0SMarkus Armbruster     error_free_or_abort(&err);
194d454dbe0SMarkus Armbruster     g_assert(!qdict);
1958bf12c4fSKevin Wolf 
1968bf12c4fSKevin Wolf     /* "help" by itself, without implied key */
1978bf12c4fSKevin Wolf     qdict = keyval_parse("help", NULL, &help, &error_abort);
1988bf12c4fSKevin Wolf     g_assert_cmpuint(qdict_size(qdict), ==, 0);
1998bf12c4fSKevin Wolf     g_assert(help);
2008bf12c4fSKevin Wolf     qobject_unref(qdict);
2018bf12c4fSKevin Wolf 
2028bf12c4fSKevin Wolf     /* "help" by itself, with implied key */
2038bf12c4fSKevin Wolf     qdict = keyval_parse("help", "implied", &help, &error_abort);
2048bf12c4fSKevin Wolf     g_assert_cmpuint(qdict_size(qdict), ==, 0);
2058bf12c4fSKevin Wolf     g_assert(help);
2068bf12c4fSKevin Wolf     qobject_unref(qdict);
2078bf12c4fSKevin Wolf 
2088bf12c4fSKevin Wolf     /* "help" when no help is available, without implied key */
2098bf12c4fSKevin Wolf     qdict = keyval_parse("help", NULL, NULL, &err);
2108bf12c4fSKevin Wolf     error_free_or_abort(&err);
2118bf12c4fSKevin Wolf     g_assert(!qdict);
2128bf12c4fSKevin Wolf 
2138bf12c4fSKevin Wolf     /* "help" when no help is available, with implied key */
2148bf12c4fSKevin Wolf     qdict = keyval_parse("help", "implied", NULL, &err);
2158bf12c4fSKevin Wolf     error_free_or_abort(&err);
2168bf12c4fSKevin Wolf     g_assert(!qdict);
2178bf12c4fSKevin Wolf 
2188bf12c4fSKevin Wolf     /* Key "help" */
2198bf12c4fSKevin Wolf     qdict = keyval_parse("help=on", NULL, &help, &error_abort);
2208bf12c4fSKevin Wolf     g_assert_cmpuint(qdict_size(qdict), ==, 1);
2218bf12c4fSKevin Wolf     g_assert_cmpstr(qdict_get_try_str(qdict, "help"), ==, "on");
2228bf12c4fSKevin Wolf     g_assert(!help);
2238bf12c4fSKevin Wolf     qobject_unref(qdict);
2248bf12c4fSKevin Wolf 
2258bf12c4fSKevin Wolf     /* "help" followed by crap, without implied key */
2268bf12c4fSKevin Wolf     qdict = keyval_parse("help.abc", NULL, &help, &err);
2278bf12c4fSKevin Wolf     error_free_or_abort(&err);
2288bf12c4fSKevin Wolf     g_assert(!qdict);
2298bf12c4fSKevin Wolf 
2308bf12c4fSKevin Wolf     /* "help" followed by crap, with implied key */
2318bf12c4fSKevin Wolf     qdict = keyval_parse("help.abc", "implied", &help, &err);
2328bf12c4fSKevin Wolf     g_assert_cmpuint(qdict_size(qdict), ==, 1);
2338bf12c4fSKevin Wolf     g_assert_cmpstr(qdict_get_try_str(qdict, "implied"), ==, "help.abc");
2348bf12c4fSKevin Wolf     g_assert(!help);
2358bf12c4fSKevin Wolf     qobject_unref(qdict);
2368bf12c4fSKevin Wolf 
2378bf12c4fSKevin Wolf     /* "help" with other stuff, without implied key */
2388bf12c4fSKevin Wolf     qdict = keyval_parse("number=42,help,foo=bar", NULL, &help, &error_abort);
2398bf12c4fSKevin Wolf     g_assert_cmpuint(qdict_size(qdict), ==, 2);
2408bf12c4fSKevin Wolf     g_assert_cmpstr(qdict_get_try_str(qdict, "number"), ==, "42");
2418bf12c4fSKevin Wolf     g_assert_cmpstr(qdict_get_try_str(qdict, "foo"), ==, "bar");
2428bf12c4fSKevin Wolf     g_assert(help);
2438bf12c4fSKevin Wolf     qobject_unref(qdict);
2448bf12c4fSKevin Wolf 
2458bf12c4fSKevin Wolf     /* "help" with other stuff, with implied key */
2468bf12c4fSKevin Wolf     qdict = keyval_parse("val,help,foo=bar", "implied", &help, &error_abort);
2478bf12c4fSKevin Wolf     g_assert_cmpuint(qdict_size(qdict), ==, 2);
2488bf12c4fSKevin Wolf     g_assert_cmpstr(qdict_get_try_str(qdict, "implied"), ==, "val");
2498bf12c4fSKevin Wolf     g_assert_cmpstr(qdict_get_try_str(qdict, "foo"), ==, "bar");
2508bf12c4fSKevin Wolf     g_assert(help);
2518bf12c4fSKevin Wolf     qobject_unref(qdict);
252d454dbe0SMarkus Armbruster }
253d454dbe0SMarkus Armbruster 
2540b2c1beeSMarkus Armbruster static void check_list012(QList *qlist)
2550b2c1beeSMarkus Armbruster {
2560b2c1beeSMarkus Armbruster     static const char *expected[] = { "null", "eins", "zwei" };
2570b2c1beeSMarkus Armbruster     int i;
2580b2c1beeSMarkus Armbruster     QString *qstr;
2590b2c1beeSMarkus Armbruster 
2600b2c1beeSMarkus Armbruster     g_assert(qlist);
2610b2c1beeSMarkus Armbruster     for (i = 0; i < ARRAY_SIZE(expected); i++) {
2627dc847ebSMax Reitz         qstr = qobject_to(QString, qlist_pop(qlist));
2630b2c1beeSMarkus Armbruster         g_assert(qstr);
2640b2c1beeSMarkus Armbruster         g_assert_cmpstr(qstring_get_str(qstr), ==, expected[i]);
265cb3e7f08SMarc-André Lureau         qobject_unref(qstr);
2660b2c1beeSMarkus Armbruster     }
2670b2c1beeSMarkus Armbruster     g_assert(qlist_empty(qlist));
2680b2c1beeSMarkus Armbruster }
2690b2c1beeSMarkus Armbruster 
2700b2c1beeSMarkus Armbruster static void test_keyval_parse_list(void)
2710b2c1beeSMarkus Armbruster {
2720b2c1beeSMarkus Armbruster     Error *err = NULL;
2730b2c1beeSMarkus Armbruster     QDict *qdict, *sub_qdict;
2740b2c1beeSMarkus Armbruster 
2750b2c1beeSMarkus Armbruster     /* Root can't be a list */
2768bf12c4fSKevin Wolf     qdict = keyval_parse("0=1", NULL, NULL, &err);
2770b2c1beeSMarkus Armbruster     error_free_or_abort(&err);
2780b2c1beeSMarkus Armbruster     g_assert(!qdict);
2790b2c1beeSMarkus Armbruster 
2800b2c1beeSMarkus Armbruster     /* List elements need not be in order */
2818bf12c4fSKevin Wolf     qdict = keyval_parse("list.0=null,list.2=zwei,list.1=eins", NULL, NULL,
2828bf12c4fSKevin Wolf                          &error_abort);
2830b2c1beeSMarkus Armbruster     g_assert_cmpint(qdict_size(qdict), ==, 1);
2840b2c1beeSMarkus Armbruster     check_list012(qdict_get_qlist(qdict, "list"));
285cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
2860b2c1beeSMarkus Armbruster 
2870b2c1beeSMarkus Armbruster     /* Multiple indexes, last one wins */
288b2cd5b92SMarkus Armbruster     qdict = keyval_parse("list.1=goner,list.0=null,list.01=eins,list.2=zwei",
2898bf12c4fSKevin Wolf                          NULL, NULL, &error_abort);
2900b2c1beeSMarkus Armbruster     g_assert_cmpint(qdict_size(qdict), ==, 1);
2910b2c1beeSMarkus Armbruster     check_list012(qdict_get_qlist(qdict, "list"));
292cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
2930b2c1beeSMarkus Armbruster 
2940b2c1beeSMarkus Armbruster     /* List at deeper nesting */
2958bf12c4fSKevin Wolf     qdict = keyval_parse("a.list.1=eins,a.list.00=null,a.list.2=zwei", NULL,
2960b2c1beeSMarkus Armbruster                          NULL, &error_abort);
2970b2c1beeSMarkus Armbruster     g_assert_cmpint(qdict_size(qdict), ==, 1);
2980b2c1beeSMarkus Armbruster     sub_qdict = qdict_get_qdict(qdict, "a");
2990b2c1beeSMarkus Armbruster     g_assert_cmpint(qdict_size(sub_qdict), ==, 1);
3000b2c1beeSMarkus Armbruster     check_list012(qdict_get_qlist(sub_qdict, "list"));
301cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
3020b2c1beeSMarkus Armbruster 
3030b2c1beeSMarkus Armbruster     /* Inconsistent dotted keys: both list and dictionary */
3048bf12c4fSKevin Wolf     qdict = keyval_parse("a.b.c=1,a.b.0=2", NULL, NULL, &err);
3050b2c1beeSMarkus Armbruster     error_free_or_abort(&err);
3060b2c1beeSMarkus Armbruster     g_assert(!qdict);
3078bf12c4fSKevin Wolf     qdict = keyval_parse("a.0.c=1,a.b.c=2", NULL, NULL, &err);
3080b2c1beeSMarkus Armbruster     error_free_or_abort(&err);
3090b2c1beeSMarkus Armbruster     g_assert(!qdict);
3100b2c1beeSMarkus Armbruster 
3110b2c1beeSMarkus Armbruster     /* Missing list indexes */
3128bf12c4fSKevin Wolf     qdict = keyval_parse("list.1=lonely", NULL, NULL, &err);
3130b2c1beeSMarkus Armbruster     error_free_or_abort(&err);
3140b2c1beeSMarkus Armbruster     g_assert(!qdict);
3158bf12c4fSKevin Wolf     qdict = keyval_parse("list.0=null,list.2=eins,list.02=zwei", NULL, NULL,
3168bf12c4fSKevin Wolf                          &err);
3170b2c1beeSMarkus Armbruster     error_free_or_abort(&err);
3180b2c1beeSMarkus Armbruster     g_assert(!qdict);
3190b2c1beeSMarkus Armbruster }
3200b2c1beeSMarkus Armbruster 
3219e3943f8SMarkus Armbruster static void test_keyval_visit_bool(void)
3229e3943f8SMarkus Armbruster {
3239e3943f8SMarkus Armbruster     Error *err = NULL;
3249e3943f8SMarkus Armbruster     Visitor *v;
3259e3943f8SMarkus Armbruster     QDict *qdict;
3269e3943f8SMarkus Armbruster     bool b;
3279e3943f8SMarkus Armbruster 
3288bf12c4fSKevin Wolf     qdict = keyval_parse("bool1=on,bool2=off", NULL, NULL, &error_abort);
3299e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
330cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
3319e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
3329e3943f8SMarkus Armbruster     visit_type_bool(v, "bool1", &b, &error_abort);
3339e3943f8SMarkus Armbruster     g_assert(b);
3349e3943f8SMarkus Armbruster     visit_type_bool(v, "bool2", &b, &error_abort);
3359e3943f8SMarkus Armbruster     g_assert(!b);
3369e3943f8SMarkus Armbruster     visit_check_struct(v, &error_abort);
3379e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
3389e3943f8SMarkus Armbruster     visit_free(v);
3399e3943f8SMarkus Armbruster 
3408bf12c4fSKevin Wolf     qdict = keyval_parse("bool1=offer", NULL, NULL, &error_abort);
3419e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
342cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
3439e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
3449e3943f8SMarkus Armbruster     visit_type_bool(v, "bool1", &b, &err);
3459e3943f8SMarkus Armbruster     error_free_or_abort(&err);
3469e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
3479e3943f8SMarkus Armbruster     visit_free(v);
3489e3943f8SMarkus Armbruster }
3499e3943f8SMarkus Armbruster 
3509e3943f8SMarkus Armbruster static void test_keyval_visit_number(void)
3519e3943f8SMarkus Armbruster {
3529e3943f8SMarkus Armbruster     Error *err = NULL;
3539e3943f8SMarkus Armbruster     Visitor *v;
3549e3943f8SMarkus Armbruster     QDict *qdict;
3559e3943f8SMarkus Armbruster     uint64_t u;
3569e3943f8SMarkus Armbruster 
3579e3943f8SMarkus Armbruster     /* Lower limit zero */
3588bf12c4fSKevin Wolf     qdict = keyval_parse("number1=0", NULL, NULL, &error_abort);
3599e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
360cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
3619e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
3629e3943f8SMarkus Armbruster     visit_type_uint64(v, "number1", &u, &error_abort);
3639e3943f8SMarkus Armbruster     g_assert_cmpuint(u, ==, 0);
3649e3943f8SMarkus Armbruster     visit_check_struct(v, &error_abort);
3659e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
3669e3943f8SMarkus Armbruster     visit_free(v);
3679e3943f8SMarkus Armbruster 
3689e3943f8SMarkus Armbruster     /* Upper limit 2^64-1 */
3698bf12c4fSKevin Wolf     qdict = keyval_parse("number1=18446744073709551615,number2=-1", NULL,
3709e3943f8SMarkus Armbruster                          NULL, &error_abort);
3719e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
372cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
3739e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
3749e3943f8SMarkus Armbruster     visit_type_uint64(v, "number1", &u, &error_abort);
3759e3943f8SMarkus Armbruster     g_assert_cmphex(u, ==, UINT64_MAX);
3769e3943f8SMarkus Armbruster     visit_type_uint64(v, "number2", &u, &error_abort);
3779e3943f8SMarkus Armbruster     g_assert_cmphex(u, ==, UINT64_MAX);
3789e3943f8SMarkus Armbruster     visit_check_struct(v, &error_abort);
3799e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
3809e3943f8SMarkus Armbruster     visit_free(v);
3819e3943f8SMarkus Armbruster 
3829e3943f8SMarkus Armbruster     /* Above upper limit */
3838bf12c4fSKevin Wolf     qdict = keyval_parse("number1=18446744073709551616", NULL, NULL,
3848bf12c4fSKevin Wolf                          &error_abort);
3859e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
386cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
3879e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
3889e3943f8SMarkus Armbruster     visit_type_uint64(v, "number1", &u, &err);
3899e3943f8SMarkus Armbruster     error_free_or_abort(&err);
3909e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
3919e3943f8SMarkus Armbruster     visit_free(v);
3929e3943f8SMarkus Armbruster 
3939e3943f8SMarkus Armbruster     /* Below lower limit */
3948bf12c4fSKevin Wolf     qdict = keyval_parse("number1=-18446744073709551616", NULL, NULL,
3958bf12c4fSKevin Wolf                          &error_abort);
3969e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
397cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
3989e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
3999e3943f8SMarkus Armbruster     visit_type_uint64(v, "number1", &u, &err);
4009e3943f8SMarkus Armbruster     error_free_or_abort(&err);
4019e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
4029e3943f8SMarkus Armbruster     visit_free(v);
4039e3943f8SMarkus Armbruster 
4049e3943f8SMarkus Armbruster     /* Hex and octal */
4058bf12c4fSKevin Wolf     qdict = keyval_parse("number1=0x2a,number2=052", NULL, NULL, &error_abort);
4069e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
407cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
4089e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
4099e3943f8SMarkus Armbruster     visit_type_uint64(v, "number1", &u, &error_abort);
4109e3943f8SMarkus Armbruster     g_assert_cmpuint(u, ==, 42);
4119e3943f8SMarkus Armbruster     visit_type_uint64(v, "number2", &u, &error_abort);
4129e3943f8SMarkus Armbruster     g_assert_cmpuint(u, ==, 42);
4139e3943f8SMarkus Armbruster     visit_check_struct(v, &error_abort);
4149e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
4159e3943f8SMarkus Armbruster     visit_free(v);
4169e3943f8SMarkus Armbruster 
4179e3943f8SMarkus Armbruster     /* Trailing crap */
4188bf12c4fSKevin Wolf     qdict = keyval_parse("number1=3.14,number2=08", NULL, NULL, &error_abort);
4199e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
420cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
4219e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
4229e3943f8SMarkus Armbruster     visit_type_uint64(v, "number1", &u, &err);
4239e3943f8SMarkus Armbruster     error_free_or_abort(&err);
4249e3943f8SMarkus Armbruster     visit_type_uint64(v, "number2", &u, &err);
4259e3943f8SMarkus Armbruster     error_free_or_abort(&err);
4269e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
4279e3943f8SMarkus Armbruster     visit_free(v);
4289e3943f8SMarkus Armbruster }
4299e3943f8SMarkus Armbruster 
4309e3943f8SMarkus Armbruster static void test_keyval_visit_size(void)
4319e3943f8SMarkus Armbruster {
4329e3943f8SMarkus Armbruster     Error *err = NULL;
4339e3943f8SMarkus Armbruster     Visitor *v;
4349e3943f8SMarkus Armbruster     QDict *qdict;
4359e3943f8SMarkus Armbruster     uint64_t sz;
4369e3943f8SMarkus Armbruster 
4379e3943f8SMarkus Armbruster     /* Lower limit zero */
4388bf12c4fSKevin Wolf     qdict = keyval_parse("sz1=0", NULL, NULL, &error_abort);
4399e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
440cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
4419e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
4429e3943f8SMarkus Armbruster     visit_type_size(v, "sz1", &sz, &error_abort);
4439e3943f8SMarkus Armbruster     g_assert_cmpuint(sz, ==, 0);
4449e3943f8SMarkus Armbruster     visit_check_struct(v, &error_abort);
4459e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
4469e3943f8SMarkus Armbruster     visit_free(v);
4479e3943f8SMarkus Armbruster 
448cf923b78SEric Blake     /* Note: full 64 bits of precision */
4499e3943f8SMarkus Armbruster 
450cf923b78SEric Blake     /* Around double limit of precision: 2^53-1, 2^53, 2^53+1 */
4519e3943f8SMarkus Armbruster     qdict = keyval_parse("sz1=9007199254740991,"
4529e3943f8SMarkus Armbruster                          "sz2=9007199254740992,"
4539e3943f8SMarkus Armbruster                          "sz3=9007199254740993",
4548bf12c4fSKevin Wolf                          NULL, NULL, &error_abort);
4559e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
456cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
4579e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
4589e3943f8SMarkus Armbruster     visit_type_size(v, "sz1", &sz, &error_abort);
4599e3943f8SMarkus Armbruster     g_assert_cmphex(sz, ==, 0x1fffffffffffff);
4609e3943f8SMarkus Armbruster     visit_type_size(v, "sz2", &sz, &error_abort);
4619e3943f8SMarkus Armbruster     g_assert_cmphex(sz, ==, 0x20000000000000);
4629e3943f8SMarkus Armbruster     visit_type_size(v, "sz3", &sz, &error_abort);
463cf923b78SEric Blake     g_assert_cmphex(sz, ==, 0x20000000000001);
4649e3943f8SMarkus Armbruster     visit_check_struct(v, &error_abort);
4659e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
4669e3943f8SMarkus Armbruster     visit_free(v);
4679e3943f8SMarkus Armbruster 
468cf923b78SEric Blake     /* Close to signed integer limit 2^63 */
469cf923b78SEric Blake     qdict = keyval_parse("sz1=9223372036854775807," /* 7fffffffffffffff */
470cf923b78SEric Blake                          "sz2=9223372036854775808," /* 8000000000000000 */
471cf923b78SEric Blake                          "sz3=9223372036854775809", /* 8000000000000001 */
4728bf12c4fSKevin Wolf                          NULL, NULL, &error_abort);
4739e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
474cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
4759e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
4769e3943f8SMarkus Armbruster     visit_type_size(v, "sz1", &sz, &error_abort);
477cf923b78SEric Blake     g_assert_cmphex(sz, ==, 0x7fffffffffffffff);
4789e3943f8SMarkus Armbruster     visit_type_size(v, "sz2", &sz, &error_abort);
479cf923b78SEric Blake     g_assert_cmphex(sz, ==, 0x8000000000000000);
480cf923b78SEric Blake     visit_type_size(v, "sz3", &sz, &error_abort);
481cf923b78SEric Blake     g_assert_cmphex(sz, ==, 0x8000000000000001);
4829e3943f8SMarkus Armbruster     visit_check_struct(v, &error_abort);
4839e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
4849e3943f8SMarkus Armbruster     visit_free(v);
4859e3943f8SMarkus Armbruster 
4869e3943f8SMarkus Armbruster     /* Close to actual upper limit 0xfffffffffffff800 (53 msbs set) */
4879e3943f8SMarkus Armbruster     qdict = keyval_parse("sz1=18446744073709549568," /* fffffffffffff800 */
4889e3943f8SMarkus Armbruster                          "sz2=18446744073709550591", /* fffffffffffffbff */
4898bf12c4fSKevin Wolf                          NULL, NULL, &error_abort);
4909e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
491cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
4929e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
4939e3943f8SMarkus Armbruster     visit_type_size(v, "sz1", &sz, &error_abort);
4949e3943f8SMarkus Armbruster     g_assert_cmphex(sz, ==, 0xfffffffffffff800);
4959e3943f8SMarkus Armbruster     visit_type_size(v, "sz2", &sz, &error_abort);
496cf923b78SEric Blake     g_assert_cmphex(sz, ==, 0xfffffffffffffbff);
497cf923b78SEric Blake     visit_check_struct(v, &error_abort);
498cf923b78SEric Blake     visit_end_struct(v, NULL);
499cf923b78SEric Blake     visit_free(v);
500cf923b78SEric Blake 
501cf923b78SEric Blake     /* Actual limit 2^64-1*/
502cf923b78SEric Blake     qdict = keyval_parse("sz1=18446744073709551615", /* ffffffffffffffff */
503cf923b78SEric Blake                          NULL, NULL, &error_abort);
504cf923b78SEric Blake     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
505cf923b78SEric Blake     qobject_unref(qdict);
506cf923b78SEric Blake     visit_start_struct(v, NULL, NULL, 0, &error_abort);
507cf923b78SEric Blake     visit_type_size(v, "sz1", &sz, &error_abort);
508cf923b78SEric Blake     g_assert_cmphex(sz, ==, 0xffffffffffffffff);
5099e3943f8SMarkus Armbruster     visit_check_struct(v, &error_abort);
5109e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
5119e3943f8SMarkus Armbruster     visit_free(v);
5129e3943f8SMarkus Armbruster 
5139e3943f8SMarkus Armbruster     /* Beyond limits */
5149e3943f8SMarkus Armbruster     qdict = keyval_parse("sz1=-1,"
515cf923b78SEric Blake                          "sz2=18446744073709551616", /* 2^64 */
5168bf12c4fSKevin Wolf                          NULL, NULL, &error_abort);
5179e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
518cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
5199e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
5209e3943f8SMarkus Armbruster     visit_type_size(v, "sz1", &sz, &err);
5219e3943f8SMarkus Armbruster     error_free_or_abort(&err);
5229e3943f8SMarkus Armbruster     visit_type_size(v, "sz2", &sz, &err);
5239e3943f8SMarkus Armbruster     error_free_or_abort(&err);
5249e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
5259e3943f8SMarkus Armbruster     visit_free(v);
5269e3943f8SMarkus Armbruster 
5279e3943f8SMarkus Armbruster     /* Suffixes */
5289e3943f8SMarkus Armbruster     qdict = keyval_parse("sz1=8b,sz2=1.5k,sz3=2M,sz4=0.1G,sz5=16777215T",
5298bf12c4fSKevin Wolf                          NULL, NULL, &error_abort);
5309e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
531cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
5329e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
5339e3943f8SMarkus Armbruster     visit_type_size(v, "sz1", &sz, &error_abort);
5349e3943f8SMarkus Armbruster     g_assert_cmpuint(sz, ==, 8);
5359e3943f8SMarkus Armbruster     visit_type_size(v, "sz2", &sz, &error_abort);
5369e3943f8SMarkus Armbruster     g_assert_cmpuint(sz, ==, 1536);
5379e3943f8SMarkus Armbruster     visit_type_size(v, "sz3", &sz, &error_abort);
538d23b6caaSPhilippe Mathieu-Daudé     g_assert_cmphex(sz, ==, 2 * MiB);
5399e3943f8SMarkus Armbruster     visit_type_size(v, "sz4", &sz, &error_abort);
540d23b6caaSPhilippe Mathieu-Daudé     g_assert_cmphex(sz, ==, GiB / 10);
5419e3943f8SMarkus Armbruster     visit_type_size(v, "sz5", &sz, &error_abort);
542d23b6caaSPhilippe Mathieu-Daudé     g_assert_cmphex(sz, ==, 16777215ULL * TiB);
5439e3943f8SMarkus Armbruster     visit_check_struct(v, &error_abort);
5449e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
5459e3943f8SMarkus Armbruster     visit_free(v);
5469e3943f8SMarkus Armbruster 
5479e3943f8SMarkus Armbruster     /* Beyond limit with suffix */
5488bf12c4fSKevin Wolf     qdict = keyval_parse("sz1=16777216T", NULL, NULL, &error_abort);
5499e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
550cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
5519e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
5529e3943f8SMarkus Armbruster     visit_type_size(v, "sz1", &sz, &err);
5539e3943f8SMarkus Armbruster     error_free_or_abort(&err);
5549e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
5559e3943f8SMarkus Armbruster     visit_free(v);
5569e3943f8SMarkus Armbruster 
5579e3943f8SMarkus Armbruster     /* Trailing crap */
5588bf12c4fSKevin Wolf     qdict = keyval_parse("sz1=0Z,sz2=16Gi", NULL, NULL, &error_abort);
5599e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
560cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
5619e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
5629e3943f8SMarkus Armbruster     visit_type_size(v, "sz1", &sz, &err);
5639e3943f8SMarkus Armbruster     error_free_or_abort(&err);
5649e3943f8SMarkus Armbruster     visit_type_size(v, "sz2", &sz, &err);
5659e3943f8SMarkus Armbruster     error_free_or_abort(&err);
5669e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
5679e3943f8SMarkus Armbruster     visit_free(v);
5689e3943f8SMarkus Armbruster }
5699e3943f8SMarkus Armbruster 
5709e3943f8SMarkus Armbruster static void test_keyval_visit_dict(void)
5719e3943f8SMarkus Armbruster {
5729e3943f8SMarkus Armbruster     Error *err = NULL;
5739e3943f8SMarkus Armbruster     Visitor *v;
5749e3943f8SMarkus Armbruster     QDict *qdict;
5759e3943f8SMarkus Armbruster     int64_t i;
5769e3943f8SMarkus Armbruster 
5778bf12c4fSKevin Wolf     qdict = keyval_parse("a.b.c=1,a.b.c=2,d=3", NULL, NULL, &error_abort);
5789e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
579cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
5809e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
5819e3943f8SMarkus Armbruster     visit_start_struct(v, "a", NULL, 0, &error_abort);
5829e3943f8SMarkus Armbruster     visit_start_struct(v, "b", NULL, 0, &error_abort);
5839e3943f8SMarkus Armbruster     visit_type_int(v, "c", &i, &error_abort);
5849e3943f8SMarkus Armbruster     g_assert_cmpint(i, ==, 2);
5859e3943f8SMarkus Armbruster     visit_check_struct(v, &error_abort);
5869e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
5879e3943f8SMarkus Armbruster     visit_check_struct(v, &error_abort);
5889e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
5899e3943f8SMarkus Armbruster     visit_type_int(v, "d", &i, &error_abort);
5909e3943f8SMarkus Armbruster     g_assert_cmpint(i, ==, 3);
5919e3943f8SMarkus Armbruster     visit_check_struct(v, &error_abort);
5929e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
5939e3943f8SMarkus Armbruster     visit_free(v);
5949e3943f8SMarkus Armbruster 
5958bf12c4fSKevin Wolf     qdict = keyval_parse("a.b=", NULL, NULL, &error_abort);
5969e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
597cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
5989e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
5999e3943f8SMarkus Armbruster     visit_start_struct(v, "a", NULL, 0, &error_abort);
6009e3943f8SMarkus Armbruster     visit_type_int(v, "c", &i, &err);   /* a.c missing */
6019e3943f8SMarkus Armbruster     error_free_or_abort(&err);
6029e3943f8SMarkus Armbruster     visit_check_struct(v, &err);
6039e3943f8SMarkus Armbruster     error_free_or_abort(&err);          /* a.b unexpected */
6049e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
6059e3943f8SMarkus Armbruster     visit_check_struct(v, &error_abort);
6069e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
6079e3943f8SMarkus Armbruster     visit_free(v);
6089e3943f8SMarkus Armbruster }
6099e3943f8SMarkus Armbruster 
6100b2c1beeSMarkus Armbruster static void test_keyval_visit_list(void)
6110b2c1beeSMarkus Armbruster {
6120b2c1beeSMarkus Armbruster     Error *err = NULL;
6130b2c1beeSMarkus Armbruster     Visitor *v;
6140b2c1beeSMarkus Armbruster     QDict *qdict;
6150b2c1beeSMarkus Armbruster     char *s;
6160b2c1beeSMarkus Armbruster 
6178bf12c4fSKevin Wolf     qdict = keyval_parse("a.0=,a.1=I,a.2.0=II", NULL, NULL, &error_abort);
6180b2c1beeSMarkus Armbruster     /* TODO empty list */
6190b2c1beeSMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
620cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
6210b2c1beeSMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
6220b2c1beeSMarkus Armbruster     visit_start_list(v, "a", NULL, 0, &error_abort);
6230b2c1beeSMarkus Armbruster     visit_type_str(v, NULL, &s, &error_abort);
6240b2c1beeSMarkus Armbruster     g_assert_cmpstr(s, ==, "");
6250b2c1beeSMarkus Armbruster     g_free(s);
6260b2c1beeSMarkus Armbruster     visit_type_str(v, NULL, &s, &error_abort);
6270b2c1beeSMarkus Armbruster     g_assert_cmpstr(s, ==, "I");
6280b2c1beeSMarkus Armbruster     g_free(s);
6290b2c1beeSMarkus Armbruster     visit_start_list(v, NULL, NULL, 0, &error_abort);
6300b2c1beeSMarkus Armbruster     visit_type_str(v, NULL, &s, &error_abort);
6310b2c1beeSMarkus Armbruster     g_assert_cmpstr(s, ==, "II");
6320b2c1beeSMarkus Armbruster     g_free(s);
6330b2c1beeSMarkus Armbruster     visit_check_list(v, &error_abort);
6340b2c1beeSMarkus Armbruster     visit_end_list(v, NULL);
6350b2c1beeSMarkus Armbruster     visit_check_list(v, &error_abort);
6360b2c1beeSMarkus Armbruster     visit_end_list(v, NULL);
6370b2c1beeSMarkus Armbruster     visit_check_struct(v, &error_abort);
6380b2c1beeSMarkus Armbruster     visit_end_struct(v, NULL);
6390b2c1beeSMarkus Armbruster     visit_free(v);
6400b2c1beeSMarkus Armbruster 
6418bf12c4fSKevin Wolf     qdict = keyval_parse("a.0=,b.0.0=head", NULL, NULL, &error_abort);
6420b2c1beeSMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
643cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
6440b2c1beeSMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
6450b2c1beeSMarkus Armbruster     visit_start_list(v, "a", NULL, 0, &error_abort);
6460b2c1beeSMarkus Armbruster     visit_check_list(v, &err);  /* a[0] unexpected */
6470b2c1beeSMarkus Armbruster     error_free_or_abort(&err);
6480b2c1beeSMarkus Armbruster     visit_end_list(v, NULL);
6490b2c1beeSMarkus Armbruster     visit_start_list(v, "b", NULL, 0, &error_abort);
6500b2c1beeSMarkus Armbruster     visit_start_list(v, NULL, NULL, 0, &error_abort);
6510b2c1beeSMarkus Armbruster     visit_type_str(v, NULL, &s, &error_abort);
6520b2c1beeSMarkus Armbruster     g_assert_cmpstr(s, ==, "head");
6530b2c1beeSMarkus Armbruster     g_free(s);
6540b2c1beeSMarkus Armbruster     visit_type_str(v, NULL, &s, &err); /* b[0][1] missing */
6550b2c1beeSMarkus Armbruster     error_free_or_abort(&err);
6560b2c1beeSMarkus Armbruster     visit_end_list(v, NULL);
6570b2c1beeSMarkus Armbruster     visit_end_list(v, NULL);
6580b2c1beeSMarkus Armbruster     visit_check_struct(v, &error_abort);
6590b2c1beeSMarkus Armbruster     visit_end_struct(v, NULL);
6600b2c1beeSMarkus Armbruster     visit_free(v);
6610b2c1beeSMarkus Armbruster }
6620b2c1beeSMarkus Armbruster 
6639e3943f8SMarkus Armbruster static void test_keyval_visit_optional(void)
6649e3943f8SMarkus Armbruster {
6659e3943f8SMarkus Armbruster     Visitor *v;
6669e3943f8SMarkus Armbruster     QDict *qdict;
6679e3943f8SMarkus Armbruster     bool present;
6689e3943f8SMarkus Armbruster     int64_t i;
6699e3943f8SMarkus Armbruster 
6708bf12c4fSKevin Wolf     qdict = keyval_parse("a.b=1", NULL, NULL, &error_abort);
6719e3943f8SMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
672cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
6739e3943f8SMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
6749e3943f8SMarkus Armbruster     visit_optional(v, "b", &present);
6759e3943f8SMarkus Armbruster     g_assert(!present);         /* b missing */
6769e3943f8SMarkus Armbruster     visit_optional(v, "a", &present);
6779e3943f8SMarkus Armbruster     g_assert(present);          /* a present */
6789e3943f8SMarkus Armbruster     visit_start_struct(v, "a", NULL, 0, &error_abort);
6799e3943f8SMarkus Armbruster     visit_optional(v, "b", &present);
6809e3943f8SMarkus Armbruster     g_assert(present);          /* a.b present */
6819e3943f8SMarkus Armbruster     visit_type_int(v, "b", &i, &error_abort);
6829e3943f8SMarkus Armbruster     g_assert_cmpint(i, ==, 1);
6839e3943f8SMarkus Armbruster     visit_optional(v, "a", &present);
6849e3943f8SMarkus Armbruster     g_assert(!present);         /* a.a missing */
6859e3943f8SMarkus Armbruster     visit_check_struct(v, &error_abort);
6869e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
6879e3943f8SMarkus Armbruster     visit_check_struct(v, &error_abort);
6889e3943f8SMarkus Armbruster     visit_end_struct(v, NULL);
6899e3943f8SMarkus Armbruster     visit_free(v);
6909e3943f8SMarkus Armbruster }
6919e3943f8SMarkus Armbruster 
692599c156bSMarkus Armbruster static void test_keyval_visit_alternate(void)
693599c156bSMarkus Armbruster {
694599c156bSMarkus Armbruster     Error *err = NULL;
695599c156bSMarkus Armbruster     Visitor *v;
696599c156bSMarkus Armbruster     QDict *qdict;
697c0644771SMarkus Armbruster     AltStrObj *aso;
6987c877c80SMarc-André Lureau     AltNumEnum *ane;
699c0644771SMarkus Armbruster     AltEnumBool *aeb;
700599c156bSMarkus Armbruster 
701599c156bSMarkus Armbruster     /*
702599c156bSMarkus Armbruster      * Can't do scalar alternate variants other than string.  You get
703599c156bSMarkus Armbruster      * the string variant if there is one, else an error.
704c0644771SMarkus Armbruster      * TODO make it work for unambiguous cases like AltEnumBool below
705599c156bSMarkus Armbruster      */
7068bf12c4fSKevin Wolf     qdict = keyval_parse("a=1,b=2,c=on", NULL, NULL, &error_abort);
707599c156bSMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
708cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
709599c156bSMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
710c0644771SMarkus Armbruster     visit_type_AltStrObj(v, "a", &aso, &error_abort);
711c0644771SMarkus Armbruster     g_assert_cmpint(aso->type, ==, QTYPE_QSTRING);
712c0644771SMarkus Armbruster     g_assert_cmpstr(aso->u.s, ==, "1");
713c0644771SMarkus Armbruster     qapi_free_AltStrObj(aso);
7147c877c80SMarc-André Lureau     visit_type_AltNumEnum(v, "b", &ane, &err);
715c0644771SMarkus Armbruster     error_free_or_abort(&err);
716c0644771SMarkus Armbruster     visit_type_AltEnumBool(v, "c", &aeb, &err);
717599c156bSMarkus Armbruster     error_free_or_abort(&err);
718599c156bSMarkus Armbruster     visit_end_struct(v, NULL);
719599c156bSMarkus Armbruster     visit_free(v);
720599c156bSMarkus Armbruster }
721599c156bSMarkus Armbruster 
722599c156bSMarkus Armbruster static void test_keyval_visit_any(void)
723599c156bSMarkus Armbruster {
724599c156bSMarkus Armbruster     Visitor *v;
725599c156bSMarkus Armbruster     QDict *qdict;
726599c156bSMarkus Armbruster     QObject *any;
727599c156bSMarkus Armbruster     QList *qlist;
728599c156bSMarkus Armbruster     QString *qstr;
729599c156bSMarkus Armbruster 
7308bf12c4fSKevin Wolf     qdict = keyval_parse("a.0=null,a.1=1", NULL, NULL, &error_abort);
731599c156bSMarkus Armbruster     v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
732cb3e7f08SMarc-André Lureau     qobject_unref(qdict);
733599c156bSMarkus Armbruster     visit_start_struct(v, NULL, NULL, 0, &error_abort);
734599c156bSMarkus Armbruster     visit_type_any(v, "a", &any, &error_abort);
7357dc847ebSMax Reitz     qlist = qobject_to(QList, any);
736599c156bSMarkus Armbruster     g_assert(qlist);
7377dc847ebSMax Reitz     qstr = qobject_to(QString, qlist_pop(qlist));
738599c156bSMarkus Armbruster     g_assert_cmpstr(qstring_get_str(qstr), ==, "null");
739cb3e7f08SMarc-André Lureau     qobject_unref(qstr);
7407dc847ebSMax Reitz     qstr = qobject_to(QString, qlist_pop(qlist));
741599c156bSMarkus Armbruster     g_assert_cmpstr(qstring_get_str(qstr), ==, "1");
742599c156bSMarkus Armbruster     g_assert(qlist_empty(qlist));
743cb3e7f08SMarc-André Lureau     qobject_unref(qstr);
744cb3e7f08SMarc-André Lureau     qobject_unref(any);
745599c156bSMarkus Armbruster     visit_check_struct(v, &error_abort);
746599c156bSMarkus Armbruster     visit_end_struct(v, NULL);
747599c156bSMarkus Armbruster     visit_free(v);
748599c156bSMarkus Armbruster }
749599c156bSMarkus Armbruster 
7509176e800SPaolo Bonzini static void test_keyval_merge_dict(void)
7519176e800SPaolo Bonzini {
7529176e800SPaolo Bonzini     QDict *first = keyval_parse("opt1=abc,opt2.sub1=def,opt2.sub2=ghi,opt3=xyz",
7539176e800SPaolo Bonzini                                 NULL, NULL, &error_abort);
7549176e800SPaolo Bonzini     QDict *second = keyval_parse("opt1=ABC,opt2.sub2=GHI,opt2.sub3=JKL",
7559176e800SPaolo Bonzini                                  NULL, NULL, &error_abort);
7569176e800SPaolo Bonzini     QDict *combined = keyval_parse("opt1=ABC,opt2.sub1=def,opt2.sub2=GHI,opt2.sub3=JKL,opt3=xyz",
7579176e800SPaolo Bonzini                                    NULL, NULL, &error_abort);
7589176e800SPaolo Bonzini     Error *err = NULL;
7599176e800SPaolo Bonzini 
7609176e800SPaolo Bonzini     keyval_merge(first, second, &err);
7619176e800SPaolo Bonzini     g_assert(!err);
7629176e800SPaolo Bonzini     g_assert(qobject_is_equal(QOBJECT(combined), QOBJECT(first)));
7639176e800SPaolo Bonzini     qobject_unref(first);
7649176e800SPaolo Bonzini     qobject_unref(second);
7659176e800SPaolo Bonzini     qobject_unref(combined);
7669176e800SPaolo Bonzini }
7679176e800SPaolo Bonzini 
7689176e800SPaolo Bonzini static void test_keyval_merge_list(void)
7699176e800SPaolo Bonzini {
7709176e800SPaolo Bonzini     QDict *first = keyval_parse("opt1.0=abc,opt2.0=xyz",
7719176e800SPaolo Bonzini                                 NULL, NULL, &error_abort);
7729176e800SPaolo Bonzini     QDict *second = keyval_parse("opt1.0=def",
7739176e800SPaolo Bonzini                                  NULL, NULL, &error_abort);
7749176e800SPaolo Bonzini     QDict *combined = keyval_parse("opt1.0=abc,opt1.1=def,opt2.0=xyz",
7759176e800SPaolo Bonzini                                    NULL, NULL, &error_abort);
7769176e800SPaolo Bonzini     Error *err = NULL;
7779176e800SPaolo Bonzini 
7789176e800SPaolo Bonzini     keyval_merge(first, second, &err);
7799176e800SPaolo Bonzini     g_assert(!err);
7809176e800SPaolo Bonzini     g_assert(qobject_is_equal(QOBJECT(combined), QOBJECT(first)));
7819176e800SPaolo Bonzini     qobject_unref(first);
7829176e800SPaolo Bonzini     qobject_unref(second);
7839176e800SPaolo Bonzini     qobject_unref(combined);
7849176e800SPaolo Bonzini }
7859176e800SPaolo Bonzini 
7869176e800SPaolo Bonzini static void test_keyval_merge_conflict(void)
7879176e800SPaolo Bonzini {
7889176e800SPaolo Bonzini     QDict *first = keyval_parse("opt2=ABC",
7899176e800SPaolo Bonzini                                 NULL, NULL, &error_abort);
7909176e800SPaolo Bonzini     QDict *second = keyval_parse("opt2.sub1=def,opt2.sub2=ghi",
7919176e800SPaolo Bonzini                                  NULL, NULL, &error_abort);
7929176e800SPaolo Bonzini     QDict *third = qdict_clone_shallow(first);
7939176e800SPaolo Bonzini     Error *err = NULL;
7949176e800SPaolo Bonzini 
7959176e800SPaolo Bonzini     keyval_merge(first, second, &err);
7969176e800SPaolo Bonzini     error_free_or_abort(&err);
7979176e800SPaolo Bonzini     keyval_merge(second, third, &err);
7989176e800SPaolo Bonzini     error_free_or_abort(&err);
7999176e800SPaolo Bonzini 
8009176e800SPaolo Bonzini     qobject_unref(first);
8019176e800SPaolo Bonzini     qobject_unref(second);
8029176e800SPaolo Bonzini     qobject_unref(third);
8039176e800SPaolo Bonzini }
8049176e800SPaolo Bonzini 
805d454dbe0SMarkus Armbruster int main(int argc, char *argv[])
806d454dbe0SMarkus Armbruster {
807d454dbe0SMarkus Armbruster     g_test_init(&argc, &argv, NULL);
808d454dbe0SMarkus Armbruster     g_test_add_func("/keyval/keyval_parse", test_keyval_parse);
8090b2c1beeSMarkus Armbruster     g_test_add_func("/keyval/keyval_parse/list", test_keyval_parse_list);
8109e3943f8SMarkus Armbruster     g_test_add_func("/keyval/visit/bool", test_keyval_visit_bool);
8119e3943f8SMarkus Armbruster     g_test_add_func("/keyval/visit/number", test_keyval_visit_number);
8129e3943f8SMarkus Armbruster     g_test_add_func("/keyval/visit/size", test_keyval_visit_size);
8139e3943f8SMarkus Armbruster     g_test_add_func("/keyval/visit/dict", test_keyval_visit_dict);
8140b2c1beeSMarkus Armbruster     g_test_add_func("/keyval/visit/list", test_keyval_visit_list);
8159e3943f8SMarkus Armbruster     g_test_add_func("/keyval/visit/optional", test_keyval_visit_optional);
816599c156bSMarkus Armbruster     g_test_add_func("/keyval/visit/alternate", test_keyval_visit_alternate);
817599c156bSMarkus Armbruster     g_test_add_func("/keyval/visit/any", test_keyval_visit_any);
8189176e800SPaolo Bonzini     g_test_add_func("/keyval/merge/dict", test_keyval_merge_dict);
8199176e800SPaolo Bonzini     g_test_add_func("/keyval/merge/list", test_keyval_merge_list);
8209176e800SPaolo Bonzini     g_test_add_func("/keyval/merge/conflict", test_keyval_merge_conflict);
821d454dbe0SMarkus Armbruster     g_test_run();
822d454dbe0SMarkus Armbruster     return 0;
823d454dbe0SMarkus Armbruster }
824