Meson: Add -Wl,-z,nodelete and -Wl,-Bsymbolic-functions where supported
[glib.git] / gobject / tests / properties.c
bloba1af3f8baea5e606e7088c0427491ae15640d6af
1 #include <stdlib.h>
2 #include <gstdio.h>
3 #include <glib-object.h>
5 typedef struct _TestObject {
6 GObject parent_instance;
7 gint foo;
8 gboolean bar;
9 gchar *baz;
10 gchar *quux;
11 } TestObject;
13 typedef struct _TestObjectClass {
14 GObjectClass parent_class;
15 } TestObjectClass;
17 enum { PROP_0, PROP_FOO, PROP_BAR, PROP_BAZ, PROP_QUUX, N_PROPERTIES };
19 static GParamSpec *properties[N_PROPERTIES] = { NULL, };
21 static GType test_object_get_type (void);
22 G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT)
24 static void
25 test_object_set_foo (TestObject *obj,
26 gint foo)
28 if (obj->foo != foo)
30 obj->foo = foo;
32 g_assert (properties[PROP_FOO] != NULL);
33 g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_FOO]);
37 static void
38 test_object_set_bar (TestObject *obj,
39 gboolean bar)
41 bar = !!bar;
43 if (obj->bar != bar)
45 obj->bar = bar;
47 g_assert (properties[PROP_BAR] != NULL);
48 g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_BAR]);
52 static void
53 test_object_set_baz (TestObject *obj,
54 const gchar *baz)
56 if (g_strcmp0 (obj->baz, baz) != 0)
58 g_free (obj->baz);
59 obj->baz = g_strdup (baz);
61 g_assert (properties[PROP_BAZ] != NULL);
62 g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_BAZ]);
66 static void
67 test_object_set_quux (TestObject *obj,
68 const gchar *quux)
70 if (g_strcmp0 (obj->quux, quux) != 0)
72 g_free (obj->quux);
73 obj->quux = g_strdup (quux);
75 g_assert (properties[PROP_QUUX] != NULL);
76 g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_QUUX]);
80 static void
81 test_object_finalize (GObject *gobject)
83 g_free (((TestObject *) gobject)->baz);
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)
89 g_object_notify (gobject, "foo");
90 g_object_notify_by_pspec (gobject, properties[PROP_BAR]);
92 G_OBJECT_CLASS (test_object_parent_class)->finalize (gobject);
95 static void
96 test_object_set_property (GObject *gobject,
97 guint prop_id,
98 const GValue *value,
99 GParamSpec *pspec)
101 TestObject *tobj = (TestObject *) gobject;
103 g_assert_cmpint (prop_id, !=, 0);
104 g_assert_cmpint (prop_id, !=, N_PROPERTIES);
105 g_assert (pspec == properties[prop_id]);
107 switch (prop_id)
109 case PROP_FOO:
110 test_object_set_foo (tobj, g_value_get_int (value));
111 break;
113 case PROP_BAR:
114 test_object_set_bar (tobj, g_value_get_boolean (value));
115 break;
117 case PROP_BAZ:
118 test_object_set_baz (tobj, g_value_get_string (value));
119 break;
121 case PROP_QUUX:
122 test_object_set_quux (tobj, g_value_get_string (value));
123 break;
125 default:
126 g_assert_not_reached ();
130 static void
131 test_object_get_property (GObject *gobject,
132 guint prop_id,
133 GValue *value,
134 GParamSpec *pspec)
136 TestObject *tobj = (TestObject *) gobject;
138 g_assert_cmpint (prop_id, !=, 0);
139 g_assert_cmpint (prop_id, !=, N_PROPERTIES);
140 g_assert (pspec == properties[prop_id]);
142 switch (prop_id)
144 case PROP_FOO:
145 g_value_set_int (value, tobj->foo);
146 break;
148 case PROP_BAR:
149 g_value_set_boolean (value, tobj->bar);
150 break;
152 case PROP_BAZ:
153 g_value_set_string (value, tobj->baz);
154 break;
156 case PROP_QUUX:
157 g_value_set_string (value, tobj->quux);
158 break;
160 default:
161 g_assert_not_reached ();
165 static void
166 test_object_class_init (TestObjectClass *klass)
168 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
170 properties[PROP_FOO] = g_param_spec_int ("foo", "Foo", "Foo",
171 -1, G_MAXINT,
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);
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;
188 g_object_class_install_properties (gobject_class, N_PROPERTIES, properties);
191 static void
192 test_object_init (TestObject *self)
194 self->foo = 42;
195 self->bar = TRUE;
196 self->baz = g_strdup ("Hello");
197 self->quux = NULL;
200 static void
201 properties_install (void)
203 TestObject *obj = g_object_new (test_object_get_type (), NULL);
204 GParamSpec *pspec;
206 g_assert (properties[PROP_FOO] != NULL);
208 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "foo");
209 g_assert (properties[PROP_FOO] == pspec);
211 g_object_unref (obj);
214 typedef struct {
215 const gchar *name;
216 GParamSpec *pspec;
217 gboolean fired;
218 } TestNotifyClosure;
220 static void
221 on_notify (GObject *gobject,
222 GParamSpec *pspec,
223 TestNotifyClosure *clos)
225 g_assert (clos->pspec == pspec);
226 g_assert_cmpstr (clos->name, ==, pspec->name);
227 clos->fired = TRUE;
230 static void
231 properties_notify (void)
233 TestObject *obj = g_object_new (test_object_get_type (), NULL);
234 TestNotifyClosure clos;
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);
240 clos.name = "foo";
241 clos.pspec = properties[PROP_FOO];
243 clos.fired = FALSE;
244 g_object_set (obj, "foo", 47, NULL);
245 g_assert (clos.fired);
247 clos.name = "baz";
248 clos.pspec = properties[PROP_BAZ];
250 clos.fired = FALSE;
251 g_object_set (obj, "baz", "something new", NULL);
252 g_assert (clos.fired);
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);
259 /* quux on the other hand, ... */
260 clos.name = "quux";
261 clos.pspec = properties[PROP_QUUX];
263 clos.fired = FALSE;
264 g_object_set (obj, "quux", "something new", NULL);
265 g_assert (clos.fired);
267 /* no change; no notify */
268 clos.fired = FALSE;
269 g_object_set (obj, "quux", "something new", NULL);
270 g_assert (!clos.fired);
273 g_object_unref (obj);
276 typedef struct {
277 GParamSpec *pspec[3];
278 gint pos;
279 } Notifys;
281 static void
282 on_notify2 (GObject *gobject,
283 GParamSpec *pspec,
284 Notifys *n)
286 g_assert (n->pspec[n->pos] == pspec);
287 n->pos++;
290 static void
291 properties_notify_queue (void)
293 TestObject *obj = g_object_new (test_object_get_type (), NULL);
294 Notifys n;
296 g_assert (properties[PROP_FOO] != NULL);
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;
303 g_signal_connect (obj, "notify", G_CALLBACK (on_notify2), &n);
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);
311 g_object_unref (obj);
314 static void
315 properties_construct (void)
317 TestObject *obj;
318 gint val;
319 gboolean b;
320 gchar *s;
322 g_test_bug ("630357");
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);
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);
356 g_object_unref (obj);
359 static void
360 properties_testv_with_no_properties (void)
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;
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);
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);
378 for (i = 0; i < 4; i++)
379 g_value_unset (&values_out[i]);
380 g_object_unref (test_obj);
383 static void
384 properties_testv_with_valid_properties (void)
386 TestObject *test_obj;
387 const char *prop_names[4] = { "foo", "bar", "baz", "quux" };
389 GValue values_in[4] = { G_VALUE_INIT };
390 GValue values_out[4] = { G_VALUE_INIT };
391 guint i;
393 g_value_init (&(values_in[0]), G_TYPE_INT);
394 g_value_set_int (&(values_in[0]), 100);
396 g_value_init (&(values_in[1]), G_TYPE_BOOLEAN);
397 g_value_set_boolean (&(values_in[1]), TRUE);
399 g_value_init (&(values_in[2]), G_TYPE_STRING);
400 g_value_set_string (&(values_in[2]), "pigs");
402 g_value_init (&(values_in[3]), G_TYPE_STRING);
403 g_value_set_string (&(values_in[3]), "fly");
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);
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");
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);
420 g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out);
422 g_assert_cmpint (g_value_get_int (&values_out[0]), ==, 100);
423 g_assert_true (g_value_get_boolean (&values_out[1]));
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");
429 for (i = 0; i < 4; i++)
431 g_value_unset (&values_in[i]);
432 g_value_unset (&values_out[i]);
435 g_object_unref (test_obj);
438 static void
439 properties_testv_with_invalid_property_type (void)
441 if (g_test_subprocess ())
443 TestObject *test_obj;
444 const char *invalid_prop_names[1] = { "foo" };
445 GValue values_in[1] = { G_VALUE_INIT };
447 g_value_init (&(values_in[0]), G_TYPE_STRING);
448 g_value_set_string (&(values_in[0]), "fly");
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 */
454 g_object_unref (test_obj);
456 g_test_trap_subprocess (NULL, 0, 0);
457 g_test_trap_assert_failed ();
458 g_test_trap_assert_stderr ("*WARNING*foo*gint*gchararray*");
462 static void
463 properties_testv_with_invalid_property_names (void)
465 if (g_test_subprocess ())
467 TestObject *test_obj;
468 const char *invalid_prop_names[4] = { "foo", "boo", "moo", "poo" };
469 GValue values_in[4] = { G_VALUE_INIT };
471 g_value_init (&(values_in[0]), G_TYPE_INT);
472 g_value_set_int (&(values_in[0]), 100);
474 g_value_init (&(values_in[1]), G_TYPE_BOOLEAN);
475 g_value_set_boolean (&(values_in[1]), TRUE);
477 g_value_init (&(values_in[2]), G_TYPE_STRING);
478 g_value_set_string (&(values_in[2]), "pigs");
480 g_value_init (&(values_in[3]), G_TYPE_STRING);
481 g_value_set_string (&(values_in[3]), "fly");
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.
491 g_object_unref (test_obj);
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*");
499 static void
500 properties_testv_getv (void)
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;
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);
513 test_obj = (TestObject *) g_object_new_with_properties (
514 test_object_get_type (), 0, NULL, NULL);
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);
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);
532 for (i = 0; i < 4; i++)
534 g_value_unset (&values_out_initialized[i]);
535 g_value_unset (&values_out_uninitialized[i]);
537 g_object_unref (test_obj);
540 static void
541 properties_testv_notify_queue (void)
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;
549 g_value_init (&(values_in[0]), G_TYPE_INT);
550 g_value_set_int (&(values_in[0]), 100);
552 g_value_init (&(values_in[1]), G_TYPE_BOOLEAN);
553 g_value_set_boolean (&(values_in[1]), TRUE);
555 g_value_init (&(values_in[2]), G_TYPE_STRING);
556 g_value_set_string (&(values_in[2]), "");
558 /* Test newv_with_properties && getv */
559 test_obj = (TestObject *) g_object_new_with_properties (
560 test_object_get_type (), 0, NULL, NULL);
562 g_assert_nonnull (properties[PROP_FOO]);
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;
569 g_signal_connect (test_obj, "notify", G_CALLBACK (on_notify2), &n);
571 g_object_freeze_notify (G_OBJECT (test_obj));
573 g_object_setv (G_OBJECT (test_obj), 3, prop_names, values_in);
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);
579 g_object_thaw_notify (G_OBJECT (test_obj));
580 g_assert_cmpint (n.pos, ==, 3);
582 for (i = 0; i < 3; i++)
583 g_value_unset (&values_in[i]);
584 g_object_unref (test_obj);
588 main (int argc, char *argv[])
590 g_test_init (&argc, &argv, NULL);
592 g_test_bug_base ("http://bugzilla.gnome.org/");
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);
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);
611 return g_test_run ();