Patchwork [3/3] qom: add unit test for Interfaces

login
register
mail settings
Submitter Anthony Liguori
Date June 13, 2012, 8:55 p.m.
Message ID <1339620902-4481-4-git-send-email-aliguori@us.ibm.com>
Download mbox | patch
Permalink /patch/164759/
State New
Headers show

Comments

Anthony Liguori - June 13, 2012, 8:55 p.m.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 tests/Makefile      |    5 +-
 tests/test-object.c |  222 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 226 insertions(+), 1 deletions(-)
 create mode 100644 tests/test-object.c
Peter A. G. Crosthwaite - June 16, 2012, 10:31 a.m.
On Thu, Jun 14, 2012 at 6:55 AM, Anthony Liguori <aliguori@us.ibm.com> wrote:
> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>

Reviewed-by: Peter A.G. Crosthwaite <peter.crosthwaite@petalogix.com>

> ---
>  tests/Makefile      |    5 +-
>  tests/test-object.c |  222 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 226 insertions(+), 1 deletions(-)
>  create mode 100644 tests/test-object.c
>
> diff --git a/tests/Makefile b/tests/Makefile
> index d66ab19..d1f979d 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -14,6 +14,7 @@ check-unit-y += tests/test-string-input-visitor$(EXESUF)
>  check-unit-y += tests/test-string-output-visitor$(EXESUF)
>  check-unit-y += tests/test-coroutine$(EXESUF)
>  check-unit-y += tests/test-visitor-serialization$(EXESUF)
> +check-unit-y += tests/test-object$(EXESUF)
>
>  check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
>
> @@ -32,7 +33,8 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
>        tests/test-coroutine.o tests/test-string-output-visitor.o \
>        tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \
>        tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \
> -       tests/test-qmp-commands.o tests/test-visitor-serialization.o
> +       tests/test-qmp-commands.o tests/test-visitor-serialization.o \
> +       tests/test-object.o
>
>  test-qapi-obj-y =  $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y)
>  test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o
> @@ -66,6 +68,7 @@ tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qap
>  tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y)
>  tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y)
>  tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y)
> +tests/test-object$(EXESUF): tests/test-object.o $(qom-obj-y) $(test-qapi-obj-y)
>
>  tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y)
>  tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y)
> diff --git a/tests/test-object.c b/tests/test-object.c
> new file mode 100644
> index 0000000..9f41da0
> --- /dev/null
> +++ b/tests/test-object.c
> @@ -0,0 +1,222 @@
> +/*
> + * QEMU Object Model unit test
> + *
> + * Copyright IBM, Corp. 2012
> + *
> + * Authors:
> + *  Anthony Liguori   <aliguori@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + */
> +#include "qemu/object.h"
> +#include "module.h"
> +
> +#define TYPE_HERBIVORE "herbivore"
> +
> +#define HERBIVORE_CLASS(klass) \
> +    OBJECT_CLASS_CHECK(HerbivoreClass, (klass), TYPE_HERBIVORE)
> +#define HERBIVORE_GET_CLASS(obj) \
> +    OBJECT_GET_CLASS(HerbivoreClass, (obj), TYPE_HERBIVORE)
> +#define HERBIVORE(obj) \
> +    INTERFACE_CHECK(Herbivore, (obj), TYPE_HERBIVORE)
> +
> +typedef struct Herbivore
> +{
> +    Object obj;
> +} Herbivore;

All this is doing is saying Herbivores are Objects right? A user cant
add anything to this struct given that interfaces are stateless so
could this be simplified to

typedef Object Herbivore;

?

