1 #ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
2 #define GLIB_DISABLE_DEPRECATION_WARNINGS
3 #endif
4
5 #include <glib-object.h>
6 #include <stdlib.h>
7
8 static void
test_param_value(void)9 test_param_value (void)
10 {
11 GParamSpec *p, *p2;
12 GParamSpec *pp;
13 GValue value = G_VALUE_INIT;
14
15 g_value_init (&value, G_TYPE_PARAM);
16 g_assert_true (G_VALUE_HOLDS_PARAM (&value));
17
18 p = g_param_spec_int ("my-int", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE);
19
20 g_value_take_param (&value, p);
21 p2 = g_value_get_param (&value);
22 g_assert_true (p2 == p);
23
24 pp = g_param_spec_uint ("my-uint", "My UInt", "Blurb", 0, 10, 5, G_PARAM_READWRITE);
25 g_value_set_param (&value, pp);
26
27 p2 = g_value_dup_param (&value);
28 g_assert_true (p2 == pp); /* param specs use ref/unref for copy/free */
29 g_param_spec_unref (p2);
30
31 g_value_unset (&value);
32 g_param_spec_unref (pp);
33 }
34
35 static gint destroy_count;
36
37 static void
my_destroy(gpointer data)38 my_destroy (gpointer data)
39 {
40 destroy_count++;
41 }
42
43 static void
test_param_qdata(void)44 test_param_qdata (void)
45 {
46 GParamSpec *p;
47 gchar *bla;
48 GQuark q;
49
50 q = g_quark_from_string ("bla");
51
52 p = g_param_spec_int ("my-int", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE);
53 g_param_spec_set_qdata (p, q, "bla");
54 bla = g_param_spec_get_qdata (p, q);
55 g_assert_cmpstr (bla, ==, "bla");
56
57 g_assert_cmpint (destroy_count, ==, 0);
58 g_param_spec_set_qdata_full (p, q, "bla", my_destroy);
59 g_param_spec_set_qdata_full (p, q, "blabla", my_destroy);
60 g_assert_cmpint (destroy_count, ==, 1);
61 g_assert_cmpstr (g_param_spec_steal_qdata (p, q), ==, "blabla");
62 g_assert_cmpint (destroy_count, ==, 1);
63 g_assert_null (g_param_spec_get_qdata (p, q));
64
65 g_param_spec_ref_sink (p);
66
67 g_param_spec_unref (p);
68 }
69
70 static void
test_param_validate(void)71 test_param_validate (void)
72 {
73 GParamSpec *p;
74 GValue value = G_VALUE_INIT;
75
76 p = g_param_spec_int ("my-int", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE);
77
78 g_value_init (&value, G_TYPE_INT);
79 g_value_set_int (&value, 100);
80 g_assert_false (g_param_value_defaults (p, &value));
81 g_assert_true (g_param_value_validate (p, &value));
82 g_assert_cmpint (g_value_get_int (&value), ==, 20);
83
84 g_param_value_set_default (p, &value);
85 g_assert_true (g_param_value_defaults (p, &value));
86 g_assert_cmpint (g_value_get_int (&value), ==, 10);
87
88 g_param_spec_unref (p);
89 }
90
91 static void
test_param_strings(void)92 test_param_strings (void)
93 {
94 GParamSpec *p;
95
96 /* test canonicalization */
97 p = g_param_spec_int ("my_int", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE);
98
99 g_assert_cmpstr (g_param_spec_get_name (p), ==, "my-int");
100 g_assert_cmpstr (g_param_spec_get_nick (p), ==, "My Int");
101 g_assert_cmpstr (g_param_spec_get_blurb (p), ==, "Blurb");
102
103 g_param_spec_unref (p);
104
105 /* test nick defaults to name */
106 p = g_param_spec_int ("my-int", NULL, NULL, 0, 20, 10, G_PARAM_READWRITE);
107
108 g_assert_cmpstr (g_param_spec_get_name (p), ==, "my-int");
109 g_assert_cmpstr (g_param_spec_get_nick (p), ==, "my-int");
110 g_assert_null (g_param_spec_get_blurb (p));
111
112 g_param_spec_unref (p);
113 }
114
115 static void
test_param_invalid_name(gconstpointer test_data)116 test_param_invalid_name (gconstpointer test_data)
117 {
118 const gchar *invalid_name = test_data;
119
120 g_test_summary ("Test that properties cannot be created with invalid names");
121
122 if (g_test_subprocess ())
123 {
124 GParamSpec *p;
125 p = g_param_spec_int (invalid_name, "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE);
126 g_param_spec_unref (p);
127 return;
128 }
129
130 g_test_trap_subprocess (NULL, 0, 0);
131 g_test_trap_assert_failed ();
132 g_test_trap_assert_stderr ("*CRITICAL*g_param_spec_is_valid_name (name)*");
133 }
134
135 static void
test_param_convert(void)136 test_param_convert (void)
137 {
138 GParamSpec *p;
139 GValue v1 = G_VALUE_INIT;
140 GValue v2 = G_VALUE_INIT;
141
142 p = g_param_spec_int ("my-int", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE);
143 g_value_init (&v1, G_TYPE_UINT);
144 g_value_set_uint (&v1, 43);
145
146 g_value_init (&v2, G_TYPE_INT);
147 g_value_set_int (&v2, -4);
148
149 g_assert_false (g_param_value_convert (p, &v1, &v2, TRUE));
150 g_assert_cmpint (g_value_get_int (&v2), ==, -4);
151
152 g_assert_true (g_param_value_convert (p, &v1, &v2, FALSE));
153 g_assert_cmpint (g_value_get_int (&v2), ==, 20);
154
155 g_param_spec_unref (p);
156 }
157
158 static void
test_value_transform(void)159 test_value_transform (void)
160 {
161 GValue src = G_VALUE_INIT;
162 GValue dest = G_VALUE_INIT;
163
164 #define CHECK_INT_CONVERSION(type, getter, value) \
165 g_assert_true (g_value_type_transformable (G_TYPE_INT, type)); \
166 g_value_init (&src, G_TYPE_INT); \
167 g_value_init (&dest, type); \
168 g_value_set_int (&src, value); \
169 g_assert_true (g_value_transform (&src, &dest)); \
170 g_assert_cmpint (g_value_get_##getter (&dest), ==, value); \
171 g_value_unset (&src); \
172 g_value_unset (&dest);
173
174 /* Keep a check for an integer in the range of 0-127 so we're
175 * still testing g_value_get_char(). See
176 * https://bugzilla.gnome.org/show_bug.cgi?id=659870
177 * for why it is broken.
178 */
179 CHECK_INT_CONVERSION(G_TYPE_CHAR, char, 124)
180
181 CHECK_INT_CONVERSION(G_TYPE_CHAR, schar, -124)
182 CHECK_INT_CONVERSION(G_TYPE_CHAR, schar, 124)
183 CHECK_INT_CONVERSION(G_TYPE_UCHAR, uchar, 0)
184 CHECK_INT_CONVERSION(G_TYPE_UCHAR, uchar, 255)
185 CHECK_INT_CONVERSION(G_TYPE_INT, int, -12345)
186 CHECK_INT_CONVERSION(G_TYPE_INT, int, 12345)
187 CHECK_INT_CONVERSION(G_TYPE_UINT, uint, 0)
188 CHECK_INT_CONVERSION(G_TYPE_UINT, uint, 12345)
189 CHECK_INT_CONVERSION(G_TYPE_LONG, long, -12345678)
190 CHECK_INT_CONVERSION(G_TYPE_ULONG, ulong, 12345678)
191 CHECK_INT_CONVERSION(G_TYPE_INT64, int64, -12345678)
192 CHECK_INT_CONVERSION(G_TYPE_UINT64, uint64, 12345678)
193 CHECK_INT_CONVERSION(G_TYPE_FLOAT, float, 12345678)
194 CHECK_INT_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
195
196 #define CHECK_UINT_CONVERSION(type, getter, value) \
197 g_assert_true (g_value_type_transformable (G_TYPE_UINT, type)); \
198 g_value_init (&src, G_TYPE_UINT); \
199 g_value_init (&dest, type); \
200 g_value_set_uint (&src, value); \
201 g_assert_true (g_value_transform (&src, &dest)); \
202 g_assert_cmpuint (g_value_get_##getter (&dest), ==, value); \
203 g_value_unset (&src); \
204 g_value_unset (&dest);
205
206 CHECK_UINT_CONVERSION(G_TYPE_CHAR, char, 124)
207 CHECK_UINT_CONVERSION(G_TYPE_CHAR, char, 124)
208 CHECK_UINT_CONVERSION(G_TYPE_UCHAR, uchar, 0)
209 CHECK_UINT_CONVERSION(G_TYPE_UCHAR, uchar, 255)
210 CHECK_UINT_CONVERSION(G_TYPE_INT, int, 12345)
211 CHECK_UINT_CONVERSION(G_TYPE_INT, int, 12345)
212 CHECK_UINT_CONVERSION(G_TYPE_UINT, uint, 0)
213 CHECK_UINT_CONVERSION(G_TYPE_UINT, uint, 12345)
214 CHECK_UINT_CONVERSION(G_TYPE_LONG, long, 12345678)
215 CHECK_UINT_CONVERSION(G_TYPE_ULONG, ulong, 12345678)
216 CHECK_UINT_CONVERSION(G_TYPE_INT64, int64, 12345678)
217 CHECK_UINT_CONVERSION(G_TYPE_UINT64, uint64, 12345678)
218 CHECK_UINT_CONVERSION(G_TYPE_FLOAT, float, 12345678)
219 CHECK_UINT_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
220
221 #define CHECK_LONG_CONVERSION(type, getter, value) \
222 g_assert_true (g_value_type_transformable (G_TYPE_LONG, type)); \
223 g_value_init (&src, G_TYPE_LONG); \
224 g_value_init (&dest, type); \
225 g_value_set_long (&src, value); \
226 g_assert_true (g_value_transform (&src, &dest)); \
227 g_assert_cmpint (g_value_get_##getter (&dest), ==, value); \
228 g_value_unset (&src); \
229 g_value_unset (&dest);
230
231 CHECK_LONG_CONVERSION(G_TYPE_CHAR, schar, -124)
232 CHECK_LONG_CONVERSION(G_TYPE_CHAR, schar, 124)
233 CHECK_LONG_CONVERSION(G_TYPE_UCHAR, uchar, 0)
234 CHECK_LONG_CONVERSION(G_TYPE_UCHAR, uchar, 255)
235 CHECK_LONG_CONVERSION(G_TYPE_INT, int, -12345)
236 CHECK_LONG_CONVERSION(G_TYPE_INT, int, 12345)
237 CHECK_LONG_CONVERSION(G_TYPE_UINT, uint, 0)
238 CHECK_LONG_CONVERSION(G_TYPE_UINT, uint, 12345)
239 CHECK_LONG_CONVERSION(G_TYPE_LONG, long, -12345678)
240 CHECK_LONG_CONVERSION(G_TYPE_ULONG, ulong, 12345678)
241 CHECK_LONG_CONVERSION(G_TYPE_INT64, int64, -12345678)
242 CHECK_LONG_CONVERSION(G_TYPE_UINT64, uint64, 12345678)
243 CHECK_LONG_CONVERSION(G_TYPE_FLOAT, float, 12345678)
244 CHECK_LONG_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
245
246 #define CHECK_ULONG_CONVERSION(type, getter, value) \
247 g_assert_true (g_value_type_transformable (G_TYPE_ULONG, type)); \
248 g_value_init (&src, G_TYPE_ULONG); \
249 g_value_init (&dest, type); \
250 g_value_set_ulong (&src, value); \
251 g_assert_true (g_value_transform (&src, &dest)); \
252 g_assert_cmpuint (g_value_get_##getter (&dest), ==, value); \
253 g_value_unset (&src); \
254 g_value_unset (&dest);
255
256 CHECK_ULONG_CONVERSION(G_TYPE_CHAR, char, 124)
257 CHECK_ULONG_CONVERSION(G_TYPE_CHAR, char, 124)
258 CHECK_ULONG_CONVERSION(G_TYPE_UCHAR, uchar, 0)
259 CHECK_ULONG_CONVERSION(G_TYPE_UCHAR, uchar, 255)
260 CHECK_ULONG_CONVERSION(G_TYPE_INT, int, -12345)
261 CHECK_ULONG_CONVERSION(G_TYPE_INT, int, 12345)
262 CHECK_ULONG_CONVERSION(G_TYPE_UINT, uint, 0)
263 CHECK_ULONG_CONVERSION(G_TYPE_UINT, uint, 12345)
264 CHECK_ULONG_CONVERSION(G_TYPE_LONG, long, 12345678)
265 CHECK_ULONG_CONVERSION(G_TYPE_ULONG, ulong, 12345678)
266 CHECK_ULONG_CONVERSION(G_TYPE_INT64, int64, 12345678)
267 CHECK_ULONG_CONVERSION(G_TYPE_UINT64, uint64, 12345678)
268 CHECK_ULONG_CONVERSION(G_TYPE_FLOAT, float, 12345678)
269 CHECK_ULONG_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
270
271 #define CHECK_INT64_CONVERSION(type, getter, value) \
272 g_assert_true (g_value_type_transformable (G_TYPE_INT64, type)); \
273 g_value_init (&src, G_TYPE_INT64); \
274 g_value_init (&dest, type); \
275 g_value_set_int64 (&src, value); \
276 g_assert_true (g_value_transform (&src, &dest)); \
277 g_assert_cmpint (g_value_get_##getter (&dest), ==, value); \
278 g_value_unset (&src); \
279 g_value_unset (&dest);
280
281 CHECK_INT64_CONVERSION(G_TYPE_CHAR, schar, -124)
282 CHECK_INT64_CONVERSION(G_TYPE_CHAR, schar, 124)
283 CHECK_INT64_CONVERSION(G_TYPE_UCHAR, uchar, 0)
284 CHECK_INT64_CONVERSION(G_TYPE_UCHAR, uchar, 255)
285 CHECK_INT64_CONVERSION(G_TYPE_INT, int, -12345)
286 CHECK_INT64_CONVERSION(G_TYPE_INT, int, 12345)
287 CHECK_INT64_CONVERSION(G_TYPE_UINT, uint, 0)
288 CHECK_INT64_CONVERSION(G_TYPE_UINT, uint, 12345)
289 CHECK_INT64_CONVERSION(G_TYPE_LONG, long, -12345678)
290 CHECK_INT64_CONVERSION(G_TYPE_ULONG, ulong, 12345678)
291 CHECK_INT64_CONVERSION(G_TYPE_INT64, int64, -12345678)
292 CHECK_INT64_CONVERSION(G_TYPE_UINT64, uint64, 12345678)
293 CHECK_INT64_CONVERSION(G_TYPE_FLOAT, float, 12345678)
294 CHECK_INT64_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
295
296 #define CHECK_UINT64_CONVERSION(type, getter, value) \
297 g_assert_true (g_value_type_transformable (G_TYPE_UINT64, type)); \
298 g_value_init (&src, G_TYPE_UINT64); \
299 g_value_init (&dest, type); \
300 g_value_set_uint64 (&src, value); \
301 g_assert_true (g_value_transform (&src, &dest)); \
302 g_assert_cmpuint (g_value_get_##getter (&dest), ==, value); \
303 g_value_unset (&src); \
304 g_value_unset (&dest);
305
306 CHECK_UINT64_CONVERSION(G_TYPE_CHAR, schar, -124)
307 CHECK_UINT64_CONVERSION(G_TYPE_CHAR, schar, 124)
308 CHECK_UINT64_CONVERSION(G_TYPE_UCHAR, uchar, 0)
309 CHECK_UINT64_CONVERSION(G_TYPE_UCHAR, uchar, 255)
310 CHECK_UINT64_CONVERSION(G_TYPE_INT, int, -12345)
311 CHECK_UINT64_CONVERSION(G_TYPE_INT, int, 12345)
312 CHECK_UINT64_CONVERSION(G_TYPE_UINT, uint, 0)
313 CHECK_UINT64_CONVERSION(G_TYPE_UINT, uint, 12345)
314 CHECK_UINT64_CONVERSION(G_TYPE_LONG, long, -12345678)
315 CHECK_UINT64_CONVERSION(G_TYPE_ULONG, ulong, 12345678)
316 CHECK_UINT64_CONVERSION(G_TYPE_INT64, int64, -12345678)
317 CHECK_UINT64_CONVERSION(G_TYPE_UINT64, uint64, 12345678)
318 CHECK_UINT64_CONVERSION(G_TYPE_FLOAT, float, 12345678)
319 CHECK_UINT64_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
320
321 #define CHECK_FLOAT_CONVERSION(type, getter, value) \
322 g_assert_true (g_value_type_transformable (G_TYPE_FLOAT, type)); \
323 g_value_init (&src, G_TYPE_FLOAT); \
324 g_value_init (&dest, type); \
325 g_value_set_float (&src, value); \
326 g_assert_true (g_value_transform (&src, &dest)); \
327 g_assert_cmpfloat (g_value_get_##getter (&dest), ==, value); \
328 g_value_unset (&src); \
329 g_value_unset (&dest);
330
331 CHECK_FLOAT_CONVERSION(G_TYPE_CHAR, schar, -124)
332 CHECK_FLOAT_CONVERSION(G_TYPE_CHAR, schar, 124)
333 CHECK_FLOAT_CONVERSION(G_TYPE_UCHAR, uchar, 0)
334 CHECK_FLOAT_CONVERSION(G_TYPE_UCHAR, uchar, 255)
335 CHECK_FLOAT_CONVERSION(G_TYPE_INT, int, -12345)
336 CHECK_FLOAT_CONVERSION(G_TYPE_INT, int, 12345)
337 CHECK_FLOAT_CONVERSION(G_TYPE_UINT, uint, 0)
338 CHECK_FLOAT_CONVERSION(G_TYPE_UINT, uint, 12345)
339 CHECK_FLOAT_CONVERSION(G_TYPE_LONG, long, -12345678)
340 CHECK_FLOAT_CONVERSION(G_TYPE_ULONG, ulong, 12345678)
341 CHECK_FLOAT_CONVERSION(G_TYPE_INT64, int64, -12345678)
342 CHECK_FLOAT_CONVERSION(G_TYPE_UINT64, uint64, 12345678)
343 CHECK_FLOAT_CONVERSION(G_TYPE_FLOAT, float, 12345678)
344 CHECK_FLOAT_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
345
346 #define CHECK_DOUBLE_CONVERSION(type, getter, value) \
347 g_assert_true (g_value_type_transformable (G_TYPE_DOUBLE, type)); \
348 g_value_init (&src, G_TYPE_DOUBLE); \
349 g_value_init (&dest, type); \
350 g_value_set_double (&src, value); \
351 g_assert_true (g_value_transform (&src, &dest)); \
352 g_assert_cmpfloat (g_value_get_##getter (&dest), ==, value); \
353 g_value_unset (&src); \
354 g_value_unset (&dest);
355
356 CHECK_DOUBLE_CONVERSION(G_TYPE_CHAR, schar, -124)
357 CHECK_DOUBLE_CONVERSION(G_TYPE_CHAR, schar, 124)
358 CHECK_DOUBLE_CONVERSION(G_TYPE_UCHAR, uchar, 0)
359 CHECK_DOUBLE_CONVERSION(G_TYPE_UCHAR, uchar, 255)
360 CHECK_DOUBLE_CONVERSION(G_TYPE_INT, int, -12345)
361 CHECK_DOUBLE_CONVERSION(G_TYPE_INT, int, 12345)
362 CHECK_DOUBLE_CONVERSION(G_TYPE_UINT, uint, 0)
363 CHECK_DOUBLE_CONVERSION(G_TYPE_UINT, uint, 12345)
364 CHECK_DOUBLE_CONVERSION(G_TYPE_LONG, long, -12345678)
365 CHECK_DOUBLE_CONVERSION(G_TYPE_ULONG, ulong, 12345678)
366 CHECK_DOUBLE_CONVERSION(G_TYPE_INT64, int64, -12345678)
367 CHECK_DOUBLE_CONVERSION(G_TYPE_UINT64, uint64, 12345678)
368 CHECK_DOUBLE_CONVERSION(G_TYPE_FLOAT, float, 12345678)
369 CHECK_DOUBLE_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
370
371 #define CHECK_BOOLEAN_CONVERSION(type, setter, value) \
372 g_assert_true (g_value_type_transformable (type, G_TYPE_BOOLEAN)); \
373 g_value_init (&src, type); \
374 g_value_init (&dest, G_TYPE_BOOLEAN); \
375 g_value_set_##setter (&src, value); \
376 g_assert_true (g_value_transform (&src, &dest)); \
377 g_assert_cmpint (g_value_get_boolean (&dest), ==, TRUE); \
378 g_value_set_##setter (&src, 0); \
379 g_assert_true (g_value_transform (&src, &dest)); \
380 g_assert_cmpint (g_value_get_boolean (&dest), ==, FALSE); \
381 g_value_unset (&src); \
382 g_value_unset (&dest);
383
384 CHECK_BOOLEAN_CONVERSION(G_TYPE_INT, int, -12345)
385 CHECK_BOOLEAN_CONVERSION(G_TYPE_UINT, uint, 12345)
386 CHECK_BOOLEAN_CONVERSION(G_TYPE_LONG, long, -12345678)
387 CHECK_BOOLEAN_CONVERSION(G_TYPE_ULONG, ulong, 12345678)
388 CHECK_BOOLEAN_CONVERSION(G_TYPE_INT64, int64, -12345678)
389 CHECK_BOOLEAN_CONVERSION(G_TYPE_UINT64, uint64, 12345678)
390
391 #define CHECK_STRING_CONVERSION(int_type, setter, int_value) \
392 g_assert_true (g_value_type_transformable (int_type, G_TYPE_STRING)); \
393 g_value_init (&src, int_type); \
394 g_value_init (&dest, G_TYPE_STRING); \
395 g_value_set_##setter (&src, int_value); \
396 g_assert_true (g_value_transform (&src, &dest)); \
397 g_assert_cmpstr (g_value_get_string (&dest), ==, #int_value); \
398 g_value_unset (&src); \
399 g_value_unset (&dest);
400
401 CHECK_STRING_CONVERSION(G_TYPE_INT, int, -12345)
402 CHECK_STRING_CONVERSION(G_TYPE_UINT, uint, 12345)
403 CHECK_STRING_CONVERSION(G_TYPE_LONG, long, -12345678)
404 CHECK_STRING_CONVERSION(G_TYPE_ULONG, ulong, 12345678)
405 CHECK_STRING_CONVERSION(G_TYPE_INT64, int64, -12345678)
406 CHECK_STRING_CONVERSION(G_TYPE_UINT64, uint64, 12345678)
407 CHECK_STRING_CONVERSION(G_TYPE_FLOAT, float, 0.500000)
408 CHECK_STRING_CONVERSION(G_TYPE_DOUBLE, double, -1.234567)
409
410 g_assert_false (g_value_type_transformable (G_TYPE_STRING, G_TYPE_CHAR));
411 g_value_init (&src, G_TYPE_STRING);
412 g_value_init (&dest, G_TYPE_CHAR);
413 g_value_set_static_string (&src, "bla");
414 g_value_set_schar (&dest, 'c');
415 g_assert_false (g_value_transform (&src, &dest));
416 g_assert_cmpint (g_value_get_schar (&dest), ==, 'c');
417 g_value_unset (&src);
418 g_value_unset (&dest);
419 }
420
421
422 /* We create some dummy objects with a simple relationship:
423 *
424 * GObject
425 * / \
426 * TestObjectA TestObjectC
427 * |
428 * TestObjectB
429 *
430 * ie: TestObjectB is a subclass of TestObjectA and TestObjectC is
431 * related to neither.
432 */
433
434 static GType test_object_a_get_type (void);
435 typedef GObject TestObjectA; typedef GObjectClass TestObjectAClass;
G_DEFINE_TYPE(TestObjectA,test_object_a,G_TYPE_OBJECT)436 G_DEFINE_TYPE (TestObjectA, test_object_a, G_TYPE_OBJECT)
437 static void test_object_a_class_init (TestObjectAClass *class) { }
test_object_a_init(TestObjectA * a)438 static void test_object_a_init (TestObjectA *a) { }
439
440 static GType test_object_b_get_type (void);
441 typedef GObject TestObjectB; typedef GObjectClass TestObjectBClass;
G_DEFINE_TYPE(TestObjectB,test_object_b,test_object_a_get_type ())442 G_DEFINE_TYPE (TestObjectB, test_object_b, test_object_a_get_type ())
443 static void test_object_b_class_init (TestObjectBClass *class) { }
test_object_b_init(TestObjectB * b)444 static void test_object_b_init (TestObjectB *b) { }
445
446 static GType test_object_c_get_type (void);
447 typedef GObject TestObjectC; typedef GObjectClass TestObjectCClass;
G_DEFINE_TYPE(TestObjectC,test_object_c,G_TYPE_OBJECT)448 G_DEFINE_TYPE (TestObjectC, test_object_c, G_TYPE_OBJECT)
449 static void test_object_c_class_init (TestObjectCClass *class) { }
test_object_c_init(TestObjectC * c)450 static void test_object_c_init (TestObjectC *c) { }
451
452 /* We create an interface and programmatically populate it with
453 * properties of each of the above type, with various flag combinations.
454 *
455 * Properties are named like "type-perm" where type is 'a', 'b' or 'c'
456 * and perm is a series of characters, indicating the permissions:
457 *
458 * - 'r': readable
459 * - 'w': writable
460 * - 'c': construct
461 * - 'C': construct-only
462 *
463 * It doesn't make sense to have a property that is neither readable nor
464 * writable. It is also not valid to have construct or construct-only
465 * on read-only params. Finally, it is invalid to have both construct
466 * and construct-only specified, so we do not consider those cases.
467 * That gives us 7 possible permissions:
468 *
469 * 'r', 'w', 'rw', 'wc', 'rwc', 'wC', 'rwC'
470 *
471 * And 9 impossible ones:
472 *
473 * '', 'c', 'rc', 'C', 'rC', 'cC', 'rcC', 'wcC', rwcC'
474 *
475 * For a total of 16 combinations.
476 *
477 * That gives a total of 48 (16 * 3) possible flag/type combinations, of
478 * which 27 (9 * 3) are impossible to install.
479 *
480 * That gives 21 (7 * 3) properties that will be installed.
481 */
482 typedef GTypeInterface TestInterfaceInterface;
483 static GType test_interface_get_type (void);
484 //typedef struct _TestInterface TestInterface;
G_DEFINE_INTERFACE(TestInterface,test_interface,G_TYPE_OBJECT)485 G_DEFINE_INTERFACE (TestInterface, test_interface, G_TYPE_OBJECT)
486 static void
487 test_interface_default_init (TestInterfaceInterface *iface)
488 {
489 const gchar *names[] = { "a", "b", "c" };
490 const gchar *perms[] = { NULL, "r", "w", "rw",
491 NULL, NULL, "wc", "rwc",
492 NULL, NULL, "wC", "rwC",
493 NULL, NULL, NULL, NULL };
494 const GType types[] = { test_object_a_get_type (), test_object_b_get_type (), test_object_c_get_type () };
495 guint i, j;
496
497 for (i = 0; i < G_N_ELEMENTS (types); i++)
498 for (j = 0; j < G_N_ELEMENTS (perms); j++)
499 {
500 gchar prop_name[10];
501 GParamSpec *pspec;
502
503 if (perms[j] == NULL)
504 {
505 if (!g_test_undefined ())
506 continue;
507
508 /* we think that this is impossible. make sure. */
509 pspec = g_param_spec_object ("xyz", "xyz", "xyz", types[i], j);
510
511 g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
512 "*assertion*pspec->flags*failed*");
513 g_object_interface_install_property (iface, pspec);
514 g_test_assert_expected_messages ();
515
516 g_param_spec_unref (pspec);
517 continue;
518 }
519
520 /* install the property */
521 g_snprintf (prop_name, sizeof prop_name, "%s-%s", names[i], perms[j]);
522 pspec = g_param_spec_object (prop_name, prop_name, prop_name, types[i], j);
523 g_object_interface_install_property (iface, pspec);
524 }
525 }
526
527 /* We now have 21 properties. Each property may be correctly
528 * implemented with the following types:
529 *
530 * Properties Valid Types Reason
531 *
532 * a-r a, b Read only can provide subclasses
533 * a-w, wc, wC a, GObject Write only can accept superclasses
534 * a-rw, rwc, rwC a Read-write must be exactly equal
535 *
536 * b-r b (as above)
537 * b-w, wc, wC b, a, GObject
538 * b-rw, rwc, rwC b
539 *
540 * c-r c (as above)
541 * c-wo, wc, wC c, GObject
542 * c-rw, rwc, rwC c
543 *
544 * We can express this in a 48-by-4 table where each row represents an
545 * installed property and each column represents a type. The value in
546 * the table represents if it is valid to subclass the row's property
547 * with the type of the column:
548 *
549 * - 0: invalid because the interface property doesn't exist (invalid flags)
550 * - 'v': valid
551 * - '=': invalid because of the type not being exactly equal
552 * - '<': invalid because of the type not being a subclass
553 * - '>': invalid because of the type not being a superclass
554 *
555 * We organise the table by interface property type ('a', 'b', 'c') then
556 * by interface property flags.
557 */
558
559 static gint valid_impl_types[48][4] = {
560 /* a b c GObject */
561 /* 'a-' */ { 0, },
562 /* 'a-r' */ { 'v', 'v', '<', '<' },
563 /* 'a-w' */ { 'v', '>', '>', 'v' },
564 /* 'a-rw' */ { 'v', '=', '=', '=' },
565 /* 'a-c */ { 0, },
566 /* 'a-rc' */ { 0, },
567 /* 'a-wc' */ { 'v', '>', '>', 'v' },
568 /* 'a-rwc' */ { 'v', '=', '=', '=' },
569 /* 'a-C */ { 0, },
570 /* 'a-rC' */ { 0, },
571 /* 'a-wC' */ { 'v', '>', '>', 'v' },
572 /* 'a-rwC' */ { 'v', '=', '=', '=' },
573 /* 'a-cC */ { 0, },
574 /* 'a-rcC' */ { 0, },
575 /* 'a-wcC' */ { 0, },
576 /* 'a-rwcC' */ { 0, },
577
578 /* 'b-' */ { 0, },
579 /* 'b-r' */ { '<', 'v', '<', '<' },
580 /* 'b-w' */ { 'v', 'v', '>', 'v' },
581 /* 'b-rw' */ { '=', 'v', '=', '=' },
582 /* 'b-c */ { 0, },
583 /* 'b-rc' */ { 0, },
584 /* 'b-wc' */ { 'v', 'v', '>', 'v' },
585 /* 'b-rwc' */ { '=', 'v', '=', '=' },
586 /* 'b-C */ { 0, },
587 /* 'b-rC' */ { 0, },
588 /* 'b-wC' */ { 'v', 'v', '>', 'v' },
589 /* 'b-rwC' */ { '=', 'v', '=', '=' },
590 /* 'b-cC */ { 0, },
591 /* 'b-rcC' */ { 0, },
592 /* 'b-wcC' */ { 0, },
593 /* 'b-rwcC' */ { 0, },
594
595 /* 'c-' */ { 0, },
596 /* 'c-r' */ { '<', '<', 'v', '<' },
597 /* 'c-w' */ { '>', '>', 'v', 'v' },
598 /* 'c-rw' */ { '=', '=', 'v', '=' },
599 /* 'c-c */ { 0, },
600 /* 'c-rc' */ { 0, },
601 /* 'c-wc' */ { '>', '>', 'v', 'v' },
602 /* 'c-rwc' */ { '=', '=', 'v', '=' },
603 /* 'c-C */ { 0, },
604 /* 'c-rC' */ { 0, },
605 /* 'c-wC' */ { '>', '>', 'v', 'v' },
606 /* 'c-rwC' */ { '=', '=', 'v', '=' },
607 /* 'c-cC */ { 0, },
608 /* 'c-rcC' */ { 0, },
609 /* 'c-wcC' */ { 0, },
610 /* 'c-rwcC' */ { 0, }
611 };
612
613 /* We also try to change the flags. We must ensure that all
614 * implementations provide all functionality promised by the interface.
615 * We must therefore never remove readability or writability (but we can
616 * add them). Construct-only is a restrictions that applies to
617 * writability, so we can never add it unless writability was never
618 * present in the first place, in which case "writable at construct
619 * only" is still better than "not writable".
620 *
621 * The 'construct' flag is of interest only to the implementation. It
622 * may be changed at any time.
623 *
624 * Properties Valid Access Reason
625 *
626 * *-r r, rw, rwc, rwC Must keep readable, but can restrict newly-added writable
627 * *-w w, rw, rwc Must keep writable unrestricted
628 * *-rw rw, rwc Must not add any restrictions
629 * *-rwc rw, rwc Must not add any restrictions
630 * *-rwC rw, rwc, rwC Can remove 'construct-only' restriction
631 * *-wc rwc, rw, w, wc Can add readability
632 * *-wC rwC, rw, w, wC Can add readability or remove 'construct only' restriction
633 * rwc, wc
634 *
635 * We can represent this with a 16-by-16 table. The rows represent the
636 * flags of the property on the interface. The columns is the flags to
637 * try to use when overriding the property. The cell contents are:
638 *
639 * - 0: invalid because the interface property doesn't exist (invalid flags)
640 * - 'v': valid
641 * - 'i': invalid because the implementation flags are invalid
642 * - 'f': invalid because of the removal of functionality
643 * - 'r': invalid because of the addition of restrictions (ie: construct-only)
644 *
645 * We also ensure that removal of functionality is reported before
646 * addition of restrictions, since this is a more basic problem.
647 */
648 static gint valid_impl_flags[16][16] = {
649 /* '' r w rw c rc wc rwc C rC wC rwC cC rcC wcC rwcC */
650 /* '*-' */ { 0, },
651 /* '*-r' */ { 'i', 'v', 'f', 'v', 'i', 'i', 'f', 'v', 'i', 'i', 'f', 'v', 'i', 'i', 'i', 'i' },
652 /* '*-w' */ { 'i', 'f', 'v', 'v', 'i', 'i', 'v', 'v', 'i', 'i', 'r', 'r', 'i', 'i', 'i', 'i' },
653 /* '*-rw' */ { 'i', 'f', 'f', 'v', 'i', 'i', 'f', 'v', 'i', 'i', 'f', 'r', 'i', 'i', 'i', 'i' },
654 /* '*-c */ { 0, },
655 /* '*-rc' */ { 0, },
656 /* '*-wc' */ { 'i', 'f', 'v', 'v', 'i', 'i', 'v', 'v', 'i', 'i', 'r', 'r', 'i', 'i', 'i', 'i' },
657 /* '*-rwc' */ { 'i', 'f', 'f', 'v', 'i', 'i', 'f', 'v', 'i', 'i', 'f', 'r', 'i', 'i', 'i', 'i' },
658 /* '*-C */ { 0, },
659 /* '*-rC' */ { 0, },
660 /* '*-wC' */ { 'i', 'f', 'v', 'v', 'i', 'i', 'v', 'v', 'i', 'i', 'v', 'v', 'i', 'i', 'i', 'i' },
661 /* '*-rwC' */ { 'i', 'f', 'f', 'v', 'i', 'i', 'f', 'v', 'i', 'i', 'f', 'v', 'i', 'i', 'i', 'i' },
662 };
663
664 static guint change_this_flag;
665 static guint change_this_type;
666 static guint use_this_flag;
667 static guint use_this_type;
668
669 typedef GObjectClass TestImplementationClass;
670 typedef GObject TestImplementation;
671
test_implementation_init(TestImplementation * impl)672 static void test_implementation_init (TestImplementation *impl) { }
test_implementation_iface_init(TestInterfaceInterface * iface)673 static void test_implementation_iface_init (TestInterfaceInterface *iface) { }
674
675 static GType test_implementation_get_type (void);
G_DEFINE_TYPE_WITH_CODE(TestImplementation,test_implementation,G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (test_interface_get_type (),test_implementation_iface_init))676 G_DEFINE_TYPE_WITH_CODE (TestImplementation, test_implementation, G_TYPE_OBJECT,
677 G_IMPLEMENT_INTERFACE (test_interface_get_type (), test_implementation_iface_init))
678
679 static void test_implementation_class_init (TestImplementationClass *class)
680 {
681 const gchar *names[] = { "a", "b", "c" };
682 const gchar *perms[] = { NULL, "r", "w", "rw",
683 NULL, NULL, "wc", "rwc",
684 NULL, NULL, "wC", "rwC",
685 NULL, NULL, NULL, NULL };
686 const GType types[] = { test_object_a_get_type (), test_object_b_get_type (),
687 test_object_c_get_type (), G_TYPE_OBJECT };
688 gchar prop_name[10];
689 GParamSpec *pspec;
690 guint i, j;
691
692 class->get_property = GINT_TO_POINTER (1);
693 class->set_property = GINT_TO_POINTER (1);
694
695 /* Install all of the non-modified properties or else GObject will
696 * complain about non-implemented properties.
697 */
698 for (i = 0; i < 3; i++)
699 for (j = 0; j < G_N_ELEMENTS (perms); j++)
700 {
701 if (i == change_this_type && j == change_this_flag)
702 continue;
703
704 if (perms[j] != NULL)
705 {
706 /* override the property without making changes */
707 g_snprintf (prop_name, sizeof prop_name, "%s-%s", names[i], perms[j]);
708 g_object_class_override_property (class, 1, prop_name);
709 }
710 }
711
712 /* Now try installing our modified property */
713 if (perms[change_this_flag] == NULL)
714 g_error ("Interface property does not exist");
715
716 g_snprintf (prop_name, sizeof prop_name, "%s-%s", names[change_this_type], perms[change_this_flag]);
717 pspec = g_param_spec_object (prop_name, prop_name, prop_name, types[use_this_type], use_this_flag);
718 g_object_class_install_property (class, 1, pspec);
719 }
720
721 typedef struct {
722 gint change_this_flag;
723 gint change_this_type;
724 gint use_this_flag;
725 gint use_this_type;
726 } TestParamImplementData;
727
728 static void
test_param_implement_child(gconstpointer user_data)729 test_param_implement_child (gconstpointer user_data)
730 {
731 TestParamImplementData *data = (gpointer) user_data;
732
733 /* GObject oddity: GObjectClass must be initialised before we can
734 * initialise a GTypeInterface.
735 */
736 g_type_class_ref (G_TYPE_OBJECT);
737
738 /* Bring up the interface first. */
739 g_type_default_interface_ref (test_interface_get_type ());
740
741 /* Copy the flags into the global vars so
742 * test_implementation_class_init() will see them.
743 */
744 change_this_flag = data->change_this_flag;
745 change_this_type = data->change_this_type;
746 use_this_flag = data->use_this_flag;
747 use_this_type = data->use_this_type;
748
749 g_type_class_ref (test_implementation_get_type ());
750 }
751
752 static void
test_param_implement(void)753 test_param_implement (void)
754 {
755 gchar *test_path;
756
757 for (change_this_flag = 0; change_this_flag < 16; change_this_flag++)
758 for (change_this_type = 0; change_this_type < 3; change_this_type++)
759 for (use_this_flag = 0; use_this_flag < 16; use_this_flag++)
760 for (use_this_type = 0; use_this_type < 4; use_this_type++)
761 {
762 if (!g_test_undefined ())
763 {
764 /* only test the valid (defined) cases, e.g. under valgrind */
765 if (valid_impl_flags[change_this_flag][use_this_flag] != 'v')
766 continue;
767
768 if (valid_impl_types[change_this_type * 16 + change_this_flag][use_this_type] != 'v')
769 continue;
770 }
771
772 test_path = g_strdup_printf ("/param/implement/subprocess/%d-%d-%d-%d",
773 change_this_flag, change_this_type,
774 use_this_flag, use_this_type);
775 g_test_trap_subprocess (test_path, G_TIME_SPAN_SECOND, 0);
776 g_free (test_path);
777
778 /* We want to ensure that any flags mismatch problems are reported first. */
779 switch (valid_impl_flags[change_this_flag][use_this_flag])
780 {
781 case 0:
782 /* make sure the other table agrees */
783 g_assert_cmpint (valid_impl_types[change_this_type * 16 + change_this_flag][use_this_type], ==, 0);
784 g_test_trap_assert_failed ();
785 g_test_trap_assert_stderr ("*Interface property does not exist*");
786 continue;
787
788 case 'i':
789 g_test_trap_assert_failed ();
790 g_test_trap_assert_stderr ("*g_object_class_install_property*");
791 continue;
792
793 case 'f':
794 g_test_trap_assert_failed ();
795 g_test_trap_assert_stderr ("*remove functionality*");
796 continue;
797
798 case 'r':
799 g_test_trap_assert_failed ();
800 g_test_trap_assert_stderr ("*introduce additional restrictions*");
801 continue;
802
803 case 'v':
804 break;
805 }
806
807 /* Next, we check if there should have been a type error. */
808 switch (valid_impl_types[change_this_type * 16 + change_this_flag][use_this_type])
809 {
810 case 0:
811 /* this should have been caught above */
812 g_assert_not_reached ();
813
814 case '=':
815 g_test_trap_assert_failed ();
816 g_test_trap_assert_stderr ("*exactly equal*");
817 continue;
818
819 case '<':
820 g_test_trap_assert_failed ();
821 g_test_trap_assert_stderr ("*equal to or more restrictive*");
822 continue;
823
824 case '>':
825 g_test_trap_assert_failed ();
826 g_test_trap_assert_stderr ("*equal to or less restrictive*");
827 continue;
828
829 case 'v':
830 break;
831 }
832
833 g_test_trap_assert_passed ();
834 }
835 }
836
837 static void
test_param_default(void)838 test_param_default (void)
839 {
840 GParamSpec *param;
841 const GValue *def;
842
843 param = g_param_spec_int ("my-int", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE);
844 def = g_param_spec_get_default_value (param);
845
846 g_assert_true (G_VALUE_HOLDS (def, G_TYPE_INT));
847 g_assert_cmpint (g_value_get_int (def), ==, 10);
848
849 g_param_spec_unref (param);
850 }
851
852 static void
test_param_is_valid_name(void)853 test_param_is_valid_name (void)
854 {
855 const gchar *valid_names[] =
856 {
857 "property",
858 "i",
859 "multiple-segments",
860 "segment0-SEGMENT1",
861 "using_underscores",
862 };
863 const gchar *invalid_names[] =
864 {
865 "",
866 "7zip",
867 "my_int:hello",
868 };
869 gsize i;
870
871 for (i = 0; i < G_N_ELEMENTS (valid_names); i++)
872 g_assert_true (g_param_spec_is_valid_name (valid_names[i]));
873
874 for (i = 0; i < G_N_ELEMENTS (invalid_names); i++)
875 g_assert_false (g_param_spec_is_valid_name (invalid_names[i]));
876 }
877
878 int
main(int argc,char * argv[])879 main (int argc, char *argv[])
880 {
881 TestParamImplementData data, *test_data;
882 gchar *test_path;
883
884 g_test_init (&argc, &argv, NULL);
885
886 g_test_add_func ("/param/value", test_param_value);
887 g_test_add_func ("/param/strings", test_param_strings);
888 g_test_add_data_func ("/param/invalid-name/colon", "my_int:hello", test_param_invalid_name);
889 g_test_add_data_func ("/param/invalid-name/first-char", "7zip", test_param_invalid_name);
890 g_test_add_data_func ("/param/invalid-name/empty", "", test_param_invalid_name);
891 g_test_add_func ("/param/qdata", test_param_qdata);
892 g_test_add_func ("/param/validate", test_param_validate);
893 g_test_add_func ("/param/convert", test_param_convert);
894
895 if (g_test_slow ())
896 g_test_add_func ("/param/implement", test_param_implement);
897
898 for (data.change_this_flag = 0; data.change_this_flag < 16; data.change_this_flag++)
899 for (data.change_this_type = 0; data.change_this_type < 3; data.change_this_type++)
900 for (data.use_this_flag = 0; data.use_this_flag < 16; data.use_this_flag++)
901 for (data.use_this_type = 0; data.use_this_type < 4; data.use_this_type++)
902 {
903 test_path = g_strdup_printf ("/param/implement/subprocess/%d-%d-%d-%d",
904 data.change_this_flag, data.change_this_type,
905 data.use_this_flag, data.use_this_type);
906 test_data = g_memdup2 (&data, sizeof (TestParamImplementData));
907 g_test_add_data_func_full (test_path, test_data, test_param_implement_child, g_free);
908 g_free (test_path);
909 }
910
911 g_test_add_func ("/value/transform", test_value_transform);
912 g_test_add_func ("/param/default", test_param_default);
913 g_test_add_func ("/param/is-valid-name", test_param_is_valid_name);
914
915 return g_test_run ();
916 }
917