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), pspec: 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), pspec: 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 (str1: obj->baz, str2: baz) != 0) |
57 | { |
58 | g_free (mem: obj->baz); |
59 | obj->baz = g_strdup (str: baz); |
60 | |
61 | g_assert (properties[PROP_BAZ] != NULL); |
62 | g_object_notify_by_pspec (G_OBJECT (obj), pspec: 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 (str1: obj->quux, str2: quux) != 0) |
71 | { |
72 | g_free (mem: obj->quux); |
73 | obj->quux = g_strdup (str: quux); |
74 | |
75 | g_assert (properties[PROP_QUUX] != NULL); |
76 | g_object_notify_by_pspec (G_OBJECT (obj), pspec: 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 (mem: self->baz); |
86 | g_free (mem: 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 (object: gobject, property_name: "foo" ); |
93 | g_object_notify_by_pspec (object: gobject, pspec: 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_cmpint (prop_id, !=, N_PROPERTIES); |
108 | g_assert (pspec == properties[prop_id]); |
109 | |
110 | switch (prop_id) |
111 | { |
112 | case PROP_FOO: |
113 | test_object_set_foo (obj: tobj, foo: g_value_get_int (value)); |
114 | break; |
115 | |
116 | case PROP_BAR: |
117 | test_object_set_bar (obj: tobj, bar: g_value_get_boolean (value)); |
118 | break; |
119 | |
120 | case PROP_BAZ: |
121 | test_object_set_baz (obj: tobj, baz: g_value_get_string (value)); |
122 | break; |
123 | |
124 | case PROP_QUUX: |
125 | test_object_set_quux (obj: tobj, quux: g_value_get_string (value)); |
126 | break; |
127 | |
128 | default: |
129 | g_assert_not_reached (); |
130 | } |
131 | } |
132 | |
133 | static void |
134 | test_object_get_property (GObject *gobject, |
135 | guint prop_id, |
136 | GValue *value, |
137 | GParamSpec *pspec) |
138 | { |
139 | TestObject *tobj = (TestObject *) gobject; |
140 | |
141 | g_assert_cmpint (prop_id, !=, 0); |
142 | g_assert_cmpint (prop_id, !=, N_PROPERTIES); |
143 | g_assert (pspec == properties[prop_id]); |
144 | |
145 | switch (prop_id) |
146 | { |
147 | case PROP_FOO: |
148 | g_value_set_int (value, v_int: tobj->foo); |
149 | break; |
150 | |
151 | case PROP_BAR: |
152 | g_value_set_boolean (value, v_boolean: tobj->bar); |
153 | break; |
154 | |
155 | case PROP_BAZ: |
156 | g_value_set_string (value, v_string: tobj->baz); |
157 | break; |
158 | |
159 | case PROP_QUUX: |
160 | g_value_set_string (value, v_string: tobj->quux); |
161 | break; |
162 | |
163 | default: |
164 | g_assert_not_reached (); |
165 | } |
166 | } |
167 | |
168 | static void |
169 | test_object_class_init (TestObjectClass *klass) |
170 | { |
171 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
172 | |
173 | properties[PROP_FOO] = g_param_spec_int (name: "foo" , nick: "Foo" , blurb: "Foo" , |
174 | minimum: -1, G_MAXINT, |
175 | default_value: 0, |
176 | flags: G_PARAM_READWRITE); |
177 | properties[PROP_BAR] = g_param_spec_boolean (name: "bar" , nick: "Bar" , blurb: "Bar" , |
178 | FALSE, |
179 | flags: G_PARAM_READWRITE); |
180 | properties[PROP_BAZ] = g_param_spec_string (name: "baz" , nick: "Baz" , blurb: "Baz" , |
181 | NULL, |
182 | flags: G_PARAM_READWRITE); |
183 | properties[PROP_QUUX] = g_param_spec_string (name: "quux" , nick: "quux" , blurb: "quux" , |
184 | NULL, |
185 | flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); |
186 | |
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; |
190 | |
191 | g_object_class_install_properties (oclass: gobject_class, n_pspecs: N_PROPERTIES, pspecs: properties); |
192 | } |
193 | |
194 | static void |
195 | test_object_init (TestObject *self) |
196 | { |
197 | self->foo = 42; |
198 | self->bar = TRUE; |
199 | self->baz = g_strdup (str: "Hello" ); |
200 | self->quux = NULL; |
201 | } |
202 | |
203 | static void |
204 | properties_install (void) |
205 | { |
206 | TestObject *obj = g_object_new (object_type: test_object_get_type (), NULL); |
207 | GParamSpec *pspec; |
208 | |
209 | g_assert (properties[PROP_FOO] != NULL); |
210 | |
211 | pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), property_name: "foo" ); |
212 | g_assert (properties[PROP_FOO] == pspec); |
213 | |
214 | g_object_unref (object: obj); |
215 | } |
216 | |
217 | typedef struct { |
218 | const gchar *name; |
219 | GParamSpec *pspec; |
220 | gboolean fired; |
221 | } TestNotifyClosure; |
222 | |
223 | static void |
224 | on_notify (GObject *gobject, |
225 | GParamSpec *pspec, |
226 | TestNotifyClosure *closure) |
227 | { |
228 | g_assert (closure->pspec == pspec); |
229 | g_assert_cmpstr (closure->name, ==, pspec->name); |
230 | closure->fired = TRUE; |
231 | } |
232 | |
233 | static void |
234 | properties_notify (void) |
235 | { |
236 | TestObject *obj = g_object_new (object_type: test_object_get_type (), NULL); |
237 | TestNotifyClosure closure; |
238 | |
239 | g_assert (properties[PROP_FOO] != NULL); |
240 | g_assert (properties[PROP_QUUX] != NULL); |
241 | g_signal_connect (obj, "notify" , G_CALLBACK (on_notify), &closure); |
242 | |
243 | closure.name = "foo" ; |
244 | closure.pspec = properties[PROP_FOO]; |
245 | |
246 | closure.fired = FALSE; |
247 | g_object_set (object: obj, first_property_name: "foo" , 47, NULL); |
248 | g_assert (closure.fired); |
249 | |
250 | closure.name = "baz" ; |
251 | closure.pspec = properties[PROP_BAZ]; |
252 | |
253 | closure.fired = FALSE; |
254 | g_object_set (object: obj, first_property_name: "baz" , "something new" , NULL); |
255 | g_assert (closure.fired); |
256 | |
257 | /* baz lacks explicit notify, so we will see this twice */ |
258 | closure.fired = FALSE; |
259 | g_object_set (object: obj, first_property_name: "baz" , "something new" , NULL); |
260 | g_assert (closure.fired); |
261 | |
262 | /* quux on the other hand, ... */ |
263 | closure.name = "quux" ; |
264 | closure.pspec = properties[PROP_QUUX]; |
265 | |
266 | closure.fired = FALSE; |
267 | g_object_set (object: obj, first_property_name: "quux" , "something new" , NULL); |
268 | g_assert (closure.fired); |
269 | |
270 | /* no change; no notify */ |
271 | closure.fired = FALSE; |
272 | g_object_set (object: obj, first_property_name: "quux" , "something new" , NULL); |
273 | g_assert (!closure.fired); |
274 | |
275 | |
276 | g_object_unref (object: obj); |
277 | } |
278 | |
279 | typedef struct { |
280 | GParamSpec *pspec[3]; |
281 | gint pos; |
282 | } Notifys; |
283 | |
284 | static void |
285 | on_notify2 (GObject *gobject, |
286 | GParamSpec *pspec, |
287 | Notifys *n) |
288 | { |
289 | g_assert (n->pspec[n->pos] == pspec); |
290 | n->pos++; |
291 | } |
292 | |
293 | static void |
294 | properties_notify_queue (void) |
295 | { |
296 | TestObject *obj = g_object_new (object_type: test_object_get_type (), NULL); |
297 | Notifys n; |
298 | |
299 | g_assert (properties[PROP_FOO] != NULL); |
300 | |
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; |
305 | |
306 | g_signal_connect (obj, "notify" , G_CALLBACK (on_notify2), &n); |
307 | |
308 | g_object_freeze_notify (G_OBJECT (obj)); |
309 | g_object_set (object: obj, first_property_name: "foo" , 47, NULL); |
310 | g_object_set (object: obj, first_property_name: "bar" , TRUE, "foo" , 42, "baz" , "abc" , NULL); |
311 | g_object_thaw_notify (G_OBJECT (obj)); |
312 | g_assert (n.pos == 3); |
313 | |
314 | g_object_unref (object: obj); |
315 | } |
316 | |
317 | static void |
318 | properties_construct (void) |
319 | { |
320 | TestObject *obj; |
321 | gint val; |
322 | gboolean b; |
323 | gchar *s; |
324 | |
325 | g_test_bug (bug_uri_snippet: "630357" ); |
326 | |
327 | /* more than 16 args triggers a realloc in g_object_new_valist() */ |
328 | obj = g_object_new (object_type: test_object_get_type (), |
329 | first_property_name: "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); |
350 | |
351 | g_object_get (object: obj, first_property_name: "foo" , &val, NULL); |
352 | g_assert (val == 18); |
353 | g_object_get (object: obj, first_property_name: "bar" , &b, NULL); |
354 | g_assert (!b); |
355 | g_object_get (object: obj, first_property_name: "baz" , &s, NULL); |
356 | g_assert_cmpstr (s, ==, "boo" ); |
357 | g_free (mem: s); |
358 | |
359 | g_object_unref (object: obj); |
360 | } |
361 | |
362 | static void |
363 | properties_testv_with_no_properties (void) |
364 | { |
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; |
369 | |
370 | /* Test newv_with_properties && getv */ |
371 | test_obj = (TestObject *) g_object_new_with_properties ( |
372 | object_type: test_object_get_type (), n_properties: 0, NULL, NULL); |
373 | g_object_getv (G_OBJECT (test_obj), n_properties: 4, names: prop_names, values: values_out); |
374 | |
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); |
380 | |
381 | for (i = 0; i < 4; i++) |
382 | g_value_unset (value: &values_out[i]); |
383 | g_object_unref (object: test_obj); |
384 | } |
385 | |
386 | static void |
387 | properties_testv_with_valid_properties (void) |
388 | { |
389 | TestObject *test_obj; |
390 | const char *prop_names[4] = { "foo" , "bar" , "baz" , "quux" }; |
391 | |
392 | GValue values_in[4] = { G_VALUE_INIT }; |
393 | GValue values_out[4] = { G_VALUE_INIT }; |
394 | guint i; |
395 | |
396 | g_value_init (value: &(values_in[0]), G_TYPE_INT); |
397 | g_value_set_int (value: &(values_in[0]), v_int: 100); |
398 | |
399 | g_value_init (value: &(values_in[1]), G_TYPE_BOOLEAN); |
400 | g_value_set_boolean (value: &(values_in[1]), TRUE); |
401 | |
402 | g_value_init (value: &(values_in[2]), G_TYPE_STRING); |
403 | g_value_set_string (value: &(values_in[2]), v_string: "pigs" ); |
404 | |
405 | g_value_init (value: &(values_in[3]), G_TYPE_STRING); |
406 | g_value_set_string (value: &(values_in[3]), v_string: "fly" ); |
407 | |
408 | /* Test newv_with_properties && getv */ |
409 | test_obj = (TestObject *) g_object_new_with_properties ( |
410 | object_type: test_object_get_type (), n_properties: 4, names: prop_names, values: values_in); |
411 | g_object_getv (G_OBJECT (test_obj), n_properties: 4, names: prop_names, values: values_out); |
412 | |
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" ); |
417 | |
418 | for (i = 0; i < G_N_ELEMENTS (values_out); i++) |
419 | g_value_unset (value: &values_out[i]); |
420 | |
421 | /* Test newv2 && getv */ |
422 | g_value_set_string (value: &(values_in[2]), v_string: "Elmo knows" ); |
423 | g_value_set_string (value: &(values_in[3]), v_string: "where you live" ); |
424 | g_object_setv (G_OBJECT (test_obj), n_properties: 4, names: prop_names, values: values_in); |
425 | |
426 | g_object_getv (G_OBJECT (test_obj), n_properties: 4, names: prop_names, values: values_out); |
427 | |
428 | g_assert_cmpint (g_value_get_int (&values_out[0]), ==, 100); |
429 | g_assert_true (g_value_get_boolean (&values_out[1])); |
430 | |
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" ); |
433 | |
434 | for (i = 0; i < G_N_ELEMENTS (values_in); i++) |
435 | g_value_unset (value: &values_in[i]); |
436 | for (i = 0; i < G_N_ELEMENTS (values_out); i++) |
437 | g_value_unset (value: &values_out[i]); |
438 | |
439 | g_object_unref (object: test_obj); |
440 | } |
441 | |
442 | static void |
443 | properties_testv_with_invalid_property_type (void) |
444 | { |
445 | if (g_test_subprocess ()) |
446 | { |
447 | TestObject *test_obj; |
448 | const char *invalid_prop_names[1] = { "foo" }; |
449 | GValue values_in[1] = { G_VALUE_INIT }; |
450 | |
451 | g_value_init (value: &(values_in[0]), G_TYPE_STRING); |
452 | g_value_set_string (value: &(values_in[0]), v_string: "fly" ); |
453 | |
454 | test_obj = (TestObject *) g_object_new_with_properties ( |
455 | object_type: test_object_get_type (), n_properties: 1, names: invalid_prop_names, values: values_in); |
456 | /* should give a warning */ |
457 | |
458 | g_object_unref (object: test_obj); |
459 | } |
460 | g_test_trap_subprocess (NULL, usec_timeout: 0, test_flags: 0); |
461 | g_test_trap_assert_failed (); |
462 | g_test_trap_assert_stderr ("*WARNING*foo*gint*gchararray*" ); |
463 | } |
464 | |
465 | |
466 | static void |
467 | properties_testv_with_invalid_property_names (void) |
468 | { |
469 | if (g_test_subprocess ()) |
470 | { |
471 | TestObject *test_obj; |
472 | const char *invalid_prop_names[4] = { "foo" , "boo" , "moo" , "poo" }; |
473 | GValue values_in[4] = { G_VALUE_INIT }; |
474 | |
475 | g_value_init (value: &(values_in[0]), G_TYPE_INT); |
476 | g_value_set_int (value: &(values_in[0]), v_int: 100); |
477 | |
478 | g_value_init (value: &(values_in[1]), G_TYPE_BOOLEAN); |
479 | g_value_set_boolean (value: &(values_in[1]), TRUE); |
480 | |
481 | g_value_init (value: &(values_in[2]), G_TYPE_STRING); |
482 | g_value_set_string (value: &(values_in[2]), v_string: "pigs" ); |
483 | |
484 | g_value_init (value: &(values_in[3]), G_TYPE_STRING); |
485 | g_value_set_string (value: &(values_in[3]), v_string: "fly" ); |
486 | |
487 | test_obj = (TestObject *) g_object_new_with_properties ( |
488 | object_type: test_object_get_type (), n_properties: 4, names: invalid_prop_names, values: 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. |
493 | */ |
494 | |
495 | g_object_unref (object: test_obj); |
496 | } |
497 | |
498 | g_test_trap_subprocess (NULL, usec_timeout: 0, test_flags: 0); |
499 | g_test_trap_assert_failed (); |
500 | g_test_trap_assert_stderr ("*CRITICAL*g_object_new_is_valid_property*boo*" ); |
501 | } |
502 | |
503 | static void |
504 | properties_testv_getv (void) |
505 | { |
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; |
511 | |
512 | g_value_init (value: &(values_out_initialized[0]), G_TYPE_INT); |
513 | g_value_init (value: &(values_out_initialized[1]), G_TYPE_BOOLEAN); |
514 | g_value_init (value: &(values_out_initialized[2]), G_TYPE_STRING); |
515 | g_value_init (value: &(values_out_initialized[3]), G_TYPE_STRING); |
516 | |
517 | test_obj = (TestObject *) g_object_new_with_properties ( |
518 | object_type: test_object_get_type (), n_properties: 0, NULL, NULL); |
519 | |
520 | /* Test g_object_getv for an initialized values array */ |
521 | g_object_getv (G_OBJECT (test_obj), n_properties: 4, names: prop_names, values: 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); |
527 | |
528 | /* Test g_object_getv for an uninitialized values array */ |
529 | g_object_getv (G_OBJECT (test_obj), n_properties: 4, names: prop_names, values: 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); |
535 | |
536 | for (i = 0; i < 4; i++) |
537 | { |
538 | g_value_unset (value: &values_out_initialized[i]); |
539 | g_value_unset (value: &values_out_uninitialized[i]); |
540 | } |
541 | g_object_unref (object: test_obj); |
542 | } |
543 | |
544 | static void |
545 | properties_get_property (void) |
546 | { |
547 | TestObject *test_obj; |
548 | struct { |
549 | const char *name; |
550 | GType gtype; |
551 | GValue value; |
552 | } test_props[] = { |
553 | { "foo" , G_TYPE_INT, G_VALUE_INIT }, |
554 | { "bar" , G_TYPE_INVALID, G_VALUE_INIT }, |
555 | { "bar" , G_TYPE_STRING, G_VALUE_INIT }, |
556 | }; |
557 | gsize i; |
558 | |
559 | g_test_summary (summary: "g_object_get_property() accepts uninitialized, " |
560 | "initialized, and transformable values" ); |
561 | |
562 | for (i = 0; i < G_N_ELEMENTS (test_props); i++) |
563 | { |
564 | if (test_props[i].gtype != G_TYPE_INVALID) |
565 | g_value_init (value: &(test_props[i].value), g_type: test_props[i].gtype); |
566 | } |
567 | |
568 | test_obj = (TestObject *) g_object_new_with_properties (object_type: test_object_get_type (), n_properties: 0, NULL, NULL); |
569 | |
570 | g_test_message (format: "Test g_object_get_property with an initialized value" ); |
571 | g_object_get_property (G_OBJECT (test_obj), property_name: test_props[0].name, value: &(test_props[0].value)); |
572 | g_assert_cmpint (g_value_get_int (&(test_props[0].value)), ==, 42); |
573 | |
574 | g_test_message (format: "Test g_object_get_property with an uninitialized value" ); |
575 | g_object_get_property (G_OBJECT (test_obj), property_name: test_props[1].name, value: &(test_props[1].value)); |
576 | g_assert_true (g_value_get_boolean (&(test_props[1].value))); |
577 | |
578 | g_test_message (format: "Test g_object_get_property with a transformable value" ); |
579 | g_object_get_property (G_OBJECT (test_obj), property_name: test_props[2].name, value: &(test_props[2].value)); |
580 | g_assert_true (G_VALUE_HOLDS_STRING (&(test_props[2].value))); |
581 | g_assert_cmpstr (g_value_get_string (&(test_props[2].value)), ==, "TRUE" ); |
582 | |
583 | for (i = 0; i < G_N_ELEMENTS (test_props); i++) |
584 | g_value_unset (value: &(test_props[i].value)); |
585 | |
586 | g_object_unref (object: test_obj); |
587 | } |
588 | |
589 | static void |
590 | properties_testv_notify_queue (void) |
591 | { |
592 | TestObject *test_obj; |
593 | const char *prop_names[3] = { "foo" , "bar" , "baz" }; |
594 | GValue values_in[3] = { G_VALUE_INIT }; |
595 | Notifys n; |
596 | guint i; |
597 | |
598 | g_value_init (value: &(values_in[0]), G_TYPE_INT); |
599 | g_value_set_int (value: &(values_in[0]), v_int: 100); |
600 | |
601 | g_value_init (value: &(values_in[1]), G_TYPE_BOOLEAN); |
602 | g_value_set_boolean (value: &(values_in[1]), TRUE); |
603 | |
604 | g_value_init (value: &(values_in[2]), G_TYPE_STRING); |
605 | g_value_set_string (value: &(values_in[2]), v_string: "" ); |
606 | |
607 | /* Test newv_with_properties && getv */ |
608 | test_obj = (TestObject *) g_object_new_with_properties ( |
609 | object_type: test_object_get_type (), n_properties: 0, NULL, NULL); |
610 | |
611 | g_assert_nonnull (properties[PROP_FOO]); |
612 | |
613 | n.pspec[0] = properties[PROP_BAZ]; |
614 | n.pspec[1] = properties[PROP_BAR]; |
615 | n.pspec[2] = properties[PROP_FOO]; |
616 | n.pos = 0; |
617 | |
618 | g_signal_connect (test_obj, "notify" , G_CALLBACK (on_notify2), &n); |
619 | |
620 | g_object_freeze_notify (G_OBJECT (test_obj)); |
621 | { |
622 | g_object_setv (G_OBJECT (test_obj), n_properties: 3, names: prop_names, values: values_in); |
623 | |
624 | /* Set "foo" to 70 */ |
625 | g_value_set_int (value: &(values_in[0]), v_int: 100); |
626 | g_object_setv (G_OBJECT (test_obj), n_properties: 1, names: prop_names, values: values_in); |
627 | } |
628 | g_object_thaw_notify (G_OBJECT (test_obj)); |
629 | g_assert_cmpint (n.pos, ==, 3); |
630 | |
631 | for (i = 0; i < 3; i++) |
632 | g_value_unset (value: &values_in[i]); |
633 | g_object_unref (object: test_obj); |
634 | } |
635 | |
636 | int |
637 | main (int argc, char *argv[]) |
638 | { |
639 | g_test_init (argc: &argc, argv: &argv, NULL); |
640 | |
641 | g_test_bug_base (uri_pattern: "http://bugzilla.gnome.org/" ); |
642 | |
643 | g_test_add_func (testpath: "/properties/install" , test_func: properties_install); |
644 | g_test_add_func (testpath: "/properties/notify" , test_func: properties_notify); |
645 | g_test_add_func (testpath: "/properties/notify-queue" , test_func: properties_notify_queue); |
646 | g_test_add_func (testpath: "/properties/construct" , test_func: properties_construct); |
647 | g_test_add_func (testpath: "/properties/get-property" , test_func: properties_get_property); |
648 | |
649 | g_test_add_func (testpath: "/properties/testv_with_no_properties" , |
650 | test_func: properties_testv_with_no_properties); |
651 | g_test_add_func (testpath: "/properties/testv_with_valid_properties" , |
652 | test_func: properties_testv_with_valid_properties); |
653 | g_test_add_func (testpath: "/properties/testv_with_invalid_property_type" , |
654 | test_func: properties_testv_with_invalid_property_type); |
655 | g_test_add_func (testpath: "/properties/testv_with_invalid_property_names" , |
656 | test_func: properties_testv_with_invalid_property_names); |
657 | g_test_add_func (testpath: "/properties/testv_getv" , test_func: properties_testv_getv); |
658 | g_test_add_func (testpath: "/properties/testv_notify_queue" , |
659 | test_func: properties_testv_notify_queue); |
660 | |
661 | return g_test_run (); |
662 | } |
663 | |