Imported Upstream version 2.53.1
[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   gchar *quux;
11 } TestObject;
12
13 typedef struct _TestObjectClass {
14   GObjectClass parent_class;
15 } TestObjectClass;
16
17 enum { PROP_0, PROP_FOO, PROP_BAR, PROP_BAZ, PROP_QUUX, N_PROPERTIES };
18
19 static GParamSpec *properties[N_PROPERTIES] = { NULL, };
20
21 static GType test_object_get_type (void);
22 G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT)
23
24 static void
25 test_object_set_foo (TestObject *obj,
26                      gint        foo)
27 {
28   if (obj->foo != foo)
29     {
30       obj->foo = foo;
31
32       g_assert (properties[PROP_FOO] != NULL);
33       g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_FOO]);
34     }
35 }
36
37 static void
38 test_object_set_bar (TestObject *obj,
39                      gboolean    bar)
40 {
41   bar = !!bar;
42
43   if (obj->bar != bar)
44     {
45       obj->bar = bar;
46
47       g_assert (properties[PROP_BAR] != NULL);
48       g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_BAR]);
49     }
50 }
51
52 static void
53 test_object_set_baz (TestObject  *obj,
54                      const gchar *baz)
55 {
56   if (g_strcmp0 (obj->baz, baz) != 0)
57     {
58       g_free (obj->baz);
59       obj->baz = g_strdup (baz);
60
61       g_assert (properties[PROP_BAZ] != NULL);
62       g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_BAZ]);
63     }
64 }
65
66 static void
67 test_object_set_quux (TestObject  *obj,
68                       const gchar *quux)
69 {
70   if (g_strcmp0 (obj->quux, quux) != 0)
71     {
72       g_free (obj->quux);
73       obj->quux = g_strdup (quux);
74
75       g_assert (properties[PROP_QUUX] != NULL);
76       g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_QUUX]);
77     }
78 }
79
80 static void
81 test_object_finalize (GObject *gobject)
82 {
83   g_free (((TestObject *) gobject)->baz);
84
85   /* When the ref_count of an object is zero it is still
86    * possible to notify the property, but it should do
87    * nothing and silenty quit (bug #705570)
88    */
89   g_object_notify (gobject, "foo");
90   g_object_notify_by_pspec (gobject, properties[PROP_BAR]);
91
92   G_OBJECT_CLASS (test_object_parent_class)->finalize (gobject);
93 }
94
95 static void
96 test_object_set_property (GObject *gobject,
97                           guint prop_id,
98                           const GValue *value,
99                           GParamSpec *pspec)
100 {
101   TestObject *tobj = (TestObject *) gobject;
102
103   g_assert_cmpint (prop_id, !=, 0);
104   g_assert_cmpint (prop_id, !=, N_PROPERTIES);
105   g_assert (pspec == properties[prop_id]);
106
107   switch (prop_id)
108     {
109     case PROP_FOO:
110       test_object_set_foo (tobj, g_value_get_int (value));
111       break;
112
113     case PROP_BAR:
114       test_object_set_bar (tobj, g_value_get_boolean (value));
115       break;
116
117     case PROP_BAZ:
118       test_object_set_baz (tobj, g_value_get_string (value));
119       break;
120
121     case PROP_QUUX:
122       test_object_set_quux (tobj, g_value_get_string (value));
123       break;
124
125     default:
126       g_assert_not_reached ();
127     }
128 }
129
130 static void
131 test_object_get_property (GObject *gobject,
132                           guint prop_id,
133                           GValue *value,
134                           GParamSpec *pspec)
135 {
136   TestObject *tobj = (TestObject *) gobject;
137
138   g_assert_cmpint (prop_id, !=, 0);
139   g_assert_cmpint (prop_id, !=, N_PROPERTIES);
140   g_assert (pspec == properties[prop_id]);
141
142   switch (prop_id)
143     {
144     case PROP_FOO:
145       g_value_set_int (value, tobj->foo);
146       break;
147
148     case PROP_BAR:
149       g_value_set_boolean (value, tobj->bar);
150       break;
151
152     case PROP_BAZ:
153       g_value_set_string (value, tobj->baz);
154       break;
155
156     case PROP_QUUX:
157       g_value_set_string (value, tobj->quux);
158       break;
159
160     default:
161       g_assert_not_reached ();
162     }
163 }
164
165 static void
166 test_object_class_init (TestObjectClass *klass)
167 {
168   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
169
170   properties[PROP_FOO] = g_param_spec_int ("foo", "Foo", "Foo",
171                                            -1, G_MAXINT,
172                                            0,
173                                            G_PARAM_READWRITE);
174   properties[PROP_BAR] = g_param_spec_boolean ("bar", "Bar", "Bar",
175                                                FALSE,
176                                                G_PARAM_READWRITE);
177   properties[PROP_BAZ] = g_param_spec_string ("baz", "Baz", "Baz",
178                                               NULL,
179                                               G_PARAM_READWRITE);
180   properties[PROP_QUUX] = g_param_spec_string ("quux", "quux", "quux",
181                                                NULL,
182                                                G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
183
184   gobject_class->set_property = test_object_set_property;
185   gobject_class->get_property = test_object_get_property;
186   gobject_class->finalize = test_object_finalize;
187
188   g_object_class_install_properties (gobject_class, N_PROPERTIES, properties);
189 }
190
191 static void
192 test_object_init (TestObject *self)
193 {
194   self->foo = 42;
195   self->bar = TRUE;
196   self->baz = g_strdup ("Hello");
197   self->quux = NULL;
198 }
199
200 static void
201 properties_install (void)
202 {
203   TestObject *obj = g_object_new (test_object_get_type (), NULL);
204   GParamSpec *pspec;
205
206   g_assert (properties[PROP_FOO] != NULL);
207
208   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "foo");
209   g_assert (properties[PROP_FOO] == pspec);
210
211   g_object_unref (obj);
212 }
213
214 typedef struct {
215   const gchar *name;
216   GParamSpec *pspec;
217   gboolean    fired;
218 } TestNotifyClosure;
219
220 static void
221 on_notify (GObject           *gobject,
222            GParamSpec        *pspec,
223            TestNotifyClosure *clos)
224 {
225   g_assert (clos->pspec == pspec);
226   g_assert_cmpstr (clos->name, ==, pspec->name);
227   clos->fired = TRUE;
228 }
229
230 static void
231 properties_notify (void)
232 {
233   TestObject *obj = g_object_new (test_object_get_type (), NULL);
234   TestNotifyClosure clos;
235
236   g_assert (properties[PROP_FOO] != NULL);
237   g_assert (properties[PROP_QUUX] != NULL);
238   g_signal_connect (obj, "notify", G_CALLBACK (on_notify), &clos);
239
240   clos.name = "foo";
241   clos.pspec = properties[PROP_FOO];
242
243   clos.fired = FALSE;
244   g_object_set (obj, "foo", 47, NULL);
245   g_assert (clos.fired);
246
247   clos.name = "baz";
248   clos.pspec = properties[PROP_BAZ];
249
250   clos.fired = FALSE;
251   g_object_set (obj, "baz", "something new", NULL);
252   g_assert (clos.fired);
253
254   /* baz lacks explicit notify, so we will see this twice */
255   clos.fired = FALSE;
256   g_object_set (obj, "baz", "something new", NULL);
257   g_assert (clos.fired);
258
259   /* quux on the other hand, ... */
260   clos.name = "quux";
261   clos.pspec = properties[PROP_QUUX];
262
263   clos.fired = FALSE;
264   g_object_set (obj, "quux", "something new", NULL);
265   g_assert (clos.fired);
266
267   /* no change; no notify */
268   clos.fired = FALSE;
269   g_object_set (obj, "quux", "something new", NULL);
270   g_assert (!clos.fired);
271
272
273   g_object_unref (obj);
274 }
275
276 typedef struct {
277   GParamSpec *pspec[3];
278   gint pos;
279 } Notifys;
280
281 static void
282 on_notify2 (GObject    *gobject,
283             GParamSpec *pspec,
284             Notifys    *n)
285 {
286   g_assert (n->pspec[n->pos] == pspec);
287   n->pos++;
288 }
289
290 static void
291 properties_notify_queue (void)
292 {
293   TestObject *obj = g_object_new (test_object_get_type (), NULL);
294   Notifys n;
295
296   g_assert (properties[PROP_FOO] != NULL);
297
298   n.pspec[0] = properties[PROP_BAZ];
299   n.pspec[1] = properties[PROP_BAR];
300   n.pspec[2] = properties[PROP_FOO];
301   n.pos = 0;
302
303   g_signal_connect (obj, "notify", G_CALLBACK (on_notify2), &n);
304
305   g_object_freeze_notify (G_OBJECT (obj));
306   g_object_set (obj, "foo", 47, NULL);
307   g_object_set (obj, "bar", TRUE, "foo", 42, "baz", "abc", NULL);
308   g_object_thaw_notify (G_OBJECT (obj));
309   g_assert (n.pos == 3);
310
311   g_object_unref (obj);
312 }
313
314 static void
315 properties_construct (void)
316 {
317   TestObject *obj;
318   gint val;
319   gboolean b;
320   gchar *s;
321
322   g_test_bug ("630357");
323
324   /* more than 16 args triggers a realloc in g_object_new_valist() */
325   obj = g_object_new (test_object_get_type (),
326                       "foo", 1,
327                       "foo", 2,
328                       "foo", 3,
329                       "foo", 4,
330                       "foo", 5,
331                       "bar", FALSE,
332                       "foo", 6,
333                       "foo", 7,
334                       "foo", 8,
335                       "foo", 9,
336                       "foo", 10,
337                       "baz", "boo",
338                       "foo", 11,
339                       "foo", 12,
340                       "foo", 13,
341                       "foo", 14,
342                       "foo", 15,
343                       "foo", 16,
344                       "foo", 17,
345                       "foo", 18,
346                       NULL);
347
348   g_object_get (obj, "foo", &val, NULL);
349   g_assert (val == 18);
350   g_object_get (obj, "bar", &b, NULL);
351   g_assert (!b);
352   g_object_get (obj, "baz", &s, NULL);
353   g_assert_cmpstr (s, ==, "boo");
354   g_free (s);
355
356   g_object_unref (obj);
357 }
358
359 static void
360 properties_testv_with_no_properties (void)
361 {
362   TestObject *test_obj;
363   const char *prop_names[4] = { "foo", "bar", "baz", "quux" };
364   GValue values_out[4] = { G_VALUE_INIT };
365   guint i;
366
367   /* Test newv_with_properties && getv */
368   test_obj = (TestObject *) g_object_new_with_properties (
369       test_object_get_type (), 0, NULL, NULL);
370   g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out);
371
372   /* It should have init values */
373   g_assert_cmpint (g_value_get_int (&values_out[0]), ==, 42);
374   g_assert_true (g_value_get_boolean (&values_out[1]));
375   g_assert_cmpstr (g_value_get_string (&values_out[2]), ==, "Hello");
376   g_assert_cmpstr (g_value_get_string (&values_out[3]), ==, NULL);
377
378   for (i = 0; i < 4; i++)
379     g_value_unset (&values_out[i]);
380   g_object_unref (test_obj);
381 }
382
383 static void
384 properties_testv_with_valid_properties (void)
385 {
386   TestObject *test_obj;
387   const char *prop_names[4] = { "foo", "bar", "baz", "quux" };
388
389   GValue values_in[4] = { G_VALUE_INIT };
390   GValue values_out[4] = { G_VALUE_INIT };
391   guint i;
392
393   g_value_init (&(values_in[0]), G_TYPE_INT);
394   g_value_set_int (&(values_in[0]), 100);
395
396   g_value_init (&(values_in[1]), G_TYPE_BOOLEAN);
397   g_value_set_boolean (&(values_in[1]), TRUE);
398
399   g_value_init (&(values_in[2]), G_TYPE_STRING);
400   g_value_set_string (&(values_in[2]), "pigs");
401
402   g_value_init (&(values_in[3]), G_TYPE_STRING);
403   g_value_set_string (&(values_in[3]), "fly");
404
405   /* Test newv_with_properties && getv */
406   test_obj = (TestObject *) g_object_new_with_properties (
407       test_object_get_type (), 4, prop_names, values_in);
408   g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out);
409
410   g_assert_cmpint (g_value_get_int (&values_out[0]), ==, 100);
411   g_assert_true (g_value_get_boolean (&values_out[1]));
412   g_assert_cmpstr (g_value_get_string (&values_out[2]), ==, "pigs");
413   g_assert_cmpstr (g_value_get_string (&values_out[3]), ==, "fly");
414
415   /* Test newv2 && getv */
416   g_value_set_string (&(values_in[2]), "Elmo knows");
417   g_value_set_string (&(values_in[3]), "where you live");
418   g_object_setv (G_OBJECT (test_obj), 4, prop_names, values_in);
419
420   g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out);
421
422   g_assert_cmpint (g_value_get_int (&values_out[0]), ==, 100);
423   g_assert_true (g_value_get_boolean (&values_out[1]));
424
425   g_assert_cmpstr (g_value_get_string (&values_out[2]), ==, "Elmo knows");
426   g_assert_cmpstr (g_value_get_string (&values_out[3]), ==, "where you live");
427
428
429   for (i = 0; i < 4; i++)
430     {
431       g_value_unset (&values_in[i]);
432       g_value_unset (&values_out[i]);
433     }
434
435   g_object_unref (test_obj);
436 }
437
438 static void
439 properties_testv_with_invalid_property_type (void)
440 {
441   if (g_test_subprocess ())
442     {
443       TestObject *test_obj;
444       const char *invalid_prop_names[1] = { "foo" };
445       GValue values_in[1] = { G_VALUE_INIT };
446
447       g_value_init (&(values_in[0]), G_TYPE_STRING);
448       g_value_set_string (&(values_in[0]), "fly");
449
450       test_obj = (TestObject *) g_object_new_with_properties (
451           test_object_get_type (), 1, invalid_prop_names, values_in);
452       /* should give a warning */
453
454       g_object_unref (test_obj);
455     }
456   g_test_trap_subprocess (NULL, 0, 0);
457   g_test_trap_assert_failed ();
458   g_test_trap_assert_stderr ("*WARNING*foo*gint*gchararray*");
459 }
460
461
462 static void
463 properties_testv_with_invalid_property_names (void)
464 {
465   if (g_test_subprocess ())
466     {
467       TestObject *test_obj;
468       const char *invalid_prop_names[4] = { "foo", "boo", "moo", "poo" };
469       GValue values_in[4] = { G_VALUE_INIT };
470
471       g_value_init (&(values_in[0]), G_TYPE_INT);
472       g_value_set_int (&(values_in[0]), 100);
473
474       g_value_init (&(values_in[1]), G_TYPE_BOOLEAN);
475       g_value_set_boolean (&(values_in[1]), TRUE);
476
477       g_value_init (&(values_in[2]), G_TYPE_STRING);
478       g_value_set_string (&(values_in[2]), "pigs");
479
480       g_value_init (&(values_in[3]), G_TYPE_STRING);
481       g_value_set_string (&(values_in[3]), "fly");
482
483       test_obj = (TestObject *) g_object_new_with_properties (
484           test_object_get_type (), 4, invalid_prop_names, values_in);
485       /* This call should give 3 Critical warnings. Actually, a critical warning
486        * shouldn't make g_object_new_with_properties to fail when a bad named
487        * property is given, because, it will just ignore that property. However,
488        * for test purposes, it is considered that the test doesn't pass.
489        */
490
491       g_object_unref (test_obj);
492     }
493
494   g_test_trap_subprocess (NULL, 0, 0);
495   g_test_trap_assert_failed ();
496   g_test_trap_assert_stderr ("*CRITICAL*g_object_new_is_valid_property*boo*");
497 }
498
499 static void
500 properties_testv_getv (void)
501 {
502   TestObject *test_obj;
503   const char *prop_names[4] = { "foo", "bar", "baz", "quux" };
504   GValue values_out_initialized[4] = { G_VALUE_INIT };
505   GValue values_out_uninitialized[4] = { G_VALUE_INIT };
506   guint i;
507
508   g_value_init (&(values_out_initialized[0]), G_TYPE_INT);
509   g_value_init (&(values_out_initialized[1]), G_TYPE_BOOLEAN);
510   g_value_init (&(values_out_initialized[2]), G_TYPE_STRING);
511   g_value_init (&(values_out_initialized[3]), G_TYPE_STRING);
512
513   test_obj = (TestObject *) g_object_new_with_properties (
514       test_object_get_type (), 0, NULL, NULL);
515
516   /* Test g_object_getv for an initialized values array */
517   g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out_initialized);
518   /* It should have init values */
519   g_assert_cmpint (g_value_get_int (&values_out_initialized[0]), ==, 42);
520   g_assert_true (g_value_get_boolean (&values_out_initialized[1]));
521   g_assert_cmpstr (g_value_get_string (&values_out_initialized[2]), ==, "Hello");
522   g_assert_cmpstr (g_value_get_string (&values_out_initialized[3]), ==, NULL);
523
524   /* Test g_object_getv for an uninitialized values array */
525   g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out_uninitialized);
526   /* It should have init values */
527   g_assert_cmpint (g_value_get_int (&values_out_uninitialized[0]), ==, 42);
528   g_assert_true (g_value_get_boolean (&values_out_uninitialized[1]));
529   g_assert_cmpstr (g_value_get_string (&values_out_uninitialized[2]), ==, "Hello");
530   g_assert_cmpstr (g_value_get_string (&values_out_uninitialized[3]), ==, NULL);
531
532   for (i = 0; i < 4; i++)
533     {
534       g_value_unset (&values_out_initialized[i]);
535       g_value_unset (&values_out_uninitialized[i]);
536     }
537   g_object_unref (test_obj);
538 }
539
540 static void
541 properties_testv_notify_queue (void)
542 {
543   TestObject *test_obj;
544   const char *prop_names[3] = { "foo", "bar", "baz" };
545   GValue values_in[3] = { G_VALUE_INIT };
546   Notifys n;
547   guint i;
548
549   g_value_init (&(values_in[0]), G_TYPE_INT);
550   g_value_set_int (&(values_in[0]), 100);
551
552   g_value_init (&(values_in[1]), G_TYPE_BOOLEAN);
553   g_value_set_boolean (&(values_in[1]), TRUE);
554
555   g_value_init (&(values_in[2]), G_TYPE_STRING);
556   g_value_set_string (&(values_in[2]), "");
557
558   /* Test newv_with_properties && getv */
559   test_obj = (TestObject *) g_object_new_with_properties (
560       test_object_get_type (), 0, NULL, NULL);
561
562   g_assert_nonnull (properties[PROP_FOO]);
563
564   n.pspec[0] = properties[PROP_BAZ];
565   n.pspec[1] = properties[PROP_BAR];
566   n.pspec[2] = properties[PROP_FOO];
567   n.pos = 0;
568
569   g_signal_connect (test_obj, "notify", G_CALLBACK (on_notify2), &n);
570
571   g_object_freeze_notify (G_OBJECT (test_obj));
572   {
573     g_object_setv (G_OBJECT (test_obj), 3, prop_names, values_in);
574
575     /* Set "foo" to 70 */
576     g_value_set_int (&(values_in[0]), 100);
577     g_object_setv (G_OBJECT (test_obj), 1, prop_names, values_in);
578   }
579   g_object_thaw_notify (G_OBJECT (test_obj));
580   g_assert_cmpint (n.pos, ==, 3);
581
582   for (i = 0; i < 3; i++)
583     g_value_unset (&values_in[i]);
584   g_object_unref (test_obj);
585 }
586
587 int
588 main (int argc, char *argv[])
589 {
590   g_test_init (&argc, &argv, NULL);
591
592   g_test_bug_base ("http://bugzilla.gnome.org/");
593
594   g_test_add_func ("/properties/install", properties_install);
595   g_test_add_func ("/properties/notify", properties_notify);
596   g_test_add_func ("/properties/notify-queue", properties_notify_queue);
597   g_test_add_func ("/properties/construct", properties_construct);
598
599   g_test_add_func ("/properties/testv_with_no_properties",
600       properties_testv_with_no_properties);
601   g_test_add_func ("/properties/testv_with_valid_properties",
602       properties_testv_with_valid_properties);
603   g_test_add_func ("/properties/testv_with_invalid_property_type",
604       properties_testv_with_invalid_property_type);
605   g_test_add_func ("/properties/testv_with_invalid_property_names",
606       properties_testv_with_invalid_property_names);
607   g_test_add_func ("/properties/testv_getv", properties_testv_getv);
608   g_test_add_func ("/properties/testv_notify_queue",
609       properties_testv_notify_queue);
610
611   return g_test_run ();
612 }