1da668aa1SThomas Huth /*
2da668aa1SThomas Huth * QemuOpts unit-tests.
3da668aa1SThomas Huth *
4da668aa1SThomas Huth * Copyright (C) 2014 Leandro Dorileo <l@dorileo.org>
5da668aa1SThomas Huth *
6da668aa1SThomas Huth * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
7da668aa1SThomas Huth * See the COPYING.LIB file in the top-level directory.
8da668aa1SThomas Huth */
9da668aa1SThomas Huth
10da668aa1SThomas Huth #include "qemu/osdep.h"
11da668aa1SThomas Huth #include "qemu/units.h"
12da668aa1SThomas Huth #include "qemu/option.h"
13da668aa1SThomas Huth #include "qemu/option_int.h"
14da668aa1SThomas Huth #include "qapi/error.h"
15da668aa1SThomas Huth #include "qapi/qmp/qdict.h"
16da668aa1SThomas Huth #include "qapi/qmp/qstring.h"
17da668aa1SThomas Huth #include "qemu/config-file.h"
18da668aa1SThomas Huth
19da668aa1SThomas Huth
20da668aa1SThomas Huth static QemuOptsList opts_list_01 = {
21da668aa1SThomas Huth .name = "opts_list_01",
22da668aa1SThomas Huth .head = QTAILQ_HEAD_INITIALIZER(opts_list_01.head),
23da668aa1SThomas Huth .desc = {
24da668aa1SThomas Huth {
25da668aa1SThomas Huth .name = "str1",
26da668aa1SThomas Huth .type = QEMU_OPT_STRING,
27da668aa1SThomas Huth .help = "Help texts are preserved in qemu_opts_append",
28da668aa1SThomas Huth .def_value_str = "default",
29da668aa1SThomas Huth },{
30da668aa1SThomas Huth .name = "str2",
31da668aa1SThomas Huth .type = QEMU_OPT_STRING,
32da668aa1SThomas Huth },{
33da668aa1SThomas Huth .name = "str3",
34da668aa1SThomas Huth .type = QEMU_OPT_STRING,
35da668aa1SThomas Huth },{
36da668aa1SThomas Huth .name = "number1",
37da668aa1SThomas Huth .type = QEMU_OPT_NUMBER,
38da668aa1SThomas Huth .help = "Having help texts only for some options is okay",
39da668aa1SThomas Huth },{
40da668aa1SThomas Huth .name = "number2",
41da668aa1SThomas Huth .type = QEMU_OPT_NUMBER,
42da668aa1SThomas Huth },
43da668aa1SThomas Huth { /* end of list */ }
44da668aa1SThomas Huth },
45da668aa1SThomas Huth };
46da668aa1SThomas Huth
47da668aa1SThomas Huth static QemuOptsList opts_list_02 = {
48da668aa1SThomas Huth .name = "opts_list_02",
49da668aa1SThomas Huth .head = QTAILQ_HEAD_INITIALIZER(opts_list_02.head),
50da668aa1SThomas Huth .desc = {
51da668aa1SThomas Huth {
52da668aa1SThomas Huth .name = "str1",
53da668aa1SThomas Huth .type = QEMU_OPT_STRING,
54da668aa1SThomas Huth },{
55da668aa1SThomas Huth .name = "str2",
56da668aa1SThomas Huth .type = QEMU_OPT_STRING,
57da668aa1SThomas Huth },{
58da668aa1SThomas Huth .name = "bool1",
59da668aa1SThomas Huth .type = QEMU_OPT_BOOL,
60da668aa1SThomas Huth },{
61da668aa1SThomas Huth .name = "bool2",
62da668aa1SThomas Huth .type = QEMU_OPT_BOOL,
63da668aa1SThomas Huth },{
64da668aa1SThomas Huth .name = "size1",
65da668aa1SThomas Huth .type = QEMU_OPT_SIZE,
66da668aa1SThomas Huth },{
67da668aa1SThomas Huth .name = "size2",
68da668aa1SThomas Huth .type = QEMU_OPT_SIZE,
69da668aa1SThomas Huth },{
70da668aa1SThomas Huth .name = "size3",
71da668aa1SThomas Huth .type = QEMU_OPT_SIZE,
72da668aa1SThomas Huth },
73da668aa1SThomas Huth { /* end of list */ }
74da668aa1SThomas Huth },
75da668aa1SThomas Huth };
76da668aa1SThomas Huth
77da668aa1SThomas Huth static QemuOptsList opts_list_03 = {
78da668aa1SThomas Huth .name = "opts_list_03",
79da668aa1SThomas Huth .implied_opt_name = "implied",
80da668aa1SThomas Huth .head = QTAILQ_HEAD_INITIALIZER(opts_list_03.head),
81da668aa1SThomas Huth .desc = {
82da668aa1SThomas Huth /* no elements => accept any params */
83da668aa1SThomas Huth { /* end of list */ }
84da668aa1SThomas Huth },
85da668aa1SThomas Huth };
86da668aa1SThomas Huth
87da668aa1SThomas Huth static QemuOptsList opts_list_04 = {
88da668aa1SThomas Huth .name = "opts_list_04",
89da668aa1SThomas Huth .head = QTAILQ_HEAD_INITIALIZER(opts_list_04.head),
90da668aa1SThomas Huth .merge_lists = true,
91da668aa1SThomas Huth .desc = {
92da668aa1SThomas Huth {
93da668aa1SThomas Huth .name = "str3",
94da668aa1SThomas Huth .type = QEMU_OPT_STRING,
95da668aa1SThomas Huth },
96da668aa1SThomas Huth { /* end of list */ }
97da668aa1SThomas Huth },
98da668aa1SThomas Huth };
99da668aa1SThomas Huth
register_opts(void)100da668aa1SThomas Huth static void register_opts(void)
101da668aa1SThomas Huth {
102da668aa1SThomas Huth qemu_add_opts(&opts_list_01);
103da668aa1SThomas Huth qemu_add_opts(&opts_list_02);
104da668aa1SThomas Huth qemu_add_opts(&opts_list_03);
105da668aa1SThomas Huth qemu_add_opts(&opts_list_04);
106da668aa1SThomas Huth }
107da668aa1SThomas Huth
test_find_unknown_opts(void)108da668aa1SThomas Huth static void test_find_unknown_opts(void)
109da668aa1SThomas Huth {
110da668aa1SThomas Huth QemuOptsList *list;
111da668aa1SThomas Huth Error *err = NULL;
112da668aa1SThomas Huth
113da668aa1SThomas Huth /* should not return anything, we don't have an "unknown" option */
114da668aa1SThomas Huth list = qemu_find_opts_err("unknown", &err);
115da668aa1SThomas Huth g_assert(list == NULL);
116da668aa1SThomas Huth error_free_or_abort(&err);
117da668aa1SThomas Huth }
118da668aa1SThomas Huth
test_qemu_find_opts(void)119da668aa1SThomas Huth static void test_qemu_find_opts(void)
120da668aa1SThomas Huth {
121da668aa1SThomas Huth QemuOptsList *list;
122da668aa1SThomas Huth
123da668aa1SThomas Huth /* we have an "opts_list_01" option, should return it */
124da668aa1SThomas Huth list = qemu_find_opts("opts_list_01");
125da668aa1SThomas Huth g_assert(list != NULL);
126da668aa1SThomas Huth g_assert_cmpstr(list->name, ==, "opts_list_01");
127da668aa1SThomas Huth }
128da668aa1SThomas Huth
test_qemu_opts_create(void)129da668aa1SThomas Huth static void test_qemu_opts_create(void)
130da668aa1SThomas Huth {
131da668aa1SThomas Huth QemuOptsList *list;
132da668aa1SThomas Huth QemuOpts *opts;
133da668aa1SThomas Huth
134da668aa1SThomas Huth list = qemu_find_opts("opts_list_01");
135da668aa1SThomas Huth g_assert(list != NULL);
136da668aa1SThomas Huth g_assert(QTAILQ_EMPTY(&list->head));
137da668aa1SThomas Huth g_assert_cmpstr(list->name, ==, "opts_list_01");
138da668aa1SThomas Huth
139da668aa1SThomas Huth /* should not find anything at this point */
140da668aa1SThomas Huth opts = qemu_opts_find(list, NULL);
141da668aa1SThomas Huth g_assert(opts == NULL);
142da668aa1SThomas Huth
143da668aa1SThomas Huth /* create the opts */
144da668aa1SThomas Huth opts = qemu_opts_create(list, NULL, 0, &error_abort);
145da668aa1SThomas Huth g_assert(opts != NULL);
146da668aa1SThomas Huth g_assert(!QTAILQ_EMPTY(&list->head));
147da668aa1SThomas Huth
148da668aa1SThomas Huth /* now we've create the opts, must find it */
149da668aa1SThomas Huth opts = qemu_opts_find(list, NULL);
150da668aa1SThomas Huth g_assert(opts != NULL);
151da668aa1SThomas Huth
152da668aa1SThomas Huth qemu_opts_del(opts);
153da668aa1SThomas Huth
154da668aa1SThomas Huth /* should not find anything at this point */
155da668aa1SThomas Huth opts = qemu_opts_find(list, NULL);
156da668aa1SThomas Huth g_assert(opts == NULL);
157da668aa1SThomas Huth }
158da668aa1SThomas Huth
test_qemu_opt_get(void)159da668aa1SThomas Huth static void test_qemu_opt_get(void)
160da668aa1SThomas Huth {
161da668aa1SThomas Huth QemuOptsList *list;
162da668aa1SThomas Huth QemuOpts *opts;
163da668aa1SThomas Huth const char *opt = NULL;
164da668aa1SThomas Huth
165da668aa1SThomas Huth list = qemu_find_opts("opts_list_01");
166da668aa1SThomas Huth g_assert(list != NULL);
167da668aa1SThomas Huth g_assert(QTAILQ_EMPTY(&list->head));
168da668aa1SThomas Huth g_assert_cmpstr(list->name, ==, "opts_list_01");
169da668aa1SThomas Huth
170da668aa1SThomas Huth /* should not find anything at this point */
171da668aa1SThomas Huth opts = qemu_opts_find(list, NULL);
172da668aa1SThomas Huth g_assert(opts == NULL);
173da668aa1SThomas Huth
174da668aa1SThomas Huth /* create the opts */
175da668aa1SThomas Huth opts = qemu_opts_create(list, NULL, 0, &error_abort);
176da668aa1SThomas Huth g_assert(opts != NULL);
177da668aa1SThomas Huth g_assert(!QTAILQ_EMPTY(&list->head));
178da668aa1SThomas Huth
179da668aa1SThomas Huth /* haven't set anything to str2 yet */
180da668aa1SThomas Huth opt = qemu_opt_get(opts, "str2");
181da668aa1SThomas Huth g_assert(opt == NULL);
182da668aa1SThomas Huth
183da668aa1SThomas Huth qemu_opt_set(opts, "str2", "value", &error_abort);
184da668aa1SThomas Huth
185da668aa1SThomas Huth /* now we have set str2, should know about it */
186da668aa1SThomas Huth opt = qemu_opt_get(opts, "str2");
187da668aa1SThomas Huth g_assert_cmpstr(opt, ==, "value");
188da668aa1SThomas Huth
189da668aa1SThomas Huth qemu_opt_set(opts, "str2", "value2", &error_abort);
190da668aa1SThomas Huth
191da668aa1SThomas Huth /* having reset the value, the returned should be the reset one */
192da668aa1SThomas Huth opt = qemu_opt_get(opts, "str2");
193da668aa1SThomas Huth g_assert_cmpstr(opt, ==, "value2");
194da668aa1SThomas Huth
195da668aa1SThomas Huth qemu_opts_del(opts);
196da668aa1SThomas Huth
197da668aa1SThomas Huth /* should not find anything at this point */
198da668aa1SThomas Huth opts = qemu_opts_find(list, NULL);
199da668aa1SThomas Huth g_assert(opts == NULL);
200da668aa1SThomas Huth }
201da668aa1SThomas Huth
test_qemu_opt_get_bool(void)202da668aa1SThomas Huth static void test_qemu_opt_get_bool(void)
203da668aa1SThomas Huth {
204da668aa1SThomas Huth QemuOptsList *list;
205da668aa1SThomas Huth QemuOpts *opts;
206da668aa1SThomas Huth bool opt;
207da668aa1SThomas Huth
208da668aa1SThomas Huth list = qemu_find_opts("opts_list_02");
209da668aa1SThomas Huth g_assert(list != NULL);
210da668aa1SThomas Huth g_assert(QTAILQ_EMPTY(&list->head));
211da668aa1SThomas Huth g_assert_cmpstr(list->name, ==, "opts_list_02");
212da668aa1SThomas Huth
213da668aa1SThomas Huth /* should not find anything at this point */
214da668aa1SThomas Huth opts = qemu_opts_find(list, NULL);
215da668aa1SThomas Huth g_assert(opts == NULL);
216da668aa1SThomas Huth
217da668aa1SThomas Huth /* create the opts */
218da668aa1SThomas Huth opts = qemu_opts_create(list, NULL, 0, &error_abort);
219da668aa1SThomas Huth g_assert(opts != NULL);
220da668aa1SThomas Huth g_assert(!QTAILQ_EMPTY(&list->head));
221da668aa1SThomas Huth
222da668aa1SThomas Huth /* haven't set anything to bool1 yet, so defval should be returned */
223da668aa1SThomas Huth opt = qemu_opt_get_bool(opts, "bool1", false);
224da668aa1SThomas Huth g_assert(opt == false);
225da668aa1SThomas Huth
226da668aa1SThomas Huth qemu_opt_set_bool(opts, "bool1", true, &error_abort);
227da668aa1SThomas Huth
228da668aa1SThomas Huth /* now we have set bool1, should know about it */
229da668aa1SThomas Huth opt = qemu_opt_get_bool(opts, "bool1", false);
230da668aa1SThomas Huth g_assert(opt == true);
231da668aa1SThomas Huth
232da668aa1SThomas Huth /* having reset the value, opt should be the reset one not defval */
233da668aa1SThomas Huth qemu_opt_set_bool(opts, "bool1", false, &error_abort);
234da668aa1SThomas Huth
235da668aa1SThomas Huth opt = qemu_opt_get_bool(opts, "bool1", true);
236da668aa1SThomas Huth g_assert(opt == false);
237da668aa1SThomas Huth
238da668aa1SThomas Huth qemu_opts_del(opts);
239da668aa1SThomas Huth
240da668aa1SThomas Huth /* should not find anything at this point */
241da668aa1SThomas Huth opts = qemu_opts_find(list, NULL);
242da668aa1SThomas Huth g_assert(opts == NULL);
243da668aa1SThomas Huth }
244da668aa1SThomas Huth
test_qemu_opt_get_number(void)245da668aa1SThomas Huth static void test_qemu_opt_get_number(void)
246da668aa1SThomas Huth {
247da668aa1SThomas Huth QemuOptsList *list;
248da668aa1SThomas Huth QemuOpts *opts;
249da668aa1SThomas Huth uint64_t opt;
250da668aa1SThomas Huth
251da668aa1SThomas Huth list = qemu_find_opts("opts_list_01");
252da668aa1SThomas Huth g_assert(list != NULL);
253da668aa1SThomas Huth g_assert(QTAILQ_EMPTY(&list->head));
254da668aa1SThomas Huth g_assert_cmpstr(list->name, ==, "opts_list_01");
255da668aa1SThomas Huth
256da668aa1SThomas Huth /* should not find anything at this point */
257da668aa1SThomas Huth opts = qemu_opts_find(list, NULL);
258da668aa1SThomas Huth g_assert(opts == NULL);
259da668aa1SThomas Huth
260da668aa1SThomas Huth /* create the opts */
261da668aa1SThomas Huth opts = qemu_opts_create(list, NULL, 0, &error_abort);
262da668aa1SThomas Huth g_assert(opts != NULL);
263da668aa1SThomas Huth g_assert(!QTAILQ_EMPTY(&list->head));
264da668aa1SThomas Huth
265da668aa1SThomas Huth /* haven't set anything to number1 yet, so defval should be returned */
266da668aa1SThomas Huth opt = qemu_opt_get_number(opts, "number1", 5);
267da668aa1SThomas Huth g_assert(opt == 5);
268da668aa1SThomas Huth
269da668aa1SThomas Huth qemu_opt_set_number(opts, "number1", 10, &error_abort);
270da668aa1SThomas Huth
271da668aa1SThomas Huth /* now we have set number1, should know about it */
272da668aa1SThomas Huth opt = qemu_opt_get_number(opts, "number1", 5);
273da668aa1SThomas Huth g_assert(opt == 10);
274da668aa1SThomas Huth
275da668aa1SThomas Huth /* having reset it, the returned should be the reset one not defval */
276da668aa1SThomas Huth qemu_opt_set_number(opts, "number1", 15, &error_abort);
277da668aa1SThomas Huth
278da668aa1SThomas Huth opt = qemu_opt_get_number(opts, "number1", 5);
279da668aa1SThomas Huth g_assert(opt == 15);
280da668aa1SThomas Huth
281da668aa1SThomas Huth qemu_opts_del(opts);
282da668aa1SThomas Huth
283da668aa1SThomas Huth /* should not find anything at this point */
284da668aa1SThomas Huth opts = qemu_opts_find(list, NULL);
285da668aa1SThomas Huth g_assert(opts == NULL);
286da668aa1SThomas Huth }
287da668aa1SThomas Huth
test_qemu_opt_get_size(void)288da668aa1SThomas Huth static void test_qemu_opt_get_size(void)
289da668aa1SThomas Huth {
290da668aa1SThomas Huth QemuOptsList *list;
291da668aa1SThomas Huth QemuOpts *opts;
292da668aa1SThomas Huth uint64_t opt;
293da668aa1SThomas Huth QDict *dict;
294da668aa1SThomas Huth
295da668aa1SThomas Huth list = qemu_find_opts("opts_list_02");
296da668aa1SThomas Huth g_assert(list != NULL);
297da668aa1SThomas Huth g_assert(QTAILQ_EMPTY(&list->head));
298da668aa1SThomas Huth g_assert_cmpstr(list->name, ==, "opts_list_02");
299da668aa1SThomas Huth
300da668aa1SThomas Huth /* should not find anything at this point */
301da668aa1SThomas Huth opts = qemu_opts_find(list, NULL);
302da668aa1SThomas Huth g_assert(opts == NULL);
303da668aa1SThomas Huth
304da668aa1SThomas Huth /* create the opts */
305da668aa1SThomas Huth opts = qemu_opts_create(list, NULL, 0, &error_abort);
306da668aa1SThomas Huth g_assert(opts != NULL);
307da668aa1SThomas Huth g_assert(!QTAILQ_EMPTY(&list->head));
308da668aa1SThomas Huth
309da668aa1SThomas Huth /* haven't set anything to size1 yet, so defval should be returned */
310da668aa1SThomas Huth opt = qemu_opt_get_size(opts, "size1", 5);
311da668aa1SThomas Huth g_assert(opt == 5);
312da668aa1SThomas Huth
313da668aa1SThomas Huth dict = qdict_new();
314da668aa1SThomas Huth g_assert(dict != NULL);
315da668aa1SThomas Huth
316da668aa1SThomas Huth qdict_put_str(dict, "size1", "10");
317da668aa1SThomas Huth
318da668aa1SThomas Huth qemu_opts_absorb_qdict(opts, dict, &error_abort);
319da668aa1SThomas Huth g_assert(error_abort == NULL);
320da668aa1SThomas Huth
321da668aa1SThomas Huth /* now we have set size1, should know about it */
322da668aa1SThomas Huth opt = qemu_opt_get_size(opts, "size1", 5);
323da668aa1SThomas Huth g_assert(opt == 10);
324da668aa1SThomas Huth
325da668aa1SThomas Huth /* reset value */
326da668aa1SThomas Huth qdict_put_str(dict, "size1", "15");
327da668aa1SThomas Huth
328da668aa1SThomas Huth qemu_opts_absorb_qdict(opts, dict, &error_abort);
329da668aa1SThomas Huth g_assert(error_abort == NULL);
330da668aa1SThomas Huth
331da668aa1SThomas Huth /* test the reset value */
332da668aa1SThomas Huth opt = qemu_opt_get_size(opts, "size1", 5);
333da668aa1SThomas Huth g_assert(opt == 15);
334da668aa1SThomas Huth
335da668aa1SThomas Huth qdict_del(dict, "size1");
336da668aa1SThomas Huth g_free(dict);
337da668aa1SThomas Huth
338da668aa1SThomas Huth qemu_opts_del(opts);
339da668aa1SThomas Huth
340da668aa1SThomas Huth /* should not find anything at this point */
341da668aa1SThomas Huth opts = qemu_opts_find(list, NULL);
342da668aa1SThomas Huth g_assert(opts == NULL);
343da668aa1SThomas Huth }
344da668aa1SThomas Huth
test_qemu_opt_unset(void)345da668aa1SThomas Huth static void test_qemu_opt_unset(void)
346da668aa1SThomas Huth {
347da668aa1SThomas Huth QemuOpts *opts;
348da668aa1SThomas Huth const char *value;
349da668aa1SThomas Huth int ret;
350da668aa1SThomas Huth
351da668aa1SThomas Huth /* dynamically initialized (parsed) opts */
352da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, "key=value", false, NULL);
353da668aa1SThomas Huth g_assert(opts != NULL);
354da668aa1SThomas Huth
355da668aa1SThomas Huth /* check default/parsed value */
356da668aa1SThomas Huth value = qemu_opt_get(opts, "key");
357da668aa1SThomas Huth g_assert_cmpstr(value, ==, "value");
358da668aa1SThomas Huth
359da668aa1SThomas Huth /* reset it to value2 */
360da668aa1SThomas Huth qemu_opt_set(opts, "key", "value2", &error_abort);
361da668aa1SThomas Huth
362da668aa1SThomas Huth value = qemu_opt_get(opts, "key");
363da668aa1SThomas Huth g_assert_cmpstr(value, ==, "value2");
364da668aa1SThomas Huth
365da668aa1SThomas Huth /* unset, valid only for "accept any" */
366da668aa1SThomas Huth ret = qemu_opt_unset(opts, "key");
367da668aa1SThomas Huth g_assert(ret == 0);
368da668aa1SThomas Huth
369da668aa1SThomas Huth /* after reset the value should be the parsed/default one */
370da668aa1SThomas Huth value = qemu_opt_get(opts, "key");
371da668aa1SThomas Huth g_assert_cmpstr(value, ==, "value");
372da668aa1SThomas Huth
373da668aa1SThomas Huth qemu_opts_del(opts);
374da668aa1SThomas Huth }
375da668aa1SThomas Huth
test_qemu_opts_reset(void)376da668aa1SThomas Huth static void test_qemu_opts_reset(void)
377da668aa1SThomas Huth {
378da668aa1SThomas Huth QemuOptsList *list;
379da668aa1SThomas Huth QemuOpts *opts;
380da668aa1SThomas Huth uint64_t opt;
381da668aa1SThomas Huth
382da668aa1SThomas Huth list = qemu_find_opts("opts_list_01");
383da668aa1SThomas Huth g_assert(list != NULL);
384da668aa1SThomas Huth g_assert(QTAILQ_EMPTY(&list->head));
385da668aa1SThomas Huth g_assert_cmpstr(list->name, ==, "opts_list_01");
386da668aa1SThomas Huth
387da668aa1SThomas Huth /* should not find anything at this point */
388da668aa1SThomas Huth opts = qemu_opts_find(list, NULL);
389da668aa1SThomas Huth g_assert(opts == NULL);
390da668aa1SThomas Huth
391da668aa1SThomas Huth /* create the opts */
392da668aa1SThomas Huth opts = qemu_opts_create(list, NULL, 0, &error_abort);
393da668aa1SThomas Huth g_assert(opts != NULL);
394da668aa1SThomas Huth g_assert(!QTAILQ_EMPTY(&list->head));
395da668aa1SThomas Huth
396da668aa1SThomas Huth /* haven't set anything to number1 yet, so defval should be returned */
397da668aa1SThomas Huth opt = qemu_opt_get_number(opts, "number1", 5);
398da668aa1SThomas Huth g_assert(opt == 5);
399da668aa1SThomas Huth
400da668aa1SThomas Huth qemu_opt_set_number(opts, "number1", 10, &error_abort);
401da668aa1SThomas Huth
402da668aa1SThomas Huth /* now we have set number1, should know about it */
403da668aa1SThomas Huth opt = qemu_opt_get_number(opts, "number1", 5);
404da668aa1SThomas Huth g_assert(opt == 10);
405da668aa1SThomas Huth
406da668aa1SThomas Huth qemu_opts_reset(list);
407da668aa1SThomas Huth
408da668aa1SThomas Huth /* should not find anything at this point */
409da668aa1SThomas Huth opts = qemu_opts_find(list, NULL);
410da668aa1SThomas Huth g_assert(opts == NULL);
411da668aa1SThomas Huth }
412da668aa1SThomas Huth
opts_count_iter(void * opaque,const char * name,const char * value,Error ** errp)413da668aa1SThomas Huth static int opts_count_iter(void *opaque, const char *name, const char *value,
414da668aa1SThomas Huth Error **errp)
415da668aa1SThomas Huth {
416da668aa1SThomas Huth (*(size_t *)opaque)++;
417da668aa1SThomas Huth return 0;
418da668aa1SThomas Huth }
419da668aa1SThomas Huth
opts_count(QemuOpts * opts)420da668aa1SThomas Huth static size_t opts_count(QemuOpts *opts)
421da668aa1SThomas Huth {
422da668aa1SThomas Huth size_t n = 0;
423da668aa1SThomas Huth
424da668aa1SThomas Huth qemu_opt_foreach(opts, opts_count_iter, &n, NULL);
425da668aa1SThomas Huth return n;
426da668aa1SThomas Huth }
427da668aa1SThomas Huth
test_opts_parse(void)428da668aa1SThomas Huth static void test_opts_parse(void)
429da668aa1SThomas Huth {
430da668aa1SThomas Huth Error *err = NULL;
431da668aa1SThomas Huth QemuOpts *opts;
432da668aa1SThomas Huth
433da668aa1SThomas Huth /* Nothing */
434da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, "", false, &error_abort);
435da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 0);
436da668aa1SThomas Huth
437da668aa1SThomas Huth /* Empty key */
438da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, "=val", false, &error_abort);
439da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 1);
440da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val");
441da668aa1SThomas Huth
442da668aa1SThomas Huth /* Multiple keys, last one wins */
443da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, "a=1,b=2,,x,a=3",
444da668aa1SThomas Huth false, &error_abort);
445da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 3);
446da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "3");
447da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, "b"), ==, "2,x");
448da668aa1SThomas Huth
449da668aa1SThomas Huth /* Except when it doesn't */
450da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, "id=foo,id=bar",
451da668aa1SThomas Huth false, &error_abort);
452da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 0);
453da668aa1SThomas Huth g_assert_cmpstr(qemu_opts_id(opts), ==, "foo");
454da668aa1SThomas Huth
455da668aa1SThomas Huth /* TODO Cover low-level access to repeated keys */
456da668aa1SThomas Huth
457da668aa1SThomas Huth /* Trailing comma is ignored */
458da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, "x=y,", false, &error_abort);
459da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 1);
460da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, "y");
461da668aa1SThomas Huth
462da668aa1SThomas Huth /* Except when it isn't */
463da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, ",", false, &error_abort);
464da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 1);
465da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "on");
466da668aa1SThomas Huth
467da668aa1SThomas Huth /* Duplicate ID */
468da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, "x=y,id=foo", false, &err);
469da668aa1SThomas Huth error_free_or_abort(&err);
470da668aa1SThomas Huth g_assert(!opts);
471da668aa1SThomas Huth /* TODO Cover .merge_lists = true */
472da668aa1SThomas Huth
473da668aa1SThomas Huth /* Buggy ID recognition (fixed) */
474da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, "x=,,id=bar", false, &error_abort);
475da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 1);
476da668aa1SThomas Huth g_assert(!qemu_opts_id(opts));
477da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, ",id=bar");
478da668aa1SThomas Huth
479da668aa1SThomas Huth /* Anti-social ID */
480da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_01, "id=666", false, &err);
481da668aa1SThomas Huth error_free_or_abort(&err);
482da668aa1SThomas Huth g_assert(!opts);
483da668aa1SThomas Huth
484da668aa1SThomas Huth /* Implied value (qemu_opts_parse warns but accepts it) */
485da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=",
486da668aa1SThomas Huth false, &error_abort);
487da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 3);
488da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, "an"), ==, "on");
489da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off");
490da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, "");
491da668aa1SThomas Huth
492da668aa1SThomas Huth /* Implied value, negated empty key */
493da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, "no", false, &error_abort);
494da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 1);
495da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "off");
496da668aa1SThomas Huth
497da668aa1SThomas Huth /* Implied key */
498da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=", true,
499da668aa1SThomas Huth &error_abort);
500da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 3);
501da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, "an");
502da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off");
503da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, "");
504da668aa1SThomas Huth
505da668aa1SThomas Huth /* Implied key with empty value */
506da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, ",", true, &error_abort);
507da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 1);
508da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, "");
509da668aa1SThomas Huth
510da668aa1SThomas Huth /* Implied key with comma value */
511da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, ",,,a=1", true, &error_abort);
512da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 2);
513da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, ",");
514da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "1");
515da668aa1SThomas Huth
516da668aa1SThomas Huth /* Empty key is not an implied key */
517da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, "=val", true, &error_abort);
518da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 1);
519da668aa1SThomas Huth g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val");
520da668aa1SThomas Huth
521da668aa1SThomas Huth /* Unknown key */
522da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_01, "nonexistent=", false, &err);
523da668aa1SThomas Huth error_free_or_abort(&err);
524da668aa1SThomas Huth g_assert(!opts);
525da668aa1SThomas Huth
526da668aa1SThomas Huth qemu_opts_reset(&opts_list_01);
527da668aa1SThomas Huth qemu_opts_reset(&opts_list_03);
528da668aa1SThomas Huth }
529da668aa1SThomas Huth
test_opts_parse_bool(void)530da668aa1SThomas Huth static void test_opts_parse_bool(void)
531da668aa1SThomas Huth {
532da668aa1SThomas Huth Error *err = NULL;
533da668aa1SThomas Huth QemuOpts *opts;
534da668aa1SThomas Huth
535da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_02, "bool1=on,bool2=off",
536da668aa1SThomas Huth false, &error_abort);
537da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 2);
538da668aa1SThomas Huth g_assert(qemu_opt_get_bool(opts, "bool1", false));
539da668aa1SThomas Huth g_assert(!qemu_opt_get_bool(opts, "bool2", true));
540da668aa1SThomas Huth
541da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_02, "bool1=offer", false, &err);
542da668aa1SThomas Huth error_free_or_abort(&err);
543da668aa1SThomas Huth g_assert(!opts);
544da668aa1SThomas Huth
545da668aa1SThomas Huth qemu_opts_reset(&opts_list_02);
546da668aa1SThomas Huth }
547da668aa1SThomas Huth
test_opts_parse_number(void)548da668aa1SThomas Huth static void test_opts_parse_number(void)
549da668aa1SThomas Huth {
550da668aa1SThomas Huth Error *err = NULL;
551da668aa1SThomas Huth QemuOpts *opts;
552da668aa1SThomas Huth
553da668aa1SThomas Huth /* Lower limit zero */
554da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_01, "number1=0", false, &error_abort);
555da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 1);
556da668aa1SThomas Huth g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 0);
557da668aa1SThomas Huth
558da668aa1SThomas Huth /* Upper limit 2^64-1 */
559da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_01,
560da668aa1SThomas Huth "number1=18446744073709551615,number2=-1",
561da668aa1SThomas Huth false, &error_abort);
562da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 2);
563da668aa1SThomas Huth g_assert_cmphex(qemu_opt_get_number(opts, "number1", 1), ==, UINT64_MAX);
564da668aa1SThomas Huth g_assert_cmphex(qemu_opt_get_number(opts, "number2", 0), ==, UINT64_MAX);
565da668aa1SThomas Huth
566da668aa1SThomas Huth /* Above upper limit */
567da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_01, "number1=18446744073709551616",
568da668aa1SThomas Huth false, &err);
569da668aa1SThomas Huth error_free_or_abort(&err);
570da668aa1SThomas Huth g_assert(!opts);
571da668aa1SThomas Huth
572da668aa1SThomas Huth /* Below lower limit */
573da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_01, "number1=-18446744073709551616",
574da668aa1SThomas Huth false, &err);
575da668aa1SThomas Huth error_free_or_abort(&err);
576da668aa1SThomas Huth g_assert(!opts);
577da668aa1SThomas Huth
578da668aa1SThomas Huth /* Hex and octal */
579da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_01, "number1=0x2a,number2=052",
580da668aa1SThomas Huth false, &error_abort);
581da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 2);
582da668aa1SThomas Huth g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42);
583da668aa1SThomas Huth g_assert_cmpuint(qemu_opt_get_number(opts, "number2", 0), ==, 42);
584da668aa1SThomas Huth
585da668aa1SThomas Huth /* Invalid */
586da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_01, "number1=", false, &err);
587da668aa1SThomas Huth error_free_or_abort(&err);
588da668aa1SThomas Huth g_assert(!opts);
589da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_01, "number1=eins", false, &err);
590da668aa1SThomas Huth error_free_or_abort(&err);
591da668aa1SThomas Huth g_assert(!opts);
592da668aa1SThomas Huth
593da668aa1SThomas Huth /* Leading whitespace */
594da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_01, "number1= \t42",
595da668aa1SThomas Huth false, &error_abort);
596da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 1);
597da668aa1SThomas Huth g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42);
598da668aa1SThomas Huth
599da668aa1SThomas Huth /* Trailing crap */
600da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_01, "number1=3.14", false, &err);
601da668aa1SThomas Huth error_free_or_abort(&err);
602da668aa1SThomas Huth g_assert(!opts);
603da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_01, "number1=08", false, &err);
604da668aa1SThomas Huth error_free_or_abort(&err);
605da668aa1SThomas Huth g_assert(!opts);
606da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_01, "number1=0 ", false, &err);
607da668aa1SThomas Huth error_free_or_abort(&err);
608da668aa1SThomas Huth g_assert(!opts);
609da668aa1SThomas Huth
610da668aa1SThomas Huth qemu_opts_reset(&opts_list_01);
611da668aa1SThomas Huth }
612da668aa1SThomas Huth
test_opts_parse_size(void)613da668aa1SThomas Huth static void test_opts_parse_size(void)
614da668aa1SThomas Huth {
615da668aa1SThomas Huth Error *err = NULL;
616da668aa1SThomas Huth QemuOpts *opts;
617da668aa1SThomas Huth
618da668aa1SThomas Huth /* Lower limit zero */
619da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_02, "size1=0", false, &error_abort);
620da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 1);
621da668aa1SThomas Huth g_assert_cmpuint(qemu_opt_get_size(opts, "size1", 1), ==, 0);
622da668aa1SThomas Huth
623*757acb9aSPeter Maydell /* Note: full 64 bits of precision */
624da668aa1SThomas Huth
625*757acb9aSPeter Maydell /* Around double limit of precision: 2^53-1, 2^53, 2^53+1 */
626da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_02,
627da668aa1SThomas Huth "size1=9007199254740991,"
628da668aa1SThomas Huth "size2=9007199254740992,"
629da668aa1SThomas Huth "size3=9007199254740993",
630da668aa1SThomas Huth false, &error_abort);
631da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 3);
632da668aa1SThomas Huth g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1),
633da668aa1SThomas Huth ==, 0x1fffffffffffff);
634da668aa1SThomas Huth g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1),
635da668aa1SThomas Huth ==, 0x20000000000000);
636da668aa1SThomas Huth g_assert_cmphex(qemu_opt_get_size(opts, "size3", 1),
637*757acb9aSPeter Maydell ==, 0x20000000000001);
638da668aa1SThomas Huth
639*757acb9aSPeter Maydell /* Close to signed int limit: 2^63-1, 2^63, 2^63+1 */
640da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_02,
641*757acb9aSPeter Maydell "size1=9223372036854775807," /* 7fffffffffffffff */
642*757acb9aSPeter Maydell "size2=9223372036854775808," /* 8000000000000000 */
643*757acb9aSPeter Maydell "size3=9223372036854775809", /* 8000000000000001 */
644da668aa1SThomas Huth false, &error_abort);
645*757acb9aSPeter Maydell g_assert_cmpuint(opts_count(opts), ==, 3);
646da668aa1SThomas Huth g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1),
647*757acb9aSPeter Maydell ==, 0x7fffffffffffffff);
648da668aa1SThomas Huth g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1),
649*757acb9aSPeter Maydell ==, 0x8000000000000000);
650*757acb9aSPeter Maydell g_assert_cmphex(qemu_opt_get_size(opts, "size3", 1),
651*757acb9aSPeter Maydell ==, 0x8000000000000001);
652da668aa1SThomas Huth
653da668aa1SThomas Huth /* Close to actual upper limit 0xfffffffffffff800 (53 msbs set) */
654da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_02,
655da668aa1SThomas Huth "size1=18446744073709549568," /* fffffffffffff800 */
656da668aa1SThomas Huth "size2=18446744073709550591", /* fffffffffffffbff */
657da668aa1SThomas Huth false, &error_abort);
658da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 2);
659da668aa1SThomas Huth g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1),
660da668aa1SThomas Huth ==, 0xfffffffffffff800);
661da668aa1SThomas Huth g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1),
662*757acb9aSPeter Maydell ==, 0xfffffffffffffbff);
663*757acb9aSPeter Maydell
664*757acb9aSPeter Maydell /* Actual limit, 2^64-1 */
665*757acb9aSPeter Maydell opts = qemu_opts_parse(&opts_list_02,
666*757acb9aSPeter Maydell "size1=18446744073709551615", /* ffffffffffffffff */
667*757acb9aSPeter Maydell false, &error_abort);
668*757acb9aSPeter Maydell g_assert_cmpuint(opts_count(opts), ==, 1);
669*757acb9aSPeter Maydell g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1),
670*757acb9aSPeter Maydell ==, 0xffffffffffffffff);
671da668aa1SThomas Huth
672da668aa1SThomas Huth /* Beyond limits */
673da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_02, "size1=-1", false, &err);
674da668aa1SThomas Huth error_free_or_abort(&err);
675da668aa1SThomas Huth g_assert(!opts);
676da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_02,
677*757acb9aSPeter Maydell "size1=18446744073709551616", /* 2^64 */
678da668aa1SThomas Huth false, &err);
679da668aa1SThomas Huth error_free_or_abort(&err);
680da668aa1SThomas Huth g_assert(!opts);
681da668aa1SThomas Huth
682da668aa1SThomas Huth /* Suffixes */
683da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_02, "size1=8b,size2=1.5k,size3=2M",
684da668aa1SThomas Huth false, &error_abort);
685da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 3);
686da668aa1SThomas Huth g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, 8);
687da668aa1SThomas Huth g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), ==, 1536);
688da668aa1SThomas Huth g_assert_cmphex(qemu_opt_get_size(opts, "size3", 0), ==, 2 * MiB);
689da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_02, "size1=0.1G,size2=16777215T",
690da668aa1SThomas Huth false, &error_abort);
691da668aa1SThomas Huth g_assert_cmpuint(opts_count(opts), ==, 2);
692da668aa1SThomas Huth g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, GiB / 10);
693da668aa1SThomas Huth g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), ==, 16777215ULL * TiB);
694da668aa1SThomas Huth
695da668aa1SThomas Huth /* Beyond limit with suffix */
696da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_02, "size1=16777216T",
697da668aa1SThomas Huth false, &err);
698da668aa1SThomas Huth error_free_or_abort(&err);
699da668aa1SThomas Huth g_assert(!opts);
700da668aa1SThomas Huth
701da668aa1SThomas Huth /* Trailing crap */
702da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_02, "size1=16E", false, &err);
703da668aa1SThomas Huth error_free_or_abort(&err);
704da668aa1SThomas Huth g_assert(!opts);
705da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_02, "size1=16Gi", false, &err);
706da668aa1SThomas Huth error_free_or_abort(&err);
707da668aa1SThomas Huth g_assert(!opts);
708da668aa1SThomas Huth
709da668aa1SThomas Huth qemu_opts_reset(&opts_list_02);
710da668aa1SThomas Huth }
711da668aa1SThomas Huth
test_has_help_option(void)712da668aa1SThomas Huth static void test_has_help_option(void)
713da668aa1SThomas Huth {
714da668aa1SThomas Huth static const struct {
715da668aa1SThomas Huth const char *params;
716da668aa1SThomas Huth /* expected value of qemu_opt_has_help_opt() with implied=false */
717da668aa1SThomas Huth bool expect;
718da668aa1SThomas Huth /* expected value of qemu_opt_has_help_opt() with implied=true */
719da668aa1SThomas Huth bool expect_implied;
720da668aa1SThomas Huth } test[] = {
721da668aa1SThomas Huth { "help", true, false },
722da668aa1SThomas Huth { "?", true, false },
723da668aa1SThomas Huth { "helpme", false, false },
724da668aa1SThomas Huth { "?me", false, false },
725da668aa1SThomas Huth { "a,help", true, true },
726da668aa1SThomas Huth { "a,?", true, true },
727da668aa1SThomas Huth { "a=0,help,b", true, true },
728da668aa1SThomas Huth { "a=0,?,b", true, true },
729da668aa1SThomas Huth { "help,b=1", true, false },
730da668aa1SThomas Huth { "?,b=1", true, false },
731da668aa1SThomas Huth { "a,b,,help", true, true },
732da668aa1SThomas Huth { "a,b,,?", true, true },
733da668aa1SThomas Huth };
734da668aa1SThomas Huth int i;
735da668aa1SThomas Huth QemuOpts *opts;
736da668aa1SThomas Huth
737da668aa1SThomas Huth for (i = 0; i < ARRAY_SIZE(test); i++) {
738da668aa1SThomas Huth g_assert_cmpint(has_help_option(test[i].params),
739da668aa1SThomas Huth ==, test[i].expect);
740da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, test[i].params, false,
741da668aa1SThomas Huth &error_abort);
742da668aa1SThomas Huth g_assert_cmpint(qemu_opt_has_help_opt(opts),
743da668aa1SThomas Huth ==, test[i].expect);
744da668aa1SThomas Huth qemu_opts_del(opts);
745da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, test[i].params, true,
746da668aa1SThomas Huth &error_abort);
747da668aa1SThomas Huth g_assert_cmpint(qemu_opt_has_help_opt(opts),
748da668aa1SThomas Huth ==, test[i].expect_implied);
749da668aa1SThomas Huth qemu_opts_del(opts);
750da668aa1SThomas Huth }
751da668aa1SThomas Huth }
752da668aa1SThomas Huth
append_verify_list_01(QemuOptDesc * desc,bool with_overlapping)753da668aa1SThomas Huth static void append_verify_list_01(QemuOptDesc *desc, bool with_overlapping)
754da668aa1SThomas Huth {
755da668aa1SThomas Huth int i = 0;
756da668aa1SThomas Huth
757da668aa1SThomas Huth if (with_overlapping) {
758da668aa1SThomas Huth g_assert_cmpstr(desc[i].name, ==, "str1");
759da668aa1SThomas Huth g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
760da668aa1SThomas Huth g_assert_cmpstr(desc[i].help, ==,
761da668aa1SThomas Huth "Help texts are preserved in qemu_opts_append");
762da668aa1SThomas Huth g_assert_cmpstr(desc[i].def_value_str, ==, "default");
763da668aa1SThomas Huth i++;
764da668aa1SThomas Huth
765da668aa1SThomas Huth g_assert_cmpstr(desc[i].name, ==, "str2");
766da668aa1SThomas Huth g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
767da668aa1SThomas Huth g_assert_cmpstr(desc[i].help, ==, NULL);
768da668aa1SThomas Huth g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
769da668aa1SThomas Huth i++;
770da668aa1SThomas Huth }
771da668aa1SThomas Huth
772da668aa1SThomas Huth g_assert_cmpstr(desc[i].name, ==, "str3");
773da668aa1SThomas Huth g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
774da668aa1SThomas Huth g_assert_cmpstr(desc[i].help, ==, NULL);
775da668aa1SThomas Huth g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
776da668aa1SThomas Huth i++;
777da668aa1SThomas Huth
778da668aa1SThomas Huth g_assert_cmpstr(desc[i].name, ==, "number1");
779da668aa1SThomas Huth g_assert_cmpint(desc[i].type, ==, QEMU_OPT_NUMBER);
780da668aa1SThomas Huth g_assert_cmpstr(desc[i].help, ==,
781da668aa1SThomas Huth "Having help texts only for some options is okay");
782da668aa1SThomas Huth g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
783da668aa1SThomas Huth i++;
784da668aa1SThomas Huth
785da668aa1SThomas Huth g_assert_cmpstr(desc[i].name, ==, "number2");
786da668aa1SThomas Huth g_assert_cmpint(desc[i].type, ==, QEMU_OPT_NUMBER);
787da668aa1SThomas Huth g_assert_cmpstr(desc[i].help, ==, NULL);
788da668aa1SThomas Huth g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
789da668aa1SThomas Huth i++;
790da668aa1SThomas Huth
791da668aa1SThomas Huth g_assert_cmpstr(desc[i].name, ==, NULL);
792da668aa1SThomas Huth }
793da668aa1SThomas Huth
append_verify_list_02(QemuOptDesc * desc)794da668aa1SThomas Huth static void append_verify_list_02(QemuOptDesc *desc)
795da668aa1SThomas Huth {
796da668aa1SThomas Huth int i = 0;
797da668aa1SThomas Huth
798da668aa1SThomas Huth g_assert_cmpstr(desc[i].name, ==, "str1");
799da668aa1SThomas Huth g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
800da668aa1SThomas Huth g_assert_cmpstr(desc[i].help, ==, NULL);
801da668aa1SThomas Huth g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
802da668aa1SThomas Huth i++;
803da668aa1SThomas Huth
804da668aa1SThomas Huth g_assert_cmpstr(desc[i].name, ==, "str2");
805da668aa1SThomas Huth g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
806da668aa1SThomas Huth g_assert_cmpstr(desc[i].help, ==, NULL);
807da668aa1SThomas Huth g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
808da668aa1SThomas Huth i++;
809da668aa1SThomas Huth
810da668aa1SThomas Huth g_assert_cmpstr(desc[i].name, ==, "bool1");
811da668aa1SThomas Huth g_assert_cmpint(desc[i].type, ==, QEMU_OPT_BOOL);
812da668aa1SThomas Huth g_assert_cmpstr(desc[i].help, ==, NULL);
813da668aa1SThomas Huth g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
814da668aa1SThomas Huth i++;
815da668aa1SThomas Huth
816da668aa1SThomas Huth g_assert_cmpstr(desc[i].name, ==, "bool2");
817da668aa1SThomas Huth g_assert_cmpint(desc[i].type, ==, QEMU_OPT_BOOL);
818da668aa1SThomas Huth g_assert_cmpstr(desc[i].help, ==, NULL);
819da668aa1SThomas Huth g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
820da668aa1SThomas Huth i++;
821da668aa1SThomas Huth
822da668aa1SThomas Huth g_assert_cmpstr(desc[i].name, ==, "size1");
823da668aa1SThomas Huth g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE);
824da668aa1SThomas Huth g_assert_cmpstr(desc[i].help, ==, NULL);
825da668aa1SThomas Huth g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
826da668aa1SThomas Huth i++;
827da668aa1SThomas Huth
828da668aa1SThomas Huth g_assert_cmpstr(desc[i].name, ==, "size2");
829da668aa1SThomas Huth g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE);
830da668aa1SThomas Huth g_assert_cmpstr(desc[i].help, ==, NULL);
831da668aa1SThomas Huth g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
832da668aa1SThomas Huth i++;
833da668aa1SThomas Huth
834da668aa1SThomas Huth g_assert_cmpstr(desc[i].name, ==, "size3");
835da668aa1SThomas Huth g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE);
836da668aa1SThomas Huth g_assert_cmpstr(desc[i].help, ==, NULL);
837da668aa1SThomas Huth g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
838da668aa1SThomas Huth }
839da668aa1SThomas Huth
test_opts_append_to_null(void)840da668aa1SThomas Huth static void test_opts_append_to_null(void)
841da668aa1SThomas Huth {
842da668aa1SThomas Huth QemuOptsList *merged;
843da668aa1SThomas Huth
844da668aa1SThomas Huth merged = qemu_opts_append(NULL, &opts_list_01);
845da668aa1SThomas Huth g_assert(merged != &opts_list_01);
846da668aa1SThomas Huth
847da668aa1SThomas Huth g_assert_cmpstr(merged->name, ==, NULL);
848da668aa1SThomas Huth g_assert_cmpstr(merged->implied_opt_name, ==, NULL);
849da668aa1SThomas Huth g_assert_false(merged->merge_lists);
850da668aa1SThomas Huth
851da668aa1SThomas Huth append_verify_list_01(merged->desc, true);
852da668aa1SThomas Huth
853da668aa1SThomas Huth qemu_opts_free(merged);
854da668aa1SThomas Huth }
855da668aa1SThomas Huth
test_opts_append(void)856da668aa1SThomas Huth static void test_opts_append(void)
857da668aa1SThomas Huth {
858da668aa1SThomas Huth QemuOptsList *first, *merged;
859da668aa1SThomas Huth
860da668aa1SThomas Huth first = qemu_opts_append(NULL, &opts_list_02);
861da668aa1SThomas Huth merged = qemu_opts_append(first, &opts_list_01);
862da668aa1SThomas Huth g_assert(first != &opts_list_02);
863da668aa1SThomas Huth g_assert(merged != &opts_list_01);
864da668aa1SThomas Huth
865da668aa1SThomas Huth g_assert_cmpstr(merged->name, ==, NULL);
866da668aa1SThomas Huth g_assert_cmpstr(merged->implied_opt_name, ==, NULL);
867da668aa1SThomas Huth g_assert_false(merged->merge_lists);
868da668aa1SThomas Huth
869da668aa1SThomas Huth append_verify_list_02(&merged->desc[0]);
870da668aa1SThomas Huth append_verify_list_01(&merged->desc[7], false);
871da668aa1SThomas Huth
872da668aa1SThomas Huth qemu_opts_free(merged);
873da668aa1SThomas Huth }
874da668aa1SThomas Huth
test_opts_to_qdict_basic(void)875da668aa1SThomas Huth static void test_opts_to_qdict_basic(void)
876da668aa1SThomas Huth {
877da668aa1SThomas Huth QemuOpts *opts;
878da668aa1SThomas Huth QDict *dict;
879da668aa1SThomas Huth
880da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_01, "str1=foo,str2=,str3=bar,number1=42",
881da668aa1SThomas Huth false, &error_abort);
882da668aa1SThomas Huth g_assert(opts != NULL);
883da668aa1SThomas Huth
884da668aa1SThomas Huth dict = qemu_opts_to_qdict(opts, NULL);
885da668aa1SThomas Huth g_assert(dict != NULL);
886da668aa1SThomas Huth
887da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
888da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
889da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar");
890da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42");
891da668aa1SThomas Huth g_assert_false(qdict_haskey(dict, "number2"));
892da668aa1SThomas Huth
893da668aa1SThomas Huth qobject_unref(dict);
894da668aa1SThomas Huth qemu_opts_del(opts);
895da668aa1SThomas Huth }
896da668aa1SThomas Huth
test_opts_to_qdict_filtered(void)897da668aa1SThomas Huth static void test_opts_to_qdict_filtered(void)
898da668aa1SThomas Huth {
899da668aa1SThomas Huth QemuOptsList *first, *merged;
900da668aa1SThomas Huth QemuOpts *opts;
901da668aa1SThomas Huth QDict *dict;
902da668aa1SThomas Huth
903da668aa1SThomas Huth first = qemu_opts_append(NULL, &opts_list_02);
904da668aa1SThomas Huth merged = qemu_opts_append(first, &opts_list_01);
905da668aa1SThomas Huth
906da668aa1SThomas Huth opts = qemu_opts_parse(merged,
907da668aa1SThomas Huth "str1=foo,str2=,str3=bar,bool1=off,number1=42",
908da668aa1SThomas Huth false, &error_abort);
909da668aa1SThomas Huth g_assert(opts != NULL);
910da668aa1SThomas Huth
911da668aa1SThomas Huth /* Convert to QDict without deleting from opts */
912da668aa1SThomas Huth dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_01, false);
913da668aa1SThomas Huth g_assert(dict != NULL);
914da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
915da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
916da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar");
917da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42");
918da668aa1SThomas Huth g_assert_false(qdict_haskey(dict, "number2"));
919da668aa1SThomas Huth g_assert_false(qdict_haskey(dict, "bool1"));
920da668aa1SThomas Huth qobject_unref(dict);
921da668aa1SThomas Huth
922da668aa1SThomas Huth dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_02, false);
923da668aa1SThomas Huth g_assert(dict != NULL);
924da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
925da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
926da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "bool1"), ==, "off");
927da668aa1SThomas Huth g_assert_false(qdict_haskey(dict, "str3"));
928da668aa1SThomas Huth g_assert_false(qdict_haskey(dict, "number1"));
929da668aa1SThomas Huth g_assert_false(qdict_haskey(dict, "number2"));
930da668aa1SThomas Huth qobject_unref(dict);
931da668aa1SThomas Huth
932da668aa1SThomas Huth /* Now delete converted options from opts */
933da668aa1SThomas Huth dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_01, true);
934da668aa1SThomas Huth g_assert(dict != NULL);
935da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
936da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
937da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar");
938da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42");
939da668aa1SThomas Huth g_assert_false(qdict_haskey(dict, "number2"));
940da668aa1SThomas Huth g_assert_false(qdict_haskey(dict, "bool1"));
941da668aa1SThomas Huth qobject_unref(dict);
942da668aa1SThomas Huth
943da668aa1SThomas Huth dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_02, true);
944da668aa1SThomas Huth g_assert(dict != NULL);
945da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "bool1"), ==, "off");
946da668aa1SThomas Huth g_assert_false(qdict_haskey(dict, "str1"));
947da668aa1SThomas Huth g_assert_false(qdict_haskey(dict, "str2"));
948da668aa1SThomas Huth g_assert_false(qdict_haskey(dict, "str3"));
949da668aa1SThomas Huth g_assert_false(qdict_haskey(dict, "number1"));
950da668aa1SThomas Huth g_assert_false(qdict_haskey(dict, "number2"));
951da668aa1SThomas Huth qobject_unref(dict);
952da668aa1SThomas Huth
953da668aa1SThomas Huth g_assert_true(QTAILQ_EMPTY(&opts->head));
954da668aa1SThomas Huth
955da668aa1SThomas Huth qemu_opts_del(opts);
956da668aa1SThomas Huth qemu_opts_free(merged);
957da668aa1SThomas Huth }
958da668aa1SThomas Huth
test_opts_to_qdict_duplicates(void)959da668aa1SThomas Huth static void test_opts_to_qdict_duplicates(void)
960da668aa1SThomas Huth {
961da668aa1SThomas Huth QemuOpts *opts;
962da668aa1SThomas Huth QemuOpt *opt;
963da668aa1SThomas Huth QDict *dict;
964da668aa1SThomas Huth
965da668aa1SThomas Huth opts = qemu_opts_parse(&opts_list_03, "foo=a,foo=b", false, &error_abort);
966da668aa1SThomas Huth g_assert(opts != NULL);
967da668aa1SThomas Huth
968da668aa1SThomas Huth /* Verify that opts has two options with the same name */
969da668aa1SThomas Huth opt = QTAILQ_FIRST(&opts->head);
970da668aa1SThomas Huth g_assert_cmpstr(opt->name, ==, "foo");
971da668aa1SThomas Huth g_assert_cmpstr(opt->str , ==, "a");
972da668aa1SThomas Huth
973da668aa1SThomas Huth opt = QTAILQ_NEXT(opt, next);
974da668aa1SThomas Huth g_assert_cmpstr(opt->name, ==, "foo");
975da668aa1SThomas Huth g_assert_cmpstr(opt->str , ==, "b");
976da668aa1SThomas Huth
977da668aa1SThomas Huth opt = QTAILQ_NEXT(opt, next);
978da668aa1SThomas Huth g_assert(opt == NULL);
979da668aa1SThomas Huth
980da668aa1SThomas Huth /* In the conversion to QDict, the last one wins */
981da668aa1SThomas Huth dict = qemu_opts_to_qdict(opts, NULL);
982da668aa1SThomas Huth g_assert(dict != NULL);
983da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "b");
984da668aa1SThomas Huth qobject_unref(dict);
985da668aa1SThomas Huth
986da668aa1SThomas Huth /* The last one still wins if entries are deleted, and both are deleted */
987da668aa1SThomas Huth dict = qemu_opts_to_qdict_filtered(opts, NULL, NULL, true);
988da668aa1SThomas Huth g_assert(dict != NULL);
989da668aa1SThomas Huth g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "b");
990da668aa1SThomas Huth qobject_unref(dict);
991da668aa1SThomas Huth
992da668aa1SThomas Huth g_assert_true(QTAILQ_EMPTY(&opts->head));
993da668aa1SThomas Huth
994da668aa1SThomas Huth qemu_opts_del(opts);
995da668aa1SThomas Huth }
996da668aa1SThomas Huth
main(int argc,char * argv[])997da668aa1SThomas Huth int main(int argc, char *argv[])
998da668aa1SThomas Huth {
999da668aa1SThomas Huth register_opts();
1000da668aa1SThomas Huth g_test_init(&argc, &argv, NULL);
1001da668aa1SThomas Huth g_test_add_func("/qemu-opts/find_unknown_opts", test_find_unknown_opts);
1002da668aa1SThomas Huth g_test_add_func("/qemu-opts/find_opts", test_qemu_find_opts);
1003da668aa1SThomas Huth g_test_add_func("/qemu-opts/opts_create", test_qemu_opts_create);
1004da668aa1SThomas Huth g_test_add_func("/qemu-opts/opt_get", test_qemu_opt_get);
1005da668aa1SThomas Huth g_test_add_func("/qemu-opts/opt_get_bool", test_qemu_opt_get_bool);
1006da668aa1SThomas Huth g_test_add_func("/qemu-opts/opt_get_number", test_qemu_opt_get_number);
1007da668aa1SThomas Huth g_test_add_func("/qemu-opts/opt_get_size", test_qemu_opt_get_size);
1008da668aa1SThomas Huth g_test_add_func("/qemu-opts/opt_unset", test_qemu_opt_unset);
1009da668aa1SThomas Huth g_test_add_func("/qemu-opts/opts_reset", test_qemu_opts_reset);
1010da668aa1SThomas Huth g_test_add_func("/qemu-opts/opts_parse/general", test_opts_parse);
1011da668aa1SThomas Huth g_test_add_func("/qemu-opts/opts_parse/bool", test_opts_parse_bool);
1012da668aa1SThomas Huth g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number);
1013da668aa1SThomas Huth g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size);
1014da668aa1SThomas Huth g_test_add_func("/qemu-opts/has_help_option", test_has_help_option);
1015da668aa1SThomas Huth g_test_add_func("/qemu-opts/append_to_null", test_opts_append_to_null);
1016da668aa1SThomas Huth g_test_add_func("/qemu-opts/append", test_opts_append);
1017da668aa1SThomas Huth g_test_add_func("/qemu-opts/to_qdict/basic", test_opts_to_qdict_basic);
1018da668aa1SThomas Huth g_test_add_func("/qemu-opts/to_qdict/filtered", test_opts_to_qdict_filtered);
1019da668aa1SThomas Huth g_test_add_func("/qemu-opts/to_qdict/duplicates", test_opts_to_qdict_duplicates);
1020da668aa1SThomas Huth g_test_run();
1021da668aa1SThomas Huth return 0;
1022da668aa1SThomas Huth }
1023