> +
> +typedef struct HerbivoreClass
> +{
> +    InterfaceClass parent;
> +
> +    void (*feed_greens)(Herbivore *obj);
> +} HerbivoreClass;
> +
> +static void herbivore_feed_greens(Herbivore *herbie)
> +{
> +    HerbivoreClass *k = HERBIVORE_GET_CLASS(herbie);
> +
> +    k->feed_greens(herbie);
> +}
> +
> +static TypeInfo herbivore_info = {
> +    .name = TYPE_HERBIVORE,
> +    .parent = TYPE_INTERFACE,
> +    .class_size = sizeof(HerbivoreClass),
> +};
> +
> +#define TYPE_CARNIVORE "carnivore"
> +#define CARNIVORE_CLASS(klass) \
> +    OBJECT_CLASS_CHECK(CarnivoreClass, (klass), TYPE_CARNIVORE)
> +#define CARNIVORE_GET_CLASS(obj) \
> +    OBJECT_GET_CLASS(CarnivoreClass, (obj), TYPE_CARNIVORE)
> +#define CARNIVORE(obj) \
> +    INTERFACE_CHECK(Carnivore, (obj), TYPE_CARNIVORE)
> +
> +typedef struct Carnivore
> +{
> +    Object parent;
> +} Carnivore;
> +
> +typedef struct CarnivoreClass
> +{
> +    InterfaceClass parent;
> +
> +    void (*feed_bugs)(Carnivore *obj);
> +} CarnivoreClass;
> +
> +static void carnivore_feed_bugs(Carnivore *carnie)
> +{
> +    CarnivoreClass *k = CARNIVORE_GET_CLASS(carnie);
> +
> +    k->feed_bugs(carnie);
> +}
> +
> +static TypeInfo carnivore_info = {
> +    .name = TYPE_CARNIVORE,
> +    .parent = TYPE_INTERFACE,
> +    .class_size = sizeof(CarnivoreClass),
> +};
> +
> +#define TYPE_REPTILE "reptile"
> +#define REPTILE(obj) OBJECT_CHECK(Reptile, (obj), TYPE_REPTILE)
> +
> +typedef struct Reptile
> +{
> +    Object parent;
> +} Reptile;
> +
> +static TypeInfo reptile_info = {
> +    .name = TYPE_REPTILE,
> +    .instance_size = sizeof(Reptile),
> +    .abstract = true,
> +    .class_size = sizeof(ObjectClass),
> +};
> +
> +#define TYPE_LIZARD "lizard"
> +#define LIZARD(obj) OBJECT_CHECK(Lizard, (obj), TYPE_LIZARD)
> +
> +typedef struct Lizard
> +{
> +    Reptile parent;
> +} Lizard;
> +
> +static TypeInfo lizard_info = {
> +    .name = TYPE_LIZARD,
> +    .parent = TYPE_REPTILE,
> +    .instance_size = sizeof(Lizard),
> +    .abstract = true,
> +};
> +
> +#define TYPE_IGUANA "iguana"
> +#define IGUANA(obj) OBJECT_CHECK(Iguana, (obj), TYPE_IGUANA)
> +
> +typedef struct Iguana
> +{
> +    Lizard parent;
> +    int greens;
> +} Iguana;
> +
> +static void iguana_feed(Herbivore *herbie)
> +{
> +    Iguana *iggie = IGUANA(herbie);
> +
> +    iggie->greens++;
> +}
> +
> +static void iguana_class_initfn(ObjectClass *klass, void *data)
> +{
> +    HerbivoreClass *iface = HERBIVORE_CLASS(klass);
> +
> +    iface->feed_greens = iguana_feed;
> +}
> +
> +static TypeInfo iguana_info = {
> +    .name = TYPE_IGUANA,
> +    .parent = TYPE_LIZARD,
> +    .instance_size = sizeof(Iguana),
> +    .class_init = iguana_class_initfn,
> +    .interfaces = (InterfaceInfo[]) {
> +        { TYPE_HERBIVORE },
> +        { }
> +    },
> +};
> +
> +#define TYPE_BEARDED_DRAGON "bearded-dragon"
> +#define BEARDED_DRAGON(obj) OBJECT_CHECK(BeardedDragon, (obj), TYPE_BEARDED_DRAGON)
> +
> +typedef struct BeardedDragon
> +{
> +    Lizard parent;
> +    int bugs;
> +} BeardedDragon;
> +
> +static void bearded_dragon_feed(Carnivore *carnie)
> +{
> +    BeardedDragon *dragon = BEARDED_DRAGON(carnie);
> +
> +    dragon->bugs++;
> +}
> +
> +static void bearded_dragon_class_initfn(ObjectClass *klass, void *data)
> +{
> +    CarnivoreClass *iface = CARNIVORE_CLASS(klass);
> +
> +    iface->feed_bugs = bearded_dragon_feed;
> +}
> +
> +static TypeInfo bearded_dragon_info = {
> +    .name = TYPE_BEARDED_DRAGON,
> +    .parent = TYPE_LIZARD,
> +    .instance_size = sizeof(BeardedDragon),
> +    .class_init = bearded_dragon_class_initfn,
> +    .interfaces = (InterfaceInfo[]) {
> +        { TYPE_CARNIVORE },
> +        { }
> +    },
> +};
> +
> +static void basic_init(void)
> +{
> +    BeardedDragon dragon;
> +    Iguana iguana;
> +
> +    object_initialize(&dragon, TYPE_BEARDED_DRAGON);
> +
> +    g_assert_cmpint(dragon.bugs, ==, 0);
> +    carnivore_feed_bugs(CARNIVORE(&dragon));
> +    g_assert_cmpint(dragon.bugs, ==, 1);
> +
> +    object_finalize(&dragon);
> +
> +    object_initialize(&iguana, TYPE_IGUANA);
> +
> +    g_assert_cmpint(iguana.greens, ==, 0);
> +    herbivore_feed_greens(HERBIVORE(&iguana));
> +    g_assert_cmpint(iguana.greens, ==, 1);
> +
> +    object_finalize(&iguana);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +    g_test_init(&argc, &argv, NULL);
> +
> +    module_call_init(MODULE_INIT_QOM);
> +
> +    type_register_static(&carnivore_info);
> +    type_register_static(&herbivore_info);
> +
> +    type_register_static(&reptile_info);
> +    type_register_static(&lizard_info);
> +    type_register_static(&iguana_info);
> +    type_register_static(&bearded_dragon_info);
> +
> +    g_test_add_func("/basic/init", basic_init);
> +
> +    g_test_run();
> +
> +    return 0;
> +}
> --
> 1.7.5.4
>
Anthony Liguori - June 18, 2012, 1:26 p.m.
On 06/16/2012 05:31 AM, Peter Crosthwaite wrote:
> On Thu, Jun 14, 2012 at 6:55 AM, Anthony Liguori<aliguori@us.ibm.com>  wrote:
>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
>
> Reviewed-by: Peter A.G. Crosthwaite<peter.crosthwaite@petalogix.com>
>
>> ---
>>   tests/Makefile      |    5 +-
>>   tests/test-object.c |  222 +++++++++++++++++++++++++++++++++++++++++++++++++++
>>   2 files changed, 226 insertions(+), 1 deletions(-)
>>   create mode 100644 tests/test-object.c
>>
>> diff --git a/tests/Makefile b/tests/Makefile
>> index d66ab19..d1f979d 100644
>> --- a/tests/Makefile
>> +++ b/tests/Makefile
>> @@ -14,6 +14,7 @@ check-unit-y += tests/test-string-input-visitor$(EXESUF)
>>   check-unit-y += tests/test-string-output-visitor$(EXESUF)
>>   check-unit-y += tests/test-coroutine$(EXESUF)
>>   check-unit-y += tests/test-visitor-serialization$(EXESUF)
>> +check-unit-y += tests/test-object$(EXESUF)
>>
>>   check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
>>
>> @@ -32,7 +33,8 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
>>         tests/test-coroutine.o tests/test-string-output-visitor.o \
>>         tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \
>>         tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \
>> -       tests/test-qmp-commands.o tests/test-visitor-serialization.o
>> +       tests/test-qmp-commands.o tests/test-visitor-serialization.o \
>> +       tests/test-object.o
>>
>>   test-qapi-obj-y =  $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y)
>>   test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o
>> @@ -66,6 +68,7 @@ tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qap
>>   tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y)
>>   tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y)
>>   tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y)
>> +tests/test-object$(EXESUF): tests/test-object.o $(qom-obj-y) $(test-qapi-obj-y)
>>
>>   tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y)
>>   tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y)
>> diff --git a/tests/test-object.c b/tests/test-object.c
>> new file mode 100644
>> index 0000000..9f41da0
>> --- /dev/null
>> +++ b/tests/test-object.c
>> @@ -0,0 +1,222 @@
>> +/*
>> + * QEMU Object Model unit test
>> + *
>> + * Copyright IBM, Corp. 2012
>> + *
>> + * Authors:
>> + *  Anthony Liguori<aliguori@us.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>> + * See the COPYING file in the top-level directory.
>> + *
>> + */
>> +#include "qemu/object.h"
>> +#include "module.h"
>> +
>> +#define TYPE_HERBIVORE "herbivore"
>> +
>> +#define HERBIVORE_CLASS(klass) \
>> +    OBJECT_CLASS_CHECK(HerbivoreClass, (klass), TYPE_HERBIVORE)
>> +#define HERBIVORE_GET_CLASS(obj) \
>> +    OBJECT_GET_CLASS(HerbivoreClass, (obj), TYPE_HERBIVORE)
>> +#define HERBIVORE(obj) \
>> +    INTERFACE_CHECK(Herbivore, (obj), TYPE_HERBIVORE)
>> +
>> +typedef struct Herbivore
>> +{
>> +    Object obj;
>> +} Herbivore;
>
> All this is doing is saying Herbivores are Objects right? A user cant
> add anything to this struct given that interfaces are stateless so
> could this be simplified to
>
> typedef Object Herbivore;

