Meson: Remove hack that got fixed a while ago
[glib.git] / gobject / tests / properties.c
blob0aa325a74470e4fc89a1d67212f6faef45867394
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 TestObject *self = (TestObject *) gobject;
85 g_free (self->baz);
86 g_free (self->quux);
88 /* When the ref_count of an object is zero it is still
89 * possible to notify the property, but it should do
90 * nothing and silenty quit (bug #705570)
92 g_object_notify (gobject, "foo");
93 g_object_notify_by_pspec (gobject, properties[PROP_BAR]);
95 G_OBJECT_CLASS (test_object_parent_class)->finalize (gobject);
98 static void
99 test_object_set_property (GObject *gobject,
100 guint prop_id,
101 const GValue *value,
102 GParamSpec *pspec)
104 TestObject *tobj = (TestObject *) gobject;
106 g_assert_cmpint (prop_id, !=, 0);
107 g_assert_cmpint (prop_id, !=, N_PROPERTIES);
108 g_assert (pspec == properties[prop_id]);
110 switch (prop_id)
112 case PROP_FOO:
113 test_object_set_foo (tobj, g_value_get_int (value));
114 break;
116 case PROP_BAR:
117 test_object_set_bar (tobj, g_value_get_boolean (value));
118 break;
120 case PROP_BAZ:
121 test_object_set_baz (tobj, g_value_get_string (value));
122 break;
124 case PROP_QUUX:
125 test_object_set_quux (tobj, g_value_get_string (value));
126 break;
128 default:
129 g_assert_not_reached ();
133 static void
134 test_object_get_property (GObject *gobject,
135 guint prop_id,
136 GValue *value,
137 GParamSpec *pspec)
139 TestObject *tobj = (TestObject *) gobject;
141 g_assert_cmpint (prop_id, !=, 0);
142 g_assert_cmpint (prop_id, !=, N_PROPERTIES);
143 g_assert (pspec == properties[prop_id]);
145 switch (prop_id)
147 case PROP_FOO:
148 g_value_set_int (value, tobj->foo);
149 break;
151 case PROP_BAR:
152 g_value_set_boolean (value, tobj->bar);
153 break;
155 case PROP_BAZ:
156 g_value_set_string (value, tobj->baz);
157 break;
159 case PROP_QUUX:
160 g_value_set_string (value, tobj->quux);
161 break;
163 default:
164 g_assert_not_reached ();
168 static void
169 test_object_class_init (TestObjectClass *klass)
171 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
173 properties[PROP_FOO] = g_param_spec_int ("foo", "Foo", "Foo",
174 -1, G_MAXINT,
176 G_PARAM_READWRITE);
177 properties[PROP_BAR] = g_param_spec_boolean ("bar", "Bar", "Bar",
178 FALSE,
179 G_PARAM_READWRITE);
180 properties[PROP_BAZ] = g_param_spec_string ("baz", "Baz", "Baz",
181 NULL,
182 G_PARAM_READWRITE);
183 properties[PROP_QUUX] = g_param_spec_string ("quux", "quux", "quux",
184 NULL,
185 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
187 gobject_class->set_property = test_object_set_property;
188 gobject_class->get_property = test_object_get_property;
189 gobject_class->finalize = test_object_finalize;
191 g_object_class_install_properties (gobject_class, N_PROPERTIES, properties);
194 static void
195 test_object_init (TestObject *self)
197 self->foo = 42;
198 self->bar = TRUE;
199 self->baz = g_strdup ("Hello");
200 self->quux = NULL;
203 static void
204 properties_install (void)
206 TestObject *obj = g_object_new (test_object_get_type (), NULL);
207 GParamSpec *pspec;
209 g_assert (properties[PROP_FOO] != NULL);
211 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "foo");
212 g_assert (properties[PROP_FOO] == pspec);
214 g_object_unref (obj);
217 typedef struct {
218 const gchar *name;
219 GParamSpec *pspec;
220 gboolean fired;
221 } TestNotifyClosure;
223 static void
224 on_notify (GObject *gobject,
225 GParamSpec *pspec,
226 TestNotifyClosure *clos)
228 g_assert (clos->pspec == pspec);
229 g_assert_cmpstr (clos->name, ==, pspec->name);
230 clos->fired = TRUE;
233 static void
234 properties_notify (void)
236 TestObject *obj = g_object_new (test_object_get_type (), NULL);
237 TestNotifyClosure clos;
239 g_assert (properties[PROP_FOO] != NULL);
240 g_assert (properties[PROP_QUUX] != NULL);
241 g_signal_connect (obj, "notify", G_CALLBACK (on_notify), &clos);
243 clos.name = "foo";
244 clos.pspec = properties[PROP_FOO];
246 clos.fired = FALSE;
247 g_object_set (obj, "foo", 47, NULL);
248 g_assert (clos.fired);
250 clos.name = "baz";
251 clos.pspec = properties[PROP_BAZ];
253 clos.fired = FALSE;
254 g_object_set (obj, "baz", "something new", NULL);
255 g_assert (clos.fired);
257 /* baz lacks explicit notify, so we will see this twice */
258 clos.fired = FALSE;
259 g_object_set (obj, "baz", "something new", NULL);
260 g_assert (clos.fired);
262 /* quux on the other hand, ... */
263 clos.name = "quux";
264 clos.pspec = properties[PROP_QUUX];
266 clos.fired = FALSE;
267 g_object_set (obj, "quux", "something new", NULL);
268 g_assert (clos.fired);
270 /* no change; no notify */
271 clos.fired = FALSE;
272 g_object_set (obj, "quux", "something new", NULL);
273 g_assert (!clos.fired);
276 g_object_unref (obj);
279 typedef struct {
280 GParamSpec *pspec[3];
281 gint pos;
282 } Notifys;
284 static void
285 on_notify2 (GObject *gobject,
286 GParamSpec *pspec,
287 Notifys *n)
289 g_assert (n->pspec[n->pos] == pspec);
290 n->pos++;
293 static void
294 properties_notify_queue (void)
296 TestObject *obj = g_object_new (test_object_get_type (), NULL);
297 Notifys n;
299 g_assert (properties[PROP_FOO] != NULL);
301 n.pspec[0] = properties[PROP_BAZ];
302 n.pspec[1] = properties[PROP_BAR];
303 n.pspec[2] = properties[PROP_FOO];
304 n.pos = 0;
306 g_signal_connect (obj, "notify", G_CALLBACK (on_notify2), &n);
308 g_object_freeze_notify (G_OBJECT (obj));
309 g_object_set (obj, "foo", 47, NULL);
310 g_object_set (obj, "bar", TRUE, "foo", 42, "baz", "abc", NULL);
311 g_object_thaw_notify (G_OBJECT (obj));
312 g_assert (n.pos == 3);
314 g_object_unref (obj);
317 static void
318 properties_construct (void)
320 TestObject *obj;
321 gint val;
322 gboolean b;
323 gchar *s;
325 g_test_bug ("630357");
327 /* more than 16 args triggers a realloc in g_object_new_valist() */
328 obj = g_object_new (test_object_get_type (),
329 "foo", 1,
330 "foo", 2,
331 "foo", 3,
332 "foo", 4,
333 "foo", 5,
334 "bar", FALSE,
335 "foo", 6,
336 "foo", 7,
337 "foo", 8,
338 "foo", 9,
339 "foo", 10,
340 "baz", "boo",
341 "foo", 11,
342 "foo", 12,
343 "foo", 13,
344 "foo", 14,
345 "foo", 15,
346 "foo", 16,
347 "foo", 17,
348 "foo", 18,
349 NULL);
351 g_object_get (obj, "foo", &val, NULL);
352 g_assert (val == 18);
353 g_object_get (obj, "bar", &b, NULL);
354 g_assert (!b);
355 g_object_get (obj, "baz", &s, NULL);
356 g_assert_cmpstr (s, ==, "boo");
357 g_free (s);
359 g_object_unref (obj);
362 static void
363 properties_testv_with_no_properties (void)
365 TestObject *test_obj;
366 const char *prop_names[4] = { "foo", "bar", "baz", "quux" };
367 GValue values_out[4] = { G_VALUE_INIT };
368 guint i;
370 /* Test newv_with_properties && getv */
371 test_obj = (TestObject *) g_object_new_with_properties (
372 test_object_get_type (), 0, NULL, NULL);
373 g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out);
375 /* It should have init values */
376 g_assert_cmpint (g_value_get_int (&values_out[0]), ==, 42);
377 g_assert_true (g_value_get_boolean (&values_out[1]));
378 g_assert_cmpstr (g_value_get_string (&values_out[2]), ==, "Hello");
379 g_assert_cmpstr (g_value_get_string (&values_out[3]), ==, NULL);
381 for (i = 0; i < 4; i++)
382 g_value_unset (&values_out[i]);
383 g_object_unref (test_obj);
386 static void
387 properties_testv_with_valid_properties (void)
389 TestObject *test_obj;
390 const char *prop_names[4] = { "foo", "bar", "baz", "quux" };
392 GValue values_in[4] = { G_VALUE_INIT };
393 GValue values_out[4] = { G_VALUE_INIT };
394 guint i;
396 g_value_init (&(values_in[0]), G_TYPE_INT);
397 g_value_set_int (&(values_in[0]), 100);
399 g_value_init (&(values_in[1]), G_TYPE_BOOLEAN);
400 g_value_set_boolean (&(values_in[1]), TRUE);
402 g_value_init (&(values_in[2]), G_TYPE_STRING);
403 g_value_set_string (&(values_in[2]), "pigs");
405 g_value_init (&(values_in[3]), G_TYPE_STRING);
406 g_value_set_string (&(values_in[3]), "fly");
408 /* Test newv_with_properties && getv */
409 test_obj = (TestObject *) g_object_new_with_properties (
410 test_object_get_type (), 4, prop_names, values_in);
411 g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out);
413 g_assert_cmpint (g_value_get_int (&values_out[0]), ==, 100);
414 g_assert_true (g_value_get_boolean (&values_out[1]));
415 g_assert_cmpstr (g_value_get_string (&values_out[2]), ==, "pigs");
416 g_assert_cmpstr (g_value_get_string (&values_out[3]), ==, "fly");
418 for (i = 0; i < G_N_ELEMENTS (values_out); i++)
419 g_value_unset (&values_out[i]);
421 /* Test newv2 && getv */
422 g_value_set_string (&(values_in[2]), "Elmo knows");
423 g_value_set_string (&(values_in[3]), "where you live");
424 g_object_setv (G_OBJECT (test_obj), 4, prop_names, values_in);
426 g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out);
428 g_assert_cmpint (g_value_get_int (&values_out[0]), ==, 100);
429 g_assert_true (g_value_get_boolean (&values_out[1]));
431 g_assert_cmpstr (g_value_get_string (&values_out[2]), ==, "Elmo knows");
432 g_assert_cmpstr (g_value_get_string (&values_out[3]), ==, "where you live");
434 for (i = 0; i < G_N_ELEMENTS (values_in); i++)
435 g_value_unset (&values_in[i]);
436 for (i = 0; i < G_N_ELEMENTS (values_out); i++)
437 g_value_unset (&values_out[i]);
439 g_object_unref (test_obj);
442 static void
443 properties_testv_with_invalid_property_type (void)
445 if (g_test_subprocess ())
447 TestObject *test_obj;
448 const char *invalid_prop_names[1] = { "foo" };
449 GValue values_in[1] = { G_VALUE_INIT };
451 g_value_init (&(values_in[0]), G_TYPE_STRING);
452 g_value_set_string (&(values_in[0]), "fly");
454 test_obj = (TestObject *) g_object_new_with_properties (
455 test_object_get_type (), 1, invalid_prop_names, values_in);
456 /* should give a warning */
458 g_object_unref (test_obj);
460 g_test_trap_subprocess (NULL, 0, 0);
461 g_test_trap_assert_failed ();
462 g_test_trap_assert_stderr ("*WARNING*foo*gint*gchararray*");
466 static void
467 properties_testv_with_invalid_property_names (void)
469 if (g_test_subprocess ())
471 TestObject *test_obj;
472 const char *invalid_prop_names[4] = { "foo", "boo", "moo", "poo" };
473 GValue values_in[4] = { G_VALUE_INIT };
475 g_value_init (&(values_in[0]), G_TYPE_INT);
476 g_value_set_int (&(values_in[0]), 100);
478 g_value_init (&(values_in[1]), G_TYPE_BOOLEAN);
479 g_value_set_boolean (&(values_in[1]), TRUE);
481 g_value_init (&(values_in[2]), G_TYPE_STRING);
482 g_value_set_string (&(values_in[2]), "pigs");
484 g_value_init (&(values_in[3]), G_TYPE_STRING);
485 g_value_set_string (&(values_in[3]), "fly");
487 test_obj = (TestObject *) g_object_new_with_properties (
488 test_object_get_type (), 4, invalid_prop_names, values_in);
489 /* This call should give 3 Critical warnings. Actually, a critical warning
490 * shouldn't make g_object_new_with_properties to fail when a bad named
491 * property is given, because, it will just ignore that property. However,
492 * for test purposes, it is considered that the test doesn't pass.
495 g_object_unref (test_obj);
498 g_test_trap_subprocess (NULL, 0, 0);
499 g_test_trap_assert_failed ();
500 g_test_trap_assert_stderr ("*CRITICAL*g_object_new_is_valid_property*boo*");
503 static void
504 properties_testv_getv (void)
506 TestObject *test_obj;
507 const char *prop_names[4] = { "foo", "bar", "baz", "quux" };
508 GValue values_out_initialized[4] = { G_VALUE_INIT };
509 GValue values_out_uninitialized[4] = { G_VALUE_INIT };
510 guint i;
512 g_value_init (&(values_out_initialized[0]), G_TYPE_INT);
513 g_value_init (&(values_out_initialized[1]), G_TYPE_BOOLEAN);
514 g_value_init (&(values_out_initialized[2]), G_TYPE_STRING);
515 g_value_init (&(values_out_initialized[3]), G_TYPE_STRING);
517 test_obj = (TestObject *) g_object_new_with_properties (
518 test_object_get_type (), 0, NULL, NULL);
520 /* Test g_object_getv for an initialized values array */
521 g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out_initialized);
522 /* It should have init values */
523 g_assert_cmpint (g_value_get_int (&values_out_initialized[0]), ==, 42);
524 g_assert_true (g_value_get_boolean (&values_out_initialized[1]));
525 g_assert_cmpstr (g_value_get_string (&values_out_initialized[2]), ==, "Hello");
526 g_assert_cmpstr (g_value_get_string (&values_out_initialized[3]), ==, NULL);
528 /* Test g_object_getv for an uninitialized values array */
529 g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out_uninitialized);
530 /* It should have init values */
531 g_assert_cmpint (g_value_get_int (&values_out_uninitialized[0]), ==, 42);
532 g_assert_true (g_value_get_boolean (&values_out_uninitialized[1]));
533 g_assert_cmpstr (g_value_get_string (&values_out_uninitialized[2]), ==, "Hello");
534 g_assert_cmpstr (g_value_get_string (&values_out_uninitialized[3]), ==, NULL);
536 for (i = 0; i < 4; i++)
538 g_value_unset (&values_out_initialized[i]);
539 g_value_unset (&values_out_uninitialized[i]);
541 g_object_unref (test_obj);
544 static void
545 properties_testv_notify_queue (void)
547 TestObject *test_obj;
548 const char *prop_names[3] = { "foo", "bar", "baz" };
549 GValue values_in[3] = { G_VALUE_INIT };
550 Notifys n;
551 guint i;
553 g_value_init (&(values_in[0]), G_TYPE_INT);
554 g_value_set_int (&(values_in[0]), 100);
556 g_value_init (&(values_in[1]), G_TYPE_BOOLEAN);
557 g_value_set_boolean (&(values_in[1]), TRUE);
559 g_value_init (&(values_in[2]), G_TYPE_STRING);
560 g_value_set_string (&(values_in[2]), "");
562 /* Test newv_with_properties && getv */
563 test_obj = (TestObject *) g_object_new_with_properties (
564 test_object_get_type (), 0, NULL, NULL);
566 g_assert_nonnull (properties[PROP_FOO]);
568 n.pspec[0] = properties[PROP_BAZ];
569 n.pspec[1] = properties[PROP_BAR];
570 n.pspec[2] = properties[PROP_FOO];
571 n.pos = 0;
573 g_signal_connect (test_obj, "notify", G_CALLBACK (on_notify2), &n);
575 g_object_freeze_notify (G_OBJECT (test_obj));
577 g_object_setv (G_OBJECT (test_obj), 3, prop_names, values_in);
579 /* Set "foo" to 70 */
580 g_value_set_int (&(values_in[0]), 100);
581 g_object_setv (G_OBJECT (test_obj), 1, prop_names, values_in);
583 g_object_thaw_notify (G_OBJECT (test_obj));
584 g_assert_cmpint (n.pos, ==, 3);
586 for (i = 0; i < 3; i++)
587 g_value_unset (&values_in[i]);
588 g_object_unref (test_obj);
592 main (int argc, char *argv[])
594 g_test_init (&argc, &argv, NULL);
596 g_test_bug_base ("http://bugzilla.gnome.org/");
598 g_test_add_func ("/properties/install", properties_install);
599 g_test_add_func ("/properties/notify", properties_notify);
600 g_test_add_func ("/properties/notify-queue", properties_notify_queue);
601 g_test_add_func ("/properties/construct", properties_construct);
603 g_test_add_func ("/properties/testv_with_no_properties",
604 properties_testv_with_no_properties);
605 g_test_add_func ("/properties/testv_with_valid_properties",
606 properties_testv_with_valid_properties);
607 g_test_add_func ("/properties/testv_with_invalid_property_type",
608 properties_testv_with_invalid_property_type);
609 g_test_add_func ("/properties/testv_with_invalid_property_names",
610 properties_testv_with_invalid_property_names);
611 g_test_add_func ("/properties/testv_getv", properties_testv_getv);
612 g_test_add_func ("/properties/testv_notify_queue",
613 properties_testv_notify_queue);
615 return g_test_run ();