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