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