Imported Upstream version 2.74.0
[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   TestObject *self = (TestObject *) gobject;
84
85   g_free (self->baz);
86   g_free (self->quux);
87
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 silently quit (bug #705570)
91    */
92   g_object_notify (gobject, "foo");
93   g_object_notify_by_pspec (gobject, properties[PROP_BAR]);
94
95   G_OBJECT_CLASS (test_object_parent_class)->finalize (gobject);
96 }
97
98 static void
99 test_object_set_property (GObject *gobject,
100                           guint prop_id,
101                           const GValue *value,
102                           GParamSpec *pspec)
103 {
104   TestObject *tobj = (TestObject *) gobject;
105
106   g_assert_cmpint (prop_id, !=, 0);
107   g_assert_true (prop_id < N_PROPERTIES && pspec == properties[prop_id]);
108
109   switch (prop_id)
110     {
111     case PROP_FOO:
112       test_object_set_foo (tobj, g_value_get_int (value));
113       break;
114
115     case PROP_BAR:
116       test_object_set_bar (tobj, g_value_get_boolean (value));
117       break;
118
119     case PROP_BAZ:
120       test_object_set_baz (tobj, g_value_get_string (value));
121       break;
122
123     case PROP_QUUX:
124       test_object_set_quux (tobj, g_value_get_string (value));
125       break;
126
127     default:
128       g_assert_not_reached ();
129     }
130 }
131
132 static void
133 test_object_get_property (GObject *gobject,
134                           guint prop_id,
135                           GValue *value,
136                           GParamSpec *pspec)
137 {
138   TestObject *tobj = (TestObject *) gobject;
139
140   g_assert_cmpint (prop_id, !=, 0);
141   g_assert_true (prop_id < N_PROPERTIES && pspec == properties[prop_id]);
142
143   switch (prop_id)
144     {
145     case PROP_FOO:
146       g_value_set_int (value, tobj->foo);
147       break;
148
149     case PROP_BAR:
150       g_value_set_boolean (value, tobj->bar);
151       break;
152
153     case PROP_BAZ:
154       g_value_set_string (value, tobj->baz);
155       break;
156
157     case PROP_QUUX:
158       g_value_set_string (value, tobj->quux);
159       break;
160
161     default:
162       g_assert_not_reached ();
163     }
164 }
165
166 static void
167 test_object_class_init (TestObjectClass *klass)
168 {
169   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
170
171   properties[PROP_FOO] = g_param_spec_int ("foo", "Foo", "Foo",
172                                            -1, G_MAXINT,
173                                            0,
174                                            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
175   properties[PROP_BAR] = g_param_spec_boolean ("bar", "Bar", "Bar",
176                                                FALSE,
177                                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
178   properties[PROP_BAZ] = g_param_spec_string ("baz", "Baz", "Baz",
179                                               NULL,
180                                               G_PARAM_READWRITE);
181
182   gobject_class->set_property = test_object_set_property;
183   gobject_class->get_property = test_object_get_property;
184   gobject_class->finalize = test_object_finalize;
185
186   g_object_class_install_properties (gobject_class, N_PROPERTIES - 1, properties);
187
188   /* We intentionally install this property separately, to test
189    * that that works, and that property lookup works regardless
190    * how the property was installed.
191    */
192   properties[PROP_QUUX] = g_param_spec_string ("quux", "quux", "quux",
193                                                NULL,
194                                                G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
195
196   g_object_class_install_property (gobject_class, PROP_QUUX, properties[PROP_QUUX]);
197 }
198
199 static void
200 test_object_init (TestObject *self)
201 {
202   self->foo = 42;
203   self->bar = TRUE;
204   self->baz = g_strdup ("Hello");
205   self->quux = NULL;
206 }
207
208 static void
209 properties_install (void)
210 {
211   TestObject *obj = g_object_new (test_object_get_type (), NULL);
212   GParamSpec *pspec;
213   char *name;
214
215   g_assert (properties[PROP_FOO] != NULL);
216
217   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "foo");
218   g_assert (properties[PROP_FOO] == pspec);
219
220   name = g_strdup ("bar");
221   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), name);
222   g_assert (properties[PROP_BAR] == pspec);
223   g_free (name);
224
225   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "baz");
226   g_assert (properties[PROP_BAZ] == pspec);
227
228   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "quux");
229   g_assert (properties[PROP_QUUX] == pspec);
230
231   g_object_unref (obj);
232 }
233
234 typedef struct {
235   GObject parent_instance;
236   int value[16];
237 } ManyProps;
238
239 typedef GObjectClass ManyPropsClass;
240
241 static GParamSpec *props[16];
242
243 GType many_props_get_type (void) G_GNUC_CONST;
244
245 G_DEFINE_TYPE(ManyProps, many_props, G_TYPE_OBJECT)
246
247 static void
248 many_props_init (ManyProps *self)
249 {
250 }
251
252 static void
253 get_prop (GObject    *object,
254           guint       prop_id,
255           GValue     *value,
256           GParamSpec *pspec)
257 {
258   ManyProps *mp = (ManyProps *) object;
259
260   if (prop_id > 0 && prop_id < 13)
261     g_value_set_int (value, mp->value[prop_id]);
262   else
263     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
264 }
265
266 static void
267 set_prop (GObject      *object,
268           guint         prop_id,
269           const GValue *value,
270           GParamSpec   *pspec)
271 {
272   ManyProps *mp = (ManyProps *) object;
273
274   if (prop_id > 0 && prop_id < 13)
275     mp->value[prop_id] = g_value_get_int (value);
276   else
277     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
278 }
279
280 static void
281 many_props_class_init (ManyPropsClass *class)
282 {
283   G_OBJECT_CLASS (class)->get_property = get_prop;
284   G_OBJECT_CLASS (class)->set_property = set_prop;
285
286   props[1] = g_param_spec_int ("one", NULL, NULL,
287                                0, G_MAXINT, 0,
288                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
289   props[2] = g_param_spec_int ("two", NULL, NULL,
290                                0, G_MAXINT, 0,
291                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
292   props[3] = g_param_spec_int ("three", NULL, NULL,
293                                0, G_MAXINT, 0,
294                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
295   props[4] = g_param_spec_int ("four", NULL, NULL,
296                                0, G_MAXINT, 0,
297                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
298   props[5] = g_param_spec_int ("five", NULL, NULL,
299                                0, G_MAXINT, 0,
300                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
301   props[6] = g_param_spec_int ("six", NULL, NULL,
302                                0, G_MAXINT, 0,
303                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
304   props[7] = g_param_spec_int ("seven", NULL, NULL,
305                                0, G_MAXINT, 0,
306                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
307   props[8] = g_param_spec_int ("eight", NULL, NULL,
308                                0, G_MAXINT, 0,
309                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
310   props[9] = g_param_spec_int ("nine", NULL, NULL,
311                                0, G_MAXINT, 0,
312                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
313   props[10] = g_param_spec_int ("ten", NULL, NULL,
314                                0, G_MAXINT, 0,
315                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
316   props[11] = g_param_spec_int ("eleven", NULL, NULL,
317                                0, G_MAXINT, 0,
318                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
319   props[12] = g_param_spec_int ("twelve", NULL, NULL,
320                                0, G_MAXINT, 0,
321                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
322   g_object_class_install_properties (G_OBJECT_CLASS (class), 12, props);
323 }
324
325 static void
326 properties_install_many (void)
327 {
328   ManyProps *obj = g_object_new (many_props_get_type (), NULL);
329   GParamSpec *pspec;
330
331   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "one");
332   g_assert (props[1] == pspec);
333
334   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "ten");
335   g_assert (props[10] == pspec);
336
337   g_object_unref (obj);
338 }
339
340 typedef struct {
341   const gchar *name;
342   GParamSpec *pspec;
343   gboolean    fired;
344 } TestNotifyClosure;
345
346 static void
347 on_notify (GObject           *gobject,
348            GParamSpec        *pspec,
349            TestNotifyClosure *closure)
350 {
351   g_assert (closure->pspec == pspec);
352   g_assert_cmpstr (closure->name, ==, pspec->name);
353   closure->fired = TRUE;
354 }
355
356 static void
357 properties_notify (void)
358 {
359   TestObject *obj = g_object_new (test_object_get_type (), NULL);
360   TestNotifyClosure closure;
361
362   g_assert (properties[PROP_FOO] != NULL);
363   g_assert (properties[PROP_QUUX] != NULL);
364   g_signal_connect (obj, "notify", G_CALLBACK (on_notify), &closure);
365
366   closure.name = "foo";
367   closure.pspec = properties[PROP_FOO];
368
369   closure.fired = FALSE;
370   g_object_set (obj, "foo", 47, NULL);
371   g_assert (closure.fired);
372
373   closure.name = "baz";
374   closure.pspec = properties[PROP_BAZ];
375
376   closure.fired = FALSE;
377   g_object_set (obj, "baz", "something new", NULL);
378   g_assert (closure.fired);
379
380   /* baz lacks explicit notify, so we will see this twice */
381   closure.fired = FALSE;
382   g_object_set (obj, "baz", "something new", NULL);
383   g_assert (closure.fired);
384
385   /* quux on the other hand, ... */
386   closure.name = "quux";
387   closure.pspec = properties[PROP_QUUX];
388
389   closure.fired = FALSE;
390   g_object_set (obj, "quux", "something new", NULL);
391   g_assert (closure.fired);
392
393   /* no change; no notify */
394   closure.fired = FALSE;
395   g_object_set (obj, "quux", "something new", NULL);
396   g_assert (!closure.fired);
397
398
399   g_object_unref (obj);
400 }
401
402 typedef struct {
403   GParamSpec *pspec[3];
404   gint pos;
405 } Notifys;
406
407 static void
408 on_notify2 (GObject    *gobject,
409             GParamSpec *pspec,
410             Notifys    *n)
411 {
412   g_assert (n->pspec[n->pos] == pspec);
413   n->pos++;
414 }
415
416 static void
417 properties_notify_queue (void)
418 {
419   TestObject *obj = g_object_new (test_object_get_type (), NULL);
420   Notifys n;
421
422   g_assert (properties[PROP_FOO] != NULL);
423
424   n.pspec[0] = properties[PROP_BAZ];
425   n.pspec[1] = properties[PROP_BAR];
426   n.pspec[2] = properties[PROP_FOO];
427   n.pos = 0;
428
429   g_signal_connect (obj, "notify", G_CALLBACK (on_notify2), &n);
430
431   g_object_freeze_notify (G_OBJECT (obj));
432   g_object_set (obj, "foo", 47, NULL);
433   g_object_set (obj, "bar", TRUE, "foo", 42, "baz", "abc", NULL);
434   g_object_thaw_notify (G_OBJECT (obj));
435   g_assert (n.pos == 3);
436
437   g_object_unref (obj);
438 }
439
440 static void
441 properties_construct (void)
442 {
443   TestObject *obj;
444   gint val;
445   gboolean b;
446   gchar *s;
447
448   g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=630357");
449
450   /* more than 16 args triggers a realloc in g_object_new_valist() */
451   obj = g_object_new (test_object_get_type (),
452                       "foo", 1,
453                       "foo", 2,
454                       "foo", 3,
455                       "foo", 4,
456                       "foo", 5,
457                       "bar", FALSE,
458                       "foo", 6,
459                       "foo", 7,
460                       "foo", 8,
461                       "foo", 9,
462                       "foo", 10,
463                       "baz", "boo",
464                       "foo", 11,
465                       "foo", 12,
466                       "foo", 13,
467                       "foo", 14,
468                       "foo", 15,
469                       "foo", 16,
470                       "foo", 17,
471                       "foo", 18,
472                       NULL);
473
474   g_object_get (obj, "foo", &val, NULL);
475   g_assert (val == 18);
476   g_object_get (obj, "bar", &b, NULL);
477   g_assert (!b);
478   g_object_get (obj, "baz", &s, NULL);
479   g_assert_cmpstr (s, ==, "boo");
480   g_free (s);
481
482   g_object_unref (obj);
483 }
484
485 static void
486 properties_testv_with_no_properties (void)
487 {
488   TestObject *test_obj;
489   const char *prop_names[4] = { "foo", "bar", "baz", "quux" };
490   GValue values_out[4] = { G_VALUE_INIT };
491   guint i;
492
493   /* Test newv_with_properties && getv */
494   test_obj = (TestObject *) g_object_new_with_properties (
495       test_object_get_type (), 0, NULL, NULL);
496   g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out);
497
498   /* It should have init values */
499   g_assert_cmpint (g_value_get_int (&values_out[0]), ==, 42);
500   g_assert_true (g_value_get_boolean (&values_out[1]));
501   g_assert_cmpstr (g_value_get_string (&values_out[2]), ==, "Hello");
502   g_assert_cmpstr (g_value_get_string (&values_out[3]), ==, NULL);
503
504   for (i = 0; i < 4; i++)
505     g_value_unset (&values_out[i]);
506   g_object_unref (test_obj);
507 }
508
509 static void
510 properties_testv_with_valid_properties (void)
511 {
512   TestObject *test_obj;
513   const char *prop_names[4] = { "foo", "bar", "baz", "quux" };
514
515   GValue values_in[4] = { G_VALUE_INIT };
516   GValue values_out[4] = { G_VALUE_INIT };
517   guint i;
518
519   g_value_init (&(values_in[0]), G_TYPE_INT);
520   g_value_set_int (&(values_in[0]), 100);
521
522   g_value_init (&(values_in[1]), G_TYPE_BOOLEAN);
523   g_value_set_boolean (&(values_in[1]), TRUE);
524
525   g_value_init (&(values_in[2]), G_TYPE_STRING);
526   g_value_set_string (&(values_in[2]), "pigs");
527
528   g_value_init (&(values_in[3]), G_TYPE_STRING);
529   g_value_set_string (&(values_in[3]), "fly");
530
531   /* Test newv_with_properties && getv */
532   test_obj = (TestObject *) g_object_new_with_properties (
533       test_object_get_type (), 4, prop_names, values_in);
534   g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out);
535
536   g_assert_cmpint (g_value_get_int (&values_out[0]), ==, 100);
537   g_assert_true (g_value_get_boolean (&values_out[1]));
538   g_assert_cmpstr (g_value_get_string (&values_out[2]), ==, "pigs");
539   g_assert_cmpstr (g_value_get_string (&values_out[3]), ==, "fly");
540
541   for (i = 0; i < G_N_ELEMENTS (values_out); i++)
542     g_value_unset (&values_out[i]);
543
544   /* Test newv2 && getv */
545   g_value_set_string (&(values_in[2]), "Elmo knows");
546   g_value_set_string (&(values_in[3]), "where you live");
547   g_object_setv (G_OBJECT (test_obj), 4, prop_names, values_in);
548
549   g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out);
550
551   g_assert_cmpint (g_value_get_int (&values_out[0]), ==, 100);
552   g_assert_true (g_value_get_boolean (&values_out[1]));
553
554   g_assert_cmpstr (g_value_get_string (&values_out[2]), ==, "Elmo knows");
555   g_assert_cmpstr (g_value_get_string (&values_out[3]), ==, "where you live");
556
557   for (i = 0; i < G_N_ELEMENTS (values_in); i++)
558     g_value_unset (&values_in[i]);
559   for (i = 0; i < G_N_ELEMENTS (values_out); i++)
560     g_value_unset (&values_out[i]);
561
562   g_object_unref (test_obj);
563 }
564
565 static void
566 properties_testv_with_invalid_property_type (void)
567 {
568   if (g_test_subprocess ())
569     {
570       TestObject *test_obj;
571       const char *invalid_prop_names[1] = { "foo" };
572       GValue values_in[1] = { G_VALUE_INIT };
573
574       g_value_init (&(values_in[0]), G_TYPE_STRING);
575       g_value_set_string (&(values_in[0]), "fly");
576
577       test_obj = (TestObject *) g_object_new_with_properties (
578           test_object_get_type (), 1, invalid_prop_names, values_in);
579       /* should give a warning */
580
581       g_object_unref (test_obj);
582     }
583   g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
584   g_test_trap_assert_failed ();
585   g_test_trap_assert_stderr ("*WARNING*foo*gint*gchararray*");
586 }
587
588
589 static void
590 properties_testv_with_invalid_property_names (void)
591 {
592   if (g_test_subprocess ())
593     {
594       TestObject *test_obj;
595       const char *invalid_prop_names[4] = { "foo", "boo", "moo", "poo" };
596       GValue values_in[4] = { G_VALUE_INIT };
597
598       g_value_init (&(values_in[0]), G_TYPE_INT);
599       g_value_set_int (&(values_in[0]), 100);
600
601       g_value_init (&(values_in[1]), G_TYPE_BOOLEAN);
602       g_value_set_boolean (&(values_in[1]), TRUE);
603
604       g_value_init (&(values_in[2]), G_TYPE_STRING);
605       g_value_set_string (&(values_in[2]), "pigs");
606
607       g_value_init (&(values_in[3]), G_TYPE_STRING);
608       g_value_set_string (&(values_in[3]), "fly");
609
610       test_obj = (TestObject *) g_object_new_with_properties (
611           test_object_get_type (), 4, invalid_prop_names, values_in);
612       /* This call should give 3 Critical warnings. Actually, a critical warning
613        * shouldn't make g_object_new_with_properties to fail when a bad named
614        * property is given, because, it will just ignore that property. However,
615        * for test purposes, it is considered that the test doesn't pass.
616        */
617
618       g_object_unref (test_obj);
619     }
620
621   g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
622   g_test_trap_assert_failed ();
623   g_test_trap_assert_stderr ("*CRITICAL*g_object_new_is_valid_property*boo*");
624 }
625
626 static void
627 properties_testv_getv (void)
628 {
629   TestObject *test_obj;
630   const char *prop_names[4] = { "foo", "bar", "baz", "quux" };
631   GValue values_out_initialized[4] = { G_VALUE_INIT };
632   GValue values_out_uninitialized[4] = { G_VALUE_INIT };
633   guint i;
634
635   g_value_init (&(values_out_initialized[0]), G_TYPE_INT);
636   g_value_init (&(values_out_initialized[1]), G_TYPE_BOOLEAN);
637   g_value_init (&(values_out_initialized[2]), G_TYPE_STRING);
638   g_value_init (&(values_out_initialized[3]), G_TYPE_STRING);
639
640   test_obj = (TestObject *) g_object_new_with_properties (
641       test_object_get_type (), 0, NULL, NULL);
642
643   /* Test g_object_getv for an initialized values array */
644   g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out_initialized);
645   /* It should have init values */
646   g_assert_cmpint (g_value_get_int (&values_out_initialized[0]), ==, 42);
647   g_assert_true (g_value_get_boolean (&values_out_initialized[1]));
648   g_assert_cmpstr (g_value_get_string (&values_out_initialized[2]), ==, "Hello");
649   g_assert_cmpstr (g_value_get_string (&values_out_initialized[3]), ==, NULL);
650
651   /* Test g_object_getv for an uninitialized values array */
652   g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out_uninitialized);
653   /* It should have init values */
654   g_assert_cmpint (g_value_get_int (&values_out_uninitialized[0]), ==, 42);
655   g_assert_true (g_value_get_boolean (&values_out_uninitialized[1]));
656   g_assert_cmpstr (g_value_get_string (&values_out_uninitialized[2]), ==, "Hello");
657   g_assert_cmpstr (g_value_get_string (&values_out_uninitialized[3]), ==, NULL);
658
659   for (i = 0; i < 4; i++)
660     {
661       g_value_unset (&values_out_initialized[i]);
662       g_value_unset (&values_out_uninitialized[i]);
663     }
664   g_object_unref (test_obj);
665 }
666
667 static void
668 properties_get_property (void)
669 {
670   TestObject *test_obj;
671   struct {
672     const char *name;
673     GType gtype;
674     GValue value;
675   } test_props[] = {
676     { "foo", G_TYPE_INT, G_VALUE_INIT },
677     { "bar", G_TYPE_INVALID, G_VALUE_INIT },
678     { "bar", G_TYPE_STRING, G_VALUE_INIT },
679   };
680   gsize i;
681
682   g_test_summary ("g_object_get_property() accepts uninitialized, "
683                   "initialized, and transformable values");
684
685   for (i = 0; i < G_N_ELEMENTS (test_props); i++)
686     {
687       if (test_props[i].gtype != G_TYPE_INVALID)
688         g_value_init (&(test_props[i].value), test_props[i].gtype);
689     }
690
691   test_obj = (TestObject *) g_object_new_with_properties (test_object_get_type (), 0, NULL, NULL);
692
693   g_test_message ("Test g_object_get_property with an initialized value");
694   g_object_get_property (G_OBJECT (test_obj), test_props[0].name, &(test_props[0].value));
695   g_assert_cmpint (g_value_get_int (&(test_props[0].value)), ==, 42);
696
697   g_test_message ("Test g_object_get_property with an uninitialized value");
698   g_object_get_property (G_OBJECT (test_obj), test_props[1].name, &(test_props[1].value));
699   g_assert_true (g_value_get_boolean (&(test_props[1].value)));
700
701   g_test_message ("Test g_object_get_property with a transformable value");
702   g_object_get_property (G_OBJECT (test_obj), test_props[2].name, &(test_props[2].value));
703   g_assert_true (G_VALUE_HOLDS_STRING (&(test_props[2].value)));
704   g_assert_cmpstr (g_value_get_string (&(test_props[2].value)), ==, "TRUE");
705
706   for (i = 0; i < G_N_ELEMENTS (test_props); i++)
707     g_value_unset (&(test_props[i].value));
708
709   g_object_unref (test_obj);
710 }
711
712 static void
713 properties_testv_notify_queue (void)
714 {
715   TestObject *test_obj;
716   const char *prop_names[3] = { "foo", "bar", "baz" };
717   GValue values_in[3] = { G_VALUE_INIT };
718   Notifys n;
719   guint i;
720
721   g_value_init (&(values_in[0]), G_TYPE_INT);
722   g_value_set_int (&(values_in[0]), 100);
723
724   g_value_init (&(values_in[1]), G_TYPE_BOOLEAN);
725   g_value_set_boolean (&(values_in[1]), TRUE);
726
727   g_value_init (&(values_in[2]), G_TYPE_STRING);
728   g_value_set_string (&(values_in[2]), "");
729
730   /* Test newv_with_properties && getv */
731   test_obj = (TestObject *) g_object_new_with_properties (
732       test_object_get_type (), 0, NULL, NULL);
733
734   g_assert_nonnull (properties[PROP_FOO]);
735
736   n.pspec[0] = properties[PROP_BAZ];
737   n.pspec[1] = properties[PROP_BAR];
738   n.pspec[2] = properties[PROP_FOO];
739   n.pos = 0;
740
741   g_signal_connect (test_obj, "notify", G_CALLBACK (on_notify2), &n);
742
743   g_object_freeze_notify (G_OBJECT (test_obj));
744   {
745     g_object_setv (G_OBJECT (test_obj), 3, prop_names, values_in);
746
747     /* Set "foo" to 70 */
748     g_value_set_int (&(values_in[0]), 100);
749     g_object_setv (G_OBJECT (test_obj), 1, prop_names, values_in);
750   }
751   g_object_thaw_notify (G_OBJECT (test_obj));
752   g_assert_cmpint (n.pos, ==, 3);
753
754   for (i = 0; i < 3; i++)
755     g_value_unset (&values_in[i]);
756   g_object_unref (test_obj);
757 }
758
759 int
760 main (int argc, char *argv[])
761 {
762   g_test_init (&argc, &argv, NULL);
763
764   g_test_add_func ("/properties/install", properties_install);
765   g_test_add_func ("/properties/install-many", properties_install_many);
766   g_test_add_func ("/properties/notify", properties_notify);
767   g_test_add_func ("/properties/notify-queue", properties_notify_queue);
768   g_test_add_func ("/properties/construct", properties_construct);
769   g_test_add_func ("/properties/get-property", properties_get_property);
770
771   g_test_add_func ("/properties/testv_with_no_properties",
772       properties_testv_with_no_properties);
773   g_test_add_func ("/properties/testv_with_valid_properties",
774       properties_testv_with_valid_properties);
775   g_test_add_func ("/properties/testv_with_invalid_property_type",
776       properties_testv_with_invalid_property_type);
777   g_test_add_func ("/properties/testv_with_invalid_property_names",
778       properties_testv_with_invalid_property_names);
779   g_test_add_func ("/properties/testv_getv", properties_testv_getv);
780   g_test_add_func ("/properties/testv_notify_queue",
781       properties_testv_notify_queue);
782
783   return g_test_run ();
784 }