1 | #define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_30 |
2 | #include <glib-object.h> |
3 | |
4 | static void |
5 | test_value_basic (void) |
6 | { |
7 | GValue value = G_VALUE_INIT; |
8 | |
9 | g_assert_false (G_IS_VALUE (&value)); |
10 | g_assert_false (G_VALUE_HOLDS_INT (&value)); |
11 | g_value_unset (value: &value); |
12 | g_assert_false (G_IS_VALUE (&value)); |
13 | g_assert_false (G_VALUE_HOLDS_INT (&value)); |
14 | |
15 | g_value_init (value: &value, G_TYPE_INT); |
16 | g_assert_true (G_IS_VALUE (&value)); |
17 | g_assert_true (G_VALUE_HOLDS_INT (&value)); |
18 | g_assert_false (G_VALUE_HOLDS_UINT (&value)); |
19 | g_assert_cmpint (g_value_get_int (&value), ==, 0); |
20 | |
21 | g_value_set_int (value: &value, v_int: 10); |
22 | g_assert_cmpint (g_value_get_int (&value), ==, 10); |
23 | |
24 | g_value_reset (value: &value); |
25 | g_assert_true (G_IS_VALUE (&value)); |
26 | g_assert_true (G_VALUE_HOLDS_INT (&value)); |
27 | g_assert_cmpint (g_value_get_int (&value), ==, 0); |
28 | |
29 | g_value_unset (value: &value); |
30 | g_assert_false (G_IS_VALUE (&value)); |
31 | g_assert_false (G_VALUE_HOLDS_INT (&value)); |
32 | } |
33 | |
34 | static void |
35 | test_value_string (void) |
36 | { |
37 | const gchar *static1 = "static1" ; |
38 | const gchar *static2 = "static2" ; |
39 | const gchar *storedstr; |
40 | const gchar *copystr; |
41 | gchar *str1, *str2; |
42 | GValue value = G_VALUE_INIT; |
43 | GValue copy = G_VALUE_INIT; |
44 | |
45 | g_test_summary (summary: "Test that G_TYPE_STRING GValue copy properly" ); |
46 | |
47 | /* |
48 | * Regular strings (ownership not passed) |
49 | */ |
50 | |
51 | /* Create a regular string gvalue and make sure it copies the provided string */ |
52 | g_value_init (value: &value, G_TYPE_STRING); |
53 | g_assert_true (G_VALUE_HOLDS_STRING (&value)); |
54 | |
55 | /* The string contents should be empty at this point */ |
56 | storedstr = g_value_get_string (value: &value); |
57 | g_assert_true (storedstr == NULL); |
58 | |
59 | g_value_set_string (value: &value, v_string: static1); |
60 | /* The contents should be a copy of the same string */ |
61 | storedstr = g_value_get_string (value: &value); |
62 | g_assert_true (storedstr != static1); |
63 | g_assert_cmpstr (storedstr, ==, static1); |
64 | /* Check g_value_dup_string() provides a copy */ |
65 | str1 = g_value_dup_string (value: &value); |
66 | g_assert_true (storedstr != str1); |
67 | g_assert_cmpstr (str1, ==, static1); |
68 | g_free (mem: str1); |
69 | |
70 | /* Copying a regular string gvalue should copy the contents */ |
71 | g_value_init (value: ©, G_TYPE_STRING); |
72 | g_value_copy (src_value: &value, dest_value: ©); |
73 | copystr = g_value_get_string (value: ©); |
74 | g_assert_true (copystr != storedstr); |
75 | g_assert_cmpstr (copystr, ==, static1); |
76 | g_value_unset (value: ©); |
77 | |
78 | /* Setting a new string should change the contents */ |
79 | g_value_set_string (value: &value, v_string: static2); |
80 | /* The contents should be a copy of that *new* string */ |
81 | storedstr = g_value_get_string (value: &value); |
82 | g_assert_true (storedstr != static2); |
83 | g_assert_cmpstr (storedstr, ==, static2); |
84 | |
85 | /* Setting a static string over that should also change it (test for |
86 | * coverage and valgrind) */ |
87 | g_value_set_static_string (value: &value, v_string: static1); |
88 | storedstr = g_value_get_string (value: &value); |
89 | g_assert_true (storedstr != static2); |
90 | g_assert_cmpstr (storedstr, ==, static1); |
91 | |
92 | /* Giving a string directly (ownership passed) should replace the content */ |
93 | str2 = g_strdup (str: static2); |
94 | g_value_take_string (value: &value, v_string: str2); |
95 | storedstr = g_value_get_string (value: &value); |
96 | g_assert_true (storedstr != static2); |
97 | g_assert_cmpstr (storedstr, ==, str2); |
98 | |
99 | g_value_unset (value: &value); |
100 | |
101 | /* |
102 | * Regular strings (ownership passed) |
103 | */ |
104 | |
105 | g_value_init (value: &value, G_TYPE_STRING); |
106 | g_assert_true (G_VALUE_HOLDS_STRING (&value)); |
107 | str1 = g_strdup (str: static1); |
108 | g_value_take_string (value: &value, v_string: str1); |
109 | /* The contents should be the string we provided */ |
110 | storedstr = g_value_get_string (value: &value); |
111 | g_assert_true (storedstr == str1); |
112 | /* But g_value_dup_string() should provide a copy */ |
113 | str2 = g_value_dup_string (value: &value); |
114 | g_assert_true (storedstr != str2); |
115 | g_assert_cmpstr (str2, ==, static1); |
116 | g_free (mem: str2); |
117 | |
118 | /* Copying a regular string gvalue (even with ownership passed) should copy |
119 | * the contents */ |
120 | g_value_init (value: ©, G_TYPE_STRING); |
121 | g_value_copy (src_value: &value, dest_value: ©); |
122 | copystr = g_value_get_string (value: ©); |
123 | g_assert_true (copystr != storedstr); |
124 | g_assert_cmpstr (copystr, ==, static1); |
125 | g_value_unset (value: ©); |
126 | |
127 | /* Setting a new regular string should change the contents */ |
128 | g_value_set_string (value: &value, v_string: static2); |
129 | /* The contents should be a copy of that *new* string */ |
130 | storedstr = g_value_get_string (value: &value); |
131 | g_assert_true (storedstr != static2); |
132 | g_assert_cmpstr (storedstr, ==, static2); |
133 | |
134 | g_value_unset (value: &value); |
135 | |
136 | /* |
137 | * Static strings |
138 | */ |
139 | g_value_init (value: &value, G_TYPE_STRING); |
140 | g_assert_true (G_VALUE_HOLDS_STRING (&value)); |
141 | g_value_set_static_string (value: &value, v_string: static1); |
142 | /* The contents should be the string we provided */ |
143 | storedstr = g_value_get_string (value: &value); |
144 | g_assert_true (storedstr == static1); |
145 | /* But g_value_dup_string() should provide a copy */ |
146 | str2 = g_value_dup_string (value: &value); |
147 | g_assert_true (storedstr != str2); |
148 | g_assert_cmpstr (str2, ==, static1); |
149 | g_free (mem: str2); |
150 | |
151 | /* Copying a static string gvalue should *actually* copy the contents */ |
152 | g_value_init (value: ©, G_TYPE_STRING); |
153 | g_value_copy (src_value: &value, dest_value: ©); |
154 | copystr = g_value_get_string (value: ©); |
155 | g_assert_true (copystr != static1); |
156 | g_value_unset (value: ©); |
157 | |
158 | /* Setting a new string should change the contents */ |
159 | g_value_set_static_string (value: &value, v_string: static2); |
160 | /* The contents should be a copy of that *new* string */ |
161 | storedstr = g_value_get_string (value: &value); |
162 | g_assert_true (storedstr != static1); |
163 | g_assert_cmpstr (storedstr, ==, static2); |
164 | |
165 | g_value_unset (value: &value); |
166 | |
167 | /* |
168 | * Interned/Canonical strings |
169 | */ |
170 | static1 = g_intern_static_string (string: static1); |
171 | g_value_init (value: &value, G_TYPE_STRING); |
172 | g_assert_true (G_VALUE_HOLDS_STRING (&value)); |
173 | g_value_set_interned_string (value: &value, v_string: static1); |
174 | g_assert_true (G_VALUE_IS_INTERNED_STRING (&value)); |
175 | /* The contents should be the string we provided */ |
176 | storedstr = g_value_get_string (value: &value); |
177 | g_assert_true (storedstr == static1); |
178 | /* But g_value_dup_string() should provide a copy */ |
179 | str2 = g_value_dup_string (value: &value); |
180 | g_assert_true (storedstr != str2); |
181 | g_assert_cmpstr (str2, ==, static1); |
182 | g_free (mem: str2); |
183 | |
184 | /* Copying an interned string gvalue should *not* copy the contents |
185 | * and should still be an interned string */ |
186 | g_value_init (value: ©, G_TYPE_STRING); |
187 | g_value_copy (src_value: &value, dest_value: ©); |
188 | g_assert_true (G_VALUE_IS_INTERNED_STRING (©)); |
189 | copystr = g_value_get_string (value: ©); |
190 | g_assert_true (copystr == static1); |
191 | g_value_unset (value: ©); |
192 | |
193 | /* Setting a new interned string should change the contents */ |
194 | static2 = g_intern_static_string (string: static2); |
195 | g_value_set_interned_string (value: &value, v_string: static2); |
196 | g_assert_true (G_VALUE_IS_INTERNED_STRING (&value)); |
197 | /* The contents should be the interned string */ |
198 | storedstr = g_value_get_string (value: &value); |
199 | g_assert_cmpstr (storedstr, ==, static2); |
200 | |
201 | /* Setting a new regular string should change the contents */ |
202 | g_value_set_string (value: &value, v_string: static2); |
203 | g_assert_false (G_VALUE_IS_INTERNED_STRING (&value)); |
204 | /* The contents should be a copy of that *new* string */ |
205 | storedstr = g_value_get_string (value: &value); |
206 | g_assert_true (storedstr != static2); |
207 | g_assert_cmpstr (storedstr, ==, static2); |
208 | |
209 | g_value_unset (value: &value); |
210 | } |
211 | |
212 | static gint |
213 | cmpint (gconstpointer a, gconstpointer b) |
214 | { |
215 | const GValue *aa = a; |
216 | const GValue *bb = b; |
217 | |
218 | return g_value_get_int (value: aa) - g_value_get_int (value: bb); |
219 | } |
220 | |
221 | static void |
222 | test_valuearray_basic (void) |
223 | { |
224 | GValueArray *a; |
225 | GValueArray *a2; |
226 | GValue v = G_VALUE_INIT; |
227 | GValue *p; |
228 | guint i; |
229 | |
230 | a = g_value_array_new (n_prealloced: 20); |
231 | |
232 | g_value_init (value: &v, G_TYPE_INT); |
233 | for (i = 0; i < 100; i++) |
234 | { |
235 | g_value_set_int (value: &v, v_int: i); |
236 | g_value_array_append (value_array: a, value: &v); |
237 | } |
238 | |
239 | g_assert_cmpint (a->n_values, ==, 100); |
240 | p = g_value_array_get_nth (value_array: a, index_: 5); |
241 | g_assert_cmpint (g_value_get_int (p), ==, 5); |
242 | |
243 | for (i = 20; i < 100; i+= 5) |
244 | g_value_array_remove (value_array: a, index_: 100 - i); |
245 | |
246 | for (i = 100; i < 150; i++) |
247 | { |
248 | g_value_set_int (value: &v, v_int: i); |
249 | g_value_array_prepend (value_array: a, value: &v); |
250 | } |
251 | |
252 | g_value_array_sort (value_array: a, compare_func: cmpint); |
253 | for (i = 0; i < a->n_values - 1; i++) |
254 | g_assert_cmpint (g_value_get_int (&a->values[i]), <=, g_value_get_int (&a->values[i+1])); |
255 | |
256 | a2 = g_value_array_copy (value_array: a); |
257 | for (i = 0; i < a->n_values; i++) |
258 | g_assert_cmpint (g_value_get_int (&a->values[i]), ==, g_value_get_int (&a2->values[i])); |
259 | |
260 | g_value_array_free (value_array: a); |
261 | g_value_array_free (value_array: a2); |
262 | } |
263 | |
264 | /* We create some dummy objects with this relationship: |
265 | * |
266 | * GObject TestInterface |
267 | * / \ / / |
268 | * TestObjectA TestObjectB / |
269 | * / \ / |
270 | * TestObjectA1 TestObjectA2------- |
271 | * |
272 | * ie: TestObjectA1 and TestObjectA2 are subclasses of TestObjectA |
273 | * and TestObjectB is related to neither. TestObjectA2 and TestObjectB |
274 | * implement TestInterface |
275 | */ |
276 | |
277 | typedef GTypeInterface TestInterfaceInterface; |
278 | static GType test_interface_get_type (void); |
279 | G_DEFINE_INTERFACE (TestInterface, test_interface, G_TYPE_OBJECT) |
280 | static void test_interface_default_init (TestInterfaceInterface *iface) { } |
281 | |
282 | static GType test_object_a_get_type (void); |
283 | typedef GObject TestObjectA; typedef GObjectClass TestObjectAClass; |
284 | G_DEFINE_TYPE (TestObjectA, test_object_a, G_TYPE_OBJECT) |
285 | static void test_object_a_class_init (TestObjectAClass *class) { } |
286 | static void test_object_a_init (TestObjectA *a) { } |
287 | |
288 | static GType test_object_b_get_type (void); |
289 | typedef GObject TestObjectB; typedef GObjectClass TestObjectBClass; |
290 | static void test_object_b_iface_init (TestInterfaceInterface *iface) { } |
291 | G_DEFINE_TYPE_WITH_CODE (TestObjectB, test_object_b, G_TYPE_OBJECT, |
292 | G_IMPLEMENT_INTERFACE (test_interface_get_type (), test_object_b_iface_init)) |
293 | static void test_object_b_class_init (TestObjectBClass *class) { } |
294 | static void test_object_b_init (TestObjectB *b) { } |
295 | |
296 | static GType test_object_a1_get_type (void); |
297 | typedef GObject TestObjectA1; typedef GObjectClass TestObjectA1Class; |
298 | G_DEFINE_TYPE (TestObjectA1, test_object_a1, test_object_a_get_type ()) |
299 | static void test_object_a1_class_init (TestObjectA1Class *class) { } |
300 | static void test_object_a1_init (TestObjectA1 *c) { } |
301 | |
302 | static GType test_object_a2_get_type (void); |
303 | typedef GObject TestObjectA2; typedef GObjectClass TestObjectA2Class; |
304 | static void test_object_a2_iface_init (TestInterfaceInterface *iface) { } |
305 | G_DEFINE_TYPE_WITH_CODE (TestObjectA2, test_object_a2, test_object_a_get_type (), |
306 | G_IMPLEMENT_INTERFACE (test_interface_get_type (), test_object_a2_iface_init)) |
307 | static void test_object_a2_class_init (TestObjectA2Class *class) { } |
308 | static void test_object_a2_init (TestObjectA2 *b) { } |
309 | |
310 | static void |
311 | test_value_transform_object (void) |
312 | { |
313 | GValue src = G_VALUE_INIT; |
314 | GValue dest = G_VALUE_INIT; |
315 | GObject *object; |
316 | guint i, s, d; |
317 | GType types[] = { |
318 | G_TYPE_OBJECT, |
319 | test_interface_get_type (), |
320 | test_object_a_get_type (), |
321 | test_object_b_get_type (), |
322 | test_object_a1_get_type (), |
323 | test_object_a2_get_type () |
324 | }; |
325 | |
326 | for (i = 0; i < G_N_ELEMENTS (types); i++) |
327 | { |
328 | if (!G_TYPE_IS_CLASSED (types[i])) |
329 | continue; |
330 | |
331 | object = g_object_new (object_type: types[i], NULL); |
332 | |
333 | for (s = 0; s < G_N_ELEMENTS (types); s++) |
334 | { |
335 | if (!G_TYPE_CHECK_INSTANCE_TYPE (object, types[s])) |
336 | continue; |
337 | |
338 | g_value_init (value: &src, g_type: types[s]); |
339 | g_value_set_object (value: &src, v_object: object); |
340 | |
341 | for (d = 0; d < G_N_ELEMENTS (types); d++) |
342 | { |
343 | g_test_message (format: "Next: %s object in GValue of %s to GValue of %s" , g_type_name (type: types[i]), g_type_name (type: types[s]), g_type_name (type: types[d])); |
344 | g_assert_true (g_value_type_transformable (types[s], types[d])); |
345 | g_value_init (value: &dest, g_type: types[d]); |
346 | g_assert_true (g_value_transform (&src, &dest)); |
347 | g_assert_cmpint (g_value_get_object (&dest) != NULL, ==, G_TYPE_CHECK_INSTANCE_TYPE (object, types[d])); |
348 | g_value_unset (value: &dest); |
349 | } |
350 | g_value_unset (value: &src); |
351 | } |
352 | |
353 | g_object_unref (object); |
354 | } |
355 | } |
356 | |
357 | int |
358 | main (int argc, char *argv[]) |
359 | { |
360 | g_test_init (argc: &argc, argv: &argv, NULL); |
361 | |
362 | g_test_add_func (testpath: "/value/basic" , test_func: test_value_basic); |
363 | g_test_add_func (testpath: "/value/string" , test_func: test_value_string); |
364 | g_test_add_func (testpath: "/value/array/basic" , test_func: test_valuearray_basic); |
365 | g_test_add_func (testpath: "/value/transform-object" , test_func: test_value_transform_object); |
366 | |
367 | return g_test_run (); |
368 | } |
369 | |