gobject: Handle ref_count==0 in notify_by_pspec
[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 static void
219 properties_construct (void)
220 {
221   TestObject *obj;
222   gint val;
223   gboolean b;
224   gchar *s;
225
226   g_test_bug ("630357");
227
228   /* more than 16 args triggers a realloc in g_object_new_valist() */
229   obj = g_object_new (test_object_get_type (),
230                       "foo", 1,
231                       "foo", 2,
232                       "foo", 3,
233                       "foo", 4,
234                       "foo", 5,
235                       "bar", FALSE,
236                       "foo", 6,
237                       "foo", 7,
238                       "foo", 8,
239                       "foo", 9,
240                       "foo", 10,
241                       "baz", "boo",
242                       "foo", 11,
243                       "foo", 12,
244                       "foo", 13,
245                       "foo", 14,
246                       "foo", 15,
247                       "foo", 16,
248                       "foo", 17,
249                       "foo", 18,
250                       NULL);
251
252   g_object_get (obj, "foo", &val, NULL);
253   g_assert (val == 18);
254   g_object_get (obj, "bar", &b, NULL);
255   g_assert (!b);
256   g_object_get (obj, "baz", &s, NULL);
257   g_assert_cmpstr (s, ==, "boo");
258   g_free (s);
259
260   g_object_unref (obj);
261 }
262
263 int
264 main (int argc, char *argv[])
265 {
266   g_test_init (&argc, &argv, NULL);
267
268   g_test_bug_base ("http://bugzilla.gnome.org/");
269
270   g_test_add_func ("/properties/install", properties_install);
271   g_test_add_func ("/properties/notify", properties_notify);
272   g_test_add_func ("/properties/construct", properties_construct);
273
274   return g_test_run ();
275 }