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