Tizen 2.1 base
[platform/upstream/glib2.0.git] / gobject / tests / param.c
1 #define GLIB_DISABLE_DEPRECATION_WARNINGS
2 #include <glib-object.h>
3 #include <stdlib.h>
4
5 static void
6 test_param_value (void)
7 {
8   GParamSpec *p, *p2;
9   GParamSpec *pp;
10   GValue value = G_VALUE_INIT;
11
12   g_value_init (&value, G_TYPE_PARAM);
13   g_assert (G_VALUE_HOLDS_PARAM (&value));
14
15   p = g_param_spec_int ("my-int", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE);
16
17   g_value_take_param (&value, p);
18   p2 = g_value_get_param (&value);
19   g_assert (p2 == p);
20
21   pp = g_param_spec_uint ("my-uint", "My UInt", "Blurb", 0, 10, 5, G_PARAM_READWRITE);
22   g_value_set_param (&value, pp);
23
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);
27
28   g_value_unset (&value);
29   g_param_spec_unref (pp);
30 }
31
32 static gint destroy_count;
33
34 static void
35 my_destroy (gpointer data)
36 {
37   destroy_count++;
38 }
39
40 static void
41 test_param_qdata (void)
42 {
43   GParamSpec *p;
44   gchar *bla;
45   GQuark q;
46
47   q = g_quark_from_string ("bla");
48
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");
53
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);
61
62   g_param_spec_ref_sink (p);
63
64   g_param_spec_unref (p);
65 }
66
67 static void
68 test_param_validate (void)
69 {
70   GParamSpec *p;
71   GValue value = G_VALUE_INIT;
72
73   p = g_param_spec_int ("my-int", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE);
74
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);
80
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);
84
85   g_param_spec_unref (p);
86 }
87
88 static void
89 test_param_strings (void)
90 {
91   GParamSpec *p;
92
93   /* test canonicalization */
94   p = g_param_spec_int ("my_int:bla", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE);
95
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");
99
100   g_param_spec_unref (p);
101
102   /* test nick defaults to name */
103   p = g_param_spec_int ("my-int", NULL, NULL, 0, 20, 10, G_PARAM_READWRITE);
104
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);
108
109   g_param_spec_unref (p);
110 }
111
112 static void
113 test_param_convert (void)
114 {
115   GParamSpec *p;
116   GValue v1 = G_VALUE_INIT;
117   GValue v2 = G_VALUE_INIT;
118
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);
122
123   g_value_init (&v2, G_TYPE_INT);
124   g_value_set_int (&v2, -4);
125
126   g_assert (!g_param_value_convert (p, &v1, &v2, TRUE));
127   g_assert_cmpint (g_value_get_int (&v2), ==, -4);
128
129   g_assert (g_param_value_convert (p, &v1, &v2, FALSE));
130   g_assert_cmpint (g_value_get_int (&v2), ==, 20);
131
132   g_param_spec_unref (p);
133 }
134
135 static void
136 test_value_transform (void)
137 {
138   GValue src = G_VALUE_INIT;
139   GValue dest = G_VALUE_INIT;
140
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);
150
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.
155    */
156   CHECK_INT_CONVERSION(G_TYPE_CHAR, char, 124)
157
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)
172
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);
182
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)
197
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);
207
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)
222
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);
232
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)
247
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);
257
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)
272
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);
282
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)
297
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);
307
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)
322
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);
332
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)
347
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);
360
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)
367
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);
377
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)
386
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);
396 }
397
398
399 /* We create some dummy objects with a simple relationship:
400  *
401  *           GObject
402  *          /       \
403  * TestObjectA     TestObjectC
404  *      |
405  * TestObjectB
406  *
407  * ie: TestObjectB is a subclass of TestObjectA and TestObjectC is
408  * related to neither.
409  */
410
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) { }
416
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) { }
422
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) { }
428
429 /* We create an interface and programmatically populate it with
430  * properties of each of the above type, with various flag combinations.
431  *
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:
434  *
435  *   - 'r': readable
436  *   - 'w': writable
437  *   - 'c': construct
438  *   - 'C': construct-only
439  *
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:
445  *
446  *     'r', 'w', 'rw', 'wc', 'rwc', 'wC', 'rwC'
447  *
448  * And 9 impossible ones:
449  *
450  *     '', 'c', 'rc', 'C', 'rC', 'cC', 'rcC', 'wcC', rwcC'
451  *
452  * For a total of 16 combinations.
453  *
454  * That gives a total of 48 (16 * 3) possible flag/type combinations, of
455  * which 27 (9 * 3) are impossible to install.
456  *
457  * That gives 21 (7 * 3) properties that will be installed.
458  */
459 typedef GTypeInterface TestInterfaceInterface;
460 //typedef struct _TestInterface TestInterface;
461 G_DEFINE_INTERFACE (TestInterface, test_interface, G_TYPE_OBJECT)
462 static void
463 test_interface_default_init (TestInterfaceInterface *iface)
464 {
465   const gchar *names[] = { "a", "b", "c" };
466   const gchar *perms[] = { NULL, "r",  "w",  "rw",
467                            NULL, NULL, "wc", "rwc",
468                            NULL, NULL, "wC", "rwC",
469                            NULL, NULL, NULL, NULL };
470   const GType types[] = { test_object_a_get_type (), test_object_b_get_type (), test_object_c_get_type () };
471   guint i, j;
472
473   for (i = 0; i < G_N_ELEMENTS (types); i++)
474     for (j = 0; j < G_N_ELEMENTS (perms); j++)
475       {
476         gchar prop_name[10];
477         GParamSpec *pspec;
478
479         if (perms[j] == NULL)
480           {
481             if (!g_test_undefined ())
482               continue;
483
484             /* we think that this is impossible.  make sure. */
485             if (g_test_trap_fork (G_TIME_SPAN_SECOND, G_TEST_TRAP_SILENCE_STDERR))
486               {
487                 GParamSpec *pspec;
488
489                 pspec = g_param_spec_object ("xyz", "xyz", "xyz", types[i], j);
490                 g_object_interface_install_property (iface, pspec);
491                 exit (0);
492               }
493             g_test_trap_assert_failed ();
494             continue;
495           }
496
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);
501       }
502 }
503
504 /* We now have 21 properties.  Each property may be correctly
505  * implemented with the following types:
506  *
507  *   Properties         Valid Types       Reason
508  *
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
512  *
513  *   b-r                b                 (as above)
514  *   b-w, wc, wC        b, a, GObject
515  *   b-rw, rwc, rwC     b
516  *
517  *   c-r                c                 (as above)
518  *   c-wo, wc, wC       c, GObject
519  *   c-rw, rwc, rwC     c
520  *
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:
525  *
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
531  *
532  * We organise the table by interface property type ('a', 'b', 'c') then
533  * by interface property flags.
534  */
535
536 static gint valid_impl_types[48][4] = {
537                     /* a    b    c    GObject */
538     /* 'a-' */       { },
539     /* 'a-r' */      { 'v', 'v', '<', '<' },
540     /* 'a-w' */      { 'v', '>', '>', 'v' },
541     /* 'a-rw' */     { 'v', '=', '=', '=' },
542     /* 'a-c */       { },
543     /* 'a-rc' */     { },
544     /* 'a-wc' */     { 'v', '>', '>', 'v' },
545     /* 'a-rwc' */    { 'v', '=', '=', '=' },
546     /* 'a-C */       { },
547     /* 'a-rC' */     { },
548     /* 'a-wC' */     { 'v', '>', '>', 'v' },
549     /* 'a-rwC' */    { 'v', '=', '=', '=' },
550     /* 'a-cC */      { },
551     /* 'a-rcC' */    { },
552     /* 'a-wcC' */    { },
553     /* 'a-rwcC' */   { },
554
555     /* 'b-' */       { },
556     /* 'b-r' */      { '<', 'v', '<', '<' },
557     /* 'b-w' */      { 'v', 'v', '>', 'v' },
558     /* 'b-rw' */     { '=', 'v', '=', '=' },
559     /* 'b-c */       { },
560     /* 'b-rc' */     { },
561     /* 'b-wc' */     { 'v', 'v', '>', 'v' },
562     /* 'b-rwc' */    { '=', 'v', '=', '=' },
563     /* 'b-C */       { },
564     /* 'b-rC' */     { },
565     /* 'b-wC' */     { 'v', 'v', '>', 'v' },
566     /* 'b-rwC' */    { '=', 'v', '=', '=' },
567     /* 'b-cC */      { },
568     /* 'b-rcC' */    { },
569     /* 'b-wcC' */    { },
570     /* 'b-rwcC' */   { },
571
572     /* 'c-' */       { },
573     /* 'c-r' */      { '<', '<', 'v', '<' },
574     /* 'c-w' */      { '>', '>', 'v', 'v' },
575     /* 'c-rw' */     { '=', '=', 'v', '=' },
576     /* 'c-c */       { },
577     /* 'c-rc' */     { },
578     /* 'c-wc' */     { '>', '>', 'v', 'v' },
579     /* 'c-rwc' */    { '=', '=', 'v', '=' },
580     /* 'c-C */       { },
581     /* 'c-rC' */     { },
582     /* 'c-wC' */     { '>', '>', 'v', 'v' },
583     /* 'c-rwC' */    { '=', '=', 'v', '=' },
584     /* 'c-cC */      { },
585     /* 'c-rcC' */    { },
586     /* 'c-wcC' */    { },
587     /* 'c-rwcC' */   { }
588 };
589
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".
597  *
598  * The 'construct' flag is of interest only to the implementation.  It
599  * may be changed at any time.
600  *
601  *   Properties         Valid Access      Reason
602  *
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
611  *
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:
615  *
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)
621  *
622  * We also ensure that removal of functionality is reported before
623  * addition of restrictions, since this is a more basic problem.
624  */
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     /* '*-' */    { },
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 */    { },
632     /* '*-rc' */  { },
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 */    { },
636     /* '*-rC' */  { },
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' },
639 };
640
641 static guint change_this_flag;
642 static guint change_this_type;
643 static guint use_this_flag;
644 static guint use_this_type;
645
646 typedef GObjectClass TestImplementationClass;
647 typedef GObject TestImplementation;
648
649 static void test_implementation_init (TestImplementation *impl) { }
650 static void test_implementation_iface_init (TestInterfaceInterface *iface) { }
651
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))
655
656 static void test_implementation_class_init (TestImplementationClass *class)
657 {
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;
668
669   class->get_property = GINT_TO_POINTER (1);
670   class->set_property = GINT_TO_POINTER (1);
671
672   /* Install all of the non-modified properties or else GObject will
673    * complain about non-implemented properties.
674    */
675   for (i = 0; i < 3; i++)
676     for (j = 0; j < G_N_ELEMENTS (perms); j++)
677       {
678         if (i == change_this_type && j == change_this_flag)
679           continue;
680
681         if (perms[j] != NULL)
682           {
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);
686           }
687       }
688
689   /* Now try installing our modified property */
690   if (perms[change_this_flag] == NULL)
691     g_error ("Interface property does not exist");
692
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);
696 }
697
698 static void
699 test_param_implement (void)
700 {
701   /* GObject oddity: GObjectClass must be initialised before we can
702    * initialise a GTypeInterface.
703    */
704   g_type_class_ref (G_TYPE_OBJECT);
705
706   /* Bring up the interface first. */
707   g_type_default_interface_ref (test_interface_get_type ());
708
709   for (change_this_flag = 0; change_this_flag < 16; change_this_flag++)
710     for (change_this_type = 0; change_this_type < 3; change_this_type++)
711       for (use_this_flag = 0; use_this_flag < 16; use_this_flag++)
712         for (use_this_type = 0; use_this_type < 4; use_this_type++)
713           {
714             if (!g_test_undefined ())
715               {
716                 /* only test the valid (defined) cases, e.g. under valgrind */
717                 if (valid_impl_flags[change_this_flag][use_this_flag] != 'v')
718                   continue;
719
720                 if (valid_impl_types[change_this_type * 16 + change_this_flag][use_this_type] != 'v')
721                   continue;
722               }
723
724             if (g_test_trap_fork (G_TIME_SPAN_SECOND, G_TEST_TRAP_SILENCE_STDERR))
725               {
726                 g_type_class_ref (test_implementation_get_type ());
727                 exit (0);
728               }
729
730             /* We want to ensure that any flags mismatch problems are reported first. */
731             switch (valid_impl_flags[change_this_flag][use_this_flag])
732               {
733               case 0:
734                 /* make sure the other table agrees */
735                 g_assert (valid_impl_types[change_this_type * 16 + change_this_flag][use_this_type] == 0);
736                 g_test_trap_assert_failed ();
737                 g_test_trap_assert_stderr ("*Interface property does not exist*");
738                 continue;
739
740               case 'i':
741                 g_test_trap_assert_failed ();
742                 g_test_trap_assert_stderr ("*g_object_class_install_property*");
743                 continue;
744
745               case 'f':
746                 g_test_trap_assert_failed ();
747                 g_test_trap_assert_stderr ("*remove functionality*");
748                 continue;
749
750               case 'r':
751                 g_test_trap_assert_failed ();
752                 g_test_trap_assert_stderr ("*introduce additional restrictions*");
753                 continue;
754
755               case 'v':
756                 break;
757               }
758
759             /* Next, we check if there should have been a type error. */
760             switch (valid_impl_types[change_this_type * 16 + change_this_flag][use_this_type])
761               {
762               case 0:
763                 /* this should have been caught above */
764                 g_assert_not_reached ();
765
766               case '=':
767                 g_test_trap_assert_failed ();
768                 g_test_trap_assert_stderr ("*exactly equal*");
769                 continue;
770
771               case '<':
772                 g_test_trap_assert_failed ();
773                 g_test_trap_assert_stderr ("*equal to or more restrictive*");
774                 continue;
775
776               case '>':
777                 g_test_trap_assert_failed ();
778                 g_test_trap_assert_stderr ("*equal to or less restrictive*");
779                 continue;
780
781               case 'v':
782                 break;
783               }
784
785             g_test_trap_assert_passed ();
786           }
787 }
788
789 int
790 main (int argc, char *argv[])
791 {
792   g_type_init ();
793   g_test_init (&argc, &argv, NULL);
794
795   g_test_add_func ("/param/value", test_param_value);
796   g_test_add_func ("/param/strings", test_param_strings);
797   g_test_add_func ("/param/qdata", test_param_qdata);
798   g_test_add_func ("/param/validate", test_param_validate);
799   g_test_add_func ("/param/convert", test_param_convert);
800   g_test_add_func ("/param/implement", test_param_implement);
801   g_test_add_func ("/value/transform", test_value_transform);
802
803   return g_test_run ();
804 }