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