]>
Commit | Line | Data |
---|---|---|
a31bdae5 DB |
1 | /* |
2 | * Copyright (C) 2015 Red Hat, Inc. | |
3 | * | |
4 | * This library is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU Lesser General Public | |
6 | * License as published by the Free Software Foundation; either | |
7 | * version 2.1 of the License, or (at your option) any later version. | |
8 | * | |
9 | * This library is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | * Lesser General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU Lesser General Public | |
15 | * License along with this library. If not, see | |
16 | * <http://www.gnu.org/licenses/>. | |
17 | * | |
18 | * Author: Daniel P. Berrange <berrange@redhat.com> | |
19 | */ | |
20 | ||
681c28a3 | 21 | #include "qemu/osdep.h" |
a31bdae5 | 22 | |
da34e65c | 23 | #include "qapi/error.h" |
53c9956d PB |
24 | #include "qapi/qobject-input-visitor.h" |
25 | #include "qapi/qmp/qdict.h" | |
26 | #include "qapi/qmp/qobject.h" | |
a31bdae5 DB |
27 | #include "qom/object.h" |
28 | #include "qemu/module.h" | |
a1af255f | 29 | #include "qemu/option.h" |
9ca9c893 | 30 | #include "qemu/keyval.h" |
a1af255f MR |
31 | #include "qemu/config-file.h" |
32 | #include "qom/object_interfaces.h" | |
a31bdae5 DB |
33 | |
34 | ||
35 | #define TYPE_DUMMY "qemu-dummy" | |
36 | ||
37 | typedef struct DummyObject DummyObject; | |
38 | typedef struct DummyObjectClass DummyObjectClass; | |
39 | ||
8110fa1d EH |
40 | DECLARE_INSTANCE_CHECKER(DummyObject, DUMMY_OBJECT, |
41 | TYPE_DUMMY) | |
a31bdae5 | 42 | |
a8e3fbed DB |
43 | typedef enum DummyAnimal DummyAnimal; |
44 | ||
45 | enum DummyAnimal { | |
46 | DUMMY_FROG, | |
47 | DUMMY_ALLIGATOR, | |
48 | DUMMY_PLATYPUS, | |
49 | ||
50 | DUMMY_LAST, | |
51 | }; | |
52 | ||
f7abe0ec MAL |
53 | const QEnumLookup dummy_animal_map = { |
54 | .array = (const char *const[]) { | |
55 | [DUMMY_FROG] = "frog", | |
56 | [DUMMY_ALLIGATOR] = "alligator", | |
57 | [DUMMY_PLATYPUS] = "platypus", | |
f7abe0ec MAL |
58 | }, |
59 | .size = DUMMY_LAST | |
a8e3fbed DB |
60 | }; |
61 | ||
a31bdae5 DB |
62 | struct DummyObject { |
63 | Object parent_obj; | |
64 | ||
65 | bool bv; | |
a8e3fbed | 66 | DummyAnimal av; |
a31bdae5 DB |
67 | char *sv; |
68 | }; | |
69 | ||
70 | struct DummyObjectClass { | |
71 | ObjectClass parent_class; | |
72 | }; | |
73 | ||
74 | ||
75 | static void dummy_set_bv(Object *obj, | |
76 | bool value, | |
77 | Error **errp) | |
78 | { | |
79 | DummyObject *dobj = DUMMY_OBJECT(obj); | |
80 | ||
81 | dobj->bv = value; | |
82 | } | |
83 | ||
84 | static bool dummy_get_bv(Object *obj, | |
85 | Error **errp) | |
86 | { | |
87 | DummyObject *dobj = DUMMY_OBJECT(obj); | |
88 | ||
89 | return dobj->bv; | |
90 | } | |
91 | ||
92 | ||
a8e3fbed DB |
93 | static void dummy_set_av(Object *obj, |
94 | int value, | |
95 | Error **errp) | |
96 | { | |
97 | DummyObject *dobj = DUMMY_OBJECT(obj); | |
98 | ||
99 | dobj->av = value; | |
100 | } | |
101 | ||
102 | static int dummy_get_av(Object *obj, | |
103 | Error **errp) | |
104 | { | |
105 | DummyObject *dobj = DUMMY_OBJECT(obj); | |
106 | ||
107 | return dobj->av; | |
108 | } | |
109 | ||
110 | ||
a31bdae5 DB |
111 | static void dummy_set_sv(Object *obj, |
112 | const char *value, | |
113 | Error **errp) | |
114 | { | |
115 | DummyObject *dobj = DUMMY_OBJECT(obj); | |
116 | ||
117 | g_free(dobj->sv); | |
118 | dobj->sv = g_strdup(value); | |
119 | } | |
120 | ||
121 | static char *dummy_get_sv(Object *obj, | |
122 | Error **errp) | |
123 | { | |
124 | DummyObject *dobj = DUMMY_OBJECT(obj); | |
125 | ||
126 | return g_strdup(dobj->sv); | |
127 | } | |
128 | ||
129 | ||
130 | static void dummy_init(Object *obj) | |
131 | { | |
132 | object_property_add_bool(obj, "bv", | |
133 | dummy_get_bv, | |
d2623129 | 134 | dummy_set_bv); |
a31bdae5 DB |
135 | } |
136 | ||
16bf7f52 DB |
137 | |
138 | static void dummy_class_init(ObjectClass *cls, void *data) | |
139 | { | |
16bf7f52 DB |
140 | object_class_property_add_str(cls, "sv", |
141 | dummy_get_sv, | |
d2623129 | 142 | dummy_set_sv); |
16bf7f52 DB |
143 | object_class_property_add_enum(cls, "av", |
144 | "DummyAnimal", | |
f7abe0ec | 145 | &dummy_animal_map, |
16bf7f52 | 146 | dummy_get_av, |
d2623129 | 147 | dummy_set_av); |
16bf7f52 DB |
148 | } |
149 | ||
150 | ||
a31bdae5 DB |
151 | static void dummy_finalize(Object *obj) |
152 | { | |
153 | DummyObject *dobj = DUMMY_OBJECT(obj); | |
154 | ||
155 | g_free(dobj->sv); | |
156 | } | |
157 | ||
158 | ||
159 | static const TypeInfo dummy_info = { | |
160 | .name = TYPE_DUMMY, | |
161 | .parent = TYPE_OBJECT, | |
162 | .instance_size = sizeof(DummyObject), | |
163 | .instance_init = dummy_init, | |
164 | .instance_finalize = dummy_finalize, | |
165 | .class_size = sizeof(DummyObjectClass), | |
16bf7f52 | 166 | .class_init = dummy_class_init, |
a1af255f MR |
167 | .interfaces = (InterfaceInfo[]) { |
168 | { TYPE_USER_CREATABLE }, | |
169 | { } | |
170 | } | |
a31bdae5 DB |
171 | }; |
172 | ||
8c4d156c DB |
173 | |
174 | /* | |
175 | * The following 3 object classes are used to | |
176 | * simulate the kind of relationships seen in | |
177 | * qdev, which result in complex object | |
178 | * property destruction ordering. | |
179 | * | |
180 | * DummyDev has a 'bus' child to a DummyBus | |
181 | * DummyBus has a 'backend' child to a DummyBackend | |
182 | * DummyDev has a 'backend' link to DummyBackend | |
183 | * | |
184 | * When DummyDev is finalized, it unparents the | |
185 | * DummyBackend, which unparents the DummyDev | |
186 | * which deletes the 'backend' link from DummyDev | |
187 | * to DummyBackend. This illustrates that the | |
188 | * object_property_del_all() method needs to | |
189 | * cope with the list of properties being changed | |
190 | * while it iterates over them. | |
191 | */ | |
192 | typedef struct DummyDev DummyDev; | |
193 | typedef struct DummyDevClass DummyDevClass; | |
194 | typedef struct DummyBus DummyBus; | |
195 | typedef struct DummyBusClass DummyBusClass; | |
196 | typedef struct DummyBackend DummyBackend; | |
197 | typedef struct DummyBackendClass DummyBackendClass; | |
198 | ||
199 | #define TYPE_DUMMY_DEV "qemu-dummy-dev" | |
200 | #define TYPE_DUMMY_BUS "qemu-dummy-bus" | |
201 | #define TYPE_DUMMY_BACKEND "qemu-dummy-backend" | |
202 | ||
8110fa1d EH |
203 | DECLARE_INSTANCE_CHECKER(DummyDev, DUMMY_DEV, |
204 | TYPE_DUMMY_DEV) | |
205 | DECLARE_INSTANCE_CHECKER(DummyBus, DUMMY_BUS, | |
206 | TYPE_DUMMY_BUS) | |
207 | DECLARE_INSTANCE_CHECKER(DummyBackend, DUMMY_BACKEND, | |
208 | TYPE_DUMMY_BACKEND) | |
8c4d156c DB |
209 | |
210 | struct DummyDev { | |
211 | Object parent_obj; | |
212 | ||
213 | DummyBus *bus; | |
214 | }; | |
215 | ||
216 | struct DummyDevClass { | |
217 | ObjectClass parent_class; | |
218 | }; | |
219 | ||
220 | struct DummyBus { | |
221 | Object parent_obj; | |
222 | ||
223 | DummyBackend *backend; | |
224 | }; | |
225 | ||
226 | struct DummyBusClass { | |
227 | ObjectClass parent_class; | |
228 | }; | |
229 | ||
230 | struct DummyBackend { | |
231 | Object parent_obj; | |
232 | }; | |
233 | ||
234 | struct DummyBackendClass { | |
235 | ObjectClass parent_class; | |
236 | }; | |
237 | ||
238 | ||
3972a488 MAL |
239 | static void dummy_dev_finalize(Object *obj) |
240 | { | |
241 | DummyDev *dev = DUMMY_DEV(obj); | |
242 | ||
243 | object_unref(OBJECT(dev->bus)); | |
244 | } | |
245 | ||
8c4d156c DB |
246 | static void dummy_dev_init(Object *obj) |
247 | { | |
248 | DummyDev *dev = DUMMY_DEV(obj); | |
249 | DummyBus *bus = DUMMY_BUS(object_new(TYPE_DUMMY_BUS)); | |
250 | DummyBackend *backend = DUMMY_BACKEND(object_new(TYPE_DUMMY_BACKEND)); | |
251 | ||
d2623129 | 252 | object_property_add_child(obj, "bus", OBJECT(bus)); |
8c4d156c | 253 | dev->bus = bus; |
d2623129 | 254 | object_property_add_child(OBJECT(bus), "backend", OBJECT(backend)); |
8c4d156c DB |
255 | bus->backend = backend; |
256 | ||
257 | object_property_add_link(obj, "backend", TYPE_DUMMY_BACKEND, | |
d2623129 | 258 | (Object **)&bus->backend, NULL, 0); |
8c4d156c DB |
259 | } |
260 | ||
261 | static void dummy_dev_unparent(Object *obj) | |
262 | { | |
263 | DummyDev *dev = DUMMY_DEV(obj); | |
264 | object_unparent(OBJECT(dev->bus)); | |
265 | } | |
266 | ||
267 | static void dummy_dev_class_init(ObjectClass *klass, void *opaque) | |
268 | { | |
269 | klass->unparent = dummy_dev_unparent; | |
270 | } | |
271 | ||
272 | ||
3972a488 MAL |
273 | static void dummy_bus_finalize(Object *obj) |
274 | { | |
275 | DummyBus *bus = DUMMY_BUS(obj); | |
276 | ||
277 | object_unref(OBJECT(bus->backend)); | |
278 | } | |
279 | ||
8c4d156c DB |
280 | static void dummy_bus_init(Object *obj) |
281 | { | |
282 | } | |
283 | ||
284 | static void dummy_bus_unparent(Object *obj) | |
285 | { | |
286 | DummyBus *bus = DUMMY_BUS(obj); | |
df4fe0b2 | 287 | object_property_del(obj->parent, "backend"); |
8c4d156c DB |
288 | object_unparent(OBJECT(bus->backend)); |
289 | } | |
290 | ||
291 | static void dummy_bus_class_init(ObjectClass *klass, void *opaque) | |
292 | { | |
293 | klass->unparent = dummy_bus_unparent; | |
294 | } | |
295 | ||
296 | static void dummy_backend_init(Object *obj) | |
297 | { | |
298 | } | |
299 | ||
300 | ||
301 | static const TypeInfo dummy_dev_info = { | |
302 | .name = TYPE_DUMMY_DEV, | |
303 | .parent = TYPE_OBJECT, | |
304 | .instance_size = sizeof(DummyDev), | |
305 | .instance_init = dummy_dev_init, | |
3972a488 | 306 | .instance_finalize = dummy_dev_finalize, |
8c4d156c DB |
307 | .class_size = sizeof(DummyDevClass), |
308 | .class_init = dummy_dev_class_init, | |
309 | }; | |
310 | ||
311 | static const TypeInfo dummy_bus_info = { | |
312 | .name = TYPE_DUMMY_BUS, | |
313 | .parent = TYPE_OBJECT, | |
314 | .instance_size = sizeof(DummyBus), | |
315 | .instance_init = dummy_bus_init, | |
3972a488 | 316 | .instance_finalize = dummy_bus_finalize, |
8c4d156c DB |
317 | .class_size = sizeof(DummyBusClass), |
318 | .class_init = dummy_bus_class_init, | |
319 | }; | |
320 | ||
321 | static const TypeInfo dummy_backend_info = { | |
322 | .name = TYPE_DUMMY_BACKEND, | |
323 | .parent = TYPE_OBJECT, | |
324 | .instance_size = sizeof(DummyBackend), | |
325 | .instance_init = dummy_backend_init, | |
326 | .class_size = sizeof(DummyBackendClass), | |
327 | }; | |
328 | ||
a1af255f MR |
329 | static QemuOptsList qemu_object_opts = { |
330 | .name = "object", | |
331 | .implied_opt_name = "qom-type", | |
332 | .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head), | |
333 | .desc = { | |
334 | { } | |
335 | }, | |
336 | }; | |
8c4d156c DB |
337 | |
338 | ||
a31bdae5 DB |
339 | static void test_dummy_createv(void) |
340 | { | |
341 | Error *err = NULL; | |
342 | Object *parent = object_get_objects_root(); | |
343 | DummyObject *dobj = DUMMY_OBJECT( | |
344 | object_new_with_props(TYPE_DUMMY, | |
345 | parent, | |
346 | "dummy0", | |
347 | &err, | |
348 | "bv", "yes", | |
349 | "sv", "Hiss hiss hiss", | |
a8e3fbed | 350 | "av", "platypus", |
a31bdae5 DB |
351 | NULL)); |
352 | ||
353 | g_assert(err == NULL); | |
354 | g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss"); | |
355 | g_assert(dobj->bv == true); | |
a8e3fbed | 356 | g_assert(dobj->av == DUMMY_PLATYPUS); |
a31bdae5 DB |
357 | |
358 | g_assert(object_resolve_path_component(parent, "dummy0") | |
359 | == OBJECT(dobj)); | |
360 | ||
361 | object_unparent(OBJECT(dobj)); | |
362 | } | |
363 | ||
364 | ||
365 | static Object *new_helper(Error **errp, | |
366 | Object *parent, | |
367 | ...) | |
368 | { | |
369 | va_list vargs; | |
370 | Object *obj; | |
371 | ||
372 | va_start(vargs, parent); | |
373 | obj = object_new_with_propv(TYPE_DUMMY, | |
374 | parent, | |
375 | "dummy0", | |
376 | errp, | |
377 | vargs); | |
378 | va_end(vargs); | |
379 | return obj; | |
380 | } | |
381 | ||
382 | static void test_dummy_createlist(void) | |
383 | { | |
384 | Error *err = NULL; | |
385 | Object *parent = object_get_objects_root(); | |
386 | DummyObject *dobj = DUMMY_OBJECT( | |
387 | new_helper(&err, | |
388 | parent, | |
389 | "bv", "yes", | |
390 | "sv", "Hiss hiss hiss", | |
a8e3fbed | 391 | "av", "platypus", |
a31bdae5 DB |
392 | NULL)); |
393 | ||
394 | g_assert(err == NULL); | |
395 | g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss"); | |
396 | g_assert(dobj->bv == true); | |
a8e3fbed | 397 | g_assert(dobj->av == DUMMY_PLATYPUS); |
a31bdae5 DB |
398 | |
399 | g_assert(object_resolve_path_component(parent, "dummy0") | |
400 | == OBJECT(dobj)); | |
401 | ||
402 | object_unparent(OBJECT(dobj)); | |
403 | } | |
404 | ||
53c9956d PB |
405 | static bool test_create_obj(QDict *qdict, Error **errp) |
406 | { | |
407 | Visitor *v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); | |
408 | Object *obj = user_creatable_add_type(TYPE_DUMMY, "dev0", qdict, v, errp); | |
409 | ||
410 | visit_free(v); | |
411 | object_unref(obj); | |
412 | return !!obj; | |
413 | } | |
414 | ||
a1af255f MR |
415 | static void test_dummy_createcmdl(void) |
416 | { | |
53c9956d | 417 | QDict *qdict; |
a1af255f MR |
418 | DummyObject *dobj; |
419 | Error *err = NULL; | |
53c9956d PB |
420 | bool created, help; |
421 | const char *params = "bv=yes,sv=Hiss hiss hiss,av=platypus"; | |
a1af255f | 422 | |
53c9956d | 423 | /* Needed for user_creatable_del. */ |
a1af255f | 424 | qemu_add_opts(&qemu_object_opts); |
53c9956d PB |
425 | |
426 | qdict = keyval_parse(params, "qom-type", &help, &err); | |
a1af255f | 427 | g_assert(err == NULL); |
53c9956d PB |
428 | g_assert(qdict); |
429 | g_assert(!help); | |
a1af255f | 430 | |
53c9956d PB |
431 | created = test_create_obj(qdict, &err); |
432 | g_assert(created); | |
a1af255f | 433 | g_assert(err == NULL); |
53c9956d PB |
434 | qobject_unref(qdict); |
435 | ||
436 | dobj = DUMMY_OBJECT(object_resolve_path_component(object_get_objects_root(), | |
437 | "dev0")); | |
a1af255f MR |
438 | g_assert(dobj); |
439 | g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss"); | |
440 | g_assert(dobj->bv == true); | |
441 | g_assert(dobj->av == DUMMY_PLATYPUS); | |
442 | ||
53c9956d PB |
443 | qdict = keyval_parse(params, "qom-type", &help, &err); |
444 | created = test_create_obj(qdict, &err); | |
445 | g_assert(!created); | |
446 | g_assert(err); | |
447 | g_assert(object_resolve_path_component(object_get_objects_root(), "dev0") | |
448 | == OBJECT(dobj)); | |
449 | qobject_unref(qdict); | |
450 | error_free(err); | |
451 | err = NULL; | |
452 | ||
453 | qdict = keyval_parse(params, "qom-type", &help, &err); | |
d8da9e71 | 454 | user_creatable_del("dev0", &error_abort); |
53c9956d PB |
455 | g_assert(object_resolve_path_component(object_get_objects_root(), "dev0") |
456 | == NULL); | |
a1af255f | 457 | |
53c9956d PB |
458 | created = test_create_obj(qdict, &err); |
459 | g_assert(created); | |
460 | g_assert(err == NULL); | |
461 | qobject_unref(qdict); | |
462 | ||
463 | dobj = DUMMY_OBJECT(object_resolve_path_component(object_get_objects_root(), | |
464 | "dev0")); | |
465 | g_assert(dobj); | |
466 | g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss"); | |
467 | g_assert(dobj->bv == true); | |
468 | g_assert(dobj->av == DUMMY_PLATYPUS); | |
469 | g_assert(object_resolve_path_component(object_get_objects_root(), "dev0") | |
470 | == OBJECT(dobj)); | |
471 | ||
472 | object_unparent(OBJECT(dobj)); | |
a1af255f MR |
473 | } |
474 | ||
a8e3fbed DB |
475 | static void test_dummy_badenum(void) |
476 | { | |
477 | Error *err = NULL; | |
478 | Object *parent = object_get_objects_root(); | |
479 | Object *dobj = | |
480 | object_new_with_props(TYPE_DUMMY, | |
481 | parent, | |
482 | "dummy0", | |
483 | &err, | |
484 | "bv", "yes", | |
485 | "sv", "Hiss hiss hiss", | |
486 | "av", "yeti", | |
487 | NULL); | |
488 | ||
489 | g_assert(dobj == NULL); | |
490 | g_assert(err != NULL); | |
491 | g_assert_cmpstr(error_get_pretty(err), ==, | |
ea29331b | 492 | "Parameter 'av' does not accept value 'yeti'"); |
a8e3fbed DB |
493 | |
494 | g_assert(object_resolve_path_component(parent, "dummy0") | |
495 | == NULL); | |
496 | ||
497 | error_free(err); | |
498 | } | |
499 | ||
500 | ||
a3590dac DB |
501 | static void test_dummy_getenum(void) |
502 | { | |
503 | Error *err = NULL; | |
504 | int val; | |
505 | Object *parent = object_get_objects_root(); | |
506 | DummyObject *dobj = DUMMY_OBJECT( | |
507 | object_new_with_props(TYPE_DUMMY, | |
508 | parent, | |
509 | "dummy0", | |
510 | &err, | |
511 | "av", "platypus", | |
512 | NULL)); | |
513 | ||
514 | g_assert(err == NULL); | |
515 | g_assert(dobj->av == DUMMY_PLATYPUS); | |
516 | ||
517 | val = object_property_get_enum(OBJECT(dobj), | |
518 | "av", | |
519 | "DummyAnimal", | |
d8da9e71 | 520 | &error_abort); |
a3590dac DB |
521 | g_assert(val == DUMMY_PLATYPUS); |
522 | ||
523 | /* A bad enum type name */ | |
524 | val = object_property_get_enum(OBJECT(dobj), | |
525 | "av", | |
526 | "BadAnimal", | |
527 | &err); | |
d20f616e | 528 | g_assert(val == -1); |
7b8eb7f8 | 529 | error_free_or_abort(&err); |
a3590dac DB |
530 | |
531 | /* A non-enum property name */ | |
532 | val = object_property_get_enum(OBJECT(dobj), | |
533 | "iv", | |
534 | "DummyAnimal", | |
535 | &err); | |
d20f616e | 536 | g_assert(val == -1); |
7b8eb7f8 | 537 | error_free_or_abort(&err); |
a00c9482 DB |
538 | |
539 | object_unparent(OBJECT(dobj)); | |
540 | } | |
541 | ||
542 | ||
48942138 MA |
543 | static void test_dummy_prop_iterator(ObjectPropertyIterator *iter, |
544 | const char *expected[], int n) | |
a00c9482 | 545 | { |
a00c9482 | 546 | ObjectProperty *prop; |
48942138 | 547 | int i; |
a00c9482 | 548 | |
94ef3b30 | 549 | while ((prop = object_property_iter_next(iter))) { |
48942138 MA |
550 | for (i = 0; i < n; i++) { |
551 | if (!g_strcmp0(prop->name, expected[i])) { | |
552 | break; | |
553 | } | |
a00c9482 | 554 | } |
48942138 MA |
555 | g_assert(i < n); |
556 | expected[i] = NULL; | |
557 | } | |
558 | ||
559 | for (i = 0; i < n; i++) { | |
560 | g_assert(!expected[i]); | |
a00c9482 | 561 | } |
94ef3b30 | 562 | } |
a00c9482 | 563 | |
94ef3b30 MAL |
564 | static void test_dummy_iterator(void) |
565 | { | |
48942138 MA |
566 | const char *expected[] = { |
567 | "type", /* inherited from TYPE_OBJECT */ | |
568 | "sv", "av", /* class properties */ | |
569 | "bv"}; /* instance property */ | |
94ef3b30 MAL |
570 | Object *parent = object_get_objects_root(); |
571 | DummyObject *dobj = DUMMY_OBJECT( | |
572 | object_new_with_props(TYPE_DUMMY, | |
573 | parent, | |
574 | "dummy0", | |
575 | &error_abort, | |
576 | "bv", "yes", | |
577 | "sv", "Hiss hiss hiss", | |
578 | "av", "platypus", | |
579 | NULL)); | |
580 | ObjectPropertyIterator iter; | |
581 | ||
582 | object_property_iter_init(&iter, OBJECT(dobj)); | |
48942138 | 583 | test_dummy_prop_iterator(&iter, expected, ARRAY_SIZE(expected)); |
a00c9482 | 584 | object_unparent(OBJECT(dobj)); |
a3590dac DB |
585 | } |
586 | ||
e569ba92 MAL |
587 | static void test_dummy_class_iterator(void) |
588 | { | |
48942138 | 589 | const char *expected[] = { "type", "av", "sv" }; |
e569ba92 MAL |
590 | ObjectPropertyIterator iter; |
591 | ObjectClass *klass = object_class_by_name(TYPE_DUMMY); | |
592 | ||
593 | object_class_property_iter_init(&iter, klass); | |
48942138 | 594 | test_dummy_prop_iterator(&iter, expected, ARRAY_SIZE(expected)); |
e569ba92 | 595 | } |
a3590dac | 596 | |
8c4d156c DB |
597 | static void test_dummy_delchild(void) |
598 | { | |
599 | Object *parent = object_get_objects_root(); | |
600 | DummyDev *dev = DUMMY_DEV( | |
601 | object_new_with_props(TYPE_DUMMY_DEV, | |
602 | parent, | |
603 | "dev0", | |
604 | &error_abort, | |
605 | NULL)); | |
606 | ||
607 | object_unparent(OBJECT(dev)); | |
608 | } | |
609 | ||
3f0058bb EH |
610 | static void test_qom_partial_path(void) |
611 | { | |
612 | Object *root = object_get_objects_root(); | |
613 | Object *cont1 = container_get(root, "/cont1"); | |
614 | Object *obj1 = object_new(TYPE_DUMMY); | |
615 | Object *obj2a = object_new(TYPE_DUMMY); | |
616 | Object *obj2b = object_new(TYPE_DUMMY); | |
617 | bool ambiguous; | |
618 | ||
619 | /* Objects created: | |
620 | * /cont1 | |
621 | * /cont1/obj1 | |
622 | * /cont1/obj2 (obj2a) | |
623 | * /obj2 (obj2b) | |
624 | */ | |
d2623129 | 625 | object_property_add_child(cont1, "obj1", obj1); |
3f0058bb | 626 | object_unref(obj1); |
d2623129 | 627 | object_property_add_child(cont1, "obj2", obj2a); |
3f0058bb | 628 | object_unref(obj2a); |
d2623129 | 629 | object_property_add_child(root, "obj2", obj2b); |
3f0058bb EH |
630 | object_unref(obj2b); |
631 | ||
632 | ambiguous = false; | |
633 | g_assert(!object_resolve_path_type("", TYPE_DUMMY, &ambiguous)); | |
634 | g_assert(ambiguous); | |
ebcc479e | 635 | g_assert(!object_resolve_path_type("", TYPE_DUMMY, NULL)); |
3f0058bb EH |
636 | |
637 | ambiguous = false; | |
638 | g_assert(!object_resolve_path("obj2", &ambiguous)); | |
639 | g_assert(ambiguous); | |
ebcc479e | 640 | g_assert(!object_resolve_path("obj2", NULL)); |
3f0058bb EH |
641 | |
642 | ambiguous = false; | |
643 | g_assert(object_resolve_path("obj1", &ambiguous) == obj1); | |
644 | g_assert(!ambiguous); | |
ebcc479e | 645 | g_assert(object_resolve_path("obj1", NULL) == obj1); |
3f0058bb EH |
646 | |
647 | object_unparent(obj2b); | |
648 | object_unparent(cont1); | |
649 | } | |
650 | ||
a31bdae5 DB |
651 | int main(int argc, char **argv) |
652 | { | |
653 | g_test_init(&argc, &argv, NULL); | |
654 | ||
655 | module_call_init(MODULE_INIT_QOM); | |
656 | type_register_static(&dummy_info); | |
8c4d156c DB |
657 | type_register_static(&dummy_dev_info); |
658 | type_register_static(&dummy_bus_info); | |
659 | type_register_static(&dummy_backend_info); | |
a31bdae5 DB |
660 | |
661 | g_test_add_func("/qom/proplist/createlist", test_dummy_createlist); | |
662 | g_test_add_func("/qom/proplist/createv", test_dummy_createv); | |
a1af255f | 663 | g_test_add_func("/qom/proplist/createcmdline", test_dummy_createcmdl); |
a8e3fbed | 664 | g_test_add_func("/qom/proplist/badenum", test_dummy_badenum); |
a3590dac | 665 | g_test_add_func("/qom/proplist/getenum", test_dummy_getenum); |
a00c9482 | 666 | g_test_add_func("/qom/proplist/iterator", test_dummy_iterator); |
e569ba92 | 667 | g_test_add_func("/qom/proplist/class_iterator", test_dummy_class_iterator); |
8c4d156c | 668 | g_test_add_func("/qom/proplist/delchild", test_dummy_delchild); |
3f0058bb | 669 | g_test_add_func("/qom/resolve/partial", test_qom_partial_path); |
a31bdae5 DB |
670 | |
671 | return g_test_run(); | |
672 | } |