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