glib/gobject/tests/properties.c
Matthias Clasen f16045c9cf Add a test for notify emission ordering
This tests the ordering that was just documented.
See

https://bugzilla.gnome.org/show_bug.cgi?id=607016
2013-11-23 16:58:51 -05:00

315 lines
7.5 KiB
C

#include <stdlib.h>
#include <gstdio.h>
#include <glib-object.h>
typedef struct _TestObject {
GObject parent_instance;
gint foo;
gboolean bar;
gchar *baz;
} TestObject;
typedef struct _TestObjectClass {
GObjectClass parent_class;
} TestObjectClass;
enum { PROP_0, PROP_FOO, PROP_BAR, PROP_BAZ, N_PROPERTIES };
static GParamSpec *properties[N_PROPERTIES] = { NULL, };
static GType test_object_get_type (void);
G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT);
static void
test_object_set_foo (TestObject *obj,
gint foo)
{
if (obj->foo != foo)
{
obj->foo = foo;
g_assert (properties[PROP_FOO] != NULL);
g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_FOO]);
}
}
static void
test_object_set_bar (TestObject *obj,
gboolean bar)
{
bar = !!bar;
if (obj->bar != bar)
{
obj->bar = bar;
g_assert (properties[PROP_BAR] != NULL);
g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_BAR]);
}
}
static void
test_object_set_baz (TestObject *obj,
const gchar *baz)
{
if (g_strcmp0 (obj->baz, baz) != 0)
{
g_free (obj->baz);
obj->baz = g_strdup (baz);
g_assert (properties[PROP_BAZ] != NULL);
g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_BAZ]);
}
}
static void
test_object_finalize (GObject *gobject)
{
g_free (((TestObject *) gobject)->baz);
/* When the ref_count of an object is zero it is still
* possible to notify the property, but it should do
* nothing and silenty quit (bug #705570)
*/
g_object_notify (gobject, "foo");
g_object_notify_by_pspec (gobject, properties[PROP_BAR]);
G_OBJECT_CLASS (test_object_parent_class)->finalize (gobject);
}
static void
test_object_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
TestObject *tobj = (TestObject *) gobject;
g_assert_cmpint (prop_id, !=, 0);
g_assert_cmpint (prop_id, !=, N_PROPERTIES);
g_assert (pspec == properties[prop_id]);
switch (prop_id)
{
case PROP_FOO:
test_object_set_foo (tobj, g_value_get_int (value));
break;
case PROP_BAR:
test_object_set_bar (tobj, g_value_get_boolean (value));
break;
case PROP_BAZ:
test_object_set_baz (tobj, g_value_get_string (value));
break;
default:
g_assert_not_reached ();
}
}
static void
test_object_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
TestObject *tobj = (TestObject *) gobject;
g_assert_cmpint (prop_id, !=, 0);
g_assert_cmpint (prop_id, !=, N_PROPERTIES);
g_assert (pspec == properties[prop_id]);
switch (prop_id)
{
case PROP_FOO:
g_value_set_int (value, tobj->foo);
break;
case PROP_BAR:
g_value_set_boolean (value, tobj->bar);
break;
case PROP_BAZ:
g_value_set_string (value, tobj->baz);
break;
default:
g_assert_not_reached ();
}
}
static void
test_object_class_init (TestObjectClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
properties[PROP_FOO] = g_param_spec_int ("foo", "Foo", "Foo",
-1, G_MAXINT,
0,
G_PARAM_READWRITE);
properties[PROP_BAR] = g_param_spec_boolean ("bar", "Bar", "Bar",
FALSE,
G_PARAM_READWRITE);
properties[PROP_BAZ] = g_param_spec_string ("baz", "Baz", "Baz",
NULL,
G_PARAM_READWRITE);
gobject_class->set_property = test_object_set_property;
gobject_class->get_property = test_object_get_property;
gobject_class->finalize = test_object_finalize;
g_object_class_install_properties (gobject_class, N_PROPERTIES, properties);
}
static void
test_object_init (TestObject *self)
{
self->foo = 42;
self->bar = TRUE;
self->baz = g_strdup ("Hello");
}
static void
properties_install (void)
{
TestObject *obj = g_object_new (test_object_get_type (), NULL);
GParamSpec *pspec;
g_assert (properties[PROP_FOO] != NULL);
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "foo");
g_assert (properties[PROP_FOO] == pspec);
g_object_unref (obj);
}
typedef struct {
const gchar *name;
GParamSpec *pspec;
} TestNotifyClosure;
static void
on_notify (GObject *gobject,
GParamSpec *pspec,
TestNotifyClosure *clos)
{
g_assert (clos->pspec == pspec);
g_assert_cmpstr (clos->name, ==, pspec->name);
}
static void
properties_notify (void)
{
TestObject *obj = g_object_new (test_object_get_type (), NULL);
TestNotifyClosure clos;
g_assert (properties[PROP_FOO] != NULL);
clos.name = "foo";
clos.pspec = properties[PROP_FOO];
g_signal_connect (obj, "notify", G_CALLBACK (on_notify), &clos);
g_object_set (obj, "foo", 47, NULL);
g_object_unref (obj);
}
typedef struct {
GParamSpec *pspec[3];
gint pos;
} Notifys;
static void
on_notify2 (GObject *gobject,
GParamSpec *pspec,
Notifys *n)
{
g_assert (n->pspec[n->pos] == pspec);
n->pos++;
}
static void
properties_notify_queue (void)
{
TestObject *obj = g_object_new (test_object_get_type (), NULL);
Notifys n;
g_assert (properties[PROP_FOO] != NULL);
n.pspec[0] = properties[PROP_BAZ];
n.pspec[1] = properties[PROP_BAR];
n.pspec[2] = properties[PROP_FOO];
n.pos = 0;
g_signal_connect (obj, "notify", G_CALLBACK (on_notify2), &n);
g_object_freeze_notify (G_OBJECT (obj));
g_object_set (obj, "foo", 47, NULL);
g_object_set (obj, "bar", TRUE, "foo", 42, "baz", "abc", NULL);
g_object_thaw_notify (G_OBJECT (obj));
g_assert (n.pos == 3);
g_object_unref (obj);
}
static void
properties_construct (void)
{
TestObject *obj;
gint val;
gboolean b;
gchar *s;
g_test_bug ("630357");
/* more than 16 args triggers a realloc in g_object_new_valist() */
obj = g_object_new (test_object_get_type (),
"foo", 1,
"foo", 2,
"foo", 3,
"foo", 4,
"foo", 5,
"bar", FALSE,
"foo", 6,
"foo", 7,
"foo", 8,
"foo", 9,
"foo", 10,
"baz", "boo",
"foo", 11,
"foo", 12,
"foo", 13,
"foo", 14,
"foo", 15,
"foo", 16,
"foo", 17,
"foo", 18,
NULL);
g_object_get (obj, "foo", &val, NULL);
g_assert (val == 18);
g_object_get (obj, "bar", &b, NULL);
g_assert (!b);
g_object_get (obj, "baz", &s, NULL);
g_assert_cmpstr (s, ==, "boo");
g_free (s);
g_object_unref (obj);
}
int
main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);
g_test_bug_base ("http://bugzilla.gnome.org/");
g_test_add_func ("/properties/install", properties_install);
g_test_add_func ("/properties/notify", properties_notify);
g_test_add_func ("/properties/notify-queue", properties_notify_queue);
g_test_add_func ("/properties/construct", properties_construct);
return g_test_run ();
}