This is admittedly a little wierd...

Interfaces don't exist as Objects in QOM.  They are just classes.  But it's very 
handy to be able to have a Herbivore type that you can cast objects to.

I probably need to respin this though.  INTERFACE_CHECK() asserts that an object 
implements the interface class and then just returns the obj and casts it to the 
dummy Interface object type.

A better approach would be to just teach object_dynamic_cast to do this for 
anythign that's an interface type.  That would fix the link problem you pointed 
out too.  I'll spin a v2.

Regards,

Anthony Liguori

>
> ?
>
>> +
>> +typedef struct HerbivoreClass
>> +{
>> +    InterfaceClass parent;
>> +
>> +    void (*feed_greens)(Herbivore *obj);
>> +} HerbivoreClass;
>> +
>> +static void herbivore_feed_greens(Herbivore *herbie)
>> +{
>> +    HerbivoreClass *k = HERBIVORE_GET_CLASS(herbie);
>> +
>> +    k->feed_greens(herbie);
>> +}
>> +
>> +static TypeInfo herbivore_info = {
>> +    .name = TYPE_HERBIVORE,
>> +    .parent = TYPE_INTERFACE,
>> +    .class_size = sizeof(HerbivoreClass),
>> +};
>> +
>> +#define TYPE_CARNIVORE "carnivore"
>> +#define CARNIVORE_CLASS(klass) \
>> +    OBJECT_CLASS_CHECK(CarnivoreClass, (klass), TYPE_CARNIVORE)
>> +#define CARNIVORE_GET_CLASS(obj) \
>> +    OBJECT_GET_CLASS(CarnivoreClass, (obj), TYPE_CARNIVORE)
>> +#define CARNIVORE(obj) \
>> +    INTERFACE_CHECK(Carnivore, (obj), TYPE_CARNIVORE)
>> +
>> +typedef struct Carnivore
>> +{
>> +    Object parent;
>> +} Carnivore;
>> +
>> +typedef struct CarnivoreClass
>> +{
>> +    InterfaceClass parent;
>> +
>> +    void (*feed_bugs)(Carnivore *obj);
>> +} CarnivoreClass;
>> +
>> +static void carnivore_feed_bugs(Carnivore *carnie)
>> +{
>> +    CarnivoreClass *k = CARNIVORE_GET_CLASS(carnie);
>> +
>> +    k->feed_bugs(carnie);
>> +}
>> +
>> +static TypeInfo carnivore_info = {
>> +    .name = TYPE_CARNIVORE,
>> +    .parent = TYPE_INTERFACE,
>> +    .class_size = sizeof(CarnivoreClass),
>> +};
>> +
>> +#define TYPE_REPTILE "reptile"
>> +#define REPTILE(obj) OBJECT_CHECK(Reptile, (obj), TYPE_REPTILE)
>> +
>> +typedef struct Reptile
>> +{
>> +    Object parent;
>> +} Reptile;
>> +
>> +static TypeInfo reptile_info = {
>> +    .name = TYPE_REPTILE,
>> +    .instance_size = sizeof(Reptile),
>> +    .abstract = true,
>> +    .class_size = sizeof(ObjectClass),
>> +};
>> +
>> +#define TYPE_LIZARD "lizard"
>> +#define LIZARD(obj) OBJECT_CHECK(Lizard, (obj), TYPE_LIZARD)
>> +
>> +typedef struct Lizard
>> +{
>> +    Reptile parent;
>> +} Lizard;
>> +
>> +static TypeInfo lizard_info = {
>> +    .name = TYPE_LIZARD,
>> +    .parent = TYPE_REPTILE,
>> +    .instance_size = sizeof(Lizard),
>> +    .abstract = true,
>> +};
>> +
>> +#define TYPE_IGUANA "iguana"
>> +#define IGUANA(obj) OBJECT_CHECK(Iguana, (obj), TYPE_IGUANA)
>> +
>> +typedef struct Iguana
>> +{
>> +    Lizard parent;
>> +    int greens;
>> +} Iguana;
>> +
>> +static void iguana_feed(Herbivore *herbie)
>> +{
>> +    Iguana *iggie = IGUANA(herbie);
>> +
>> +    iggie->greens++;
>> +}
>> +
>> +static void iguana_class_initfn(ObjectClass *klass, void *data)
>> +{
>> +    HerbivoreClass *iface = HERBIVORE_CLASS(klass);
>> +
>> +    iface->feed_greens = iguana_feed;
>> +}
>> +
>> +static TypeInfo iguana_info = {
>> +    .name = TYPE_IGUANA,
>> +    .parent = TYPE_LIZARD,
>> +    .instance_size = sizeof(Iguana),
>> +    .class_init = iguana_class_initfn,
>> +    .interfaces = (InterfaceInfo[]) {
>> +        { TYPE_HERBIVORE },
>> +        { }
>> +    },
>> +};
>> +
>> +#define TYPE_BEARDED_DRAGON "bearded-dragon"
>> +#define BEARDED_DRAGON(obj) OBJECT_CHECK(BeardedDragon, (obj), TYPE_BEARDED_DRAGON)
>> +
>> +typedef struct BeardedDragon
>> +{
>> +    Lizard parent;
>> +    int bugs;
>> +} BeardedDragon;
>> +
>> +static void bearded_dragon_feed(Carnivore *carnie)
>> +{
>> +    BeardedDragon *dragon = BEARDED_DRAGON(carnie);
>> +
>> +    dragon->bugs++;
>> +}
>> +
>> +static void bearded_dragon_class_initfn(ObjectClass *klass, void *data)
>> +{
>> +    CarnivoreClass *iface = CARNIVORE_CLASS(klass);
>> +
>> +    iface->feed_bugs = bearded_dragon_feed;
>> +}
>> +
>> +static TypeInfo bearded_dragon_info = {
>> +    .name = TYPE_BEARDED_DRAGON,
>> +    .parent = TYPE_LIZARD,
>> +    .instance_size = sizeof(BeardedDragon),
>> +    .class_init = bearded_dragon_class_initfn,
>> +    .interfaces = (InterfaceInfo[]) {
>> +        { TYPE_CARNIVORE },
>> +        { }
>> +    },
>> +};
>> +
>> +static void basic_init(void)
>> +{
>> +    BeardedDragon dragon;
>> +    Iguana iguana;
>> +
>> +    object_initialize(&dragon, TYPE_BEARDED_DRAGON);
>> +
>> +    g_assert_cmpint(dragon.bugs, ==, 0);
>> +    carnivore_feed_bugs(CARNIVORE(&dragon));
>> +    g_assert_cmpint(dragon.bugs, ==, 1);
>> +
>> +    object_finalize(&dragon);
>> +
>> +    object_initialize(&iguana, TYPE_IGUANA);
>> +
>> +    g_assert_cmpint(iguana.greens, ==, 0);
>> +    herbivore_feed_greens(HERBIVORE(&iguana));
>> +    g_assert_cmpint(iguana.greens, ==, 1);
>> +
>> +    object_finalize(&iguana);
>> +}
>> +
>> +int main(int argc, char **argv)
>> +{
>> +    g_test_init(&argc,&argv, NULL);
>> +
>> +    module_call_init(MODULE_INIT_QOM);
>> +
>> +    type_register_static(&carnivore_info);
>> +    type_register_static(&herbivore_info);
>> +
>> +    type_register_static(&reptile_info);
>> +    type_register_static(&lizard_info);
>> +    type_register_static(&iguana_info);
>> +    type_register_static(&bearded_dragon_info);
>> +
>> +    g_test_add_func("/basic/init", basic_init);
>> +
>> +    g_test_run();
>> +
>> +    return 0;
>> +}
>> --
>> 1.7.5.4
>>
>
Peter A. G. Crosthwaite - June 18, 2012, 1:46 p.m.
>>> +#define HERBIVORE(obj) \
>>> +    INTERFACE_CHECK(Herbivore, (obj), TYPE_HERBIVORE)
>>> +
>>> +typedef struct Herbivore
>>> +{
>>> +    Object obj;
>>> +} Herbivore;
>>
>>
>> All this is doing is saying Herbivores are Objects right? A user cant
>> add anything to this struct given that interfaces are stateless so
>> could this be simplified to
>>
>> typedef Object Herbivore;
>
>
> This is admittedly a little wierd...
>
> Interfaces don't exist as Objects in QOM.

