Add a test for notify emission ordering
[platform/upstream/glib.git] / gobject / tests / properties.c
1 #include <stdlib.h>
2 #include <gstdio.h>
3 #include <glib-object.h>
4
5 typedef struct _TestObject {
6   GObject parent_instance;
7   gint foo;
8   gboolean bar;
9   gchar *baz;
10 } TestObject;
11
12 typedef struct _TestObjectClass {
13   GObjectClass parent_class;
14 } TestObjectClass;
15
16 enum { PROP_0, PROP_FOO, PROP_BAR, PROP_BAZ, N_PROPERTIES };
17
18 static GParamSpec *properties[N_PROPERTIES] = { NULL, };
19
20 static GType test_object_get_type (void);
21 G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT);
22
23 static void
24 test_object_set_foo (TestObject *obj,
25                      gint        foo)
26 {
27   if (obj->foo != foo)
28     {
29       obj->foo = foo;
30
31       g_assert (properties[PROP_FOO] != NULL);
32       g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_FOO]);
33     }
34 }
35
36 static void
37 test_object_set_bar (TestObject *obj,
38                      gboolean    bar)
39 {
40   bar = !!bar;
41
42   if (obj->bar != bar)
43     {
44       obj->bar = bar;
45
46       g_assert (properties[PROP_BAR] != NULL);
47       g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_BAR]);
48     }
49 }
50
51 static void
52 test_object_set_baz (TestObject  *obj,
53                      const gchar *baz)
54 {
55   if (g_strcmp0 (obj->baz, baz) != 0)
56     {
57       g_free (obj->baz);
58       obj->baz = g_strdup (baz);
59
60       g_assert (properties[PROP_BAZ] != NULL);
61       g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_BAZ]);
62     }
63 }
64
65 static void
66 test_object_finalize (GObject *gobject)
67 {
68   g_free (((TestObject *) gobject)->baz);
69
70   /* When the ref_count of an object is zero it is still
71    * possible to notify the property, but it should do
72    * nothing and silenty quit (bug #705570)
73    */
74   g_object_notify (gobject, "foo");
75   g_object_notify_by_pspec (gobject, properties[PROP_BAR]);
76
77   G_OBJECT_CLASS (test_object_parent_class)->finalize (gobject);
78 }
79
80 static void
81 test_object_set_property (GObject *gobject,
82                           guint prop_id,
83                           const GValue *value,
84                           GParamSpec *pspec)
85 {
86   TestObject *tobj = (TestObject *) gobject;
87
88   g_assert_cmpint (prop_id, !=, 0);
89   g_assert_cmpint (prop_id, !=, N_PROPERTIES);
90   g_assert (pspec == properties[prop_id]);
91
92   switch (prop_id)
93     {
94     case PROP_FOO:
95       test_object_set_foo (tobj, g_value_get_int (value));
96       break;
97
98     case PROP_BAR:
99       test_object_set_bar (tobj, g_value_get_boolean (value));
100       break;
101
102     case PROP_BAZ:
103       test_object_set_baz (tobj, g_value_get_string (value));
104       break;
105
106     default:
107       g_assert_not_reached ();
108     }
109 }
110
111 static void
112 test_object_get_property (GObject *gobject,
113                           guint prop_id,
114                           GValue *value,
115                           GParamSpec *pspec)
116 {
117   TestObject *tobj = (TestObject *) gobject;
118
119   g_assert_cmpint (prop_id, !=, 0);
120   g_assert_cmpint (prop_id, !=, N_PROPERTIES);
121   g_assert (pspec == properties[prop_id]);
122
123   switch (prop_id)
124     {
125     case PROP_FOO:
126       g_value_set_int (value, tobj->foo);
127       break;
128
129     case PROP_BAR:
130       g_value_set_boolean (value, tobj->bar);
131       break;
132
133     case PROP_BAZ:
134       g_value_set_string (value, tobj->baz);
135       break;
136
137     default:
138       g_assert_not_reached ();
139     }
140 }
141
142 static void
143 test_object_class_init (TestObjectClass *klass)
144 {
145   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
146
147   properties[PROP_FOO] = g_param_spec_int ("foo", "Foo", "Foo",
148                                            -1, G_MAXINT,
149                                            0,
150                                            G_PARAM_READWRITE);
151   properties[PROP_BAR] = g_param_spec_boolean ("bar", "Bar", "Bar",
152                                                FALSE,
153                                                G_PARAM_READWRITE);
154   properties[PROP_BAZ] = g_param_spec_string ("baz", "Baz", "Baz",
155                                               NULL,
156                                               G_PARAM_READWRITE);
157
158   gobject_class->set_property = test_object_set_property;
159   gobject_class->get_property = test_object_get_property;
160   gobject_class->finalize = test_object_finalize;
161
162   g_object_class_install_properties (gobject_class, N_PROPERTIES, properties);
163 }
164
165 static void
166 test_object_init (TestObject *self)
167 {
168   self->foo = 42;
169   self->bar = TRUE;
170   self->baz = g_strdup ("Hello");
171 }
172
173 static void
174 properties_install (void)
175 {
176   TestObject *obj = g_object_new (test_object_get_type (), NULL);
177   GParamSpec *pspec;
178
179   g_assert (properties[PROP_FOO] != NULL);
180
181   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "foo");
182   g_assert (properties[PROP_FOO] == pspec);
183
184   g_object_unref (obj);
185 }
186
187 typedef struct {
188   const gchar *name;
189   GParamSpec *pspec;
190 } TestNotifyClosure;
191
192 static void
193 on_notify (GObject           *gobject,
194            GParamSpec        *pspec,
195            TestNotifyClosure *clos)
196 {
197   g_assert (clos->pspec == pspec);
198   g_assert_cmpstr (clos->name, ==, pspec->name);
199 }
200
201 static void
202 properties_notify (void)
203 {
204   TestObject *obj = g_object_new (test_object_get_type (), NULL);
205   TestNotifyClosure clos;
206
207   g_assert (properties[PROP_FOO] != NULL);
208
209   clos.name = "foo";
210   clos.pspec = properties[PROP_FOO];
211
212   g_signal_connect (obj, "notify", G_CALLBACK (on_notify), &clos);
213   g_object_set (obj, "foo", 47, NULL);
214
215   g_object_unref (obj);
216 }
217
218 typedef struct {
219   GParamSpec *pspec[3];
220   gint pos;
221 } Notifys;
222
223 static void
224 on_notify2 (GObject    *gobject,
225             GParamSpec *pspec,
226             Notifys    *n)
227 {
228   g_assert (n->pspec[n->pos] == pspec);
229   n->pos++;
230 }
231
232 static void
233 properties_notify_queue (void)
234 {
235   TestObject *obj = g_object_new (test_object_get_type (), NULL);
236   Notifys n;
237
238   g_assert (properties[PROP_FOO] != NULL);
239
240   n.pspec[0] = properties[PROP_BAZ];
241   n.pspec[1] = properties[PROP_BAR];
242   n.pspec[2] = properties[PROP_FOO];
243   n.pos = 0;
244
245   g_signal_connect (obj, "notify", G_CALLBACK (on_notify2), &n);
246
247   g_object_freeze_notify (G_OBJECT (obj));
248   g_object_set (obj, "foo", 47, NULL);
249   g_object_set (obj, "bar", TRUE, "foo", 42, "baz", "abc", NULL);
250   g_object_thaw_notify (G_OBJECT (obj));
251   g_assert (n.pos == 3);
252
253   g_object_unref (obj);
254 }
255
256 static void
257 properties_construct (void)
258 {
259   TestObject *obj;
260   gint val;
261   gboolean b;
262   gchar *s;
263
264   g_test_bug ("630357");
265
266   /* more than 16 args triggers a realloc in g_object_new_valist() */
267   obj = g_object_new (test_object_get_type (),
268                       "foo", 1,
269                       "foo", 2,
270                       "foo", 3,
271                       "foo", 4,
272                       "foo", 5,
273                       "bar", FALSE,
274                       "foo", 6,
275                       "foo", 7,
276                       "foo", 8,
277                       "foo", 9,
278                       "foo", 10,
279                       "baz", "boo",
280                       "foo", 11,
281                       "foo", 12,
282                       "foo", 13,
283                       "foo", 14,
284                       "foo", 15,
285                       "foo", 16,
286                       "foo", 17,
287                       "foo", 18,
288                       NULL);
289
290   g_object_get (obj, "foo", &val, NULL);
291   g_assert (val == 18);
292   g_object_get (obj, "bar", &b, NULL);
293   g_assert (!b);
294   g_object_get (obj, "baz", &s, NULL);
295   g_assert_cmpstr (s, ==, "boo");
296   g_free (s);
297
298   g_object_unref (obj);
299 }
300
301 int
302 main (int argc, char *argv[])
303 {
304   g_test_init (&argc, &argv, NULL);
305
306   g_test_bug_base ("http://bugzilla.gnome.org/");
307
308   g_test_add_func ("/properties/install", properties_install);
309   g_test_add_func ("/properties/notify", properties_notify);
310   g_test_add_func ("/properties/notify-queue", properties_notify_queue);
311   g_test_add_func ("/properties/construct", properties_construct);
312
313   return g_test_run ();
314 }