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
8static void
9test_param_value (void)
10{
11 GParamSpec *p, *p2;
12 GParamSpec *pp;
13 GValue value = G_VALUE_INIT;
14
15 g_value_init (value: &value, G_TYPE_PARAM);
16 g_assert_true (G_VALUE_HOLDS_PARAM (&value));
17
18 p = g_param_spec_int (name: "my-int", nick: "My Int", blurb: "Blurb", minimum: 0, maximum: 20, default_value: 10, flags: G_PARAM_READWRITE);
19
20 g_value_take_param (value: &value, param: p);
21 p2 = g_value_get_param (value: &value);
22 g_assert_true (p2 == p);
23
24 pp = g_param_spec_uint (name: "my-uint", nick: "My UInt", blurb: "Blurb", minimum: 0, maximum: 10, default_value: 5, flags: G_PARAM_READWRITE);
25 g_value_set_param (value: &value, param: pp);
26
27 p2 = g_value_dup_param (value: &value);
28 g_assert_true (p2 == pp); /* param specs use ref/unref for copy/free */
29 g_param_spec_unref (pspec: p2);
30
31 g_value_unset (value: &value);
32 g_param_spec_unref (pspec: pp);
33}
34
35static gint destroy_count;
36
37static void
38my_destroy (gpointer data)
39{
40 destroy_count++;
41}
42
43static void
44test_param_qdata (void)
45{
46 GParamSpec *p;
47 gchar *bla;
48 GQuark q;
49
50 q = g_quark_from_string (string: "bla");
51
52 p = g_param_spec_int (name: "my-int", nick: "My Int", blurb: "Blurb", minimum: 0, maximum: 20, default_value: 10, flags: G_PARAM_READWRITE);
53 g_param_spec_set_qdata (pspec: p, quark: q, data: "bla");
54 bla = g_param_spec_get_qdata (pspec: p, quark: q);
55 g_assert_cmpstr (bla, ==, "bla");
56
57 g_assert_cmpint (destroy_count, ==, 0);
58 g_param_spec_set_qdata_full (pspec: p, quark: q, data: "bla", destroy: my_destroy);
59 g_param_spec_set_qdata_full (pspec: p, quark: q, data: "blabla", destroy: 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 (pspec: p);
66
67 g_param_spec_unref (pspec: p);
68}
69
70static void
71test_param_validate (void)
72{
73 GParamSpec *p;
74 GValue value = G_VALUE_INIT;
75
76 p = g_param_spec_int (name: "my-int", nick: "My Int", blurb: "Blurb", minimum: 0, maximum: 20, default_value: 10, flags: G_PARAM_READWRITE);
77
78 g_value_init (value: &value, G_TYPE_INT);
79 g_value_set_int (value: &value, v_int: 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 (pspec: p, value: &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 (pspec: p);
89}
90
91static void
92test_param_strings (void)
93{
94 GParamSpec *p;
95
96 /* test canonicalization */
97 p = g_param_spec_int (name: "my_int", nick: "My Int", blurb: "Blurb", minimum: 0, maximum: 20, default_value: 10, flags: 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 (pspec: p);
104
105 /* test nick defaults to name */
106 p = g_param_spec_int (name: "my-int", NULL, NULL, minimum: 0, maximum: 20, default_value: 10, flags: 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 (pspec: p);
113}
114
115static void
116test_param_invalid_name (gconstpointer test_data)
117{
118 const gchar *invalid_name = test_data;
119
120 g_test_summary (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 (name: invalid_name, nick: "My Int", blurb: "Blurb", minimum: 0, maximum: 20, default_value: 10, flags: G_PARAM_READWRITE);
126 g_param_spec_unref (pspec: p);
127 return;
128 }
129
130 g_test_trap_subprocess (NULL, usec_timeout: 0, test_flags: 0);
131 g_test_trap_assert_failed ();
132 g_test_trap_assert_stderr ("*CRITICAL*g_param_spec_is_valid_name (name)*");
133}
134
135static void
136test_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 (name: "my-int", nick: "My Int", blurb: "Blurb", minimum: 0, maximum: 20, default_value: 10, flags: G_PARAM_READWRITE);
143 g_value_init (value: &v1, G_TYPE_UINT);
144 g_value_set_uint (value: &v1, v_uint: 43);
145
146 g_value_init (value: &v2, G_TYPE_INT);
147 g_value_set_int (value: &v2, v_int: -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 (pspec: p);
156}
157
158static void
159test_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 (value: &src, G_TYPE_STRING);
412 g_value_init (value: &dest, G_TYPE_CHAR);
413 g_value_set_static_string (value: &src, v_string: "bla");
414 g_value_set_schar (value: &dest, v_char: 'c');
415 g_assert_false (g_value_transform (&src, &dest));
416 g_assert_cmpint (g_value_get_schar (&dest), ==, 'c');
417 g_value_unset (value: &src);
418 g_value_unset (value: &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
434static GType test_object_a_get_type (void);
435typedef GObject TestObjectA; typedef GObjectClass TestObjectAClass;
436G_DEFINE_TYPE (TestObjectA, test_object_a, G_TYPE_OBJECT)
437static void test_object_a_class_init (TestObjectAClass *class) { }
438static void test_object_a_init (TestObjectA *a) { }
439
440static GType test_object_b_get_type (void);
441typedef GObject TestObjectB; typedef GObjectClass TestObjectBClass;
442G_DEFINE_TYPE (TestObjectB, test_object_b, test_object_a_get_type ())
443static void test_object_b_class_init (TestObjectBClass *class) { }
444static void test_object_b_init (TestObjectB *b) { }
445
446static GType test_object_c_get_type (void);
447typedef GObject TestObjectC; typedef GObjectClass TestObjectCClass;
448G_DEFINE_TYPE (TestObjectC, test_object_c, G_TYPE_OBJECT)
449static void test_object_c_class_init (TestObjectCClass *class) { }
450static 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 */
482typedef GTypeInterface TestInterfaceInterface;
483static GType test_interface_get_type (void);
484//typedef struct _TestInterface TestInterface;
485G_DEFINE_INTERFACE (TestInterface, test_interface, G_TYPE_OBJECT)
486static void
487test_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 (name: "xyz", nick: "xyz", blurb: "xyz", object_type: types[i], flags: j);
510
511 g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL,
512 pattern: "*assertion*pspec->flags*failed*");
513 g_object_interface_install_property (g_iface: 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 (string: prop_name, n: sizeof prop_name, format: "%s-%s", names[i], perms[j]);
522 pspec = g_param_spec_object (name: prop_name, nick: prop_name, blurb: prop_name, object_type: types[i], flags: j);
523 g_object_interface_install_property (g_iface: 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
559static 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 */
648static 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
664static guint change_this_flag;
665static guint change_this_type;
666static guint use_this_flag;
667static guint use_this_type;
668
669typedef GObjectClass TestImplementationClass;
670typedef GObject TestImplementation;
671
672static void test_implementation_init (TestImplementation *impl) { }
673static void test_implementation_iface_init (TestInterfaceInterface *iface) { }
674
675static GType test_implementation_get_type (void);
676G_DEFINE_TYPE_WITH_CODE (TestImplementation, test_implementation, G_TYPE_OBJECT,
677 G_IMPLEMENT_INTERFACE (test_interface_get_type (), test_implementation_iface_init))
678
679static 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 (string: prop_name, n: sizeof prop_name, format: "%s-%s", names[i], perms[j]);
708 g_object_class_override_property (oclass: class, property_id: 1, name: 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 (string: prop_name, n: sizeof prop_name, format: "%s-%s", names[change_this_type], perms[change_this_flag]);
717 pspec = g_param_spec_object (name: prop_name, nick: prop_name, blurb: prop_name, object_type: types[use_this_type], flags: use_this_flag);
718 g_object_class_install_property (oclass: class, property_id: 1, pspec);
719}
720
721typedef struct {
722 gint change_this_flag;
723 gint change_this_type;
724 gint use_this_flag;
725 gint use_this_type;
726} TestParamImplementData;
727
728static void
729test_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 (g_type: 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 (type: test_implementation_get_type ());
750}
751
752static void
753test_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 (format: "/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, test_flags: 0);
776 g_free (mem: 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
837static void
838test_param_default (void)
839{
840 GParamSpec *param;
841 const GValue *def;
842
843 param = g_param_spec_int (name: "my-int", nick: "My Int", blurb: "Blurb", minimum: 0, maximum: 20, default_value: 10, flags: G_PARAM_READWRITE);
844 def = g_param_spec_get_default_value (pspec: 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 (pspec: param);
850}
851
852static void
853test_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
878int
879main (int argc, char *argv[])
880{
881 TestParamImplementData data, *test_data;
882 gchar *test_path;
883
884 g_test_init (argc: &argc, argv: &argv, NULL);
885
886 g_test_add_func (testpath: "/param/value", test_func: test_param_value);
887 g_test_add_func (testpath: "/param/strings", test_func: test_param_strings);
888 g_test_add_data_func (testpath: "/param/invalid-name/colon", test_data: "my_int:hello", test_func: test_param_invalid_name);
889 g_test_add_data_func (testpath: "/param/invalid-name/first-char", test_data: "7zip", test_func: test_param_invalid_name);
890 g_test_add_data_func (testpath: "/param/invalid-name/empty", test_data: "", test_func: test_param_invalid_name);
891 g_test_add_func (testpath: "/param/qdata", test_func: test_param_qdata);
892 g_test_add_func (testpath: "/param/validate", test_func: test_param_validate);
893 g_test_add_func (testpath: "/param/convert", test_func: test_param_convert);
894
895 if (g_test_slow ())
896 g_test_add_func (testpath: "/param/implement", test_func: 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 (format: "/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 (mem: &data, byte_size: sizeof (TestParamImplementData));
907 g_test_add_data_func_full (testpath: test_path, test_data, test_func: test_param_implement_child, data_free_func: g_free);
908 g_free (mem: test_path);
909 }
910
911 g_test_add_func (testpath: "/value/transform", test_func: test_value_transform);
912 g_test_add_func (testpath: "/param/default", test_func: test_param_default);
913 g_test_add_func (testpath: "/param/is-valid-name", test_func: test_param_is_valid_name);
914
915 return g_test_run ();
916}
917

source code of gtk/subprojects/glib/gobject/tests/param.c