qemu/tests/check-qom-proplist.c
<<
>>
Prefs
   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
  21#include "qemu/osdep.h"
  22#include <glib.h>
  23
  24#include "qapi/error.h"
  25#include "qom/object.h"
  26#include "qemu/module.h"
  27
  28
  29#define TYPE_DUMMY "qemu-dummy"
  30
  31typedef struct DummyObject DummyObject;
  32typedef struct DummyObjectClass DummyObjectClass;
  33
  34#define DUMMY_OBJECT(obj)                               \
  35    OBJECT_CHECK(DummyObject, (obj), TYPE_DUMMY)
  36
  37typedef enum DummyAnimal DummyAnimal;
  38
  39enum DummyAnimal {
  40    DUMMY_FROG,
  41    DUMMY_ALLIGATOR,
  42    DUMMY_PLATYPUS,
  43
  44    DUMMY_LAST,
  45};
  46
  47static const char *const dummy_animal_map[DUMMY_LAST + 1] = {
  48    [DUMMY_FROG] = "frog",
  49    [DUMMY_ALLIGATOR] = "alligator",
  50    [DUMMY_PLATYPUS] = "platypus",
  51    [DUMMY_LAST] = NULL,
  52};
  53
  54struct DummyObject {
  55    Object parent_obj;
  56
  57    bool bv;
  58    DummyAnimal av;
  59    char *sv;
  60};
  61
  62struct DummyObjectClass {
  63    ObjectClass parent_class;
  64};
  65
  66
  67static void dummy_set_bv(Object *obj,
  68                         bool value,
  69                         Error **errp)
  70{
  71    DummyObject *dobj = DUMMY_OBJECT(obj);
  72
  73    dobj->bv = value;
  74}
  75
  76static bool dummy_get_bv(Object *obj,
  77                         Error **errp)
  78{
  79    DummyObject *dobj = DUMMY_OBJECT(obj);
  80
  81    return dobj->bv;
  82}
  83
  84
  85static void dummy_set_av(Object *obj,
  86                         int value,
  87                         Error **errp)
  88{
  89    DummyObject *dobj = DUMMY_OBJECT(obj);
  90
  91    dobj->av = value;
  92}
  93
  94static int dummy_get_av(Object *obj,
  95                        Error **errp)
  96{
  97    DummyObject *dobj = DUMMY_OBJECT(obj);
  98
  99    return dobj->av;
 100}
 101
 102
 103static void dummy_set_sv(Object *obj,
 104                         const char *value,
 105                         Error **errp)
 106{
 107    DummyObject *dobj = DUMMY_OBJECT(obj);
 108
 109    g_free(dobj->sv);
 110    dobj->sv = g_strdup(value);
 111}
 112
 113static char *dummy_get_sv(Object *obj,
 114                          Error **errp)
 115{
 116    DummyObject *dobj = DUMMY_OBJECT(obj);
 117
 118    return g_strdup(dobj->sv);
 119}
 120
 121
 122static void dummy_init(Object *obj)
 123{
 124    object_property_add_bool(obj, "bv",
 125                             dummy_get_bv,
 126                             dummy_set_bv,
 127                             NULL);
 128}
 129
 130
 131static void dummy_class_init(ObjectClass *cls, void *data)
 132{
 133    object_class_property_add_bool(cls, "bv",
 134                                   dummy_get_bv,
 135                                   dummy_set_bv,
 136                                   NULL);
 137    object_class_property_add_str(cls, "sv",
 138                                  dummy_get_sv,
 139                                  dummy_set_sv,
 140                                  NULL);
 141    object_class_property_add_enum(cls, "av",
 142                                   "DummyAnimal",
 143                                   dummy_animal_map,
 144                                   dummy_get_av,
 145                                   dummy_set_av,
 146                                   NULL);
 147}
 148
 149
 150static void dummy_finalize(Object *obj)
 151{
 152    DummyObject *dobj = DUMMY_OBJECT(obj);
 153
 154    g_free(dobj->sv);
 155}
 156
 157
 158static const TypeInfo dummy_info = {
 159    .name          = TYPE_DUMMY,
 160    .parent        = TYPE_OBJECT,
 161    .instance_size = sizeof(DummyObject),
 162    .instance_init = dummy_init,
 163    .instance_finalize = dummy_finalize,
 164    .class_size = sizeof(DummyObjectClass),
 165    .class_init = dummy_class_init,
 166};
 167
 168
 169/*
 170 * The following 3 object classes are used to
 171 * simulate the kind of relationships seen in
 172 * qdev, which result in complex object
 173 * property destruction ordering.
 174 *
 175 * DummyDev has a 'bus' child to a DummyBus
 176 * DummyBus has a 'backend' child to a DummyBackend
 177 * DummyDev has a 'backend' link to DummyBackend
 178 *
 179 * When DummyDev is finalized, it unparents the
 180 * DummyBackend, which unparents the DummyDev
 181 * which deletes the 'backend' link from DummyDev
 182 * to DummyBackend. This illustrates that the
 183 * object_property_del_all() method needs to
 184 * cope with the list of properties being changed
 185 * while it iterates over them.
 186 */
 187typedef struct DummyDev DummyDev;
 188typedef struct DummyDevClass DummyDevClass;
 189typedef struct DummyBus DummyBus;
 190typedef struct DummyBusClass DummyBusClass;
 191typedef struct DummyBackend DummyBackend;
 192typedef struct DummyBackendClass DummyBackendClass;
 193
 194#define TYPE_DUMMY_DEV "qemu-dummy-dev"
 195#define TYPE_DUMMY_BUS "qemu-dummy-bus"
 196#define TYPE_DUMMY_BACKEND "qemu-dummy-backend"
 197
 198#define DUMMY_DEV(obj)                               \
 199    OBJECT_CHECK(DummyDev, (obj), TYPE_DUMMY_DEV)
 200#define DUMMY_BUS(obj)                               \
 201    OBJECT_CHECK(DummyBus, (obj), TYPE_DUMMY_BUS)
 202#define DUMMY_BACKEND(obj)                               \
 203    OBJECT_CHECK(DummyBackend, (obj), TYPE_DUMMY_BACKEND)
 204
 205struct DummyDev {
 206    Object parent_obj;
 207
 208    DummyBus *bus;
 209};
 210
 211struct DummyDevClass {
 212    ObjectClass parent_class;
 213};
 214
 215struct DummyBus {
 216    Object parent_obj;
 217
 218    DummyBackend *backend;
 219};
 220
 221struct DummyBusClass {
 222    ObjectClass parent_class;
 223};
 224
 225struct DummyBackend {
 226    Object parent_obj;
 227};
 228
 229struct DummyBackendClass {
 230    ObjectClass parent_class;
 231};
 232
 233
 234static void dummy_dev_init(Object *obj)
 235{
 236    DummyDev *dev = DUMMY_DEV(obj);
 237    DummyBus *bus = DUMMY_BUS(object_new(TYPE_DUMMY_BUS));
 238    DummyBackend *backend = DUMMY_BACKEND(object_new(TYPE_DUMMY_BACKEND));
 239
 240    object_property_add_child(obj, "bus", OBJECT(bus), NULL);
 241    dev->bus = bus;
 242    object_property_add_child(OBJECT(bus), "backend", OBJECT(backend), NULL);
 243    bus->backend = backend;
 244
 245    object_property_add_link(obj, "backend", TYPE_DUMMY_BACKEND,
 246                             (Object **)&bus->backend, NULL, 0, NULL);
 247}
 248
 249static void dummy_dev_unparent(Object *obj)
 250{
 251    DummyDev *dev = DUMMY_DEV(obj);
 252    object_unparent(OBJECT(dev->bus));
 253}
 254
 255static void dummy_dev_class_init(ObjectClass *klass, void *opaque)
 256{
 257    klass->unparent = dummy_dev_unparent;
 258}
 259
 260
 261static void dummy_bus_init(Object *obj)
 262{
 263}
 264
 265static void dummy_bus_unparent(Object *obj)
 266{
 267    DummyBus *bus = DUMMY_BUS(obj);
 268    object_property_del(obj->parent, "backend", NULL);
 269    object_unparent(OBJECT(bus->backend));
 270}
 271
 272static void dummy_bus_class_init(ObjectClass *klass, void *opaque)
 273{
 274    klass->unparent = dummy_bus_unparent;
 275}
 276
 277static void dummy_backend_init(Object *obj)
 278{
 279}
 280
 281
 282static const TypeInfo dummy_dev_info = {
 283    .name          = TYPE_DUMMY_DEV,
 284    .parent        = TYPE_OBJECT,
 285    .instance_size = sizeof(DummyDev),
 286    .instance_init = dummy_dev_init,
 287    .class_size = sizeof(DummyDevClass),
 288    .class_init = dummy_dev_class_init,
 289};
 290
 291static const TypeInfo dummy_bus_info = {
 292    .name          = TYPE_DUMMY_BUS,
 293    .parent        = TYPE_OBJECT,
 294    .instance_size = sizeof(DummyBus),
 295    .instance_init = dummy_bus_init,
 296    .class_size = sizeof(DummyBusClass),
 297    .class_init = dummy_bus_class_init,
 298};
 299
 300static const TypeInfo dummy_backend_info = {
 301    .name          = TYPE_DUMMY_BACKEND,
 302    .parent        = TYPE_OBJECT,
 303    .instance_size = sizeof(DummyBackend),
 304    .instance_init = dummy_backend_init,
 305    .class_size = sizeof(DummyBackendClass),
 306};
 307
 308
 309
 310static void test_dummy_createv(void)
 311{
 312    Error *err = NULL;
 313    Object *parent = object_get_objects_root();
 314    DummyObject *dobj = DUMMY_OBJECT(
 315        object_new_with_props(TYPE_DUMMY,
 316                              parent,
 317                              "dummy0",
 318                              &err,
 319                              "bv", "yes",
 320                              "sv", "Hiss hiss hiss",
 321                              "av", "platypus",
 322                              NULL));
 323
 324    g_assert(err == NULL);
 325    g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss");
 326    g_assert(dobj->bv == true);
 327    g_assert(dobj->av == DUMMY_PLATYPUS);
 328
 329    g_assert(object_resolve_path_component(parent, "dummy0")
 330             == OBJECT(dobj));
 331
 332    object_unparent(OBJECT(dobj));
 333}
 334
 335
 336static Object *new_helper(Error **errp,
 337                          Object *parent,
 338                          ...)
 339{
 340    va_list vargs;
 341    Object *obj;
 342
 343    va_start(vargs, parent);
 344    obj = object_new_with_propv(TYPE_DUMMY,
 345                                parent,
 346                                "dummy0",
 347                                errp,
 348                                vargs);
 349    va_end(vargs);
 350    return obj;
 351}
 352
 353static void test_dummy_createlist(void)
 354{
 355    Error *err = NULL;
 356    Object *parent = object_get_objects_root();
 357    DummyObject *dobj = DUMMY_OBJECT(
 358        new_helper(&err,
 359                   parent,
 360                   "bv", "yes",
 361                   "sv", "Hiss hiss hiss",
 362                   "av", "platypus",
 363                   NULL));
 364
 365    g_assert(err == NULL);
 366    g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss");
 367    g_assert(dobj->bv == true);
 368    g_assert(dobj->av == DUMMY_PLATYPUS);
 369
 370    g_assert(object_resolve_path_component(parent, "dummy0")
 371             == OBJECT(dobj));
 372
 373    object_unparent(OBJECT(dobj));
 374}
 375
 376static void test_dummy_badenum(void)
 377{
 378    Error *err = NULL;
 379    Object *parent = object_get_objects_root();
 380    Object *dobj =
 381        object_new_with_props(TYPE_DUMMY,
 382                              parent,
 383                              "dummy0",
 384                              &err,
 385                              "bv", "yes",
 386                              "sv", "Hiss hiss hiss",
 387                              "av", "yeti",
 388                              NULL);
 389
 390    g_assert(dobj == NULL);
 391    g_assert(err != NULL);
 392    g_assert_cmpstr(error_get_pretty(err), ==,
 393                    "Invalid parameter 'yeti'");
 394
 395    g_assert(object_resolve_path_component(parent, "dummy0")
 396             == NULL);
 397
 398    error_free(err);
 399}
 400
 401
 402static void test_dummy_getenum(void)
 403{
 404    Error *err = NULL;
 405    int val;
 406    Object *parent = object_get_objects_root();
 407    DummyObject *dobj = DUMMY_OBJECT(
 408        object_new_with_props(TYPE_DUMMY,
 409                         parent,
 410                         "dummy0",
 411                         &err,
 412                         "av", "platypus",
 413                         NULL));
 414
 415    g_assert(err == NULL);
 416    g_assert(dobj->av == DUMMY_PLATYPUS);
 417
 418    val = object_property_get_enum(OBJECT(dobj),
 419                                   "av",
 420                                   "DummyAnimal",
 421                                   &err);
 422    g_assert(err == NULL);
 423    g_assert(val == DUMMY_PLATYPUS);
 424
 425    /* A bad enum type name */
 426    val = object_property_get_enum(OBJECT(dobj),
 427                                   "av",
 428                                   "BadAnimal",
 429                                   &err);
 430    g_assert(err != NULL);
 431    error_free(err);
 432    err = NULL;
 433
 434    /* A non-enum property name */
 435    val = object_property_get_enum(OBJECT(dobj),
 436                                   "iv",
 437                                   "DummyAnimal",
 438                                   &err);
 439    g_assert(err != NULL);
 440    error_free(err);
 441
 442    object_unparent(OBJECT(dobj));
 443}
 444
 445
 446static void test_dummy_iterator(void)
 447{
 448    Object *parent = object_get_objects_root();
 449    DummyObject *dobj = DUMMY_OBJECT(
 450        object_new_with_props(TYPE_DUMMY,
 451                              parent,
 452                              "dummy0",
 453                              &error_abort,
 454                              "bv", "yes",
 455                              "sv", "Hiss hiss hiss",
 456                              "av", "platypus",
 457                              NULL));
 458
 459    ObjectProperty *prop;
 460    ObjectPropertyIterator iter;
 461    bool seenbv = false, seensv = false, seenav = false, seentype;
 462
 463    object_property_iter_init(&iter, OBJECT(dobj));
 464    while ((prop = object_property_iter_next(&iter))) {
 465        if (g_str_equal(prop->name, "bv")) {
 466            seenbv = true;
 467        } else if (g_str_equal(prop->name, "sv")) {
 468            seensv = true;
 469        } else if (g_str_equal(prop->name, "av")) {
 470            seenav = true;
 471        } else if (g_str_equal(prop->name, "type")) {
 472            /* This prop comes from the base Object class */
 473            seentype = true;
 474        } else {
 475            g_printerr("Found prop '%s'\n", prop->name);
 476            g_assert_not_reached();
 477        }
 478    }
 479    g_assert(seenbv);
 480    g_assert(seenav);
 481    g_assert(seensv);
 482    g_assert(seentype);
 483
 484    object_unparent(OBJECT(dobj));
 485}
 486
 487
 488static void test_dummy_delchild(void)
 489{
 490    Object *parent = object_get_objects_root();
 491    DummyDev *dev = DUMMY_DEV(
 492        object_new_with_props(TYPE_DUMMY_DEV,
 493                              parent,
 494                              "dev0",
 495                              &error_abort,
 496                              NULL));
 497
 498    object_unparent(OBJECT(dev));
 499}
 500
 501int main(int argc, char **argv)
 502{
 503    g_test_init(&argc, &argv, NULL);
 504
 505    module_call_init(MODULE_INIT_QOM);
 506    type_register_static(&dummy_info);
 507    type_register_static(&dummy_dev_info);
 508    type_register_static(&dummy_bus_info);
 509    type_register_static(&dummy_backend_info);
 510
 511    g_test_add_func("/qom/proplist/createlist", test_dummy_createlist);
 512    g_test_add_func("/qom/proplist/createv", test_dummy_createv);
 513    g_test_add_func("/qom/proplist/badenum", test_dummy_badenum);
 514    g_test_add_func("/qom/proplist/getenum", test_dummy_getenum);
 515    g_test_add_func("/qom/proplist/iterator", test_dummy_iterator);
 516    g_test_add_func("/qom/proplist/delchild", test_dummy_delchild);
 517
 518    return g_test_run();
 519}
 520