]>
Commit | Line | Data |
---|---|---|
4ba6fabf LD |
1 | /* |
2 | * QemuOpts unit-tests. | |
3 | * | |
4 | * Copyright (C) 2014 Leandro Dorileo <[email protected]> | |
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 | ||
681c28a3 | 10 | #include "qemu/osdep.h" |
694baf57 | 11 | #include "qemu/cutils.h" |
da34e65c | 12 | #include "qapi/error.h" |
4ba6fabf LD |
13 | #include "qapi/qmp/qstring.h" |
14 | #include "qemu/config-file.h" | |
15 | ||
4ba6fabf LD |
16 | |
17 | static QemuOptsList opts_list_01 = { | |
18 | .name = "opts_list_01", | |
19 | .head = QTAILQ_HEAD_INITIALIZER(opts_list_01.head), | |
20 | .desc = { | |
21 | { | |
22 | .name = "str1", | |
23 | .type = QEMU_OPT_STRING, | |
24 | },{ | |
25 | .name = "str2", | |
26 | .type = QEMU_OPT_STRING, | |
27 | },{ | |
28 | .name = "str3", | |
29 | .type = QEMU_OPT_STRING, | |
30 | },{ | |
31 | .name = "number1", | |
32 | .type = QEMU_OPT_NUMBER, | |
694baf57 MA |
33 | },{ |
34 | .name = "number2", | |
35 | .type = QEMU_OPT_NUMBER, | |
4ba6fabf LD |
36 | }, |
37 | { /* end of list */ } | |
38 | }, | |
39 | }; | |
40 | ||
41 | static QemuOptsList opts_list_02 = { | |
42 | .name = "opts_list_02", | |
43 | .head = QTAILQ_HEAD_INITIALIZER(opts_list_02.head), | |
44 | .desc = { | |
45 | { | |
46 | .name = "str1", | |
47 | .type = QEMU_OPT_STRING, | |
694baf57 MA |
48 | },{ |
49 | .name = "str2", | |
50 | .type = QEMU_OPT_STRING, | |
4ba6fabf LD |
51 | },{ |
52 | .name = "bool1", | |
53 | .type = QEMU_OPT_BOOL, | |
54 | },{ | |
694baf57 MA |
55 | .name = "bool2", |
56 | .type = QEMU_OPT_BOOL, | |
4ba6fabf LD |
57 | },{ |
58 | .name = "size1", | |
59 | .type = QEMU_OPT_SIZE, | |
694baf57 MA |
60 | },{ |
61 | .name = "size2", | |
62 | .type = QEMU_OPT_SIZE, | |
63 | },{ | |
64 | .name = "size3", | |
65 | .type = QEMU_OPT_SIZE, | |
4ba6fabf LD |
66 | }, |
67 | { /* end of list */ } | |
68 | }, | |
69 | }; | |
70 | ||
748bfb4e | 71 | static QemuOptsList opts_list_03 = { |
4ba6fabf | 72 | .name = "opts_list_03", |
694baf57 | 73 | .implied_opt_name = "implied", |
4ba6fabf LD |
74 | .head = QTAILQ_HEAD_INITIALIZER(opts_list_03.head), |
75 | .desc = { | |
76 | /* no elements => accept any params */ | |
77 | { /* end of list */ } | |
78 | }, | |
79 | }; | |
80 | ||
81 | static void register_opts(void) | |
82 | { | |
83 | qemu_add_opts(&opts_list_01); | |
84 | qemu_add_opts(&opts_list_02); | |
85 | qemu_add_opts(&opts_list_03); | |
86 | } | |
87 | ||
88 | static void test_find_unknown_opts(void) | |
89 | { | |
90 | QemuOptsList *list; | |
91 | Error *err = NULL; | |
92 | ||
93 | /* should not return anything, we don't have an "unknown" option */ | |
94 | list = qemu_find_opts_err("unknown", &err); | |
95 | g_assert(list == NULL); | |
157db293 | 96 | error_free_or_abort(&err); |
4ba6fabf LD |
97 | } |
98 | ||
99 | static void test_qemu_find_opts(void) | |
100 | { | |
101 | QemuOptsList *list; | |
102 | ||
103 | /* we have an "opts_list_01" option, should return it */ | |
104 | list = qemu_find_opts("opts_list_01"); | |
105 | g_assert(list != NULL); | |
106 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
107 | } | |
108 | ||
109 | static void test_qemu_opts_create(void) | |
110 | { | |
111 | QemuOptsList *list; | |
112 | QemuOpts *opts; | |
113 | ||
114 | list = qemu_find_opts("opts_list_01"); | |
115 | g_assert(list != NULL); | |
116 | g_assert(QTAILQ_EMPTY(&list->head)); | |
117 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
118 | ||
119 | /* should not find anything at this point */ | |
120 | opts = qemu_opts_find(list, NULL); | |
121 | g_assert(opts == NULL); | |
122 | ||
123 | /* create the opts */ | |
124 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
125 | g_assert(opts != NULL); | |
126 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
127 | ||
128 | /* now we've create the opts, must find it */ | |
129 | opts = qemu_opts_find(list, NULL); | |
130 | g_assert(opts != NULL); | |
131 | ||
132 | qemu_opts_del(opts); | |
133 | ||
134 | /* should not find anything at this point */ | |
135 | opts = qemu_opts_find(list, NULL); | |
136 | g_assert(opts == NULL); | |
137 | } | |
138 | ||
139 | static void test_qemu_opt_get(void) | |
140 | { | |
141 | QemuOptsList *list; | |
142 | QemuOpts *opts; | |
143 | const char *opt = NULL; | |
144 | ||
145 | list = qemu_find_opts("opts_list_01"); | |
146 | g_assert(list != NULL); | |
147 | g_assert(QTAILQ_EMPTY(&list->head)); | |
148 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
149 | ||
150 | /* should not find anything at this point */ | |
151 | opts = qemu_opts_find(list, NULL); | |
152 | g_assert(opts == NULL); | |
153 | ||
154 | /* create the opts */ | |
155 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
156 | g_assert(opts != NULL); | |
157 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
158 | ||
159 | /* haven't set anything to str2 yet */ | |
160 | opt = qemu_opt_get(opts, "str2"); | |
161 | g_assert(opt == NULL); | |
162 | ||
f43e47db | 163 | qemu_opt_set(opts, "str2", "value", &error_abort); |
4ba6fabf LD |
164 | |
165 | /* now we have set str2, should know about it */ | |
166 | opt = qemu_opt_get(opts, "str2"); | |
167 | g_assert_cmpstr(opt, ==, "value"); | |
168 | ||
f43e47db | 169 | qemu_opt_set(opts, "str2", "value2", &error_abort); |
4ba6fabf LD |
170 | |
171 | /* having reset the value, the returned should be the reset one */ | |
172 | opt = qemu_opt_get(opts, "str2"); | |
173 | g_assert_cmpstr(opt, ==, "value2"); | |
174 | ||
175 | qemu_opts_del(opts); | |
176 | ||
177 | /* should not find anything at this point */ | |
178 | opts = qemu_opts_find(list, NULL); | |
179 | g_assert(opts == NULL); | |
180 | } | |
181 | ||
182 | static void test_qemu_opt_get_bool(void) | |
183 | { | |
cccb7967 | 184 | Error *err = NULL; |
4ba6fabf LD |
185 | QemuOptsList *list; |
186 | QemuOpts *opts; | |
187 | bool opt; | |
4ba6fabf LD |
188 | |
189 | list = qemu_find_opts("opts_list_02"); | |
190 | g_assert(list != NULL); | |
191 | g_assert(QTAILQ_EMPTY(&list->head)); | |
192 | g_assert_cmpstr(list->name, ==, "opts_list_02"); | |
193 | ||
194 | /* should not find anything at this point */ | |
195 | opts = qemu_opts_find(list, NULL); | |
196 | g_assert(opts == NULL); | |
197 | ||
198 | /* create the opts */ | |
199 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
200 | g_assert(opts != NULL); | |
201 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
202 | ||
203 | /* haven't set anything to bool1 yet, so defval should be returned */ | |
204 | opt = qemu_opt_get_bool(opts, "bool1", false); | |
205 | g_assert(opt == false); | |
206 | ||
cccb7967 MA |
207 | qemu_opt_set_bool(opts, "bool1", true, &err); |
208 | g_assert(!err); | |
4ba6fabf LD |
209 | |
210 | /* now we have set bool1, should know about it */ | |
211 | opt = qemu_opt_get_bool(opts, "bool1", false); | |
212 | g_assert(opt == true); | |
213 | ||
214 | /* having reset the value, opt should be the reset one not defval */ | |
cccb7967 MA |
215 | qemu_opt_set_bool(opts, "bool1", false, &err); |
216 | g_assert(!err); | |
4ba6fabf LD |
217 | |
218 | opt = qemu_opt_get_bool(opts, "bool1", true); | |
219 | g_assert(opt == false); | |
220 | ||
221 | qemu_opts_del(opts); | |
222 | ||
223 | /* should not find anything at this point */ | |
224 | opts = qemu_opts_find(list, NULL); | |
225 | g_assert(opts == NULL); | |
226 | } | |
227 | ||
228 | static void test_qemu_opt_get_number(void) | |
229 | { | |
39101f25 | 230 | Error *err = NULL; |
4ba6fabf LD |
231 | QemuOptsList *list; |
232 | QemuOpts *opts; | |
233 | uint64_t opt; | |
4ba6fabf LD |
234 | |
235 | list = qemu_find_opts("opts_list_01"); | |
236 | g_assert(list != NULL); | |
237 | g_assert(QTAILQ_EMPTY(&list->head)); | |
238 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
239 | ||
240 | /* should not find anything at this point */ | |
241 | opts = qemu_opts_find(list, NULL); | |
242 | g_assert(opts == NULL); | |
243 | ||
244 | /* create the opts */ | |
245 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
246 | g_assert(opts != NULL); | |
247 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
248 | ||
249 | /* haven't set anything to number1 yet, so defval should be returned */ | |
250 | opt = qemu_opt_get_number(opts, "number1", 5); | |
251 | g_assert(opt == 5); | |
252 | ||
39101f25 MA |
253 | qemu_opt_set_number(opts, "number1", 10, &err); |
254 | g_assert(!err); | |
4ba6fabf LD |
255 | |
256 | /* now we have set number1, should know about it */ | |
257 | opt = qemu_opt_get_number(opts, "number1", 5); | |
258 | g_assert(opt == 10); | |
259 | ||
260 | /* having reset it, the returned should be the reset one not defval */ | |
39101f25 MA |
261 | qemu_opt_set_number(opts, "number1", 15, &err); |
262 | g_assert(!err); | |
4ba6fabf LD |
263 | |
264 | opt = qemu_opt_get_number(opts, "number1", 5); | |
265 | g_assert(opt == 15); | |
266 | ||
267 | qemu_opts_del(opts); | |
268 | ||
269 | /* should not find anything at this point */ | |
270 | opts = qemu_opts_find(list, NULL); | |
271 | g_assert(opts == NULL); | |
272 | } | |
273 | ||
274 | static void test_qemu_opt_get_size(void) | |
275 | { | |
276 | QemuOptsList *list; | |
277 | QemuOpts *opts; | |
278 | uint64_t opt; | |
279 | QDict *dict; | |
280 | ||
281 | list = qemu_find_opts("opts_list_02"); | |
282 | g_assert(list != NULL); | |
283 | g_assert(QTAILQ_EMPTY(&list->head)); | |
284 | g_assert_cmpstr(list->name, ==, "opts_list_02"); | |
285 | ||
286 | /* should not find anything at this point */ | |
287 | opts = qemu_opts_find(list, NULL); | |
288 | g_assert(opts == NULL); | |
289 | ||
290 | /* create the opts */ | |
291 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
292 | g_assert(opts != NULL); | |
293 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
294 | ||
295 | /* haven't set anything to size1 yet, so defval should be returned */ | |
296 | opt = qemu_opt_get_size(opts, "size1", 5); | |
297 | g_assert(opt == 5); | |
298 | ||
299 | dict = qdict_new(); | |
300 | g_assert(dict != NULL); | |
301 | ||
46f5ac20 | 302 | qdict_put_str(dict, "size1", "10"); |
4ba6fabf LD |
303 | |
304 | qemu_opts_absorb_qdict(opts, dict, &error_abort); | |
305 | g_assert(error_abort == NULL); | |
306 | ||
307 | /* now we have set size1, should know about it */ | |
308 | opt = qemu_opt_get_size(opts, "size1", 5); | |
309 | g_assert(opt == 10); | |
310 | ||
311 | /* reset value */ | |
46f5ac20 | 312 | qdict_put_str(dict, "size1", "15"); |
4ba6fabf LD |
313 | |
314 | qemu_opts_absorb_qdict(opts, dict, &error_abort); | |
315 | g_assert(error_abort == NULL); | |
316 | ||
317 | /* test the reset value */ | |
318 | opt = qemu_opt_get_size(opts, "size1", 5); | |
319 | g_assert(opt == 15); | |
320 | ||
321 | qdict_del(dict, "size1"); | |
322 | g_free(dict); | |
323 | ||
324 | qemu_opts_del(opts); | |
325 | ||
326 | /* should not find anything at this point */ | |
327 | opts = qemu_opts_find(list, NULL); | |
328 | g_assert(opts == NULL); | |
329 | } | |
330 | ||
331 | static void test_qemu_opt_unset(void) | |
332 | { | |
333 | QemuOpts *opts; | |
334 | const char *value; | |
335 | int ret; | |
336 | ||
337 | /* dynamically initialized (parsed) opts */ | |
70b94331 | 338 | opts = qemu_opts_parse(&opts_list_03, "key=value", false, NULL); |
4ba6fabf LD |
339 | g_assert(opts != NULL); |
340 | ||
341 | /* check default/parsed value */ | |
342 | value = qemu_opt_get(opts, "key"); | |
343 | g_assert_cmpstr(value, ==, "value"); | |
344 | ||
345 | /* reset it to value2 */ | |
f43e47db | 346 | qemu_opt_set(opts, "key", "value2", &error_abort); |
4ba6fabf LD |
347 | |
348 | value = qemu_opt_get(opts, "key"); | |
349 | g_assert_cmpstr(value, ==, "value2"); | |
350 | ||
351 | /* unset, valid only for "accept any" */ | |
352 | ret = qemu_opt_unset(opts, "key"); | |
353 | g_assert(ret == 0); | |
354 | ||
355 | /* after reset the value should be the parsed/default one */ | |
356 | value = qemu_opt_get(opts, "key"); | |
357 | g_assert_cmpstr(value, ==, "value"); | |
358 | ||
359 | qemu_opts_del(opts); | |
360 | } | |
361 | ||
362 | static void test_qemu_opts_reset(void) | |
363 | { | |
39101f25 | 364 | Error *err = NULL; |
4ba6fabf LD |
365 | QemuOptsList *list; |
366 | QemuOpts *opts; | |
367 | uint64_t opt; | |
4ba6fabf LD |
368 | |
369 | list = qemu_find_opts("opts_list_01"); | |
370 | g_assert(list != NULL); | |
371 | g_assert(QTAILQ_EMPTY(&list->head)); | |
372 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
373 | ||
374 | /* should not find anything at this point */ | |
375 | opts = qemu_opts_find(list, NULL); | |
376 | g_assert(opts == NULL); | |
377 | ||
378 | /* create the opts */ | |
379 | opts = qemu_opts_create(list, NULL, 0, &error_abort); | |
380 | g_assert(opts != NULL); | |
381 | g_assert(!QTAILQ_EMPTY(&list->head)); | |
382 | ||
383 | /* haven't set anything to number1 yet, so defval should be returned */ | |
384 | opt = qemu_opt_get_number(opts, "number1", 5); | |
385 | g_assert(opt == 5); | |
386 | ||
39101f25 MA |
387 | qemu_opt_set_number(opts, "number1", 10, &err); |
388 | g_assert(!err); | |
4ba6fabf LD |
389 | |
390 | /* now we have set number1, should know about it */ | |
391 | opt = qemu_opt_get_number(opts, "number1", 5); | |
392 | g_assert(opt == 10); | |
393 | ||
394 | qemu_opts_reset(list); | |
395 | ||
396 | /* should not find anything at this point */ | |
397 | opts = qemu_opts_find(list, NULL); | |
398 | g_assert(opts == NULL); | |
399 | } | |
400 | ||
401 | static void test_qemu_opts_set(void) | |
402 | { | |
79087c78 | 403 | Error *err = NULL; |
4ba6fabf LD |
404 | QemuOptsList *list; |
405 | QemuOpts *opts; | |
4ba6fabf LD |
406 | const char *opt; |
407 | ||
408 | list = qemu_find_opts("opts_list_01"); | |
409 | g_assert(list != NULL); | |
410 | g_assert(QTAILQ_EMPTY(&list->head)); | |
411 | g_assert_cmpstr(list->name, ==, "opts_list_01"); | |
412 | ||
413 | /* should not find anything at this point */ | |
414 | opts = qemu_opts_find(list, NULL); | |
415 | g_assert(opts == NULL); | |
416 | ||
417 | /* implicitly create opts and set str3 value */ | |
79087c78 MA |
418 | qemu_opts_set(list, NULL, "str3", "value", &err); |
419 | g_assert(!err); | |
4ba6fabf LD |
420 | g_assert(!QTAILQ_EMPTY(&list->head)); |
421 | ||
422 | /* get the just created opts */ | |
423 | opts = qemu_opts_find(list, NULL); | |
424 | g_assert(opts != NULL); | |
425 | ||
426 | /* check the str3 value */ | |
427 | opt = qemu_opt_get(opts, "str3"); | |
428 | g_assert_cmpstr(opt, ==, "value"); | |
429 | ||
430 | qemu_opts_del(opts); | |
431 | ||
432 | /* should not find anything at this point */ | |
433 | opts = qemu_opts_find(list, NULL); | |
434 | g_assert(opts == NULL); | |
435 | } | |
436 | ||
694baf57 MA |
437 | static int opts_count_iter(void *opaque, const char *name, const char *value, |
438 | Error **errp) | |
439 | { | |
440 | (*(size_t *)opaque)++; | |
441 | return 0; | |
442 | } | |
443 | ||
444 | static size_t opts_count(QemuOpts *opts) | |
445 | { | |
446 | size_t n = 0; | |
447 | ||
448 | qemu_opt_foreach(opts, opts_count_iter, &n, NULL); | |
449 | return n; | |
450 | } | |
451 | ||
452 | static void test_opts_parse(void) | |
453 | { | |
454 | Error *err = NULL; | |
455 | QemuOpts *opts; | |
456 | char long_key[129]; | |
457 | char *params; | |
458 | ||
459 | /* Nothing */ | |
460 | opts = qemu_opts_parse(&opts_list_03, "", false, &error_abort); | |
461 | g_assert_cmpuint(opts_count(opts), ==, 0); | |
462 | ||
463 | /* Empty key */ | |
464 | opts = qemu_opts_parse(&opts_list_03, "=val", false, &error_abort); | |
465 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
466 | g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val"); | |
467 | ||
468 | /* Long key */ | |
469 | memset(long_key, 'a', 127); | |
470 | long_key[127] = 'z'; | |
471 | long_key[128] = 0; | |
472 | params = g_strdup_printf("%s=v", long_key); | |
473 | opts = qemu_opts_parse(&opts_list_03, params + 1, NULL, &error_abort); | |
474 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
475 | g_assert_cmpstr(qemu_opt_get(opts, long_key + 1), ==, "v"); | |
476 | ||
477 | /* Overlong key gets truncated */ | |
478 | opts = qemu_opts_parse(&opts_list_03, params, NULL, &error_abort); | |
479 | g_assert(opts_count(opts) == 1); | |
480 | long_key[127] = 0; | |
481 | g_assert_cmpstr(qemu_opt_get(opts, long_key), ==, "v"); | |
482 | g_free(params); | |
483 | ||
484 | /* Multiple keys, last one wins */ | |
485 | opts = qemu_opts_parse(&opts_list_03, "a=1,b=2,,x,a=3", | |
486 | false, &error_abort); | |
487 | g_assert_cmpuint(opts_count(opts), ==, 3); | |
488 | g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "3"); | |
489 | g_assert_cmpstr(qemu_opt_get(opts, "b"), ==, "2,x"); | |
490 | ||
491 | /* Except when it doesn't */ | |
492 | opts = qemu_opts_parse(&opts_list_03, "id=foo,id=bar", | |
493 | false, &error_abort); | |
494 | g_assert_cmpuint(opts_count(opts), ==, 0); | |
495 | g_assert_cmpstr(qemu_opts_id(opts), ==, "foo"); | |
496 | ||
497 | /* TODO Cover low-level access to repeated keys */ | |
498 | ||
499 | /* Trailing comma is ignored */ | |
500 | opts = qemu_opts_parse(&opts_list_03, "x=y,", false, &error_abort); | |
501 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
502 | g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, "y"); | |
503 | ||
504 | /* Except when it isn't */ | |
505 | opts = qemu_opts_parse(&opts_list_03, ",", false, &error_abort); | |
506 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
507 | g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "on"); | |
508 | ||
509 | /* Duplicate ID */ | |
510 | opts = qemu_opts_parse(&opts_list_03, "x=y,id=foo", false, &err); | |
511 | error_free_or_abort(&err); | |
512 | g_assert(!opts); | |
513 | /* TODO Cover .merge_lists = true */ | |
514 | ||
515 | /* Buggy ID recognition */ | |
516 | opts = qemu_opts_parse(&opts_list_03, "x=,,id=bar", false, &error_abort); | |
517 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
518 | g_assert_cmpstr(qemu_opts_id(opts), ==, "bar"); /* BUG */ | |
519 | g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, ",id=bar"); | |
520 | ||
521 | /* Anti-social ID */ | |
522 | opts = qemu_opts_parse(&opts_list_01, "id=666", false, &err); | |
523 | error_free_or_abort(&err); | |
524 | g_assert(!opts); | |
525 | ||
526 | /* Implied value */ | |
527 | opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=", | |
528 | false, &error_abort); | |
529 | g_assert_cmpuint(opts_count(opts), ==, 3); | |
530 | g_assert_cmpstr(qemu_opt_get(opts, "an"), ==, "on"); | |
531 | g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off"); | |
532 | g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, ""); | |
533 | ||
0e2052b2 MA |
534 | /* Implied value, negated empty key */ |
535 | opts = qemu_opts_parse(&opts_list_03, "no", false, &error_abort); | |
536 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
537 | g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "off"); | |
538 | ||
694baf57 MA |
539 | /* Implied key */ |
540 | opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=", true, | |
541 | &error_abort); | |
542 | g_assert_cmpuint(opts_count(opts), ==, 3); | |
543 | g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, "an"); | |
544 | g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off"); | |
545 | g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, ""); | |
546 | ||
547 | /* Implied key with empty value */ | |
548 | opts = qemu_opts_parse(&opts_list_03, ",", true, &error_abort); | |
549 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
550 | g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, ""); | |
551 | ||
552 | /* Implied key with comma value */ | |
553 | opts = qemu_opts_parse(&opts_list_03, ",,,a=1", true, &error_abort); | |
554 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
555 | g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, ","); | |
556 | g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "1"); | |
557 | ||
558 | /* Empty key is not an implied key */ | |
559 | opts = qemu_opts_parse(&opts_list_03, "=val", true, &error_abort); | |
560 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
561 | g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val"); | |
562 | ||
563 | /* Unknown key */ | |
564 | opts = qemu_opts_parse(&opts_list_01, "nonexistent=", false, &err); | |
565 | error_free_or_abort(&err); | |
566 | g_assert(!opts); | |
567 | ||
568 | qemu_opts_reset(&opts_list_01); | |
569 | qemu_opts_reset(&opts_list_03); | |
570 | } | |
571 | ||
572 | static void test_opts_parse_bool(void) | |
573 | { | |
574 | Error *err = NULL; | |
575 | QemuOpts *opts; | |
576 | ||
577 | opts = qemu_opts_parse(&opts_list_02, "bool1=on,bool2=off", | |
578 | false, &error_abort); | |
579 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
580 | g_assert(qemu_opt_get_bool(opts, "bool1", false)); | |
581 | g_assert(!qemu_opt_get_bool(opts, "bool2", true)); | |
582 | ||
583 | opts = qemu_opts_parse(&opts_list_02, "bool1=offer", false, &err); | |
584 | error_free_or_abort(&err); | |
585 | g_assert(!opts); | |
586 | ||
587 | qemu_opts_reset(&opts_list_02); | |
588 | } | |
589 | ||
590 | static void test_opts_parse_number(void) | |
591 | { | |
592 | Error *err = NULL; | |
593 | QemuOpts *opts; | |
594 | ||
595 | /* Lower limit zero */ | |
596 | opts = qemu_opts_parse(&opts_list_01, "number1=0", false, &error_abort); | |
597 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
598 | g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 0); | |
599 | ||
600 | /* Upper limit 2^64-1 */ | |
601 | opts = qemu_opts_parse(&opts_list_01, | |
602 | "number1=18446744073709551615,number2=-1", | |
603 | false, &error_abort); | |
604 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
605 | g_assert_cmphex(qemu_opt_get_number(opts, "number1", 1), ==, UINT64_MAX); | |
606 | g_assert_cmphex(qemu_opt_get_number(opts, "number2", 0), ==, UINT64_MAX); | |
607 | ||
608 | /* Above upper limit */ | |
609 | opts = qemu_opts_parse(&opts_list_01, "number1=18446744073709551616", | |
3403e5eb MA |
610 | false, &err); |
611 | error_free_or_abort(&err); | |
612 | g_assert(!opts); | |
694baf57 MA |
613 | |
614 | /* Below lower limit */ | |
615 | opts = qemu_opts_parse(&opts_list_01, "number1=-18446744073709551616", | |
3403e5eb MA |
616 | false, &err); |
617 | error_free_or_abort(&err); | |
618 | g_assert(!opts); | |
694baf57 MA |
619 | |
620 | /* Hex and octal */ | |
621 | opts = qemu_opts_parse(&opts_list_01, "number1=0x2a,number2=052", | |
622 | false, &error_abort); | |
623 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
624 | g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42); | |
625 | g_assert_cmpuint(qemu_opt_get_number(opts, "number2", 0), ==, 42); | |
626 | ||
627 | /* Invalid */ | |
628 | opts = qemu_opts_parse(&opts_list_01, "number1=", false, &err); | |
3403e5eb MA |
629 | error_free_or_abort(&err); |
630 | g_assert(!opts); | |
694baf57 MA |
631 | opts = qemu_opts_parse(&opts_list_01, "number1=eins", false, &err); |
632 | error_free_or_abort(&err); | |
633 | g_assert(!opts); | |
634 | ||
635 | /* Leading whitespace */ | |
636 | opts = qemu_opts_parse(&opts_list_01, "number1= \t42", | |
637 | false, &error_abort); | |
638 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
639 | g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42); | |
640 | ||
641 | /* Trailing crap */ | |
642 | opts = qemu_opts_parse(&opts_list_01, "number1=3.14", false, &err); | |
643 | error_free_or_abort(&err); | |
644 | g_assert(!opts); | |
645 | opts = qemu_opts_parse(&opts_list_01, "number1=08", false, &err); | |
646 | error_free_or_abort(&err); | |
647 | g_assert(!opts); | |
648 | opts = qemu_opts_parse(&opts_list_01, "number1=0 ", false, &err); | |
649 | error_free_or_abort(&err); | |
650 | g_assert(!opts); | |
651 | ||
652 | qemu_opts_reset(&opts_list_01); | |
653 | } | |
654 | ||
655 | static void test_opts_parse_size(void) | |
656 | { | |
657 | Error *err = NULL; | |
658 | QemuOpts *opts; | |
659 | ||
660 | /* Lower limit zero */ | |
661 | opts = qemu_opts_parse(&opts_list_02, "size1=0", false, &error_abort); | |
662 | g_assert_cmpuint(opts_count(opts), ==, 1); | |
663 | g_assert_cmpuint(qemu_opt_get_size(opts, "size1", 1), ==, 0); | |
664 | ||
665 | /* Note: precision is 53 bits since we're parsing with strtod() */ | |
666 | ||
667 | /* Around limit of precision: 2^53-1, 2^53, 2^54 */ | |
668 | opts = qemu_opts_parse(&opts_list_02, | |
669 | "size1=9007199254740991," | |
670 | "size2=9007199254740992," | |
671 | "size3=9007199254740993", | |
672 | false, &error_abort); | |
673 | g_assert_cmpuint(opts_count(opts), ==, 3); | |
674 | g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1), | |
675 | ==, 0x1fffffffffffff); | |
676 | g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1), | |
677 | ==, 0x20000000000000); | |
678 | g_assert_cmphex(qemu_opt_get_size(opts, "size3", 1), | |
679 | ==, 0x20000000000000); | |
680 | ||
681 | /* Close to signed upper limit 0x7ffffffffffffc00 (53 msbs set) */ | |
682 | opts = qemu_opts_parse(&opts_list_02, | |
683 | "size1=9223372036854774784," /* 7ffffffffffffc00 */ | |
684 | "size2=9223372036854775295", /* 7ffffffffffffdff */ | |
685 | false, &error_abort); | |
686 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
687 | g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1), | |
688 | ==, 0x7ffffffffffffc00); | |
689 | g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1), | |
690 | ==, 0x7ffffffffffffc00); | |
691 | ||
692 | /* Close to actual upper limit 0xfffffffffffff800 (53 msbs set) */ | |
693 | opts = qemu_opts_parse(&opts_list_02, | |
694 | "size1=18446744073709549568," /* fffffffffffff800 */ | |
695 | "size2=18446744073709550591", /* fffffffffffffbff */ | |
696 | false, &error_abort); | |
697 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
698 | g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1), | |
699 | ==, 0xfffffffffffff800); | |
700 | g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1), | |
701 | ==, 0xfffffffffffff800); | |
702 | ||
703 | /* Beyond limits */ | |
704 | opts = qemu_opts_parse(&opts_list_02, "size1=-1", false, &err); | |
705 | error_free_or_abort(&err); | |
706 | g_assert(!opts); | |
707 | opts = qemu_opts_parse(&opts_list_02, | |
708 | "size1=18446744073709550592", /* fffffffffffffc00 */ | |
75cdcd15 MA |
709 | false, &err); |
710 | error_free_or_abort(&err); | |
711 | g_assert(!opts); | |
694baf57 MA |
712 | |
713 | /* Suffixes */ | |
714 | opts = qemu_opts_parse(&opts_list_02, "size1=8b,size2=1.5k,size3=2M", | |
715 | false, &error_abort); | |
716 | g_assert_cmpuint(opts_count(opts), ==, 3); | |
717 | g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, 8); | |
718 | g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), ==, 1536); | |
719 | g_assert_cmphex(qemu_opt_get_size(opts, "size3", 0), ==, 2 * M_BYTE); | |
720 | opts = qemu_opts_parse(&opts_list_02, "size1=0.1G,size2=16777215T", | |
721 | false, &error_abort); | |
722 | g_assert_cmpuint(opts_count(opts), ==, 2); | |
723 | g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, G_BYTE / 10); | |
724 | g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), | |
725 | ==, 16777215 * T_BYTE); | |
726 | ||
727 | /* Beyond limit with suffix */ | |
728 | opts = qemu_opts_parse(&opts_list_02, "size1=16777216T", | |
75cdcd15 MA |
729 | false, &err); |
730 | error_free_or_abort(&err); | |
731 | g_assert(!opts); | |
694baf57 MA |
732 | |
733 | /* Trailing crap */ | |
734 | opts = qemu_opts_parse(&opts_list_02, "size1=16E", false, &err); | |
735 | error_free_or_abort(&err); | |
736 | g_assert(!opts); | |
75cdcd15 MA |
737 | opts = qemu_opts_parse(&opts_list_02, "size1=16Gi", false, &err); |
738 | error_free_or_abort(&err); | |
739 | g_assert(!opts); | |
694baf57 MA |
740 | |
741 | qemu_opts_reset(&opts_list_02); | |
742 | } | |
743 | ||
4ba6fabf LD |
744 | int main(int argc, char *argv[]) |
745 | { | |
746 | register_opts(); | |
747 | g_test_init(&argc, &argv, NULL); | |
748 | g_test_add_func("/qemu-opts/find_unknown_opts", test_find_unknown_opts); | |
749 | g_test_add_func("/qemu-opts/find_opts", test_qemu_find_opts); | |
750 | g_test_add_func("/qemu-opts/opts_create", test_qemu_opts_create); | |
751 | g_test_add_func("/qemu-opts/opt_get", test_qemu_opt_get); | |
752 | g_test_add_func("/qemu-opts/opt_get_bool", test_qemu_opt_get_bool); | |
753 | g_test_add_func("/qemu-opts/opt_get_number", test_qemu_opt_get_number); | |
754 | g_test_add_func("/qemu-opts/opt_get_size", test_qemu_opt_get_size); | |
755 | g_test_add_func("/qemu-opts/opt_unset", test_qemu_opt_unset); | |
756 | g_test_add_func("/qemu-opts/opts_reset", test_qemu_opts_reset); | |
757 | g_test_add_func("/qemu-opts/opts_set", test_qemu_opts_set); | |
694baf57 MA |
758 | g_test_add_func("/qemu-opts/opts_parse/general", test_opts_parse); |
759 | g_test_add_func("/qemu-opts/opts_parse/bool", test_opts_parse_bool); | |
760 | g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number); | |
761 | g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size); | |
4ba6fabf LD |
762 | g_test_run(); |
763 | return 0; | |
764 | } |