GObject: require READ or WRITE on property install
[platform/upstream/glib.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             /* we think that this is impossible.  make sure. */
482             if (g_test_trap_fork (G_TIME_SPAN_SECOND, G_TEST_TRAP_SILENCE_STDERR))
483               {
484                 GParamSpec *pspec;
485
486                 pspec = g_param_spec_object ("xyz", "xyz", "xyz", types[i], j);
487                 g_object_interface_install_property (iface, pspec);
488                 exit (0);
489               }
490             //g_test_trap_assert_failed (); XXX g_object_interface_install_property has no checks
491             continue;
492           }
493
494         /* install the property */
495         g_snprintf (prop_name, sizeof prop_name, "%s-%s", names[i], perms[j]);
496         pspec = g_param_spec_object (prop_name, prop_name, prop_name, types[i], j);
497         g_object_interface_install_property (iface, pspec);
498       }
499 }
500
501 /* We now have 21 properties.  Each property may be correctly
502  * implemented with the following types:
503  *
504  *   Properties         Valid Types       Reason
505  *
506  *   a-r                a, b              Read only can provide subclasses
507  *   a-w, wc, wC        a, GObject        Write only can accept superclasses
508  *   a-rw, rwc, rwC     a                 Read-write must be exactly equal
509  *
510  *   b-r                b                 (as above)
511  *   b-w, wc, wC        b, a, GObject
512  *   b-rw, rwc, rwC     b
513  *
514  *   c-r                c                 (as above)
515  *   c-wo, wc, wC       c, GObject
516  *   c-rw, rwc, rwC     c
517  *
518  * We can express this in a 48-by-4 table where each row represents an
519  * installed property and each column represents a type.  The value in
520  * the table represents if it is valid to subclass the row's property
521  * with the type of the column:
522  *
523  *   - 0:   invalid because the interface property doesn't exist (invalid flags)
524  *   - 'v': valid
525  *   - '=': invalid because of the type not being exactly equal
526  *   - '<': invalid because of the type not being a subclass
527  *   - '>': invalid because of the type not being a superclass
528  *
529  * We organise the table by interface property type ('a', 'b', 'c') then
530  * by interface property flags.
531  */
532
533 static gint valid_impl_types[48][4] = {
534                     /* a    b    c    GObject */
535     /* 'a-' */       { },
536     /* 'a-r' */      { 'v', 'v', '<', '<' },
537     /* 'a-w' */      { 'v', '>', '>', 'v' },
538     /* 'a-rw' */     { 'v', '=', '=', '=' },
539     /* 'a-c */       { },
540     /* 'a-rc' */     { },
541     /* 'a-wc' */     { 'v', '>', '>', 'v' },
542     /* 'a-rwc' */    { 'v', '=', '=', '=' },
543     /* 'a-C */       { },
544     /* 'a-rC' */     { },
545     /* 'a-wC' */     { 'v', '>', '>', 'v' },
546     /* 'a-rwC' */    { 'v', '=', '=', '=' },
547     /* 'a-cC */      { },
548     /* 'a-rcC' */    { },
549     /* 'a-wcC' */    { },
550     /* 'a-rwcC' */   { },
551
552     /* 'b-' */       { },
553     /* 'b-r' */      { '<', 'v', '<', '<' },
554     /* 'b-w' */      { 'v', 'v', '>', 'v' },
555     /* 'b-rw' */     { '=', 'v', '=', '=' },
556     /* 'b-c */       { },
557     /* 'b-rc' */     { },
558     /* 'b-wc' */     { 'v', 'v', '>', 'v' },
559     /* 'b-rwc' */    { '=', 'v', '=', '=' },
560     /* 'b-C */       { },
561     /* 'b-rC' */     { },
562     /* 'b-wC' */     { 'v', 'v', '>', 'v' },
563     /* 'b-rwC' */    { '=', 'v', '=', '=' },
564     /* 'b-cC */      { },
565     /* 'b-rcC' */    { },
566     /* 'b-wcC' */    { },
567     /* 'b-rwcC' */   { },
568
569     /* 'c-' */       { },
570     /* 'c-r' */      { '<', '<', 'v', '<' },
571     /* 'c-w' */      { '>', '>', 'v', 'v' },
572     /* 'c-rw' */     { '=', '=', 'v', '=' },
573     /* 'c-c */       { },
574     /* 'c-rc' */     { },
575     /* 'c-wc' */     { '>', '>', 'v', 'v' },
576     /* 'c-rwc' */    { '=', '=', 'v', '=' },
577     /* 'c-C */       { },
578     /* 'c-rC' */     { },
579     /* 'c-wC' */     { '>', '>', 'v', 'v' },
580     /* 'c-rwC' */    { '=', '=', 'v', '=' },
581     /* 'c-cC */      { },
582     /* 'c-rcC' */    { },
583     /* 'c-wcC' */    { },
584     /* 'c-rwcC' */   { }
585 };
586
587 /* We also try to change the flags.  We must ensure that all
588  * implementations provide all functionality promised by the interface.
589  * We must therefore never remove readability or writability (but we can
590  * add them).  Construct-only is a restrictions that applies to
591  * writability, so we can never add it unless writability was never
592  * present in the first place, in which case "writable at construct
593  * only" is still better than "not writable".
594  *
595  * The 'construct' flag is of interest only to the implementation.  It
596  * may be changed at any time.
597  *
598  *   Properties         Valid Access      Reason
599  *
600  *   *-r                r, rw, rwc, rwC   Must keep readable, but can restrict newly-added writable
601  *   *-w                w, rw, rwc        Must keep writable unrestricted
602  *   *-rw               rw, rwc           Must not add any restrictions
603  *   *-rwc              rw, rwc           Must not add any restrictions
604  *   *-rwC              rw, rwc, rwC      Can remove 'construct-only' restriction
605  *   *-wc               rwc, rw, w, wc    Can add readability
606  *   *-wC               rwC, rw, w, wC    Can add readability or remove 'construct only' restriction
607  *                        rwc, wc
608  *
609  * We can represent this with a 16-by-16 table.  The rows represent the
610  * flags of the property on the interface.  The columns is the flags to
611  * try to use when overriding the property.  The cell contents are:
612  *
613  *   - 0:   invalid because the interface property doesn't exist (invalid flags)
614  *   - 'v': valid
615  *   - 'i': invalid because the implementation flags are invalid
616  *   - 'f': invalid because of the removal of functionality
617  *   - 'r': invalid because of the addition of restrictions (ie: construct-only)
618  *
619  * We also ensure that removal of functionality is reported before
620  * addition of restrictions, since this is a more basic problem.
621  */
622 static gint valid_impl_flags[16][16] = {
623                  /* ''   r    w    rw   c    rc   wc   rwc  C    rC   wC   rwC  cC   rcC  wcC  rwcC */
624     /* '*-' */    { },
625     /* '*-r' */   { 'i', 'v', 'f', 'v', 'i', 'i', 'f', 'v', 'i', 'i', 'f', 'v', 'i', 'i', 'i', 'i' },
626     /* '*-w' */   { 'i', 'f', 'v', 'v', 'i', 'i', 'v', 'v', 'i', 'i', 'r', 'r', 'i', 'i', 'i', 'i' },
627     /* '*-rw' */  { 'i', 'f', 'f', 'v', 'i', 'i', 'f', 'v', 'i', 'i', 'f', 'r', 'i', 'i', 'i', 'i' },
628     /* '*-c */    { },
629     /* '*-rc' */  { },
630     /* '*-wc' */  { 'i', 'f', 'v', 'v', 'i', 'i', 'v', 'v', 'i', 'i', 'r', 'r', 'i', 'i', 'i', 'i' },
631     /* '*-rwc' */ { 'i', 'f', 'f', 'v', 'i', 'i', 'f', 'v', 'i', 'i', 'f', 'r', 'i', 'i', 'i', 'i' },
632     /* '*-C */    { },
633     /* '*-rC' */  { },
634     /* '*-wC' */  { 'i', 'f', 'v', 'v', 'i', 'i', 'v', 'v', 'i', 'i', 'v', 'v', 'i', 'i', 'i', 'i' },
635     /* '*-rwC' */ { 'i', 'f', 'f', 'v', 'i', 'i', 'f', 'v', 'i', 'i', 'f', 'v', 'i', 'i', 'i', 'i' },
636 };
637
638 static guint change_this_flag;
639 static guint change_this_type;
640 static guint use_this_flag;
641 static guint use_this_type;
642
643 typedef GObjectClass TestImplementationClass;
644 typedef GObject TestImplementation;
645
646 static void test_implementation_init (TestImplementation *impl) { }
647 static void test_implementation_iface_init (TestInterfaceInterface *iface) { }
648
649 static GType test_implementation_get_type (void);
650 G_DEFINE_TYPE_WITH_CODE (TestImplementation, test_implementation, G_TYPE_OBJECT,
651                          G_IMPLEMENT_INTERFACE (test_interface_get_type (), test_implementation_iface_init))
652
653 static void test_implementation_class_init (TestImplementationClass *class)
654 {
655   const gchar *names[] = { "a", "b", "c" };
656   const gchar *perms[] = { NULL, "r",  "w",  "rw",
657                            NULL, NULL, "wc", "rwc",
658                            NULL, NULL, "wC", "rwC",
659                            NULL, NULL, NULL, NULL };
660   const GType types[] = { test_object_a_get_type (), test_object_b_get_type (),
661                           test_object_c_get_type (), G_TYPE_OBJECT };
662   gchar prop_name[10];
663   GParamSpec *pspec;
664   guint i, j;
665
666   class->get_property = GINT_TO_POINTER (1);
667   class->set_property = GINT_TO_POINTER (1);
668
669   /* Install all of the non-modified properties or else GObject will
670    * complain about non-implemented properties.
671    */
672   for (i = 0; i < 3; i++)
673     for (j = 0; j < G_N_ELEMENTS (perms); j++)
674       {
675         if (i == change_this_type && j == change_this_flag)
676           continue;
677
678         if (perms[j] != NULL)
679           {
680             /* override the property without making changes */
681             g_snprintf (prop_name, sizeof prop_name, "%s-%s", names[i], perms[j]);
682             g_object_class_override_property (class, 1, prop_name);
683           }
684       }
685
686   /* Now try installing our modified property */
687   if (perms[change_this_flag] == NULL)
688     g_error ("Interface property does not exist");
689
690   g_snprintf (prop_name, sizeof prop_name, "%s-%s", names[change_this_type], perms[change_this_flag]);
691   pspec = g_param_spec_object (prop_name, prop_name, prop_name, types[use_this_type], use_this_flag);
692   g_object_class_install_property (class, 1, pspec);
693 }
694
695 static void
696 test_param_implement (void)
697 {
698   /* GObject oddity: GObjectClass must be initialised before we can
699    * initialise a GTypeInterface.
700    */
701   g_type_class_ref (G_TYPE_OBJECT);
702
703   /* Bring up the interface first. */
704   g_type_default_interface_ref (test_interface_get_type ());
705
706   for (change_this_flag = 0; change_this_flag < 16; change_this_flag++)
707     for (change_this_type = 0; change_this_type < 3; change_this_type++)
708       for (use_this_flag = 0; use_this_flag < 16; use_this_flag++)
709         for (use_this_type = 0; use_this_type < 4; use_this_type++)
710           {
711             if (g_test_trap_fork (G_TIME_SPAN_SECOND, G_TEST_TRAP_SILENCE_STDERR))
712               {
713                 g_type_class_ref (test_implementation_get_type ());
714                 exit (0);
715               }
716
717             /* We want to ensure that any flags mismatch problems are reported first. */
718             switch (valid_impl_flags[change_this_flag][use_this_flag])
719               {
720               case 0:
721                 /* make sure the other table agrees */
722                 g_assert (valid_impl_types[change_this_type * 16 + change_this_flag][use_this_type] == 0);
723                 g_test_trap_assert_failed ();
724                 g_test_trap_assert_stderr ("*Interface property does not exist*");
725                 continue;
726
727               case 'i':
728                 g_test_trap_assert_failed ();
729                 g_test_trap_assert_stderr ("*g_object_class_install_property*");
730                 continue;
731
732               case 'f':
733                 g_test_trap_assert_failed ();
734                 g_test_trap_assert_stderr ("*remove functionality*");
735                 continue;
736
737               case 'r':
738                 g_test_trap_assert_failed ();
739                 g_test_trap_assert_stderr ("*introduce additional restrictions*");
740                 continue;
741
742               case 'v':
743                 break;
744               }
745
746             /* Next, we check if there should have been a type error. */
747             switch (valid_impl_types[change_this_type * 16 + change_this_flag][use_this_type])
748               {
749               case 0:
750                 /* this should have been caught above */
751                 g_assert_not_reached ();
752
753               case '=':
754                 g_test_trap_assert_failed ();
755                 g_test_trap_assert_stderr ("*exactly equal*");
756                 continue;
757
758               case '<':
759                 g_test_trap_assert_failed ();
760                 g_test_trap_assert_stderr ("*equal to or more restrictive*");
761                 continue;
762
763               case '>':
764                 g_test_trap_assert_failed ();
765                 g_test_trap_assert_stderr ("*equal to or less restrictive*");
766                 continue;
767
768               case 'v':
769                 break;
770               }
771
772             g_test_trap_assert_passed ();
773           }
774 }
775
776 int
777 main (int argc, char *argv[])
778 {
779   g_type_init ();
780   g_test_init (&argc, &argv, NULL);
781
782   g_test_add_func ("/param/value", test_param_value);
783   g_test_add_func ("/param/strings", test_param_strings);
784   g_test_add_func ("/param/qdata", test_param_qdata);
785   g_test_add_func ("/param/validate", test_param_validate);
786   g_test_add_func ("/param/convert", test_param_convert);
787   g_test_add_func ("/param/implement", test_param_implement);
788   g_test_add_func ("/value/transform", test_value_transform);
789
790   return g_test_run ();
791 }