Not in the sense that they used too, but all objects that implement an
interface are still OBJECTs just through the inheritance path of their
concrete class, which is the point of this struct yes?

 They are just classes.  But it's
> very handy to be able to have a Herbivore type that you can cast objects to.
>

Yes I agree in full, but the typedef definition is functionally
equivalent to what you have there, and removes the temptation to add
fields to the object type. Having a skeletal struct there gives the
illusion to readers that interface objects are in someway extensible.

> I probably need to respin this though.  INTERFACE_CHECK() asserts that an
> object implements the interface class and then just returns the obj and
> casts it to the dummy Interface object type.
>
> A better approach would be to just teach object_dynamic_cast to do this for
> anythign that's an interface type.  That would fix the link problem you
> pointed out too.  I'll spin a v2.

Please see my patch, I have a little 3 patch series up on the list.
that starts with your v1, does the axi-stream stuff then fixes that
bug.

Regards,
Peter

>
> Regards,
>
> Anthony Liguori
>
>>
>> ?
>>
>>> +
>>> +typedef struct HerbivoreClass
>>> +{
>>> +    InterfaceClass parent;
>>> +
>>> +    void (*feed_greens)(Herbivore *obj);
Andreas Färber - June 18, 2012, 1:51 p.m.
Am 18.06.2012 15:46, schrieb Peter Crosthwaite:
>>>> +#define HERBIVORE(obj) \
>>>> +    INTERFACE_CHECK(Herbivore, (obj), TYPE_HERBIVORE)
>>>> +
>>>> +typedef struct Herbivore
>>>> +{
>>>> +    Object obj;
>>>> +} Herbivore;
>>>
>>>
>>> All this is doing is saying Herbivores are Objects right? A user cant
>>> add anything to this struct given that interfaces are stateless so
>>> could this be simplified to
>>>
>>> typedef Object Herbivore;
>>
>>
>> This is admittedly a little wierd...
>>
>> Interfaces don't exist as Objects in QOM.
> 
> Not in the sense that they used too, but all objects that implement an
> interface are still OBJECTs just through the inheritance path of their
> concrete class, which is the point of this struct yes?
> 
>  They are just classes.  But it's
>> very handy to be able to have a Herbivore type that you can cast objects to.
>>
> 
> Yes I agree in full, but the typedef definition is functionally
> equivalent to what you have there, and removes the temptation to add
> fields to the object type. Having a skeletal struct there gives the
> illusion to readers that interface objects are in someway extensible.

Why have a typedef at all then? You can just use Object directly. If
that ever changes it leads to all kinds of problems (well, necessary
adjustments), as seen in the pci_host series.

Andreas
Anthony Liguori - June 18, 2012, 2:54 p.m.
On 06/18/2012 08:51 AM, Andreas Färber wrote:
> Am 18.06.2012 15:46, schrieb Peter Crosthwaite:
>>>>> +#define HERBIVORE(obj) \
>>>>> +    INTERFACE_CHECK(Herbivore, (obj), TYPE_HERBIVORE)
>>>>> +
>>>>> +typedef struct Herbivore
>>>>> +{
>>>>> +    Object obj;
>>>>> +} Herbivore;
>>>>
>>>>
>>>> All this is doing is saying Herbivores are Objects right? A user cant
>>>> add anything to this struct given that interfaces are stateless so
>>>> could this be simplified to
>>>>
>>>> typedef Object Herbivore;
>>>
>>>
>>> This is admittedly a little wierd...
>>>
>>> Interfaces don't exist as Objects in QOM.
>>
>> Not in the sense that they used too, but all objects that implement an
>> interface are still OBJECTs just through the inheritance path of their
>> concrete class, which is the point of this struct yes?

Yes, they are objects, which is why the struct just contains Object.  It's 
basically just a type-safe wrapper for Object.  Nothing more than that.

>>
>>   They are just classes.  But it's
>>> very handy to be able to have a Herbivore type that you can cast objects to.
>>>
>>
>> Yes I agree in full, but the typedef definition is functionally
>> equivalent to what you have there, and removes the temptation to add
>> fields to the object type. Having a skeletal struct there gives the
>> illusion to readers that interface objects are in someway extensible.

typedef struct Object Herbivore;

is a weak alias.  IOW, it's not an error to pass Object * instead of Herbivore 
*.  Worse yet, passing Carnivore * also is not an error.

The struct definition provides a strict alias.  We could wrap it in a macro to 
avoid confusing the reader I guess.

> Why have a typedef at all then? You can just use Object directly. If
> that ever changes it leads to all kinds of problems (well, necessary
> adjustments), as seen in the pci_host series.

Type safety.

Regards,

Anthony Liguori



>
> Andreas
>

Patch

diff --git a/tests/Makefile b/tests/Makefile
index d66ab19..d1f979d 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -14,6 +14,7 @@  check-unit-y += tests/test-string-input-visitor$(EXESUF)
 check-unit-y += tests/test-string-output-visitor$(EXESUF)
 check-unit-y += tests/test-coroutine$(EXESUF)
 check-unit-y += tests/test-visitor-serialization$(EXESUF)
+check-unit-y += tests/test-object$(EXESUF)
 
 check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
 
@@ -32,7 +33,8 @@  test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
 	tests/test-coroutine.o tests/test-string-output-visitor.o \
 	tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \
 	tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \
-	tests/test-qmp-commands.o tests/test-visitor-serialization.o
+	tests/test-qmp-commands.o tests/test-visitor-serialization.o \
+	tests/test-object.o
 
 test-qapi-obj-y =  $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y)
 test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o
