Some users of QOM need to be able to iterate over properties defined against an object instance. Currently they are just directly using the QTAIL macros against the object properties data structure. This is bad because it exposes them to changes in the data structure used to store properties, as well as changes in functionality such as ability to register properties against the class. This provides an ObjectPropertyIterator struct which will insulate the callers from the particular data structure used to store properties. It can be used thus ObjectProperty *prop; ObjectPropertyIterator *iter; iter = object_property_iter_init(obj); while ((prop = object_property_iter_next(iter))) { ... do something with prop ... } object_property_iter_free(iter); Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Tested-by: Pavel Fedin <p.fedin@samsung.com> [AF: Fixed examples, style cleanups] Signed-off-by: Andreas Färber <afaerber@suse.de>
349 lines
9.1 KiB
C
349 lines
9.1 KiB
C
/*
|
|
* Copyright (C) 2015 Red Hat, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
*/
|
|
|
|
#include <glib.h>
|
|
|
|
#include "qom/object.h"
|
|
#include "qemu/module.h"
|
|
|
|
|
|
#define TYPE_DUMMY "qemu-dummy"
|
|
|
|
typedef struct DummyObject DummyObject;
|
|
typedef struct DummyObjectClass DummyObjectClass;
|
|
|
|
#define DUMMY_OBJECT(obj) \
|
|
OBJECT_CHECK(DummyObject, (obj), TYPE_DUMMY)
|
|
|
|
typedef enum DummyAnimal DummyAnimal;
|
|
|
|
enum DummyAnimal {
|
|
DUMMY_FROG,
|
|
DUMMY_ALLIGATOR,
|
|
DUMMY_PLATYPUS,
|
|
|
|
DUMMY_LAST,
|
|
};
|
|
|
|
static const char *const dummy_animal_map[DUMMY_LAST + 1] = {
|
|
[DUMMY_FROG] = "frog",
|
|
[DUMMY_ALLIGATOR] = "alligator",
|
|
[DUMMY_PLATYPUS] = "platypus",
|
|
[DUMMY_LAST] = NULL,
|
|
};
|
|
|
|
struct DummyObject {
|
|
Object parent_obj;
|
|
|
|
bool bv;
|
|
DummyAnimal av;
|
|
char *sv;
|
|
};
|
|
|
|
struct DummyObjectClass {
|
|
ObjectClass parent_class;
|
|
};
|
|
|
|
|
|
static void dummy_set_bv(Object *obj,
|
|
bool value,
|
|
Error **errp)
|
|
{
|
|
DummyObject *dobj = DUMMY_OBJECT(obj);
|
|
|
|
dobj->bv = value;
|
|
}
|
|
|
|
static bool dummy_get_bv(Object *obj,
|
|
Error **errp)
|
|
{
|
|
DummyObject *dobj = DUMMY_OBJECT(obj);
|
|
|
|
return dobj->bv;
|
|
}
|
|
|
|
|
|
static void dummy_set_av(Object *obj,
|
|
int value,
|
|
Error **errp)
|
|
{
|
|
DummyObject *dobj = DUMMY_OBJECT(obj);
|
|
|
|
dobj->av = value;
|
|
}
|
|
|
|
static int dummy_get_av(Object *obj,
|
|
Error **errp)
|
|
{
|
|
DummyObject *dobj = DUMMY_OBJECT(obj);
|
|
|
|
return dobj->av;
|
|
}
|
|
|
|
|
|
static void dummy_set_sv(Object *obj,
|
|
const char *value,
|
|
Error **errp)
|
|
{
|
|
DummyObject *dobj = DUMMY_OBJECT(obj);
|
|
|
|
g_free(dobj->sv);
|
|
dobj->sv = g_strdup(value);
|
|
}
|
|
|
|
static char *dummy_get_sv(Object *obj,
|
|
Error **errp)
|
|
{
|
|
DummyObject *dobj = DUMMY_OBJECT(obj);
|
|
|
|
return g_strdup(dobj->sv);
|
|
}
|
|
|
|
|
|
static void dummy_init(Object *obj)
|
|
{
|
|
object_property_add_bool(obj, "bv",
|
|
dummy_get_bv,
|
|
dummy_set_bv,
|
|
NULL);
|
|
object_property_add_str(obj, "sv",
|
|
dummy_get_sv,
|
|
dummy_set_sv,
|
|
NULL);
|
|
object_property_add_enum(obj, "av",
|
|
"DummyAnimal",
|
|
dummy_animal_map,
|
|
dummy_get_av,
|
|
dummy_set_av,
|
|
NULL);
|
|
}
|
|
|
|
static void dummy_finalize(Object *obj)
|
|
{
|
|
DummyObject *dobj = DUMMY_OBJECT(obj);
|
|
|
|
g_free(dobj->sv);
|
|
}
|
|
|
|
|
|
static const TypeInfo dummy_info = {
|
|
.name = TYPE_DUMMY,
|
|
.parent = TYPE_OBJECT,
|
|
.instance_size = sizeof(DummyObject),
|
|
.instance_init = dummy_init,
|
|
.instance_finalize = dummy_finalize,
|
|
.class_size = sizeof(DummyObjectClass),
|
|
};
|
|
|
|
static void test_dummy_createv(void)
|
|
{
|
|
Error *err = NULL;
|
|
Object *parent = object_get_objects_root();
|
|
DummyObject *dobj = DUMMY_OBJECT(
|
|
object_new_with_props(TYPE_DUMMY,
|
|
parent,
|
|
"dummy0",
|
|
&err,
|
|
"bv", "yes",
|
|
"sv", "Hiss hiss hiss",
|
|
"av", "platypus",
|
|
NULL));
|
|
|
|
g_assert(err == NULL);
|
|
g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss");
|
|
g_assert(dobj->bv == true);
|
|
g_assert(dobj->av == DUMMY_PLATYPUS);
|
|
|
|
g_assert(object_resolve_path_component(parent, "dummy0")
|
|
== OBJECT(dobj));
|
|
|
|
object_unparent(OBJECT(dobj));
|
|
}
|
|
|
|
|
|
static Object *new_helper(Error **errp,
|
|
Object *parent,
|
|
...)
|
|
{
|
|
va_list vargs;
|
|
Object *obj;
|
|
|
|
va_start(vargs, parent);
|
|
obj = object_new_with_propv(TYPE_DUMMY,
|
|
parent,
|
|
"dummy0",
|
|
errp,
|
|
vargs);
|
|
va_end(vargs);
|
|
return obj;
|
|
}
|
|
|
|
static void test_dummy_createlist(void)
|
|
{
|
|
Error *err = NULL;
|
|
Object *parent = object_get_objects_root();
|
|
DummyObject *dobj = DUMMY_OBJECT(
|
|
new_helper(&err,
|
|
parent,
|
|
"bv", "yes",
|
|
"sv", "Hiss hiss hiss",
|
|
"av", "platypus",
|
|
NULL));
|
|
|
|
g_assert(err == NULL);
|
|
g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss");
|
|
g_assert(dobj->bv == true);
|
|
g_assert(dobj->av == DUMMY_PLATYPUS);
|
|
|
|
g_assert(object_resolve_path_component(parent, "dummy0")
|
|
== OBJECT(dobj));
|
|
|
|
object_unparent(OBJECT(dobj));
|
|
}
|
|
|
|
static void test_dummy_badenum(void)
|
|
{
|
|
Error *err = NULL;
|
|
Object *parent = object_get_objects_root();
|
|
Object *dobj =
|
|
object_new_with_props(TYPE_DUMMY,
|
|
parent,
|
|
"dummy0",
|
|
&err,
|
|
"bv", "yes",
|
|
"sv", "Hiss hiss hiss",
|
|
"av", "yeti",
|
|
NULL);
|
|
|
|
g_assert(dobj == NULL);
|
|
g_assert(err != NULL);
|
|
g_assert_cmpstr(error_get_pretty(err), ==,
|
|
"Invalid parameter 'yeti'");
|
|
|
|
g_assert(object_resolve_path_component(parent, "dummy0")
|
|
== NULL);
|
|
|
|
error_free(err);
|
|
}
|
|
|
|
|
|
static void test_dummy_getenum(void)
|
|
{
|
|
Error *err = NULL;
|
|
int val;
|
|
Object *parent = object_get_objects_root();
|
|
DummyObject *dobj = DUMMY_OBJECT(
|
|
object_new_with_props(TYPE_DUMMY,
|
|
parent,
|
|
"dummy0",
|
|
&err,
|
|
"av", "platypus",
|
|
NULL));
|
|
|
|
g_assert(err == NULL);
|
|
g_assert(dobj->av == DUMMY_PLATYPUS);
|
|
|
|
val = object_property_get_enum(OBJECT(dobj),
|
|
"av",
|
|
"DummyAnimal",
|
|
&err);
|
|
g_assert(err == NULL);
|
|
g_assert(val == DUMMY_PLATYPUS);
|
|
|
|
/* A bad enum type name */
|
|
val = object_property_get_enum(OBJECT(dobj),
|
|
"av",
|
|
"BadAnimal",
|
|
&err);
|
|
g_assert(err != NULL);
|
|
error_free(err);
|
|
err = NULL;
|
|
|
|
/* A non-enum property name */
|
|
val = object_property_get_enum(OBJECT(dobj),
|
|
"iv",
|
|
"DummyAnimal",
|
|
&err);
|
|
g_assert(err != NULL);
|
|
error_free(err);
|
|
|
|
object_unparent(OBJECT(dobj));
|
|
}
|
|
|
|
|
|
static void test_dummy_iterator(void)
|
|
{
|
|
Object *parent = object_get_objects_root();
|
|
DummyObject *dobj = DUMMY_OBJECT(
|
|
object_new_with_props(TYPE_DUMMY,
|
|
parent,
|
|
"dummy0",
|
|
&error_abort,
|
|
"bv", "yes",
|
|
"sv", "Hiss hiss hiss",
|
|
"av", "platypus",
|
|
NULL));
|
|
|
|
ObjectProperty *prop;
|
|
ObjectPropertyIterator *iter;
|
|
bool seenbv = false, seensv = false, seenav = false, seentype;
|
|
|
|
iter = object_property_iter_init(OBJECT(dobj));
|
|
while ((prop = object_property_iter_next(iter))) {
|
|
if (g_str_equal(prop->name, "bv")) {
|
|
seenbv = true;
|
|
} else if (g_str_equal(prop->name, "sv")) {
|
|
seensv = true;
|
|
} else if (g_str_equal(prop->name, "av")) {
|
|
seenav = true;
|
|
} else if (g_str_equal(prop->name, "type")) {
|
|
/* This prop comes from the base Object class */
|
|
seentype = true;
|
|
} else {
|
|
g_printerr("Found prop '%s'\n", prop->name);
|
|
g_assert_not_reached();
|
|
}
|
|
}
|
|
object_property_iter_free(iter);
|
|
g_assert(seenbv);
|
|
g_assert(seenav);
|
|
g_assert(seensv);
|
|
g_assert(seentype);
|
|
|
|
object_unparent(OBJECT(dobj));
|
|
}
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
g_test_init(&argc, &argv, NULL);
|
|
|
|
module_call_init(MODULE_INIT_QOM);
|
|
type_register_static(&dummy_info);
|
|
|
|
g_test_add_func("/qom/proplist/createlist", test_dummy_createlist);
|
|
g_test_add_func("/qom/proplist/createv", test_dummy_createv);
|
|
g_test_add_func("/qom/proplist/badenum", test_dummy_badenum);
|
|
g_test_add_func("/qom/proplist/getenum", test_dummy_getenum);
|
|
g_test_add_func("/qom/proplist/iterator", test_dummy_iterator);
|
|
|
|
return g_test_run();
|
|
}
|