@@ -66,6 +68,7 @@  tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qap
 tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y)
 tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y)
 tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y)
+tests/test-object$(EXESUF): tests/test-object.o $(qom-obj-y) $(test-qapi-obj-y)
 
 tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y)
 tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y)
diff --git a/tests/test-object.c b/tests/test-object.c
new file mode 100644
index 0000000..9f41da0
--- /dev/null
+++ b/tests/test-object.c
@@ -0,0 +1,222 @@ 
+/*
+ * QEMU Object Model unit test
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include "qemu/object.h"
+#include "module.h"
+
+#define TYPE_HERBIVORE "herbivore"
+
+#define HERBIVORE_CLASS(klass) \
+    OBJECT_CLASS_CHECK(HerbivoreClass, (klass), TYPE_HERBIVORE)
+#define HERBIVORE_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(HerbivoreClass, (obj), TYPE_HERBIVORE)
+#define HERBIVORE(obj) \
+    INTERFACE_CHECK(Herbivore, (obj), TYPE_HERBIVORE)
+
+typedef struct Herbivore
+{
+    Object obj;
+} Herbivore;
+
+typedef struct HerbivoreClass
+{
+    InterfaceClass parent;
+
+    void (*feed_greens)(Herbivore *obj);
+} HerbivoreClass;
+
+static void herbivore_feed_greens(Herbivore *herbie)
+{
+    HerbivoreClass *k = HERBIVORE_GET_CLASS(herbie);
+
+    k->feed_greens(herbie);
+}
+
+static TypeInfo herbivore_info = {
+    .name = TYPE_HERBIVORE,
+    .parent = TYPE_INTERFACE,
+    .class_size = sizeof(HerbivoreClass),
+};
+
+#define TYPE_CARNIVORE "carnivore"
+#define CARNIVORE_CLASS(klass) \
+    OBJECT_CLASS_CHECK(CarnivoreClass, (klass), TYPE_CARNIVORE)
+#define CARNIVORE_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(CarnivoreClass, (obj), TYPE_CARNIVORE)
+#define CARNIVORE(obj) \
+    INTERFACE_CHECK(Carnivore, (obj), TYPE_CARNIVORE)
+
+typedef struct Carnivore
+{
+    Object parent;
+} Carnivore;
+
+typedef struct CarnivoreClass
+{
+    InterfaceClass parent;
+
+    void (*feed_bugs)(Carnivore *obj);
+} CarnivoreClass;
+
+static void carnivore_feed_bugs(Carnivore *carnie)
+{
+    CarnivoreClass *k = CARNIVORE_GET_CLASS(carnie);
+
+    k->feed_bugs(carnie);
+}
+
+static TypeInfo carnivore_info = {
+    .name = TYPE_CARNIVORE,
+    .parent = TYPE_INTERFACE,
+    .class_size = sizeof(CarnivoreClass),
+};
+
+#define TYPE_REPTILE "reptile"
+#define REPTILE(obj) OBJECT_CHECK(Reptile, (obj), TYPE_REPTILE)
+
+typedef struct Reptile
+{
+    Object parent;
+} Reptile;
+
+static TypeInfo reptile_info = {
+    .name = TYPE_REPTILE,
+    .instance_size = sizeof(Reptile),
+    .abstract = true,
+    .class_size = sizeof(ObjectClass),
+};
+
+#define TYPE_LIZARD "lizard"
+#define LIZARD(obj) OBJECT_CHECK(Lizard, (obj), TYPE_LIZARD)
+
+typedef struct Lizard
+{
+    Reptile parent;
+} Lizard;
+
+static TypeInfo lizard_info = {
+    .name = TYPE_LIZARD,
+    .parent = TYPE_REPTILE,
+    .instance_size = sizeof(Lizard),
+    .abstract = true,
+};
+
+#define TYPE_IGUANA "iguana"
+#define IGUANA(obj) OBJECT_CHECK(Iguana, (obj), TYPE_IGUANA)
+
+typedef struct Iguana
+{
+    Lizard parent;
+    int greens;
+} Iguana;
+
+static void iguana_feed(Herbivore *herbie)
+{
+    Iguana *iggie = IGUANA(herbie);
+
+    iggie->greens++;
+}
+
+static void iguana_class_initfn(ObjectClass *klass, void *data)
+{
+    HerbivoreClass *iface = HERBIVORE_CLASS(klass);
+
+    iface->feed_greens = iguana_feed;
+}
+
+static TypeInfo iguana_info = {
+    .name = TYPE_IGUANA,
+    .parent = TYPE_LIZARD,
+    .instance_size = sizeof(Iguana),
+    .class_init = iguana_class_initfn,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_HERBIVORE },
+        { }
+    },
+};
+
+#define TYPE_BEARDED_DRAGON "bearded-dragon"
+#define BEARDED_DRAGON(obj) OBJECT_CHECK(BeardedDragon, (obj), TYPE_BEARDED_DRAGON)
+
+typedef struct BeardedDragon
+{
+    Lizard parent;
+    int bugs;
+} BeardedDragon;
+
+static void bearded_dragon_feed(Carnivore *carnie)
+{
+    BeardedDragon *dragon = BEARDED_DRAGON(carnie);
+
+    dragon->bugs++;
+}
+
+static void bearded_dragon_class_initfn(ObjectClass *klass, void *data)
+{
+    CarnivoreClass *iface = CARNIVORE_CLASS(klass);
+
+    iface->feed_bugs = bearded_dragon_feed;
+}
+
+static TypeInfo bearded_dragon_info = {
+    .name = TYPE_BEARDED_DRAGON,
+    .parent = TYPE_LIZARD,
+    .instance_size = sizeof(BeardedDragon),
+    .class_init = bearded_dragon_class_initfn,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_CARNIVORE },
+        { }
+    },
+};
+
+static void basic_init(void)
+{
+    BeardedDragon dragon;
+    Iguana iguana;
+
+    object_initialize(&dragon, TYPE_BEARDED_DRAGON);
+
+    g_assert_cmpint(dragon.bugs, ==, 0);
+    carnivore_feed_bugs(CARNIVORE(&dragon));
+    g_assert_cmpint(dragon.bugs, ==, 1);
+
+    object_finalize(&dragon);
+
+    object_initialize(&iguana, TYPE_IGUANA);
+
+    g_assert_cmpint(iguana.greens, ==, 0);
+    herbivore_feed_greens(HERBIVORE(&iguana));
+    g_assert_cmpint(iguana.greens, ==, 1);
+
+    object_finalize(&iguana);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    module_call_init(MODULE_INIT_QOM);
+
+    type_register_static(&carnivore_info);
+    type_register_static(&herbivore_info);
+
+    type_register_static(&reptile_info);
+    type_register_static(&lizard_info);
+    type_register_static(&iguana_info);
+    type_register_static(&bearded_dragon_info);
+
+    g_test_add_func("/basic/init", basic_init);
+
+    g_test_run();
+
+    return 0;
+}