1 | /* |
2 | * Copyright © 2010 Codethink Limited |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * See the included COPYING file for more information. |
10 | * |
11 | * Author: Ryan Lortie <desrt@desrt.ca> |
12 | */ |
13 | |
14 | #include "config.h" |
15 | |
16 | #include <glib/gvariant-internal.h> |
17 | #include <string.h> |
18 | #include <stdlib.h> |
19 | #include <glib.h> |
20 | |
21 | #define BASIC "bynqiuxthdsog?" |
22 | #define N_BASIC (G_N_ELEMENTS (BASIC) - 1) |
23 | |
24 | #define INVALIDS "cefjklpwz&@^$" |
25 | #define N_INVALIDS (G_N_ELEMENTS (INVALIDS) - 1) |
26 | |
27 | /* see comment in gvariant-serialiser.c about this madness. |
28 | * |
29 | * we use this to get testing of non-strictly-aligned GVariant instances |
30 | * on machines that can tolerate it. it is necessary to support this |
31 | * because some systems have malloc() that returns non-8-aligned |
32 | * pointers. it is necessary to have special support in the tests |
33 | * because on most machines malloc() is 8-aligned. |
34 | */ |
35 | #define ALIGN_BITS (sizeof (struct { char a; union { \ |
36 | guint64 x; void *y; gdouble z; } b; }) - 9) |
37 | |
38 | static gboolean |
39 | randomly (gdouble prob) |
40 | { |
41 | return g_test_rand_double_range (range_start: 0, range_end: 1) < prob; |
42 | } |
43 | |
44 | /* corecursion */ |
45 | static GVariantType * |
46 | append_tuple_type_string (GString *, GString *, gboolean, gint); |
47 | |
48 | /* append a random GVariantType to a GString |
49 | * append a description of the type to another GString |
50 | * return what the type is |
51 | */ |
52 | static GVariantType * |
53 | append_type_string (GString *string, |
54 | GString *description, |
55 | gboolean definite, |
56 | gint depth) |
57 | { |
58 | if (!depth-- || randomly (prob: 0.3)) |
59 | { |
60 | gchar b = BASIC[g_test_rand_int_range (begin: 0, N_BASIC - definite)]; |
61 | g_string_append_c (string, b); |
62 | g_string_append_c (description, b); |
63 | |
64 | switch (b) |
65 | { |
66 | case 'b': |
67 | return g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN); |
68 | case 'y': |
69 | return g_variant_type_copy (G_VARIANT_TYPE_BYTE); |
70 | case 'n': |
71 | return g_variant_type_copy (G_VARIANT_TYPE_INT16); |
72 | case 'q': |
73 | return g_variant_type_copy (G_VARIANT_TYPE_UINT16); |
74 | case 'i': |
75 | return g_variant_type_copy (G_VARIANT_TYPE_INT32); |
76 | case 'u': |
77 | return g_variant_type_copy (G_VARIANT_TYPE_UINT32); |
78 | case 'x': |
79 | return g_variant_type_copy (G_VARIANT_TYPE_INT64); |
80 | case 't': |
81 | return g_variant_type_copy (G_VARIANT_TYPE_UINT64); |
82 | case 'h': |
83 | return g_variant_type_copy (G_VARIANT_TYPE_HANDLE); |
84 | case 'd': |
85 | return g_variant_type_copy (G_VARIANT_TYPE_DOUBLE); |
86 | case 's': |
87 | return g_variant_type_copy (G_VARIANT_TYPE_STRING); |
88 | case 'o': |
89 | return g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH); |
90 | case 'g': |
91 | return g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE); |
92 | case '?': |
93 | return g_variant_type_copy (G_VARIANT_TYPE_BASIC); |
94 | default: |
95 | g_assert_not_reached (); |
96 | } |
97 | } |
98 | else |
99 | { |
100 | GVariantType *result; |
101 | |
102 | switch (g_test_rand_int_range (begin: 0, end: definite ? 5 : 7)) |
103 | { |
104 | case 0: |
105 | { |
106 | GVariantType *element; |
107 | |
108 | g_string_append_c (string, 'a'); |
109 | g_string_append (string: description, val: "a of " ); |
110 | element = append_type_string (string, description, |
111 | definite, depth); |
112 | result = g_variant_type_new_array (element); |
113 | g_variant_type_free (type: element); |
114 | } |
115 | |
116 | g_assert_true (g_variant_type_is_array (result)); |
117 | break; |
118 | |
119 | case 1: |
120 | { |
121 | GVariantType *element; |
122 | |
123 | g_string_append_c (string, 'm'); |
124 | g_string_append (string: description, val: "m of " ); |
125 | element = append_type_string (string, description, |
126 | definite, depth); |
127 | result = g_variant_type_new_maybe (element); |
128 | g_variant_type_free (type: element); |
129 | } |
130 | |
131 | g_assert_true (g_variant_type_is_maybe (result)); |
132 | break; |
133 | |
134 | case 2: |
135 | result = append_tuple_type_string (string, description, |
136 | definite, depth); |
137 | |
138 | g_assert_true (g_variant_type_is_tuple (result)); |
139 | break; |
140 | |
141 | case 3: |
142 | { |
143 | GVariantType *key, *value; |
144 | |
145 | g_string_append_c (string, '{'); |
146 | g_string_append (string: description, val: "e of [" ); |
147 | key = append_type_string (string, description, definite, depth: 0); |
148 | g_string_append (string: description, val: ", " ); |
149 | value = append_type_string (string, description, definite, depth); |
150 | g_string_append_c (description, ']'); |
151 | g_string_append_c (string, '}'); |
152 | result = g_variant_type_new_dict_entry (key, value); |
153 | g_variant_type_free (type: key); |
154 | g_variant_type_free (type: value); |
155 | } |
156 | |
157 | g_assert_true (g_variant_type_is_dict_entry (result)); |
158 | break; |
159 | |
160 | case 4: |
161 | g_string_append_c (string, 'v'); |
162 | g_string_append_c (description, 'V'); |
163 | result = g_variant_type_copy (G_VARIANT_TYPE_VARIANT); |
164 | g_assert_true (g_variant_type_equal (result, G_VARIANT_TYPE_VARIANT)); |
165 | break; |
166 | |
167 | case 5: |
168 | g_string_append_c (string, '*'); |
169 | g_string_append_c (description, 'S'); |
170 | result = g_variant_type_copy (G_VARIANT_TYPE_ANY); |
171 | g_assert_true (g_variant_type_equal (result, G_VARIANT_TYPE_ANY)); |
172 | break; |
173 | |
174 | case 6: |
175 | g_string_append_c (string, 'r'); |
176 | g_string_append_c (description, 'R'); |
177 | result = g_variant_type_copy (G_VARIANT_TYPE_TUPLE); |
178 | g_assert_true (g_variant_type_is_tuple (result)); |
179 | break; |
180 | |
181 | default: |
182 | g_assert_not_reached (); |
183 | } |
184 | |
185 | return result; |
186 | } |
187 | } |
188 | |
189 | static GVariantType * |
190 | append_tuple_type_string (GString *string, |
191 | GString *description, |
192 | gboolean definite, |
193 | gint depth) |
194 | { |
195 | GVariantType *result, *other_result; |
196 | GVariantType **types; |
197 | gsize i, size; |
198 | |
199 | g_string_append_c (string, '('); |
200 | g_string_append (string: description, val: "t of [" ); |
201 | |
202 | size = g_test_rand_int_range (begin: 0, end: 20); |
203 | types = g_new (GVariantType *, size + 1); |
204 | |
205 | for (i = 0; i < size; i++) |
206 | { |
207 | types[i] = append_type_string (string, description, definite, depth); |
208 | |
209 | if (i < size - 1) |
210 | g_string_append (string: description, val: ", " ); |
211 | } |
212 | |
213 | types[i] = NULL; |
214 | |
215 | g_string_append_c (description, ']'); |
216 | g_string_append_c (string, ')'); |
217 | |
218 | result = g_variant_type_new_tuple (items: (gpointer) types, length: size); |
219 | other_result = g_variant_type_new_tuple (items: (gpointer) types, length: -1); |
220 | g_assert_true (g_variant_type_equal (result, other_result)); |
221 | g_variant_type_free (type: other_result); |
222 | for (i = 0; i < size; i++) |
223 | g_variant_type_free (type: types[i]); |
224 | g_free (mem: types); |
225 | |
226 | return result; |
227 | } |
228 | |
229 | /* given a valid type string, make it invalid */ |
230 | static gchar * |
231 | invalid_mutation (const gchar *type_string) |
232 | { |
233 | gboolean have_parens, have_braces; |
234 | |
235 | /* it's valid, so '(' implies ')' and same for '{' and '}' */ |
236 | have_parens = strchr (s: type_string, c: '(') != NULL; |
237 | have_braces = strchr (s: type_string, c: '{') != NULL; |
238 | |
239 | if (have_parens && have_braces && randomly (prob: 0.3)) |
240 | { |
241 | /* swap a paren and a brace */ |
242 | gchar *pp, *bp; |
243 | gint np, nb; |
244 | gchar p, b; |
245 | gchar *new; |
246 | |
247 | new = g_strdup (str: type_string); |
248 | |
249 | if (randomly (prob: 0.5)) |
250 | p = '(', b = '{'; |
251 | else |
252 | p = ')', b = '}'; |
253 | |
254 | np = nb = 0; |
255 | pp = bp = new - 1; |
256 | |
257 | /* count number of parens/braces */ |
258 | while ((pp = strchr (s: pp + 1, c: p))) np++; |
259 | while ((bp = strchr (s: bp + 1, c: b))) nb++; |
260 | |
261 | /* randomly pick one of each */ |
262 | np = g_test_rand_int_range (begin: 0, end: np) + 1; |
263 | nb = g_test_rand_int_range (begin: 0, end: nb) + 1; |
264 | |
265 | /* find it */ |
266 | pp = bp = new - 1; |
267 | while (np--) pp = strchr (s: pp + 1, c: p); |
268 | while (nb--) bp = strchr (s: bp + 1, c: b); |
269 | |
270 | /* swap */ |
271 | g_assert_true (*bp == b && *pp == p); |
272 | *bp = p; |
273 | *pp = b; |
274 | |
275 | return new; |
276 | } |
277 | |
278 | if ((have_parens || have_braces) && randomly (prob: 0.3)) |
279 | { |
280 | /* drop a paren/brace */ |
281 | gchar *new; |
282 | gchar *pp; |
283 | gint np; |
284 | gchar p; |
285 | |
286 | if (have_parens) |
287 | if (randomly (prob: 0.5)) p = '('; else p = ')'; |
288 | else |
289 | if (randomly (prob: 0.5)) p = '{'; else p = '}'; |
290 | |
291 | new = g_strdup (str: type_string); |
292 | |
293 | np = 0; |
294 | pp = new - 1; |
295 | while ((pp = strchr (s: pp + 1, c: p))) np++; |
296 | np = g_test_rand_int_range (begin: 0, end: np) + 1; |
297 | pp = new - 1; |
298 | while (np--) pp = strchr (s: pp + 1, c: p); |
299 | g_assert_cmpint (*pp, ==, p); |
300 | |
301 | while (*pp) |
302 | { |
303 | *pp = *(pp + 1); |
304 | pp++; |
305 | } |
306 | |
307 | return new; |
308 | } |
309 | |
310 | /* else, perform a random mutation at a random point */ |
311 | { |
312 | gint length, n; |
313 | gchar *new; |
314 | gchar p; |
315 | |
316 | if (randomly (prob: 0.3)) |
317 | { |
318 | /* insert a paren/brace */ |
319 | if (randomly (prob: 0.5)) |
320 | if (randomly (prob: 0.5)) p = '('; else p = ')'; |
321 | else |
322 | if (randomly (prob: 0.5)) p = '{'; else p = '}'; |
323 | } |
324 | else if (randomly (prob: 0.5)) |
325 | { |
326 | /* insert junk */ |
327 | p = INVALIDS[g_test_rand_int_range (begin: 0, N_INVALIDS)]; |
328 | } |
329 | else |
330 | { |
331 | /* truncate */ |
332 | p = '\0'; |
333 | } |
334 | |
335 | |
336 | length = strlen (s: type_string); |
337 | new = g_malloc (n_bytes: length + 2); |
338 | n = g_test_rand_int_range (begin: 0, end: length); |
339 | memcpy (dest: new, src: type_string, n: n); |
340 | new[n] = p; |
341 | memcpy (dest: new + n + 1, src: type_string + n, n: length - n); |
342 | new[length + 1] = '\0'; |
343 | |
344 | return new; |
345 | } |
346 | } |
347 | |
348 | /* describe a type using the same language as is generated |
349 | * while generating the type with append_type_string |
350 | */ |
351 | static gchar * |
352 | describe_type (const GVariantType *type) |
353 | { |
354 | gchar *result; |
355 | |
356 | if (g_variant_type_is_container (type)) |
357 | { |
358 | g_assert_false (g_variant_type_is_basic (type)); |
359 | |
360 | if (g_variant_type_is_array (type)) |
361 | { |
362 | gchar *subtype = describe_type (type: g_variant_type_element (type)); |
363 | result = g_strdup_printf (format: "a of %s" , subtype); |
364 | g_free (mem: subtype); |
365 | } |
366 | else if (g_variant_type_is_maybe (type)) |
367 | { |
368 | gchar *subtype = describe_type (type: g_variant_type_element (type)); |
369 | result = g_strdup_printf (format: "m of %s" , subtype); |
370 | g_free (mem: subtype); |
371 | } |
372 | else if (g_variant_type_is_tuple (type)) |
373 | { |
374 | if (!g_variant_type_equal (type1: type, G_VARIANT_TYPE_TUPLE)) |
375 | { |
376 | const GVariantType *sub; |
377 | GString *string; |
378 | gsize i, length; |
379 | |
380 | string = g_string_new (init: "t of [" ); |
381 | |
382 | length = g_variant_type_n_items (type); |
383 | sub = g_variant_type_first (type); |
384 | for (i = 0; i < length; i++) |
385 | { |
386 | gchar *subtype = describe_type (type: sub); |
387 | g_string_append (string, val: subtype); |
388 | g_free (mem: subtype); |
389 | |
390 | if ((sub = g_variant_type_next (type: sub))) |
391 | g_string_append (string, val: ", " ); |
392 | } |
393 | g_assert_null (sub); |
394 | g_string_append_c (string, ']'); |
395 | |
396 | result = g_string_free (string, FALSE); |
397 | } |
398 | else |
399 | result = g_strdup (str: "R" ); |
400 | } |
401 | else if (g_variant_type_is_dict_entry (type)) |
402 | { |
403 | gchar *key, *value, *key2, *value2; |
404 | |
405 | key = describe_type (type: g_variant_type_key (type)); |
406 | value = describe_type (type: g_variant_type_value (type)); |
407 | key2 = describe_type (type: g_variant_type_first (type)); |
408 | value2 = describe_type ( |
409 | type: g_variant_type_next (type: g_variant_type_first (type))); |
410 | g_assert_null (g_variant_type_next (g_variant_type_next ( |
411 | g_variant_type_first (type)))); |
412 | g_assert_cmpstr (key, ==, key2); |
413 | g_assert_cmpstr (value, ==, value2); |
414 | result = g_strjoin (separator: "" , "e of [" , key, ", " , value, "]" , NULL); |
415 | g_free (mem: key2); |
416 | g_free (mem: value2); |
417 | g_free (mem: key); |
418 | g_free (mem: value); |
419 | } |
420 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_VARIANT)) |
421 | { |
422 | result = g_strdup (str: "V" ); |
423 | } |
424 | else |
425 | g_assert_not_reached (); |
426 | } |
427 | else |
428 | { |
429 | if (g_variant_type_is_definite (type)) |
430 | { |
431 | g_assert_true (g_variant_type_is_basic (type)); |
432 | |
433 | if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_BOOLEAN)) |
434 | result = g_strdup (str: "b" ); |
435 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_BYTE)) |
436 | result = g_strdup (str: "y" ); |
437 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_INT16)) |
438 | result = g_strdup (str: "n" ); |
439 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_UINT16)) |
440 | result = g_strdup (str: "q" ); |
441 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_INT32)) |
442 | result = g_strdup (str: "i" ); |
443 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_UINT32)) |
444 | result = g_strdup (str: "u" ); |
445 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_INT64)) |
446 | result = g_strdup (str: "x" ); |
447 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_UINT64)) |
448 | result = g_strdup (str: "t" ); |
449 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_HANDLE)) |
450 | result = g_strdup (str: "h" ); |
451 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_DOUBLE)) |
452 | result = g_strdup (str: "d" ); |
453 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_STRING)) |
454 | result = g_strdup (str: "s" ); |
455 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_OBJECT_PATH)) |
456 | result = g_strdup (str: "o" ); |
457 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_SIGNATURE)) |
458 | result = g_strdup (str: "g" ); |
459 | else |
460 | g_assert_not_reached (); |
461 | } |
462 | else |
463 | { |
464 | if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_ANY)) |
465 | { |
466 | result = g_strdup (str: "S" ); |
467 | } |
468 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_BASIC)) |
469 | { |
470 | result = g_strdup (str: "?" ); |
471 | } |
472 | else |
473 | g_assert_not_reached (); |
474 | } |
475 | } |
476 | |
477 | return result; |
478 | } |
479 | |
480 | /* given a type string, replace one of the indefinite type characters in |
481 | * it with a matching type (possibly the same type). |
482 | */ |
483 | static gchar * |
484 | generate_subtype (const gchar *type_string) |
485 | { |
486 | GVariantType *replacement; |
487 | GString *result, *junk; |
488 | gint l; |
489 | gsize length, n = 0; |
490 | |
491 | result = g_string_new (NULL); |
492 | junk = g_string_new (NULL); |
493 | |
494 | /* count the number of indefinite type characters */ |
495 | for (length = 0; type_string[length]; length++) |
496 | n += type_string[length] == 'r' || |
497 | type_string[length] == '?' || |
498 | type_string[length] == '*'; |
499 | /* length now is strlen (type_string) */ |
500 | |
501 | /* pick one at random to replace */ |
502 | n = g_test_rand_int_range (begin: 0, end: n) + 1; |
503 | |
504 | /* find it */ |
505 | l = -1; |
506 | while (n--) l += strcspn (s: type_string + l + 1, reject: "r?*" ) + 1; |
507 | g_assert_true (type_string[l] == 'r' || |
508 | type_string[l] == '?' || |
509 | type_string[l] == '*'); |
510 | |
511 | /* store up to that point in a GString */ |
512 | g_string_append_len (string: result, val: type_string, len: l); |
513 | |
514 | /* then store the replacement in the GString */ |
515 | if (type_string[l] == 'r') |
516 | replacement = append_tuple_type_string (string: result, description: junk, FALSE, depth: 3); |
517 | |
518 | else if (type_string[l] == '?') |
519 | replacement = append_type_string (string: result, description: junk, FALSE, depth: 0); |
520 | |
521 | else if (type_string[l] == '*') |
522 | replacement = append_type_string (string: result, description: junk, FALSE, depth: 3); |
523 | |
524 | else |
525 | g_assert_not_reached (); |
526 | |
527 | /* ensure the replacement has the proper type */ |
528 | g_assert_true (g_variant_type_is_subtype_of (replacement, |
529 | (gpointer) &type_string[l])); |
530 | |
531 | /* store the rest from the original type string */ |
532 | g_string_append (string: result, val: type_string + l + 1); |
533 | |
534 | g_variant_type_free (type: replacement); |
535 | g_string_free (string: junk, TRUE); |
536 | |
537 | return g_string_free (string: result, FALSE); |
538 | } |
539 | |
540 | struct typestack |
541 | { |
542 | const GVariantType *type; |
543 | struct typestack *parent; |
544 | }; |
545 | |
546 | /* given an indefinite type string, replace one of the indefinite |
547 | * characters in it with a matching type and ensure that the result is a |
548 | * subtype of the original. repeat. |
549 | */ |
550 | static void |
551 | subtype_check (const gchar *type_string, |
552 | struct typestack *parent_ts) |
553 | { |
554 | struct typestack ts, *node; |
555 | gchar *subtype; |
556 | gint depth = 0; |
557 | |
558 | subtype = generate_subtype (type_string); |
559 | |
560 | ts.type = G_VARIANT_TYPE (subtype); |
561 | ts.parent = parent_ts; |
562 | |
563 | for (node = &ts; node; node = node->parent) |
564 | { |
565 | /* this type should be a subtype of each parent type */ |
566 | g_assert_true (g_variant_type_is_subtype_of (ts.type, node->type)); |
567 | |
568 | /* it should only be a supertype when it is exactly equal */ |
569 | g_assert_true (g_variant_type_is_subtype_of (node->type, ts.type) == |
570 | g_variant_type_equal (ts.type, node->type)); |
571 | |
572 | depth++; |
573 | } |
574 | |
575 | if (!g_variant_type_is_definite (type: ts.type) && depth < 5) |
576 | { |
577 | /* the type is still indefinite and we haven't repeated too many |
578 | * times. go once more. |
579 | */ |
580 | |
581 | subtype_check (type_string: subtype, parent_ts: &ts); |
582 | } |
583 | |
584 | g_free (mem: subtype); |
585 | } |
586 | |
587 | static void |
588 | test_gvarianttype (void) |
589 | { |
590 | gsize i; |
591 | |
592 | for (i = 0; i < 2000; i++) |
593 | { |
594 | GString *type_string, *description; |
595 | GVariantType *type, *other_type; |
596 | const GVariantType *ctype; |
597 | gchar *invalid; |
598 | gchar *desc; |
599 | |
600 | type_string = g_string_new (NULL); |
601 | description = g_string_new (NULL); |
602 | |
603 | /* generate a random type, its type string and a description |
604 | * |
605 | * exercises type constructor functions and g_variant_type_copy() |
606 | */ |
607 | type = append_type_string (string: type_string, description, FALSE, depth: 6); |
608 | |
609 | /* convert the type string to a type and ensure that it is equal |
610 | * to the one produced with the type constructor routines |
611 | */ |
612 | ctype = G_VARIANT_TYPE (type_string->str); |
613 | g_assert_true (g_variant_type_equal (ctype, type)); |
614 | g_assert_cmpuint (g_variant_type_hash (ctype), ==, g_variant_type_hash (type)); |
615 | g_assert_true (g_variant_type_is_subtype_of (ctype, type)); |
616 | g_assert_true (g_variant_type_is_subtype_of (type, ctype)); |
617 | |
618 | /* check if the type is indefinite */ |
619 | if (!g_variant_type_is_definite (type)) |
620 | { |
621 | struct typestack ts = { type, NULL }; |
622 | |
623 | /* if it is indefinite, then replace one of the indefinite |
624 | * characters with a matching type and ensure that the result |
625 | * is a subtype of the original type. repeat. |
626 | */ |
627 | subtype_check (type_string: type_string->str, parent_ts: &ts); |
628 | } |
629 | else |
630 | /* ensure that no indefinite characters appear */ |
631 | g_assert_cmpint (strcspn (type_string->str, "r?*" ), ==, type_string->len); |
632 | |
633 | |
634 | /* describe the type. |
635 | * |
636 | * exercises the type iterator interface |
637 | */ |
638 | desc = describe_type (type); |
639 | |
640 | /* make sure the description matches */ |
641 | g_assert_cmpstr (desc, ==, description->str); |
642 | g_free (mem: desc); |
643 | |
644 | /* make an invalid mutation to the type and make sure the type |
645 | * validation routines catch it */ |
646 | invalid = invalid_mutation (type_string: type_string->str); |
647 | g_assert_true (g_variant_type_string_is_valid (type_string->str)); |
648 | g_assert_false (g_variant_type_string_is_valid (invalid)); |
649 | g_free (mem: invalid); |
650 | |
651 | /* concatenate another type to the type string and ensure that |
652 | * the result is recognised as being invalid |
653 | */ |
654 | other_type = append_type_string (string: type_string, description, FALSE, depth: 2); |
655 | |
656 | g_string_free (string: description, TRUE); |
657 | g_string_free (string: type_string, TRUE); |
658 | g_variant_type_free (type: other_type); |
659 | g_variant_type_free (type); |
660 | } |
661 | } |
662 | |
663 | /* Test that scanning a deeply recursive type string doesn’t exhaust our |
664 | * stack space (which it would if the type string scanner was recursive). */ |
665 | static void |
666 | test_gvarianttype_string_scan_recursion_tuple (void) |
667 | { |
668 | gchar *type_string = NULL; |
669 | gsize type_string_len = 1000001; /* not including nul terminator */ |
670 | gsize i; |
671 | |
672 | /* Build a long type string of ‘((…u…))’. */ |
673 | type_string = g_new0 (gchar, type_string_len + 1); |
674 | for (i = 0; i < type_string_len; i++) |
675 | { |
676 | if (i < type_string_len / 2) |
677 | type_string[i] = '('; |
678 | else if (i == type_string_len / 2) |
679 | type_string[i] = 'u'; |
680 | else |
681 | type_string[i] = ')'; |
682 | } |
683 | |
684 | /* Goes (way) over allowed recursion limit. */ |
685 | g_assert_false (g_variant_type_string_is_valid (type_string)); |
686 | |
687 | g_free (mem: type_string); |
688 | } |
689 | |
690 | /* Same as above, except with an array rather than a tuple. */ |
691 | static void |
692 | test_gvarianttype_string_scan_recursion_array (void) |
693 | { |
694 | gchar *type_string = NULL; |
695 | gsize type_string_len = 1000001; /* not including nul terminator */ |
696 | gsize i; |
697 | |
698 | /* Build a long type string of ‘aaa…aau’. */ |
699 | type_string = g_new0 (gchar, type_string_len + 1); |
700 | for (i = 0; i < type_string_len; i++) |
701 | { |
702 | if (i < type_string_len - 1) |
703 | type_string[i] = 'a'; |
704 | else |
705 | type_string[i] = 'u'; |
706 | } |
707 | |
708 | /* Goes (way) over allowed recursion limit. */ |
709 | g_assert_false (g_variant_type_string_is_valid (type_string)); |
710 | |
711 | g_free (mem: type_string); |
712 | } |
713 | |
714 | #define ALIGNED(x, y) (((x + (y - 1)) / y) * y) |
715 | |
716 | /* do our own calculation of the fixed_size and alignment of a type |
717 | * using a simple algorithm to make sure the "fancy" one in the |
718 | * implementation is correct. |
719 | */ |
720 | static void |
721 | calculate_type_info (const GVariantType *type, |
722 | gsize *fixed_size, |
723 | guint *alignment) |
724 | { |
725 | if (g_variant_type_is_array (type) || |
726 | g_variant_type_is_maybe (type)) |
727 | { |
728 | calculate_type_info (type: g_variant_type_element (type), NULL, alignment); |
729 | |
730 | if (fixed_size) |
731 | *fixed_size = 0; |
732 | } |
733 | else if (g_variant_type_is_tuple (type) || |
734 | g_variant_type_is_dict_entry (type)) |
735 | { |
736 | if (g_variant_type_n_items (type)) |
737 | { |
738 | const GVariantType *sub; |
739 | gboolean variable; |
740 | gsize size; |
741 | guint al; |
742 | |
743 | variable = FALSE; |
744 | size = 0; |
745 | al = 0; |
746 | |
747 | sub = g_variant_type_first (type); |
748 | do |
749 | { |
750 | gsize this_fs; |
751 | guint this_al; |
752 | |
753 | calculate_type_info (type: sub, fixed_size: &this_fs, alignment: &this_al); |
754 | |
755 | al = MAX (al, this_al); |
756 | |
757 | if (!this_fs) |
758 | { |
759 | variable = TRUE; |
760 | size = 0; |
761 | } |
762 | |
763 | if (!variable) |
764 | { |
765 | size = ALIGNED (size, this_al); |
766 | size += this_fs; |
767 | } |
768 | } |
769 | while ((sub = g_variant_type_next (type: sub))); |
770 | |
771 | size = ALIGNED (size, al); |
772 | |
773 | if (alignment) |
774 | *alignment = al; |
775 | |
776 | if (fixed_size) |
777 | *fixed_size = size; |
778 | } |
779 | else |
780 | { |
781 | if (fixed_size) |
782 | *fixed_size = 1; |
783 | |
784 | if (alignment) |
785 | *alignment = 1; |
786 | } |
787 | } |
788 | else |
789 | { |
790 | gint fs, al; |
791 | |
792 | if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_BOOLEAN) || |
793 | g_variant_type_equal (type1: type, G_VARIANT_TYPE_BYTE)) |
794 | { |
795 | al = fs = 1; |
796 | } |
797 | |
798 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_INT16) || |
799 | g_variant_type_equal (type1: type, G_VARIANT_TYPE_UINT16)) |
800 | { |
801 | al = fs = 2; |
802 | } |
803 | |
804 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_INT32) || |
805 | g_variant_type_equal (type1: type, G_VARIANT_TYPE_UINT32) || |
806 | g_variant_type_equal (type1: type, G_VARIANT_TYPE_HANDLE)) |
807 | { |
808 | al = fs = 4; |
809 | } |
810 | |
811 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_INT64) || |
812 | g_variant_type_equal (type1: type, G_VARIANT_TYPE_UINT64) || |
813 | g_variant_type_equal (type1: type, G_VARIANT_TYPE_DOUBLE)) |
814 | { |
815 | al = fs = 8; |
816 | } |
817 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_STRING) || |
818 | g_variant_type_equal (type1: type, G_VARIANT_TYPE_OBJECT_PATH) || |
819 | g_variant_type_equal (type1: type, G_VARIANT_TYPE_SIGNATURE)) |
820 | { |
821 | al = 1; |
822 | fs = 0; |
823 | } |
824 | else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_VARIANT)) |
825 | { |
826 | al = 8; |
827 | fs = 0; |
828 | } |
829 | else |
830 | g_assert_not_reached (); |
831 | |
832 | if (fixed_size) |
833 | *fixed_size = fs; |
834 | |
835 | if (alignment) |
836 | *alignment = al; |
837 | } |
838 | } |
839 | |
840 | /* same as the describe_type() function above, but iterates over |
841 | * typeinfo instead of types. |
842 | */ |
843 | static gchar * |
844 | describe_info (GVariantTypeInfo *info) |
845 | { |
846 | gchar *result; |
847 | |
848 | switch (g_variant_type_info_get_type_char (info)) |
849 | { |
850 | case G_VARIANT_TYPE_INFO_CHAR_MAYBE: |
851 | { |
852 | gchar *element; |
853 | |
854 | element = describe_info (info: g_variant_type_info_element (typeinfo: info)); |
855 | result = g_strdup_printf (format: "m of %s" , element); |
856 | g_free (mem: element); |
857 | } |
858 | break; |
859 | |
860 | case G_VARIANT_TYPE_INFO_CHAR_ARRAY: |
861 | { |
862 | gchar *element; |
863 | |
864 | element = describe_info (info: g_variant_type_info_element (typeinfo: info)); |
865 | result = g_strdup_printf (format: "a of %s" , element); |
866 | g_free (mem: element); |
867 | } |
868 | break; |
869 | |
870 | case G_VARIANT_TYPE_INFO_CHAR_TUPLE: |
871 | { |
872 | const gchar *sep = "" ; |
873 | GString *string; |
874 | gsize i, length; |
875 | |
876 | string = g_string_new (init: "t of [" ); |
877 | length = g_variant_type_info_n_members (typeinfo: info); |
878 | |
879 | for (i = 0; i < length; i++) |
880 | { |
881 | const GVariantMemberInfo *minfo; |
882 | gchar *subtype; |
883 | |
884 | g_string_append (string, val: sep); |
885 | sep = ", " ; |
886 | |
887 | minfo = g_variant_type_info_member_info (typeinfo: info, index: i); |
888 | subtype = describe_info (info: minfo->type_info); |
889 | g_string_append (string, val: subtype); |
890 | g_free (mem: subtype); |
891 | } |
892 | |
893 | g_string_append_c (string, ']'); |
894 | |
895 | result = g_string_free (string, FALSE); |
896 | } |
897 | break; |
898 | |
899 | case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY: |
900 | { |
901 | const GVariantMemberInfo *keyinfo, *valueinfo; |
902 | gchar *key, *value; |
903 | |
904 | g_assert_cmpint (g_variant_type_info_n_members (info), ==, 2); |
905 | keyinfo = g_variant_type_info_member_info (typeinfo: info, index: 0); |
906 | valueinfo = g_variant_type_info_member_info (typeinfo: info, index: 1); |
907 | key = describe_info (info: keyinfo->type_info); |
908 | value = describe_info (info: valueinfo->type_info); |
909 | result = g_strjoin (separator: "" , "e of [" , key, ", " , value, "]" , NULL); |
910 | g_free (mem: key); |
911 | g_free (mem: value); |
912 | } |
913 | break; |
914 | |
915 | case G_VARIANT_TYPE_INFO_CHAR_VARIANT: |
916 | result = g_strdup (str: "V" ); |
917 | break; |
918 | |
919 | default: |
920 | result = g_strdup (str: g_variant_type_info_get_type_string (typeinfo: info)); |
921 | g_assert_cmpint (strlen (result), ==, 1); |
922 | break; |
923 | } |
924 | |
925 | return result; |
926 | } |
927 | |
928 | /* check that the O(1) method of calculating offsets meshes with the |
929 | * results of simple iteration. |
930 | */ |
931 | static void |
932 | check_offsets (GVariantTypeInfo *info, |
933 | const GVariantType *type) |
934 | { |
935 | gsize flavour, length; |
936 | |
937 | length = g_variant_type_info_n_members (typeinfo: info); |
938 | g_assert_cmpuint (length, ==, g_variant_type_n_items (type)); |
939 | |
940 | /* the 'flavour' is the low order bits of the ending point of |
941 | * variable-size items in the tuple. this lets us test that the type |
942 | * info is correct for various starting alignments. |
943 | */ |
944 | for (flavour = 0; flavour < 8; flavour++) |
945 | { |
946 | const GVariantType *subtype; |
947 | gsize last_offset_index; |
948 | gsize last_offset; |
949 | gsize position; |
950 | gsize i; |
951 | |
952 | subtype = g_variant_type_first (type); |
953 | last_offset_index = -1; |
954 | last_offset = 0; |
955 | position = 0; |
956 | |
957 | /* go through the tuple, keeping track of our position */ |
958 | for (i = 0; i < length; i++) |
959 | { |
960 | gsize fixed_size; |
961 | guint alignment; |
962 | |
963 | calculate_type_info (type: subtype, fixed_size: &fixed_size, alignment: &alignment); |
964 | |
965 | position = ALIGNED (position, alignment); |
966 | |
967 | /* compare our current aligned position (ie: the start of this |
968 | * item) to the start offset that would be calculated if we |
969 | * used the type info |
970 | */ |
971 | { |
972 | const GVariantMemberInfo *member; |
973 | gsize start; |
974 | |
975 | member = g_variant_type_info_member_info (typeinfo: info, index: i); |
976 | g_assert_cmpint (member->i, ==, last_offset_index); |
977 | |
978 | /* do the calculation using the typeinfo */ |
979 | start = last_offset; |
980 | start += member->a; |
981 | start &= member->b; |
982 | start |= member->c; |
983 | |
984 | /* did we reach the same spot? */ |
985 | g_assert_cmpint (start, ==, position); |
986 | } |
987 | |
988 | if (fixed_size) |
989 | { |
990 | /* fixed size. add that size. */ |
991 | position += fixed_size; |
992 | } |
993 | else |
994 | { |
995 | /* variable size. do the flavouring. */ |
996 | while ((position & 0x7) != flavour) |
997 | position++; |
998 | |
999 | /* and store the offset, just like it would be in the |
1000 | * serialised data. |
1001 | */ |
1002 | last_offset = position; |
1003 | last_offset_index++; |
1004 | } |
1005 | |
1006 | /* next type */ |
1007 | subtype = g_variant_type_next (type: subtype); |
1008 | } |
1009 | |
1010 | /* make sure we used up exactly all the types */ |
1011 | g_assert_null (subtype); |
1012 | } |
1013 | } |
1014 | |
1015 | static void |
1016 | test_gvarianttypeinfo (void) |
1017 | { |
1018 | gsize i; |
1019 | |
1020 | for (i = 0; i < 2000; i++) |
1021 | { |
1022 | GString *type_string, *description; |
1023 | gsize fixed_size1, fixed_size2; |
1024 | guint alignment1, alignment2; |
1025 | GVariantTypeInfo *info; |
1026 | GVariantType *type; |
1027 | gchar *desc; |
1028 | |
1029 | type_string = g_string_new (NULL); |
1030 | description = g_string_new (NULL); |
1031 | |
1032 | /* random type */ |
1033 | type = append_type_string (string: type_string, description, TRUE, depth: 6); |
1034 | |
1035 | /* create a typeinfo for it */ |
1036 | info = g_variant_type_info_get (type); |
1037 | |
1038 | /* make sure the typeinfo has the right type string */ |
1039 | g_assert_cmpstr (g_variant_type_info_get_type_string (info), ==, |
1040 | type_string->str); |
1041 | |
1042 | /* calculate the alignment and fixed size, compare to the |
1043 | * typeinfo's calculations |
1044 | */ |
1045 | calculate_type_info (type, fixed_size: &fixed_size1, alignment: &alignment1); |
1046 | g_variant_type_info_query (typeinfo: info, alignment: &alignment2, size: &fixed_size2); |
1047 | g_assert_cmpint (fixed_size1, ==, fixed_size2); |
1048 | g_assert_cmpint (alignment1, ==, alignment2 + 1); |
1049 | |
1050 | /* test the iteration functions over typeinfo structures by |
1051 | * "describing" the typeinfo and verifying equality. |
1052 | */ |
1053 | desc = describe_info (info); |
1054 | g_assert_cmpstr (desc, ==, description->str); |
1055 | |
1056 | /* do extra checks for containers */ |
1057 | if (g_variant_type_is_array (type) || |
1058 | g_variant_type_is_maybe (type)) |
1059 | { |
1060 | const GVariantType *element; |
1061 | gsize efs1, efs2; |
1062 | guint ea1, ea2; |
1063 | |
1064 | element = g_variant_type_element (type); |
1065 | calculate_type_info (type: element, fixed_size: &efs1, alignment: &ea1); |
1066 | g_variant_type_info_query_element (typeinfo: info, alignment: &ea2, size: &efs2); |
1067 | g_assert_cmpint (efs1, ==, efs2); |
1068 | g_assert_cmpint (ea1, ==, ea2 + 1); |
1069 | |
1070 | g_assert_cmpint (ea1, ==, alignment1); |
1071 | g_assert_cmpint (0, ==, fixed_size1); |
1072 | } |
1073 | else if (g_variant_type_is_tuple (type) || |
1074 | g_variant_type_is_dict_entry (type)) |
1075 | { |
1076 | /* make sure the "magic constants" are working */ |
1077 | check_offsets (info, type); |
1078 | } |
1079 | |
1080 | g_string_free (string: type_string, TRUE); |
1081 | g_string_free (string: description, TRUE); |
1082 | g_variant_type_info_unref (typeinfo: info); |
1083 | g_variant_type_free (type); |
1084 | g_free (mem: desc); |
1085 | } |
1086 | |
1087 | g_variant_type_info_assert_no_infos (); |
1088 | } |
1089 | |
1090 | #define MAX_FIXED_MULTIPLIER 256 |
1091 | #define MAX_INSTANCE_SIZE 1024 |
1092 | #define MAX_ARRAY_CHILDREN 128 |
1093 | #define MAX_TUPLE_CHILDREN 128 |
1094 | |
1095 | /* this function generates a random type such that all characteristics |
1096 | * that are "interesting" to the serialiser are tested. |
1097 | * |
1098 | * this basically means: |
1099 | * - test different alignments |
1100 | * - test variable sized items and fixed sized items |
1101 | * - test different fixed sizes |
1102 | */ |
1103 | static gchar * |
1104 | random_type_string (void) |
1105 | { |
1106 | const guchar base_types[] = "ynix" ; |
1107 | guchar base_type; |
1108 | |
1109 | base_type = base_types[g_test_rand_int_range (begin: 0, end: 4)]; |
1110 | |
1111 | if (g_test_rand_bit ()) |
1112 | /* construct a fixed-sized type */ |
1113 | { |
1114 | char type_string[MAX_FIXED_MULTIPLIER]; |
1115 | guint multiplier; |
1116 | gsize i = 0; |
1117 | |
1118 | multiplier = g_test_rand_int_range (begin: 1, end: sizeof type_string - 1); |
1119 | |
1120 | type_string[i++] = '('; |
1121 | while (multiplier--) |
1122 | type_string[i++] = base_type; |
1123 | type_string[i++] = ')'; |
1124 | |
1125 | return g_strndup (str: type_string, n: i); |
1126 | } |
1127 | else |
1128 | /* construct a variable-sized type */ |
1129 | { |
1130 | char type_string[2] = { 'a', base_type }; |
1131 | |
1132 | return g_strndup (str: type_string, n: 2); |
1133 | } |
1134 | } |
1135 | |
1136 | typedef struct |
1137 | { |
1138 | GVariantTypeInfo *type_info; |
1139 | guint alignment; |
1140 | gsize size; |
1141 | gboolean is_fixed_sized; |
1142 | |
1143 | guint32 seed; |
1144 | |
1145 | #define INSTANCE_MAGIC 1287582829 |
1146 | guint magic; |
1147 | } RandomInstance; |
1148 | |
1149 | static RandomInstance * |
1150 | random_instance (GVariantTypeInfo *type_info) |
1151 | { |
1152 | RandomInstance *instance; |
1153 | |
1154 | instance = g_slice_new (RandomInstance); |
1155 | |
1156 | if (type_info == NULL) |
1157 | { |
1158 | gchar *str = random_type_string (); |
1159 | instance->type_info = g_variant_type_info_get (G_VARIANT_TYPE (str)); |
1160 | g_free (mem: str); |
1161 | } |
1162 | else |
1163 | instance->type_info = g_variant_type_info_ref (typeinfo: type_info); |
1164 | |
1165 | instance->seed = g_test_rand_int (); |
1166 | |
1167 | g_variant_type_info_query (typeinfo: instance->type_info, |
1168 | alignment: &instance->alignment, |
1169 | size: &instance->size); |
1170 | |
1171 | instance->is_fixed_sized = instance->size != 0; |
1172 | |
1173 | if (!instance->is_fixed_sized) |
1174 | instance->size = g_test_rand_int_range (begin: 0, MAX_INSTANCE_SIZE); |
1175 | |
1176 | instance->magic = INSTANCE_MAGIC; |
1177 | |
1178 | return instance; |
1179 | } |
1180 | |
1181 | static void |
1182 | random_instance_free (RandomInstance *instance) |
1183 | { |
1184 | g_variant_type_info_unref (typeinfo: instance->type_info); |
1185 | g_slice_free (RandomInstance, instance); |
1186 | } |
1187 | |
1188 | static void |
1189 | append_instance_size (RandomInstance *instance, |
1190 | gsize *offset) |
1191 | { |
1192 | *offset += (-*offset) & instance->alignment; |
1193 | *offset += instance->size; |
1194 | } |
1195 | |
1196 | static void |
1197 | random_instance_write (RandomInstance *instance, |
1198 | guchar *buffer) |
1199 | { |
1200 | GRand *rand; |
1201 | gsize i; |
1202 | |
1203 | g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0); |
1204 | |
1205 | rand = g_rand_new_with_seed (seed: instance->seed); |
1206 | for (i = 0; i < instance->size; i++) |
1207 | buffer[i] = g_rand_int (rand_: rand); |
1208 | g_rand_free (rand_: rand); |
1209 | } |
1210 | |
1211 | static void |
1212 | append_instance_data (RandomInstance *instance, |
1213 | guchar **buffer) |
1214 | { |
1215 | while (((gsize) *buffer) & instance->alignment) |
1216 | *(*buffer)++ = '\0'; |
1217 | |
1218 | random_instance_write (instance, buffer: *buffer); |
1219 | *buffer += instance->size; |
1220 | } |
1221 | |
1222 | static gboolean |
1223 | random_instance_assert (RandomInstance *instance, |
1224 | guchar *buffer, |
1225 | gsize size) |
1226 | { |
1227 | GRand *rand; |
1228 | gsize i; |
1229 | |
1230 | g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0); |
1231 | g_assert_cmpint (size, ==, instance->size); |
1232 | |
1233 | rand = g_rand_new_with_seed (seed: instance->seed); |
1234 | for (i = 0; i < instance->size; i++) |
1235 | { |
1236 | guchar byte = g_rand_int (rand_: rand); |
1237 | |
1238 | g_assert_cmpuint (buffer[i], ==, byte); |
1239 | } |
1240 | g_rand_free (rand_: rand); |
1241 | |
1242 | return i == instance->size; |
1243 | } |
1244 | |
1245 | static gboolean |
1246 | random_instance_check (RandomInstance *instance, |
1247 | guchar *buffer, |
1248 | gsize size) |
1249 | { |
1250 | GRand *rand; |
1251 | gsize i; |
1252 | |
1253 | g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0); |
1254 | |
1255 | if (size != instance->size) |
1256 | return FALSE; |
1257 | |
1258 | rand = g_rand_new_with_seed (seed: instance->seed); |
1259 | for (i = 0; i < instance->size; i++) |
1260 | if (buffer[i] != (guchar) g_rand_int (rand_: rand)) |
1261 | break; |
1262 | g_rand_free (rand_: rand); |
1263 | |
1264 | return i == instance->size; |
1265 | } |
1266 | |
1267 | static void |
1268 | random_instance_filler (GVariantSerialised *serialised, |
1269 | gpointer data) |
1270 | { |
1271 | RandomInstance *instance = data; |
1272 | |
1273 | g_assert_cmpuint (instance->magic, ==, INSTANCE_MAGIC); |
1274 | |
1275 | if (serialised->type_info == NULL) |
1276 | serialised->type_info = instance->type_info; |
1277 | |
1278 | if (serialised->size == 0) |
1279 | serialised->size = instance->size; |
1280 | |
1281 | serialised->depth = 0; |
1282 | |
1283 | g_assert_true (serialised->type_info == instance->type_info); |
1284 | g_assert_cmpuint (serialised->size, ==, instance->size); |
1285 | |
1286 | if (serialised->data) |
1287 | random_instance_write (instance, buffer: serialised->data); |
1288 | } |
1289 | |
1290 | static gsize |
1291 | calculate_offset_size (gsize body_size, |
1292 | gsize n_offsets) |
1293 | { |
1294 | if (body_size == 0) |
1295 | return 0; |
1296 | |
1297 | if (body_size + n_offsets <= G_MAXUINT8) |
1298 | return 1; |
1299 | |
1300 | if (body_size + 2 * n_offsets <= G_MAXUINT16) |
1301 | return 2; |
1302 | |
1303 | if (body_size + 4 * n_offsets <= G_MAXUINT32) |
1304 | return 4; |
1305 | |
1306 | /* the test case won't generate anything bigger */ |
1307 | g_assert_not_reached (); |
1308 | } |
1309 | |
1310 | static gpointer |
1311 | flavoured_malloc (gsize size, gsize flavour) |
1312 | { |
1313 | g_assert_cmpuint (flavour, <, 8); |
1314 | |
1315 | if (size == 0) |
1316 | return NULL; |
1317 | |
1318 | return ((gchar *) g_malloc (n_bytes: size + flavour)) + flavour; |
1319 | } |
1320 | |
1321 | static void |
1322 | flavoured_free (gpointer data, |
1323 | gsize flavour) |
1324 | { |
1325 | if (!data) |
1326 | return; |
1327 | g_free (mem: ((gchar *) data) - flavour); |
1328 | } |
1329 | |
1330 | static gpointer |
1331 | align_malloc (gsize size) |
1332 | { |
1333 | gpointer mem; |
1334 | |
1335 | #ifdef HAVE_POSIX_MEMALIGN |
1336 | if (posix_memalign (memptr: &mem, alignment: 8, size: size)) |
1337 | g_error ("posix_memalign failed" ); |
1338 | #else |
1339 | /* NOTE: there may be platforms that lack posix_memalign() and also |
1340 | * have malloc() that returns non-8-aligned. if so, we need to try |
1341 | * harder here. |
1342 | */ |
1343 | mem = malloc (size); |
1344 | #endif |
1345 | |
1346 | return mem; |
1347 | } |
1348 | |
1349 | static void |
1350 | align_free (gpointer mem) |
1351 | { |
1352 | free (ptr: mem); |
1353 | } |
1354 | |
1355 | static void |
1356 | append_offset (guchar **offset_ptr, |
1357 | gsize offset, |
1358 | guint offset_size) |
1359 | { |
1360 | union |
1361 | { |
1362 | guchar bytes[sizeof (gsize)]; |
1363 | gsize integer; |
1364 | } tmpvalue; |
1365 | |
1366 | tmpvalue.integer = GSIZE_TO_LE (offset); |
1367 | memcpy (dest: *offset_ptr, src: tmpvalue.bytes, n: offset_size); |
1368 | *offset_ptr += offset_size; |
1369 | } |
1370 | |
1371 | static void |
1372 | prepend_offset (guchar **offset_ptr, |
1373 | gsize offset, |
1374 | guint offset_size) |
1375 | { |
1376 | union |
1377 | { |
1378 | guchar bytes[sizeof (gsize)]; |
1379 | gsize integer; |
1380 | } tmpvalue; |
1381 | |
1382 | *offset_ptr -= offset_size; |
1383 | tmpvalue.integer = GSIZE_TO_LE (offset); |
1384 | memcpy (dest: *offset_ptr, src: tmpvalue.bytes, n: offset_size); |
1385 | } |
1386 | |
1387 | static void |
1388 | test_maybe (void) |
1389 | { |
1390 | GVariantTypeInfo *type_info; |
1391 | RandomInstance *instance; |
1392 | gsize needed_size; |
1393 | guchar *data; |
1394 | |
1395 | instance = random_instance (NULL); |
1396 | |
1397 | { |
1398 | const gchar *element; |
1399 | gchar *tmp; |
1400 | |
1401 | element = g_variant_type_info_get_type_string (typeinfo: instance->type_info); |
1402 | tmp = g_strdup_printf (format: "m%s" , element); |
1403 | type_info = g_variant_type_info_get (G_VARIANT_TYPE (tmp)); |
1404 | g_free (mem: tmp); |
1405 | } |
1406 | |
1407 | needed_size = g_variant_serialiser_needed_size (info: type_info, |
1408 | gsv_filler: random_instance_filler, |
1409 | NULL, n_children: 0); |
1410 | g_assert_cmpint (needed_size, ==, 0); |
1411 | |
1412 | needed_size = g_variant_serialiser_needed_size (info: type_info, |
1413 | gsv_filler: random_instance_filler, |
1414 | children: (gpointer *) &instance, n_children: 1); |
1415 | |
1416 | if (instance->is_fixed_sized) |
1417 | g_assert_cmpint (needed_size, ==, instance->size); |
1418 | else |
1419 | g_assert_cmpint (needed_size, ==, instance->size + 1); |
1420 | |
1421 | { |
1422 | guchar *ptr; |
1423 | |
1424 | ptr = data = align_malloc (size: needed_size); |
1425 | append_instance_data (instance, buffer: &ptr); |
1426 | |
1427 | if (!instance->is_fixed_sized) |
1428 | *ptr++ = '\0'; |
1429 | |
1430 | g_assert_cmpint (ptr - data, ==, needed_size); |
1431 | } |
1432 | |
1433 | { |
1434 | guint alignment; |
1435 | gsize flavour; |
1436 | |
1437 | alignment = (instance->alignment & ALIGN_BITS) + 1; |
1438 | |
1439 | for (flavour = 0; flavour < 8; flavour += alignment) |
1440 | { |
1441 | GVariantSerialised serialised; |
1442 | GVariantSerialised child; |
1443 | |
1444 | serialised.type_info = type_info; |
1445 | serialised.data = flavoured_malloc (size: needed_size, flavour); |
1446 | serialised.size = needed_size; |
1447 | serialised.depth = 0; |
1448 | |
1449 | g_variant_serialiser_serialise (container: serialised, |
1450 | gsv_filler: random_instance_filler, |
1451 | children: (gpointer *) &instance, n_children: 1); |
1452 | child = g_variant_serialised_get_child (container: serialised, index: 0); |
1453 | g_assert_true (child.type_info == instance->type_info); |
1454 | random_instance_assert (instance, buffer: child.data, size: child.size); |
1455 | g_variant_type_info_unref (typeinfo: child.type_info); |
1456 | flavoured_free (data: serialised.data, flavour); |
1457 | } |
1458 | } |
1459 | |
1460 | g_variant_type_info_unref (typeinfo: type_info); |
1461 | random_instance_free (instance); |
1462 | align_free (mem: data); |
1463 | } |
1464 | |
1465 | static void |
1466 | test_maybes (void) |
1467 | { |
1468 | gsize i; |
1469 | |
1470 | for (i = 0; i < 1000; i++) |
1471 | test_maybe (); |
1472 | |
1473 | g_variant_type_info_assert_no_infos (); |
1474 | } |
1475 | |
1476 | static void |
1477 | test_array (void) |
1478 | { |
1479 | GVariantTypeInfo *element_info; |
1480 | GVariantTypeInfo *array_info; |
1481 | RandomInstance **instances; |
1482 | gsize needed_size; |
1483 | gsize offset_size; |
1484 | guint n_children; |
1485 | guchar *data; |
1486 | |
1487 | { |
1488 | gchar *element_type, *array_type; |
1489 | |
1490 | element_type = random_type_string (); |
1491 | array_type = g_strdup_printf (format: "a%s" , element_type); |
1492 | |
1493 | element_info = g_variant_type_info_get (G_VARIANT_TYPE (element_type)); |
1494 | array_info = g_variant_type_info_get (G_VARIANT_TYPE (array_type)); |
1495 | g_assert_true (g_variant_type_info_element (array_info) == element_info); |
1496 | |
1497 | g_free (mem: element_type); |
1498 | g_free (mem: array_type); |
1499 | } |
1500 | |
1501 | { |
1502 | gsize i; |
1503 | |
1504 | n_children = g_test_rand_int_range (begin: 0, MAX_ARRAY_CHILDREN); |
1505 | instances = g_new (RandomInstance *, n_children); |
1506 | for (i = 0; i < n_children; i++) |
1507 | instances[i] = random_instance (type_info: element_info); |
1508 | } |
1509 | |
1510 | needed_size = g_variant_serialiser_needed_size (info: array_info, |
1511 | gsv_filler: random_instance_filler, |
1512 | children: (gpointer *) instances, |
1513 | n_children); |
1514 | |
1515 | { |
1516 | gsize element_fixed_size; |
1517 | gsize body_size = 0; |
1518 | gsize i; |
1519 | |
1520 | for (i = 0; i < n_children; i++) |
1521 | append_instance_size (instance: instances[i], offset: &body_size); |
1522 | |
1523 | g_variant_type_info_query (typeinfo: element_info, NULL, size: &element_fixed_size); |
1524 | |
1525 | if (!element_fixed_size) |
1526 | { |
1527 | offset_size = calculate_offset_size (body_size, n_offsets: n_children); |
1528 | |
1529 | if (offset_size == 0) |
1530 | offset_size = 1; |
1531 | } |
1532 | else |
1533 | offset_size = 0; |
1534 | |
1535 | g_assert_cmpint (needed_size, ==, body_size + n_children * offset_size); |
1536 | } |
1537 | |
1538 | { |
1539 | guchar *offset_ptr, *body_ptr; |
1540 | gsize i; |
1541 | |
1542 | body_ptr = data = align_malloc (size: needed_size); |
1543 | offset_ptr = body_ptr + needed_size - offset_size * n_children; |
1544 | |
1545 | for (i = 0; i < n_children; i++) |
1546 | { |
1547 | append_instance_data (instance: instances[i], buffer: &body_ptr); |
1548 | append_offset (offset_ptr: &offset_ptr, offset: body_ptr - data, offset_size); |
1549 | } |
1550 | |
1551 | g_assert_true (body_ptr == data + needed_size - offset_size * n_children); |
1552 | g_assert_true (offset_ptr == data + needed_size); |
1553 | } |
1554 | |
1555 | { |
1556 | guint alignment; |
1557 | gsize flavour; |
1558 | gsize i; |
1559 | |
1560 | g_variant_type_info_query (typeinfo: array_info, alignment: &alignment, NULL); |
1561 | alignment = (alignment & ALIGN_BITS) + 1; |
1562 | |
1563 | for (flavour = 0; flavour < 8; flavour += alignment) |
1564 | { |
1565 | GVariantSerialised serialised; |
1566 | |
1567 | serialised.type_info = array_info; |
1568 | serialised.data = flavoured_malloc (size: needed_size, flavour); |
1569 | serialised.size = needed_size; |
1570 | serialised.depth = 0; |
1571 | |
1572 | g_variant_serialiser_serialise (container: serialised, gsv_filler: random_instance_filler, |
1573 | children: (gpointer *) instances, n_children); |
1574 | |
1575 | if (serialised.size) |
1576 | g_assert_cmpint (memcmp (serialised.data, data, serialised.size), ==, 0); |
1577 | |
1578 | g_assert_cmpuint (g_variant_serialised_n_children (serialised), ==, n_children); |
1579 | |
1580 | for (i = 0; i < n_children; i++) |
1581 | { |
1582 | GVariantSerialised child; |
1583 | |
1584 | child = g_variant_serialised_get_child (container: serialised, index: i); |
1585 | g_assert_true (child.type_info == instances[i]->type_info); |
1586 | random_instance_assert (instance: instances[i], buffer: child.data, size: child.size); |
1587 | g_variant_type_info_unref (typeinfo: child.type_info); |
1588 | } |
1589 | |
1590 | flavoured_free (data: serialised.data, flavour); |
1591 | } |
1592 | } |
1593 | |
1594 | { |
1595 | gsize i; |
1596 | |
1597 | for (i = 0; i < n_children; i++) |
1598 | random_instance_free (instance: instances[i]); |
1599 | g_free (mem: instances); |
1600 | } |
1601 | |
1602 | g_variant_type_info_unref (typeinfo: element_info); |
1603 | g_variant_type_info_unref (typeinfo: array_info); |
1604 | align_free (mem: data); |
1605 | } |
1606 | |
1607 | static void |
1608 | test_arrays (void) |
1609 | { |
1610 | gsize i; |
1611 | |
1612 | for (i = 0; i < 100; i++) |
1613 | test_array (); |
1614 | |
1615 | g_variant_type_info_assert_no_infos (); |
1616 | } |
1617 | |
1618 | static void |
1619 | test_tuple (void) |
1620 | { |
1621 | GVariantTypeInfo *type_info; |
1622 | RandomInstance **instances; |
1623 | gboolean fixed_size; |
1624 | gsize needed_size; |
1625 | gsize offset_size; |
1626 | guint n_children; |
1627 | guint alignment; |
1628 | guchar *data; |
1629 | |
1630 | n_children = g_test_rand_int_range (begin: 0, MAX_TUPLE_CHILDREN); |
1631 | instances = g_new (RandomInstance *, n_children); |
1632 | |
1633 | { |
1634 | GString *type_string; |
1635 | gsize i; |
1636 | |
1637 | fixed_size = TRUE; |
1638 | alignment = 0; |
1639 | |
1640 | type_string = g_string_new (init: "(" ); |
1641 | for (i = 0; i < n_children; i++) |
1642 | { |
1643 | const gchar *str; |
1644 | |
1645 | instances[i] = random_instance (NULL); |
1646 | |
1647 | alignment |= instances[i]->alignment; |
1648 | if (!instances[i]->is_fixed_sized) |
1649 | fixed_size = FALSE; |
1650 | |
1651 | str = g_variant_type_info_get_type_string (typeinfo: instances[i]->type_info); |
1652 | g_string_append (string: type_string, val: str); |
1653 | } |
1654 | g_string_append_c (type_string, ')'); |
1655 | |
1656 | type_info = g_variant_type_info_get (G_VARIANT_TYPE (type_string->str)); |
1657 | g_string_free (string: type_string, TRUE); |
1658 | } |
1659 | |
1660 | needed_size = g_variant_serialiser_needed_size (info: type_info, |
1661 | gsv_filler: random_instance_filler, |
1662 | children: (gpointer *) instances, |
1663 | n_children); |
1664 | { |
1665 | gsize body_size = 0; |
1666 | gsize offsets = 0; |
1667 | gsize i; |
1668 | |
1669 | for (i = 0; i < n_children; i++) |
1670 | { |
1671 | append_instance_size (instance: instances[i], offset: &body_size); |
1672 | |
1673 | if (i != n_children - 1 && !instances[i]->is_fixed_sized) |
1674 | offsets++; |
1675 | } |
1676 | |
1677 | if (fixed_size) |
1678 | { |
1679 | body_size += (-body_size) & alignment; |
1680 | |
1681 | g_assert_true ((body_size == 0) == (n_children == 0)); |
1682 | if (n_children == 0) |
1683 | body_size = 1; |
1684 | } |
1685 | |
1686 | offset_size = calculate_offset_size (body_size, n_offsets: offsets); |
1687 | g_assert_cmpint (needed_size, ==, body_size + offsets * offset_size); |
1688 | } |
1689 | |
1690 | { |
1691 | guchar *body_ptr; |
1692 | guchar *ofs_ptr; |
1693 | gsize i; |
1694 | |
1695 | body_ptr = data = align_malloc (size: needed_size); |
1696 | ofs_ptr = body_ptr + needed_size; |
1697 | |
1698 | for (i = 0; i < n_children; i++) |
1699 | { |
1700 | append_instance_data (instance: instances[i], buffer: &body_ptr); |
1701 | |
1702 | if (i != n_children - 1 && !instances[i]->is_fixed_sized) |
1703 | prepend_offset (offset_ptr: &ofs_ptr, offset: body_ptr - data, offset_size); |
1704 | } |
1705 | |
1706 | if (fixed_size) |
1707 | { |
1708 | while (((gsize) body_ptr) & alignment) |
1709 | *body_ptr++ = '\0'; |
1710 | |
1711 | g_assert_true ((body_ptr == data) == (n_children == 0)); |
1712 | if (n_children == 0) |
1713 | *body_ptr++ = '\0'; |
1714 | |
1715 | } |
1716 | |
1717 | |
1718 | g_assert_true (body_ptr == ofs_ptr); |
1719 | } |
1720 | |
1721 | { |
1722 | gsize flavour; |
1723 | gsize i; |
1724 | |
1725 | alignment = (alignment & ALIGN_BITS) + 1; |
1726 | |
1727 | for (flavour = 0; flavour < 8; flavour += alignment) |
1728 | { |
1729 | GVariantSerialised serialised; |
1730 | |
1731 | serialised.type_info = type_info; |
1732 | serialised.data = flavoured_malloc (size: needed_size, flavour); |
1733 | serialised.size = needed_size; |
1734 | serialised.depth = 0; |
1735 | |
1736 | g_variant_serialiser_serialise (container: serialised, gsv_filler: random_instance_filler, |
1737 | children: (gpointer *) instances, n_children); |
1738 | |
1739 | if (serialised.size) |
1740 | g_assert_cmpint (memcmp (serialised.data, data, serialised.size), ==, 0); |
1741 | |
1742 | g_assert_cmpuint (g_variant_serialised_n_children (serialised), ==, n_children); |
1743 | |
1744 | for (i = 0; i < n_children; i++) |
1745 | { |
1746 | GVariantSerialised child; |
1747 | |
1748 | child = g_variant_serialised_get_child (container: serialised, index: i); |
1749 | g_assert_true (child.type_info == instances[i]->type_info); |
1750 | random_instance_assert (instance: instances[i], buffer: child.data, size: child.size); |
1751 | g_variant_type_info_unref (typeinfo: child.type_info); |
1752 | } |
1753 | |
1754 | flavoured_free (data: serialised.data, flavour); |
1755 | } |
1756 | } |
1757 | |
1758 | { |
1759 | gsize i; |
1760 | |
1761 | for (i = 0; i < n_children; i++) |
1762 | random_instance_free (instance: instances[i]); |
1763 | g_free (mem: instances); |
1764 | } |
1765 | |
1766 | g_variant_type_info_unref (typeinfo: type_info); |
1767 | align_free (mem: data); |
1768 | } |
1769 | |
1770 | static void |
1771 | test_tuples (void) |
1772 | { |
1773 | gsize i; |
1774 | |
1775 | for (i = 0; i < 100; i++) |
1776 | test_tuple (); |
1777 | |
1778 | g_variant_type_info_assert_no_infos (); |
1779 | } |
1780 | |
1781 | static void |
1782 | test_variant (void) |
1783 | { |
1784 | GVariantTypeInfo *type_info; |
1785 | RandomInstance *instance; |
1786 | const gchar *type_string; |
1787 | gsize needed_size; |
1788 | guchar *data; |
1789 | gsize len; |
1790 | |
1791 | type_info = g_variant_type_info_get (G_VARIANT_TYPE_VARIANT); |
1792 | instance = random_instance (NULL); |
1793 | |
1794 | type_string = g_variant_type_info_get_type_string (typeinfo: instance->type_info); |
1795 | len = strlen (s: type_string); |
1796 | |
1797 | needed_size = g_variant_serialiser_needed_size (info: type_info, |
1798 | gsv_filler: random_instance_filler, |
1799 | children: (gpointer *) &instance, n_children: 1); |
1800 | |
1801 | g_assert_cmpint (needed_size, ==, instance->size + 1 + len); |
1802 | |
1803 | { |
1804 | guchar *ptr; |
1805 | |
1806 | ptr = data = align_malloc (size: needed_size); |
1807 | append_instance_data (instance, buffer: &ptr); |
1808 | *ptr++ = '\0'; |
1809 | memcpy (dest: ptr, src: type_string, n: len); |
1810 | ptr += len; |
1811 | |
1812 | g_assert_true (data + needed_size == ptr); |
1813 | } |
1814 | |
1815 | { |
1816 | gsize alignment; |
1817 | gsize flavour; |
1818 | |
1819 | /* variants are always 8-aligned */ |
1820 | alignment = ALIGN_BITS + 1; |
1821 | |
1822 | for (flavour = 0; flavour < 8; flavour += alignment) |
1823 | { |
1824 | GVariantSerialised serialised; |
1825 | GVariantSerialised child; |
1826 | |
1827 | serialised.type_info = type_info; |
1828 | serialised.data = flavoured_malloc (size: needed_size, flavour); |
1829 | serialised.size = needed_size; |
1830 | serialised.depth = 0; |
1831 | |
1832 | g_variant_serialiser_serialise (container: serialised, gsv_filler: random_instance_filler, |
1833 | children: (gpointer *) &instance, n_children: 1); |
1834 | |
1835 | if (serialised.size) |
1836 | g_assert_cmpint (memcmp (serialised.data, data, serialised.size), ==, 0); |
1837 | |
1838 | g_assert_cmpuint (g_variant_serialised_n_children (serialised), ==, 1); |
1839 | |
1840 | child = g_variant_serialised_get_child (container: serialised, index: 0); |
1841 | g_assert_true (child.type_info == instance->type_info); |
1842 | random_instance_check (instance, buffer: child.data, size: child.size); |
1843 | |
1844 | g_variant_type_info_unref (typeinfo: child.type_info); |
1845 | flavoured_free (data: serialised.data, flavour); |
1846 | } |
1847 | } |
1848 | |
1849 | g_variant_type_info_unref (typeinfo: type_info); |
1850 | random_instance_free (instance); |
1851 | align_free (mem: data); |
1852 | } |
1853 | |
1854 | static void |
1855 | test_variants (void) |
1856 | { |
1857 | gsize i; |
1858 | |
1859 | for (i = 0; i < 100; i++) |
1860 | test_variant (); |
1861 | |
1862 | g_variant_type_info_assert_no_infos (); |
1863 | } |
1864 | |
1865 | static void |
1866 | test_strings (void) |
1867 | { |
1868 | struct { |
1869 | guint flags; |
1870 | guint size; |
1871 | gconstpointer data; |
1872 | } test_cases[] = { |
1873 | #define is_nval 0 |
1874 | #define is_string 1 |
1875 | #define is_objpath is_string | 2 |
1876 | #define is_sig is_string | 4 |
1877 | { is_sig, 1, "" }, |
1878 | { is_nval, 0, NULL }, |
1879 | { is_nval, 13, "hello\xffworld!" }, |
1880 | { is_string, 13, "hello world!" }, |
1881 | { is_nval, 13, "hello world\0" }, |
1882 | { is_nval, 13, "hello\0world!" }, |
1883 | { is_nval, 12, "hello world!" }, |
1884 | { is_nval, 13, "hello world!\xff" }, |
1885 | |
1886 | { is_objpath, 2, "/" }, |
1887 | { is_objpath, 3, "/a" }, |
1888 | { is_string, 3, "//" }, |
1889 | { is_objpath, 11, "/some/path" }, |
1890 | { is_string, 12, "/some/path/" }, |
1891 | { is_nval, 11, "/some\0path" }, |
1892 | { is_string, 11, "/some\\path" }, |
1893 | { is_string, 12, "/some//path" }, |
1894 | { is_string, 12, "/some-/path" }, |
1895 | |
1896 | { is_sig, 2, "i" }, |
1897 | { is_sig, 2, "s" }, |
1898 | { is_sig, 5, "(si)" }, |
1899 | { is_string, 4, "(si" }, |
1900 | { is_string, 2, "*" }, |
1901 | { is_sig, 3, "ai" }, |
1902 | { is_string, 3, "mi" }, |
1903 | { is_string, 2, "r" }, |
1904 | { is_sig, 15, "(yyy{sv}ssiai)" }, |
1905 | { is_string, 16, "(yyy{yv}ssiai))" }, |
1906 | { is_string, 15, "(yyy{vv}ssiai)" }, |
1907 | { is_string, 15, "(yyy{sv)ssiai}" } |
1908 | }; |
1909 | gsize i; |
1910 | |
1911 | for (i = 0; i < G_N_ELEMENTS (test_cases); i++) |
1912 | { |
1913 | guint flags; |
1914 | |
1915 | flags = g_variant_serialiser_is_string (data: test_cases[i].data, |
1916 | size: test_cases[i].size) |
1917 | ? 1 : 0; |
1918 | |
1919 | flags |= g_variant_serialiser_is_object_path (data: test_cases[i].data, |
1920 | size: test_cases[i].size) |
1921 | ? 2 : 0; |
1922 | |
1923 | flags |= g_variant_serialiser_is_signature (data: test_cases[i].data, |
1924 | size: test_cases[i].size) |
1925 | ? 4 : 0; |
1926 | |
1927 | g_assert_cmpuint (flags, ==, test_cases[i].flags); |
1928 | } |
1929 | } |
1930 | |
1931 | typedef struct _TreeInstance TreeInstance; |
1932 | struct _TreeInstance |
1933 | { |
1934 | GVariantTypeInfo *info; |
1935 | |
1936 | TreeInstance **children; |
1937 | gsize n_children; |
1938 | |
1939 | union { |
1940 | guint64 integer; |
1941 | gdouble floating; |
1942 | gchar string[200]; |
1943 | } data; |
1944 | gsize data_size; |
1945 | }; |
1946 | |
1947 | static GVariantType * |
1948 | make_random_definite_type (int depth) |
1949 | { |
1950 | GString *description; |
1951 | GString *type_string; |
1952 | GVariantType *type; |
1953 | |
1954 | description = g_string_new (NULL); |
1955 | type_string = g_string_new (NULL); |
1956 | type = append_type_string (string: type_string, description, TRUE, depth); |
1957 | g_string_free (string: description, TRUE); |
1958 | g_string_free (string: type_string, TRUE); |
1959 | |
1960 | return type; |
1961 | } |
1962 | |
1963 | static void |
1964 | make_random_string (gchar *string, |
1965 | gsize size, |
1966 | const GVariantType *type) |
1967 | { |
1968 | gsize i; |
1969 | |
1970 | /* create strings that are valid signature strings */ |
1971 | #define good_chars "bynqiuxthdsog" |
1972 | |
1973 | for (i = 0; i < size - 1; i++) |
1974 | string[i] = good_chars[g_test_rand_int_range (begin: 0, end: strlen (good_chars))]; |
1975 | string[i] = '\0'; |
1976 | |
1977 | /* in case we need an object path, prefix a '/' */ |
1978 | if (*g_variant_type_peek_string (type) == 'o') |
1979 | string[0] = '/'; |
1980 | |
1981 | #undef good_chars |
1982 | } |
1983 | |
1984 | static TreeInstance * |
1985 | tree_instance_new (const GVariantType *type, |
1986 | int depth) |
1987 | { |
1988 | const GVariantType *child_type = NULL; |
1989 | GVariantType *mytype = NULL; |
1990 | TreeInstance *instance; |
1991 | gboolean is_tuple_type; |
1992 | |
1993 | if (type == NULL) |
1994 | type = mytype = make_random_definite_type (depth); |
1995 | |
1996 | instance = g_slice_new (TreeInstance); |
1997 | instance->info = g_variant_type_info_get (type); |
1998 | instance->children = NULL; |
1999 | instance->n_children = 0; |
2000 | instance->data_size = 0; |
2001 | |
2002 | is_tuple_type = FALSE; |
2003 | |
2004 | switch (*g_variant_type_peek_string (type)) |
2005 | { |
2006 | case G_VARIANT_TYPE_INFO_CHAR_MAYBE: |
2007 | instance->n_children = g_test_rand_int_range (begin: 0, end: 2); |
2008 | child_type = g_variant_type_element (type); |
2009 | break; |
2010 | |
2011 | case G_VARIANT_TYPE_INFO_CHAR_ARRAY: |
2012 | instance->n_children = g_test_rand_int_range (begin: 0, MAX_ARRAY_CHILDREN); |
2013 | child_type = g_variant_type_element (type); |
2014 | break; |
2015 | |
2016 | case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY: |
2017 | case G_VARIANT_TYPE_INFO_CHAR_TUPLE: |
2018 | instance->n_children = g_variant_type_n_items (type); |
2019 | child_type = g_variant_type_first (type); |
2020 | is_tuple_type = TRUE; |
2021 | break; |
2022 | |
2023 | case G_VARIANT_TYPE_INFO_CHAR_VARIANT: |
2024 | instance->n_children = 1; |
2025 | child_type = NULL; |
2026 | break; |
2027 | |
2028 | case 'b': |
2029 | instance->data.integer = g_test_rand_int_range (begin: 0, end: 2); |
2030 | instance->data_size = 1; |
2031 | break; |
2032 | |
2033 | case 'y': |
2034 | instance->data.integer = g_test_rand_int (); |
2035 | instance->data_size = 1; |
2036 | break; |
2037 | |
2038 | case 'n': case 'q': |
2039 | instance->data.integer = g_test_rand_int (); |
2040 | instance->data_size = 2; |
2041 | break; |
2042 | |
2043 | case 'i': case 'u': case 'h': |
2044 | instance->data.integer = g_test_rand_int (); |
2045 | instance->data_size = 4; |
2046 | break; |
2047 | |
2048 | case 'x': case 't': |
2049 | instance->data.integer = g_test_rand_int (); |
2050 | instance->data.integer <<= 32; |
2051 | instance->data.integer |= (guint32) g_test_rand_int (); |
2052 | instance->data_size = 8; |
2053 | break; |
2054 | |
2055 | case 'd': |
2056 | instance->data.floating = g_test_rand_double (); |
2057 | instance->data_size = 8; |
2058 | break; |
2059 | |
2060 | case 's': case 'o': case 'g': |
2061 | instance->data_size = g_test_rand_int_range (begin: 10, end: 200); |
2062 | make_random_string (string: instance->data.string, size: instance->data_size, type); |
2063 | break; |
2064 | } |
2065 | |
2066 | if (instance->data_size == 0) |
2067 | /* no data -> it is a container */ |
2068 | { |
2069 | gsize i; |
2070 | |
2071 | instance->children = g_new (TreeInstance *, instance->n_children); |
2072 | |
2073 | for (i = 0; i < instance->n_children; i++) |
2074 | { |
2075 | instance->children[i] = tree_instance_new (type: child_type, depth: depth - 1); |
2076 | |
2077 | if (is_tuple_type) |
2078 | child_type = g_variant_type_next (type: child_type); |
2079 | } |
2080 | |
2081 | g_assert_true (!is_tuple_type || child_type == NULL); |
2082 | } |
2083 | |
2084 | g_variant_type_free (type: mytype); |
2085 | |
2086 | return instance; |
2087 | } |
2088 | |
2089 | static void |
2090 | tree_instance_free (TreeInstance *instance) |
2091 | { |
2092 | gsize i; |
2093 | |
2094 | g_variant_type_info_unref (typeinfo: instance->info); |
2095 | for (i = 0; i < instance->n_children; i++) |
2096 | tree_instance_free (instance: instance->children[i]); |
2097 | g_free (mem: instance->children); |
2098 | g_slice_free (TreeInstance, instance); |
2099 | } |
2100 | |
2101 | static gboolean i_am_writing_byteswapped; |
2102 | |
2103 | static void |
2104 | tree_filler (GVariantSerialised *serialised, |
2105 | gpointer data) |
2106 | { |
2107 | TreeInstance *instance = data; |
2108 | |
2109 | if (serialised->type_info == NULL) |
2110 | serialised->type_info = instance->info; |
2111 | |
2112 | serialised->depth = 0; |
2113 | |
2114 | if (instance->data_size == 0) |
2115 | /* is a container */ |
2116 | { |
2117 | if (serialised->size == 0) |
2118 | serialised->size = |
2119 | g_variant_serialiser_needed_size (info: instance->info, gsv_filler: tree_filler, |
2120 | children: (gpointer *) instance->children, |
2121 | n_children: instance->n_children); |
2122 | |
2123 | if (serialised->data) |
2124 | g_variant_serialiser_serialise (container: *serialised, gsv_filler: tree_filler, |
2125 | children: (gpointer *) instance->children, |
2126 | n_children: instance->n_children); |
2127 | } |
2128 | else |
2129 | /* it is a leaf */ |
2130 | { |
2131 | if (serialised->size == 0) |
2132 | serialised->size = instance->data_size; |
2133 | |
2134 | if (serialised->data) |
2135 | { |
2136 | switch (instance->data_size) |
2137 | { |
2138 | case 1: |
2139 | *serialised->data = instance->data.integer; |
2140 | break; |
2141 | |
2142 | case 2: |
2143 | { |
2144 | guint16 value = instance->data.integer; |
2145 | |
2146 | if (i_am_writing_byteswapped) |
2147 | value = GUINT16_SWAP_LE_BE (value); |
2148 | |
2149 | *(guint16 *) serialised->data = value; |
2150 | } |
2151 | break; |
2152 | |
2153 | case 4: |
2154 | { |
2155 | guint32 value = instance->data.integer; |
2156 | |
2157 | if (i_am_writing_byteswapped) |
2158 | value = GUINT32_SWAP_LE_BE (value); |
2159 | |
2160 | *(guint32 *) serialised->data = value; |
2161 | } |
2162 | break; |
2163 | |
2164 | case 8: |
2165 | { |
2166 | guint64 value = instance->data.integer; |
2167 | |
2168 | if (i_am_writing_byteswapped) |
2169 | value = GUINT64_SWAP_LE_BE (value); |
2170 | |
2171 | *(guint64 *) serialised->data = value; |
2172 | } |
2173 | break; |
2174 | |
2175 | default: |
2176 | memcpy (dest: serialised->data, |
2177 | src: instance->data.string, |
2178 | n: instance->data_size); |
2179 | break; |
2180 | } |
2181 | } |
2182 | } |
2183 | } |
2184 | |
2185 | static gboolean |
2186 | check_tree (TreeInstance *instance, |
2187 | GVariantSerialised serialised) |
2188 | { |
2189 | if (instance->info != serialised.type_info) |
2190 | return FALSE; |
2191 | |
2192 | if (instance->data_size == 0) |
2193 | /* is a container */ |
2194 | { |
2195 | gsize i; |
2196 | |
2197 | if (g_variant_serialised_n_children (container: serialised) != |
2198 | instance->n_children) |
2199 | return FALSE; |
2200 | |
2201 | for (i = 0; i < instance->n_children; i++) |
2202 | { |
2203 | GVariantSerialised child; |
2204 | gpointer data = NULL; |
2205 | gboolean ok; |
2206 | |
2207 | child = g_variant_serialised_get_child (container: serialised, index: i); |
2208 | if (child.size && child.data == NULL) |
2209 | child.data = data = g_malloc0 (n_bytes: child.size); |
2210 | ok = check_tree (instance: instance->children[i], serialised: child); |
2211 | g_variant_type_info_unref (typeinfo: child.type_info); |
2212 | g_free (mem: data); |
2213 | |
2214 | if (!ok) |
2215 | return FALSE; |
2216 | } |
2217 | |
2218 | return TRUE; |
2219 | } |
2220 | else |
2221 | /* it is a leaf */ |
2222 | { |
2223 | switch (instance->data_size) |
2224 | { |
2225 | case 1: |
2226 | g_assert_cmpuint (serialised.size, ==, 1); |
2227 | return *(guint8 *) serialised.data == |
2228 | (guint8) instance->data.integer; |
2229 | |
2230 | case 2: |
2231 | g_assert_cmpuint (serialised.size, ==, 2); |
2232 | return *(guint16 *) serialised.data == |
2233 | (guint16) instance->data.integer; |
2234 | |
2235 | case 4: |
2236 | g_assert_cmpuint (serialised.size, ==, 4); |
2237 | return *(guint32 *) serialised.data == |
2238 | (guint32) instance->data.integer; |
2239 | |
2240 | case 8: |
2241 | g_assert_cmpuint (serialised.size, ==, 8); |
2242 | return *(guint64 *) serialised.data == |
2243 | (guint64) instance->data.integer; |
2244 | |
2245 | default: |
2246 | if (serialised.size != instance->data_size) |
2247 | return FALSE; |
2248 | |
2249 | return memcmp (s1: serialised.data, |
2250 | s2: instance->data.string, |
2251 | n: instance->data_size) == 0; |
2252 | } |
2253 | } |
2254 | } |
2255 | |
2256 | static void |
2257 | serialise_tree (TreeInstance *tree, |
2258 | GVariantSerialised *serialised) |
2259 | { |
2260 | GVariantSerialised empty = {0, }; |
2261 | |
2262 | *serialised = empty; |
2263 | tree_filler (serialised, data: tree); |
2264 | serialised->data = g_malloc (n_bytes: serialised->size); |
2265 | tree_filler (serialised, data: tree); |
2266 | } |
2267 | |
2268 | static void |
2269 | test_byteswap (void) |
2270 | { |
2271 | GVariantSerialised one, two; |
2272 | TreeInstance *tree; |
2273 | |
2274 | tree = tree_instance_new (NULL, depth: 3); |
2275 | serialise_tree (tree, serialised: &one); |
2276 | |
2277 | i_am_writing_byteswapped = TRUE; |
2278 | serialise_tree (tree, serialised: &two); |
2279 | i_am_writing_byteswapped = FALSE; |
2280 | |
2281 | g_variant_serialised_byteswap (value: two); |
2282 | |
2283 | g_assert_cmpmem (one.data, one.size, two.data, two.size); |
2284 | g_assert_cmpuint (one.depth, ==, two.depth); |
2285 | |
2286 | tree_instance_free (instance: tree); |
2287 | g_free (mem: one.data); |
2288 | g_free (mem: two.data); |
2289 | } |
2290 | |
2291 | static void |
2292 | test_byteswaps (void) |
2293 | { |
2294 | int i; |
2295 | |
2296 | for (i = 0; i < 200; i++) |
2297 | test_byteswap (); |
2298 | |
2299 | g_variant_type_info_assert_no_infos (); |
2300 | } |
2301 | |
2302 | static void |
2303 | test_serialiser_children (void) |
2304 | { |
2305 | GBytes *data1, *data2; |
2306 | GVariant *child1, *child2; |
2307 | GVariantType *mv_type = g_variant_type_new_maybe (G_VARIANT_TYPE_VARIANT); |
2308 | GVariant *variant, *child; |
2309 | |
2310 | g_test_bug (bug_uri_snippet: "https://gitlab.gnome.org/GNOME/glib/issues/1865" ); |
2311 | g_test_summary (summary: "Test that getting a child variant before and after " |
2312 | "serialisation of the parent works" ); |
2313 | |
2314 | /* Construct a variable sized array containing a child which serialises to a |
2315 | * zero-length bytestring. */ |
2316 | child = g_variant_new_maybe (G_VARIANT_TYPE_VARIANT, NULL); |
2317 | variant = g_variant_new_array (child_type: mv_type, children: &child, n_children: 1); |
2318 | |
2319 | /* Get the child before serialising. */ |
2320 | child1 = g_variant_get_child_value (value: variant, index_: 0); |
2321 | data1 = g_variant_get_data_as_bytes (value: child1); |
2322 | |
2323 | /* Serialise the parent variant. */ |
2324 | g_variant_get_data (value: variant); |
2325 | |
2326 | /* Get the child again after serialising — this uses a different code path. */ |
2327 | child2 = g_variant_get_child_value (value: variant, index_: 0); |
2328 | data2 = g_variant_get_data_as_bytes (value: child2); |
2329 | |
2330 | /* Check things are equal. */ |
2331 | g_assert_cmpvariant (child1, child2); |
2332 | g_assert_true (g_bytes_equal (data1, data2)); |
2333 | |
2334 | g_variant_unref (value: child2); |
2335 | g_variant_unref (value: child1); |
2336 | g_variant_unref (value: variant); |
2337 | g_bytes_unref (bytes: data2); |
2338 | g_bytes_unref (bytes: data1); |
2339 | g_variant_type_free (type: mv_type); |
2340 | } |
2341 | |
2342 | static void |
2343 | test_fuzz (gdouble *fuzziness) |
2344 | { |
2345 | GVariantSerialised serialised; |
2346 | TreeInstance *tree; |
2347 | |
2348 | /* make an instance */ |
2349 | tree = tree_instance_new (NULL, depth: 3); |
2350 | |
2351 | /* serialise it */ |
2352 | serialise_tree (tree, serialised: &serialised); |
2353 | |
2354 | g_assert_true (g_variant_serialised_is_normal (serialised)); |
2355 | g_assert_true (check_tree (tree, serialised)); |
2356 | |
2357 | if (serialised.size) |
2358 | { |
2359 | gboolean fuzzed = FALSE; |
2360 | gboolean a, b; |
2361 | |
2362 | while (!fuzzed) |
2363 | { |
2364 | gsize i; |
2365 | |
2366 | for (i = 0; i < serialised.size; i++) |
2367 | if (randomly (prob: *fuzziness)) |
2368 | { |
2369 | serialised.data[i] += g_test_rand_int_range (begin: 1, end: 256); |
2370 | fuzzed = TRUE; |
2371 | } |
2372 | } |
2373 | |
2374 | /* at least one byte in the serialised data has changed. |
2375 | * |
2376 | * this means that at least one of the following is true: |
2377 | * |
2378 | * - the serialised data now represents a different value: |
2379 | * check_tree() will return FALSE |
2380 | * |
2381 | * - the serialised data is in non-normal form: |
2382 | * g_variant_serialiser_is_normal() will return FALSE |
2383 | * |
2384 | * we always do both checks to increase exposure of the serialiser |
2385 | * to corrupt data. |
2386 | */ |
2387 | a = g_variant_serialised_is_normal (value: serialised); |
2388 | b = check_tree (instance: tree, serialised); |
2389 | |
2390 | g_assert_true (!a || !b); |
2391 | } |
2392 | |
2393 | tree_instance_free (instance: tree); |
2394 | g_free (mem: serialised.data); |
2395 | } |
2396 | |
2397 | |
2398 | static void |
2399 | test_fuzzes (gpointer data) |
2400 | { |
2401 | gdouble fuzziness; |
2402 | int i; |
2403 | |
2404 | fuzziness = GPOINTER_TO_INT (data) / 100.; |
2405 | |
2406 | for (i = 0; i < 200; i++) |
2407 | test_fuzz (fuzziness: &fuzziness); |
2408 | |
2409 | g_variant_type_info_assert_no_infos (); |
2410 | } |
2411 | |
2412 | static GVariant * |
2413 | tree_instance_get_gvariant (TreeInstance *tree) |
2414 | { |
2415 | const GVariantType *type; |
2416 | GVariant *result; |
2417 | |
2418 | type = (GVariantType *) g_variant_type_info_get_type_string (typeinfo: tree->info); |
2419 | |
2420 | switch (g_variant_type_info_get_type_char (tree->info)) |
2421 | { |
2422 | case G_VARIANT_TYPE_INFO_CHAR_MAYBE: |
2423 | { |
2424 | const GVariantType *child_type; |
2425 | GVariant *child; |
2426 | |
2427 | if (tree->n_children) |
2428 | child = tree_instance_get_gvariant (tree: tree->children[0]); |
2429 | else |
2430 | child = NULL; |
2431 | |
2432 | child_type = g_variant_type_element (type); |
2433 | |
2434 | if (child != NULL && randomly (prob: 0.5)) |
2435 | child_type = NULL; |
2436 | |
2437 | result = g_variant_new_maybe (child_type, child); |
2438 | } |
2439 | break; |
2440 | |
2441 | case G_VARIANT_TYPE_INFO_CHAR_ARRAY: |
2442 | { |
2443 | const GVariantType *child_type; |
2444 | GVariant **children; |
2445 | gsize i; |
2446 | |
2447 | children = g_new (GVariant *, tree->n_children); |
2448 | for (i = 0; i < tree->n_children; i++) |
2449 | children[i] = tree_instance_get_gvariant (tree: tree->children[i]); |
2450 | |
2451 | child_type = g_variant_type_element (type); |
2452 | |
2453 | if (i > 0 && randomly (prob: 0.5)) |
2454 | child_type = NULL; |
2455 | |
2456 | result = g_variant_new_array (child_type, children, n_children: tree->n_children); |
2457 | g_free (mem: children); |
2458 | } |
2459 | break; |
2460 | |
2461 | case G_VARIANT_TYPE_INFO_CHAR_TUPLE: |
2462 | { |
2463 | GVariant **children; |
2464 | gsize i; |
2465 | |
2466 | children = g_new (GVariant *, tree->n_children); |
2467 | for (i = 0; i < tree->n_children; i++) |
2468 | children[i] = tree_instance_get_gvariant (tree: tree->children[i]); |
2469 | |
2470 | result = g_variant_new_tuple (children, n_children: tree->n_children); |
2471 | g_free (mem: children); |
2472 | } |
2473 | break; |
2474 | |
2475 | case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY: |
2476 | { |
2477 | GVariant *key, *val; |
2478 | |
2479 | g_assert_cmpuint (tree->n_children, ==, 2); |
2480 | |
2481 | key = tree_instance_get_gvariant (tree: tree->children[0]); |
2482 | val = tree_instance_get_gvariant (tree: tree->children[1]); |
2483 | |
2484 | result = g_variant_new_dict_entry (key, value: val); |
2485 | } |
2486 | break; |
2487 | |
2488 | case G_VARIANT_TYPE_INFO_CHAR_VARIANT: |
2489 | { |
2490 | GVariant *value; |
2491 | |
2492 | g_assert_cmpuint (tree->n_children, ==, 1); |
2493 | |
2494 | value = tree_instance_get_gvariant (tree: tree->children[0]); |
2495 | result = g_variant_new_variant (value); |
2496 | } |
2497 | break; |
2498 | |
2499 | case 'b': |
2500 | result = g_variant_new_boolean (value: tree->data.integer > 0); |
2501 | break; |
2502 | |
2503 | case 'y': |
2504 | result = g_variant_new_byte (value: tree->data.integer); |
2505 | break; |
2506 | |
2507 | case 'n': |
2508 | result = g_variant_new_int16 (value: tree->data.integer); |
2509 | break; |
2510 | |
2511 | case 'q': |
2512 | result = g_variant_new_uint16 (value: tree->data.integer); |
2513 | break; |
2514 | |
2515 | case 'i': |
2516 | result = g_variant_new_int32 (value: tree->data.integer); |
2517 | break; |
2518 | |
2519 | case 'u': |
2520 | result = g_variant_new_uint32 (value: tree->data.integer); |
2521 | break; |
2522 | |
2523 | case 'x': |
2524 | result = g_variant_new_int64 (value: tree->data.integer); |
2525 | break; |
2526 | |
2527 | case 't': |
2528 | result = g_variant_new_uint64 (value: tree->data.integer); |
2529 | break; |
2530 | |
2531 | case 'h': |
2532 | result = g_variant_new_handle (value: tree->data.integer); |
2533 | break; |
2534 | |
2535 | case 'd': |
2536 | result = g_variant_new_double (value: tree->data.floating); |
2537 | break; |
2538 | |
2539 | case 's': |
2540 | result = g_variant_new_string (string: tree->data.string); |
2541 | break; |
2542 | |
2543 | case 'o': |
2544 | result = g_variant_new_object_path (object_path: tree->data.string); |
2545 | break; |
2546 | |
2547 | case 'g': |
2548 | result = g_variant_new_signature (signature: tree->data.string); |
2549 | break; |
2550 | |
2551 | default: |
2552 | g_assert_not_reached (); |
2553 | } |
2554 | |
2555 | return result; |
2556 | } |
2557 | |
2558 | static gboolean |
2559 | tree_instance_check_gvariant (TreeInstance *tree, |
2560 | GVariant *value) |
2561 | { |
2562 | const GVariantType *type; |
2563 | |
2564 | type = (GVariantType *) g_variant_type_info_get_type_string (typeinfo: tree->info); |
2565 | g_assert_true (g_variant_is_of_type (value, type)); |
2566 | |
2567 | switch (g_variant_type_info_get_type_char (tree->info)) |
2568 | { |
2569 | case G_VARIANT_TYPE_INFO_CHAR_MAYBE: |
2570 | { |
2571 | GVariant *child; |
2572 | gboolean equal; |
2573 | |
2574 | child = g_variant_get_maybe (value); |
2575 | |
2576 | if (child != NULL && tree->n_children == 1) |
2577 | equal = tree_instance_check_gvariant (tree: tree->children[0], value: child); |
2578 | else if (child == NULL && tree->n_children == 0) |
2579 | equal = TRUE; |
2580 | else |
2581 | equal = FALSE; |
2582 | |
2583 | if (child != NULL) |
2584 | g_variant_unref (value: child); |
2585 | |
2586 | return equal; |
2587 | } |
2588 | break; |
2589 | |
2590 | case G_VARIANT_TYPE_INFO_CHAR_ARRAY: |
2591 | case G_VARIANT_TYPE_INFO_CHAR_TUPLE: |
2592 | case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY: |
2593 | { |
2594 | gsize i; |
2595 | |
2596 | if (g_variant_n_children (value) != tree->n_children) |
2597 | return FALSE; |
2598 | |
2599 | for (i = 0; i < tree->n_children; i++) |
2600 | { |
2601 | GVariant *child; |
2602 | gboolean equal; |
2603 | |
2604 | child = g_variant_get_child_value (value, index_: i); |
2605 | equal = tree_instance_check_gvariant (tree: tree->children[i], value: child); |
2606 | g_variant_unref (value: child); |
2607 | |
2608 | if (!equal) |
2609 | return FALSE; |
2610 | } |
2611 | |
2612 | return TRUE; |
2613 | } |
2614 | break; |
2615 | |
2616 | case G_VARIANT_TYPE_INFO_CHAR_VARIANT: |
2617 | { |
2618 | const gchar *str1, *str2; |
2619 | GVariant *child; |
2620 | gboolean equal; |
2621 | |
2622 | child = g_variant_get_variant (value); |
2623 | str1 = g_variant_get_type_string (value: child); |
2624 | str2 = g_variant_type_info_get_type_string (typeinfo: tree->children[0]->info); |
2625 | /* GVariant only keeps one copy of type strings around */ |
2626 | equal = str1 == str2 && |
2627 | tree_instance_check_gvariant (tree: tree->children[0], value: child); |
2628 | |
2629 | g_variant_unref (value: child); |
2630 | |
2631 | return equal; |
2632 | } |
2633 | break; |
2634 | |
2635 | case 'b': |
2636 | return g_variant_get_boolean (value) == (gboolean) tree->data.integer; |
2637 | |
2638 | case 'y': |
2639 | return g_variant_get_byte (value) == (guchar) tree->data.integer; |
2640 | |
2641 | case 'n': |
2642 | return g_variant_get_int16 (value) == (gint16) tree->data.integer; |
2643 | |
2644 | case 'q': |
2645 | return g_variant_get_uint16 (value) == (guint16) tree->data.integer; |
2646 | |
2647 | case 'i': |
2648 | return g_variant_get_int32 (value) == (gint32) tree->data.integer; |
2649 | |
2650 | case 'u': |
2651 | return g_variant_get_uint32 (value) == (guint32) tree->data.integer; |
2652 | |
2653 | case 'x': |
2654 | return g_variant_get_int64 (value) == (gint64) tree->data.integer; |
2655 | |
2656 | case 't': |
2657 | return g_variant_get_uint64 (value) == (guint64) tree->data.integer; |
2658 | |
2659 | case 'h': |
2660 | return g_variant_get_handle (value) == (gint32) tree->data.integer; |
2661 | |
2662 | case 'd': |
2663 | { |
2664 | gdouble floating = g_variant_get_double (value); |
2665 | |
2666 | return memcmp (s1: &floating, s2: &tree->data.floating, n: sizeof floating) == 0; |
2667 | } |
2668 | |
2669 | case 's': |
2670 | case 'o': |
2671 | case 'g': |
2672 | return strcmp (s1: g_variant_get_string (value, NULL), |
2673 | s2: tree->data.string) == 0; |
2674 | |
2675 | default: |
2676 | g_assert_not_reached (); |
2677 | } |
2678 | } |
2679 | |
2680 | static void |
2681 | tree_instance_build_gvariant (TreeInstance *tree, |
2682 | GVariantBuilder *builder, |
2683 | gboolean guess_ok) |
2684 | { |
2685 | const GVariantType *type; |
2686 | |
2687 | type = (GVariantType *) g_variant_type_info_get_type_string (typeinfo: tree->info); |
2688 | |
2689 | if (g_variant_type_is_container (type)) |
2690 | { |
2691 | gsize i; |
2692 | |
2693 | /* force GVariantBuilder to guess the type half the time */ |
2694 | if (guess_ok && randomly (prob: 0.5)) |
2695 | { |
2696 | if (g_variant_type_is_array (type) && tree->n_children) |
2697 | type = G_VARIANT_TYPE_ARRAY; |
2698 | |
2699 | if (g_variant_type_is_maybe (type) && tree->n_children) |
2700 | type = G_VARIANT_TYPE_MAYBE; |
2701 | |
2702 | if (g_variant_type_is_tuple (type)) |
2703 | type = G_VARIANT_TYPE_TUPLE; |
2704 | |
2705 | if (g_variant_type_is_dict_entry (type)) |
2706 | type = G_VARIANT_TYPE_DICT_ENTRY; |
2707 | } |
2708 | else |
2709 | guess_ok = FALSE; |
2710 | |
2711 | g_variant_builder_open (builder, type); |
2712 | |
2713 | for (i = 0; i < tree->n_children; i++) |
2714 | tree_instance_build_gvariant (tree: tree->children[i], builder, guess_ok); |
2715 | |
2716 | g_variant_builder_close (builder); |
2717 | } |
2718 | else |
2719 | g_variant_builder_add_value (builder, value: tree_instance_get_gvariant (tree)); |
2720 | } |
2721 | |
2722 | |
2723 | static gboolean |
2724 | tree_instance_check_iter (TreeInstance *tree, |
2725 | GVariantIter *iter) |
2726 | { |
2727 | GVariant *value; |
2728 | |
2729 | value = g_variant_iter_next_value (iter); |
2730 | |
2731 | if (g_variant_is_container (value)) |
2732 | { |
2733 | gsize i; |
2734 | |
2735 | iter = g_variant_iter_new (value); |
2736 | g_variant_unref (value); |
2737 | |
2738 | if (g_variant_iter_n_children (iter) != tree->n_children) |
2739 | { |
2740 | g_variant_iter_free (iter); |
2741 | return FALSE; |
2742 | } |
2743 | |
2744 | for (i = 0; i < tree->n_children; i++) |
2745 | if (!tree_instance_check_iter (tree: tree->children[i], iter)) |
2746 | { |
2747 | g_variant_iter_free (iter); |
2748 | return FALSE; |
2749 | } |
2750 | |
2751 | g_assert_null (g_variant_iter_next_value (iter)); |
2752 | g_variant_iter_free (iter); |
2753 | |
2754 | return TRUE; |
2755 | } |
2756 | |
2757 | else |
2758 | { |
2759 | gboolean equal; |
2760 | |
2761 | equal = tree_instance_check_gvariant (tree, value); |
2762 | g_variant_unref (value); |
2763 | |
2764 | return equal; |
2765 | } |
2766 | } |
2767 | |
2768 | static void |
2769 | test_container (void) |
2770 | { |
2771 | TreeInstance *tree; |
2772 | GVariant *value; |
2773 | gchar *s1, *s2; |
2774 | |
2775 | tree = tree_instance_new (NULL, depth: 3); |
2776 | value = g_variant_ref_sink (value: tree_instance_get_gvariant (tree)); |
2777 | |
2778 | s1 = g_variant_print (value, TRUE); |
2779 | g_assert_true (tree_instance_check_gvariant (tree, value)); |
2780 | |
2781 | g_variant_get_data (value); |
2782 | |
2783 | s2 = g_variant_print (value, TRUE); |
2784 | g_assert_true (tree_instance_check_gvariant (tree, value)); |
2785 | |
2786 | g_assert_cmpstr (s1, ==, s2); |
2787 | |
2788 | if (g_variant_is_container (value)) |
2789 | { |
2790 | GVariantBuilder builder; |
2791 | GVariantIter iter; |
2792 | GVariant *built; |
2793 | GVariant *val; |
2794 | gchar *s3; |
2795 | |
2796 | g_variant_builder_init (builder: &builder, G_VARIANT_TYPE_VARIANT); |
2797 | tree_instance_build_gvariant (tree, builder: &builder, TRUE); |
2798 | built = g_variant_builder_end (builder: &builder); |
2799 | g_variant_ref_sink (value: built); |
2800 | g_variant_get_data (value: built); |
2801 | val = g_variant_get_variant (value: built); |
2802 | |
2803 | s3 = g_variant_print (value: val, TRUE); |
2804 | g_assert_cmpstr (s1, ==, s3); |
2805 | |
2806 | g_variant_iter_init (iter: &iter, value: built); |
2807 | g_assert_true (tree_instance_check_iter (tree, &iter)); |
2808 | g_assert_null (g_variant_iter_next_value (&iter)); |
2809 | |
2810 | g_variant_unref (value: built); |
2811 | g_variant_unref (value: val); |
2812 | g_free (mem: s3); |
2813 | } |
2814 | |
2815 | tree_instance_free (instance: tree); |
2816 | g_variant_unref (value); |
2817 | g_free (mem: s2); |
2818 | g_free (mem: s1); |
2819 | } |
2820 | |
2821 | static void |
2822 | test_string (void) |
2823 | { |
2824 | /* Test some different methods of creating strings */ |
2825 | GVariant *v; |
2826 | |
2827 | v = g_variant_new_string (string: "foo" ); |
2828 | g_assert_cmpstr (g_variant_get_string (v, NULL), ==, "foo" ); |
2829 | g_variant_unref (value: v); |
2830 | |
2831 | |
2832 | v = g_variant_new_take_string (string: g_strdup (str: "foo" )); |
2833 | g_assert_cmpstr (g_variant_get_string (v, NULL), ==, "foo" ); |
2834 | g_variant_unref (value: v); |
2835 | |
2836 | v = g_variant_new_printf (format_string: "%s %d" , "foo" , 123); |
2837 | g_assert_cmpstr (g_variant_get_string (v, NULL), ==, "foo 123" ); |
2838 | g_variant_unref (value: v); |
2839 | } |
2840 | |
2841 | static void |
2842 | test_utf8 (void) |
2843 | { |
2844 | const gchar invalid[] = "hello\xffworld" ; |
2845 | GVariant *value; |
2846 | |
2847 | /* ensure that the test data is not valid utf8... */ |
2848 | g_assert_false (g_utf8_validate (invalid, -1, NULL)); |
2849 | |
2850 | /* load the data untrusted */ |
2851 | value = g_variant_new_from_data (G_VARIANT_TYPE_STRING, |
2852 | data: invalid, size: sizeof invalid, |
2853 | FALSE, NULL, NULL); |
2854 | |
2855 | /* ensure that the problem is caught and we get valid UTF-8 */ |
2856 | g_assert_true (g_utf8_validate (g_variant_get_string (value, NULL), -1, NULL)); |
2857 | g_variant_unref (value); |
2858 | |
2859 | |
2860 | /* now load it trusted */ |
2861 | value = g_variant_new_from_data (G_VARIANT_TYPE_STRING, |
2862 | data: invalid, size: sizeof invalid, |
2863 | TRUE, NULL, NULL); |
2864 | |
2865 | /* ensure we get the invalid data (ie: make sure that time wasn't |
2866 | * wasted on validating data that was marked as trusted) |
2867 | */ |
2868 | g_assert_true (g_variant_get_string (value, NULL) == invalid); |
2869 | g_variant_unref (value); |
2870 | } |
2871 | |
2872 | static void |
2873 | test_containers (void) |
2874 | { |
2875 | gsize i; |
2876 | |
2877 | for (i = 0; i < 100; i++) |
2878 | { |
2879 | test_container (); |
2880 | } |
2881 | |
2882 | g_variant_type_info_assert_no_infos (); |
2883 | } |
2884 | |
2885 | static void |
2886 | test_format_strings (void) |
2887 | { |
2888 | GVariantType *type; |
2889 | const gchar *end; |
2890 | |
2891 | g_assert_true (g_variant_format_string_scan ("i" , NULL, &end) && *end == '\0'); |
2892 | g_assert_true (g_variant_format_string_scan ("@i" , NULL, &end) && *end == '\0'); |
2893 | g_assert_true (g_variant_format_string_scan ("@ii" , NULL, &end) && *end == 'i'); |
2894 | g_assert_true (g_variant_format_string_scan ("^a&s" , NULL, &end) && *end == '\0'); |
2895 | g_assert_true (g_variant_format_string_scan ("(^as)" , NULL, &end) && |
2896 | *end == '\0'); |
2897 | g_assert_false (g_variant_format_string_scan ("(^s)" , NULL, &end)); |
2898 | g_assert_false (g_variant_format_string_scan ("(^a)" , NULL, &end)); |
2899 | g_assert_false (g_variant_format_string_scan ("(z)" , NULL, &end)); |
2900 | g_assert_false (g_variant_format_string_scan ("az" , NULL, &end)); |
2901 | g_assert_false (g_variant_format_string_scan ("{**}" , NULL, &end)); |
2902 | g_assert_false (g_variant_format_string_scan ("{@**}" , NULL, &end)); |
2903 | g_assert_true (g_variant_format_string_scan ("{@y*}" , NULL, &end) && |
2904 | *end == '\0'); |
2905 | g_assert_true (g_variant_format_string_scan ("{yv}" , NULL, &end) && |
2906 | *end == '\0'); |
2907 | g_assert_false (g_variant_format_string_scan ("{&?v}" , NULL, &end)); |
2908 | g_assert_true (g_variant_format_string_scan ("{@?v}" , NULL, &end) && |
2909 | *end == '\0'); |
2910 | g_assert_false (g_variant_format_string_scan ("{&@sv}" , NULL, &end)); |
2911 | g_assert_false (g_variant_format_string_scan ("{@&sv}" , NULL, &end)); |
2912 | g_assert_true (g_variant_format_string_scan ("{&sv}" , NULL, &end) && |
2913 | *end == '\0'); |
2914 | g_assert_false (g_variant_format_string_scan ("{vv}" , NULL, &end)); |
2915 | g_assert_false (g_variant_format_string_scan ("{y}" , NULL, &end)); |
2916 | g_assert_false (g_variant_format_string_scan ("{yyy}" , NULL, &end)); |
2917 | g_assert_false (g_variant_format_string_scan ("{ya}" , NULL, &end)); |
2918 | g_assert_true (g_variant_format_string_scan ("&s" , NULL, &end) && *end == '\0'); |
2919 | g_assert_false (g_variant_format_string_scan ("&as" , NULL, &end)); |
2920 | g_assert_false (g_variant_format_string_scan ("@z" , NULL, &end)); |
2921 | g_assert_false (g_variant_format_string_scan ("az" , NULL, &end)); |
2922 | g_assert_false (g_variant_format_string_scan ("a&s" , NULL, &end)); |
2923 | |
2924 | type = g_variant_format_string_scan_type (string: "mm(@xy^a&s*?@?)" , NULL, endptr: &end); |
2925 | g_assert_true (type && *end == '\0'); |
2926 | g_assert_true (g_variant_type_equal (type, G_VARIANT_TYPE ("mm(xyas*?\?)" ))); |
2927 | g_variant_type_free (type); |
2928 | |
2929 | type = g_variant_format_string_scan_type (string: "mm(@xy^a&*?@?)" , NULL, NULL); |
2930 | g_assert_null (type); |
2931 | } |
2932 | |
2933 | static void |
2934 | do_failed_test (const char *test, |
2935 | const gchar *pattern) |
2936 | { |
2937 | g_test_trap_subprocess (test_path: test, usec_timeout: 1000000, test_flags: 0); |
2938 | g_test_trap_assert_failed (); |
2939 | g_test_trap_assert_stderr (pattern); |
2940 | } |
2941 | |
2942 | static void |
2943 | test_invalid_varargs (void) |
2944 | { |
2945 | GVariant *value; |
2946 | const gchar *end; |
2947 | |
2948 | if (!g_test_undefined ()) |
2949 | return; |
2950 | |
2951 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL, |
2952 | pattern: "*GVariant format string*" ); |
2953 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL, |
2954 | pattern: "*valid_format_string*" ); |
2955 | value = g_variant_new (format_string: "z" ); |
2956 | g_test_assert_expected_messages (); |
2957 | g_assert_null (value); |
2958 | |
2959 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL, |
2960 | pattern: "*valid GVariant format string as a prefix*" ); |
2961 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL, |
2962 | pattern: "*valid_format_string*" ); |
2963 | value = g_variant_new_va (format_string: "z" , endptr: &end, NULL); |
2964 | g_test_assert_expected_messages (); |
2965 | g_assert_null (value); |
2966 | |
2967 | value = g_variant_new (format_string: "y" , 'a'); |
2968 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL, |
2969 | pattern: "*type of 'q' but * has a type of 'y'*" ); |
2970 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL, |
2971 | pattern: "*valid_format_string*" ); |
2972 | g_variant_get (value, format_string: "q" ); |
2973 | g_test_assert_expected_messages (); |
2974 | g_variant_unref (value); |
2975 | } |
2976 | |
2977 | static void |
2978 | check_and_free (GVariant *value, |
2979 | const gchar *str) |
2980 | { |
2981 | gchar *valstr = g_variant_print (value, FALSE); |
2982 | g_assert_cmpstr (str, ==, valstr); |
2983 | g_variant_unref (value); |
2984 | g_free (mem: valstr); |
2985 | } |
2986 | |
2987 | static void |
2988 | test_varargs_empty_array (void) |
2989 | { |
2990 | g_variant_new (format_string: "(a{s*})" , NULL); |
2991 | |
2992 | g_assert_not_reached (); |
2993 | } |
2994 | |
2995 | static void |
2996 | test_varargs (void) |
2997 | { |
2998 | { |
2999 | GVariantBuilder array; |
3000 | |
3001 | g_variant_builder_init (builder: &array, G_VARIANT_TYPE_ARRAY); |
3002 | g_variant_builder_add_parsed (builder: &array, format: "{'size', <(%i, %i)> }" , 800, 600); |
3003 | g_variant_builder_add (builder: &array, format_string: "{sv}" , "title" , |
3004 | g_variant_new_string (string: "Test case" )); |
3005 | g_variant_builder_add_value (builder: &array, |
3006 | value: g_variant_new_dict_entry (key: g_variant_new_string (string: "temperature" ), |
3007 | value: g_variant_new_variant ( |
3008 | value: g_variant_new_double (value: 37.5)))); |
3009 | check_and_free (value: g_variant_new (format_string: "(ma{sv}m(a{sv})ma{sv}ii)" , |
3010 | NULL, FALSE, NULL, &array, 7777, 8888), |
3011 | str: "(nothing, nothing, {'size': <(800, 600)>, " |
3012 | "'title': <'Test case'>, " |
3013 | "'temperature': <37.5>}, " |
3014 | "7777, 8888)" ); |
3015 | |
3016 | check_and_free (value: g_variant_new (format_string: "(imimimmimmimmi)" , |
3017 | 123, |
3018 | FALSE, 321, |
3019 | TRUE, 123, |
3020 | FALSE, TRUE, 321, |
3021 | TRUE, FALSE, 321, |
3022 | TRUE, TRUE, 123), |
3023 | str: "(123, nothing, 123, nothing, just nothing, 123)" ); |
3024 | |
3025 | check_and_free (value: g_variant_new (format_string: "(ybnixd)" , |
3026 | 'a', 1, 22, 33, (guint64) 44, 5.5), |
3027 | str: "(0x61, true, 22, 33, 44, 5.5)" ); |
3028 | |
3029 | check_and_free (value: g_variant_new (format_string: "(@y?*rv)" , |
3030 | g_variant_new (format_string: "y" , 'a'), |
3031 | g_variant_new (format_string: "y" , 'b'), |
3032 | g_variant_new (format_string: "y" , 'c'), |
3033 | g_variant_new (format_string: "(y)" , 'd'), |
3034 | g_variant_new (format_string: "y" , 'e')), |
3035 | str: "(0x61, 0x62, 0x63, (0x64,), <byte 0x65>)" ); |
3036 | } |
3037 | |
3038 | { |
3039 | GVariantBuilder array; |
3040 | GVariantIter iter; |
3041 | GVariant *value; |
3042 | gchar *number; |
3043 | gboolean just; |
3044 | guint i; |
3045 | gint val; |
3046 | |
3047 | g_variant_builder_init (builder: &array, G_VARIANT_TYPE_ARRAY); |
3048 | for (i = 0; i < 100; i++) |
3049 | { |
3050 | number = g_strdup_printf (format: "%u" , i); |
3051 | g_variant_builder_add (builder: &array, format_string: "s" , number); |
3052 | g_free (mem: number); |
3053 | } |
3054 | |
3055 | value = g_variant_builder_end (builder: &array); |
3056 | g_variant_iter_init (iter: &iter, value); |
3057 | |
3058 | i = 0; |
3059 | while (g_variant_iter_loop (iter: &iter, format_string: "s" , &number)) |
3060 | { |
3061 | gchar *check = g_strdup_printf (format: "%u" , i++); |
3062 | g_assert_cmpstr (number, ==, check); |
3063 | g_free (mem: check); |
3064 | } |
3065 | g_assert_null (number); |
3066 | g_assert_cmpuint (i, ==, 100); |
3067 | |
3068 | g_variant_unref (value); |
3069 | |
3070 | g_variant_builder_init (builder: &array, G_VARIANT_TYPE_ARRAY); |
3071 | for (i = 0; i < 100; i++) |
3072 | g_variant_builder_add (builder: &array, format_string: "mi" , i % 2 == 0, i); |
3073 | value = g_variant_builder_end (builder: &array); |
3074 | |
3075 | i = 0; |
3076 | g_variant_iter_init (iter: &iter, value); |
3077 | while (g_variant_iter_loop (iter: &iter, format_string: "mi" , NULL, &val)) |
3078 | g_assert_true (val == (gint) i++ || val == 0); |
3079 | g_assert_cmpuint (i, ==, 100); |
3080 | |
3081 | i = 0; |
3082 | g_variant_iter_init (iter: &iter, value); |
3083 | while (g_variant_iter_loop (iter: &iter, format_string: "mi" , &just, &val)) |
3084 | { |
3085 | gint this = i++; |
3086 | |
3087 | if (this % 2 == 0) |
3088 | { |
3089 | g_assert_true (just); |
3090 | g_assert_cmpint (val, ==, this); |
3091 | } |
3092 | else |
3093 | { |
3094 | g_assert_false (just); |
3095 | g_assert_cmpint (val, ==, 0); |
3096 | } |
3097 | } |
3098 | g_assert_cmpuint (i, ==, 100); |
3099 | |
3100 | g_variant_unref (value); |
3101 | } |
3102 | |
3103 | { |
3104 | const gchar *strvector[] = {"/hello" , "/world" , NULL}; |
3105 | const gchar *test_strs[] = {"/foo" , "/bar" , "/baz" }; |
3106 | GVariantBuilder builder; |
3107 | GVariantIter *array; |
3108 | GVariantIter tuple; |
3109 | const gchar **strv; |
3110 | gchar **my_strv; |
3111 | GVariant *value; |
3112 | gchar *str; |
3113 | gsize i; |
3114 | |
3115 | g_variant_builder_init (builder: &builder, G_VARIANT_TYPE ("as" )); |
3116 | g_variant_builder_add (builder: &builder, format_string: "s" , test_strs[0]); |
3117 | g_variant_builder_add (builder: &builder, format_string: "s" , test_strs[1]); |
3118 | g_variant_builder_add (builder: &builder, format_string: "s" , test_strs[2]); |
3119 | value = g_variant_new (format_string: "(as^as^a&s)" , &builder, strvector, strvector); |
3120 | g_variant_iter_init (iter: &tuple, value); |
3121 | g_variant_iter_next (iter: &tuple, format_string: "as" , &array); |
3122 | |
3123 | i = 0; |
3124 | while (g_variant_iter_loop (iter: array, format_string: "s" , &str)) |
3125 | g_assert_cmpstr (str, ==, test_strs[i++]); |
3126 | g_assert_cmpuint (i, ==, 3); |
3127 | |
3128 | g_variant_iter_free (iter: array); |
3129 | |
3130 | /* start over */ |
3131 | g_variant_iter_init (iter: &tuple, value); |
3132 | g_variant_iter_next (iter: &tuple, format_string: "as" , &array); |
3133 | |
3134 | i = 0; |
3135 | while (g_variant_iter_loop (iter: array, format_string: "&s" , &str)) |
3136 | g_assert_cmpstr (str, ==, test_strs[i++]); |
3137 | g_assert_cmpuint (i, ==, 3); |
3138 | |
3139 | g_variant_iter_free (iter: array); |
3140 | |
3141 | g_variant_iter_next (iter: &tuple, format_string: "^a&s" , &strv); |
3142 | g_variant_iter_next (iter: &tuple, format_string: "^as" , &my_strv); |
3143 | |
3144 | g_assert_cmpstrv (strv, strvector); |
3145 | g_assert_cmpstrv (my_strv, strvector); |
3146 | |
3147 | g_variant_unref (value); |
3148 | g_strfreev (str_array: my_strv); |
3149 | g_free (mem: strv); |
3150 | } |
3151 | |
3152 | { |
3153 | const gchar *strvector[] = {"/hello" , "/world" , NULL}; |
3154 | const gchar *test_strs[] = {"/foo" , "/bar" , "/baz" }; |
3155 | GVariantBuilder builder; |
3156 | GVariantIter *array; |
3157 | GVariantIter tuple; |
3158 | const gchar **strv; |
3159 | gchar **my_strv; |
3160 | GVariant *value; |
3161 | gchar *str; |
3162 | gsize i; |
3163 | |
3164 | g_variant_builder_init (builder: &builder, G_VARIANT_TYPE ("aaay" )); |
3165 | g_variant_builder_add (builder: &builder, format_string: "^aay" , strvector); |
3166 | g_variant_builder_add (builder: &builder, format_string: "^aay" , strvector); |
3167 | g_variant_builder_add (builder: &builder, format_string: "^aay" , strvector); |
3168 | value = g_variant_new (format_string: "aaay" , &builder); |
3169 | array = g_variant_iter_new (value); |
3170 | i = 0; |
3171 | while (g_variant_iter_loop (iter: array, format_string: "^aay" , &my_strv)) |
3172 | i++; |
3173 | g_assert_cmpuint (i, ==, 3); |
3174 | |
3175 | /* start over */ |
3176 | g_variant_iter_init (iter: array, value); |
3177 | i = 0; |
3178 | while (g_variant_iter_loop (iter: array, format_string: "^a&ay" , &strv)) |
3179 | i++; |
3180 | g_assert_cmpuint (i, ==, 3); |
3181 | g_variant_unref (value); |
3182 | g_variant_iter_free (iter: array); |
3183 | |
3184 | /* next test */ |
3185 | g_variant_builder_init (builder: &builder, G_VARIANT_TYPE ("aay" )); |
3186 | g_variant_builder_add (builder: &builder, format_string: "^ay" , test_strs[0]); |
3187 | g_variant_builder_add (builder: &builder, format_string: "^ay" , test_strs[1]); |
3188 | g_variant_builder_add (builder: &builder, format_string: "^ay" , test_strs[2]); |
3189 | value = g_variant_new (format_string: "(aay^aay^a&ay)" , &builder, strvector, strvector); |
3190 | g_variant_iter_init (iter: &tuple, value); |
3191 | g_variant_iter_next (iter: &tuple, format_string: "aay" , &array); |
3192 | |
3193 | i = 0; |
3194 | while (g_variant_iter_loop (iter: array, format_string: "^ay" , &str)) |
3195 | g_assert_cmpstr (str, ==, test_strs[i++]); |
3196 | g_assert_cmpuint (i, ==, 3); |
3197 | |
3198 | g_variant_iter_free (iter: array); |
3199 | |
3200 | /* start over */ |
3201 | g_variant_iter_init (iter: &tuple, value); |
3202 | g_variant_iter_next (iter: &tuple, format_string: "aay" , &array); |
3203 | |
3204 | i = 0; |
3205 | while (g_variant_iter_loop (iter: array, format_string: "^&ay" , &str)) |
3206 | g_assert_cmpstr (str, ==, test_strs[i++]); |
3207 | g_assert_cmpuint (i, ==, 3); |
3208 | |
3209 | g_variant_iter_free (iter: array); |
3210 | |
3211 | g_variant_iter_next (iter: &tuple, format_string: "^a&ay" , &strv); |
3212 | g_variant_iter_next (iter: &tuple, format_string: "^aay" , &my_strv); |
3213 | |
3214 | g_assert_cmpstrv (strv, strvector); |
3215 | g_assert_cmpstrv (my_strv, strvector); |
3216 | |
3217 | g_variant_unref (value); |
3218 | g_strfreev (str_array: my_strv); |
3219 | g_free (mem: strv); |
3220 | } |
3221 | |
3222 | { |
3223 | const gchar *strvector[] = {"/hello" , "/world" , NULL}; |
3224 | const gchar *test_strs[] = {"/foo" , "/bar" , "/baz" }; |
3225 | GVariantBuilder builder; |
3226 | GVariantIter *array; |
3227 | GVariantIter tuple; |
3228 | const gchar **strv; |
3229 | gchar **my_strv; |
3230 | GVariant *value; |
3231 | gchar *str; |
3232 | gsize i; |
3233 | |
3234 | g_variant_builder_init (builder: &builder, G_VARIANT_TYPE_OBJECT_PATH_ARRAY); |
3235 | g_variant_builder_add (builder: &builder, format_string: "o" , test_strs[0]); |
3236 | g_variant_builder_add (builder: &builder, format_string: "o" , test_strs[1]); |
3237 | g_variant_builder_add (builder: &builder, format_string: "o" , test_strs[2]); |
3238 | value = g_variant_new (format_string: "(ao^ao^a&o)" , &builder, strvector, strvector); |
3239 | g_variant_iter_init (iter: &tuple, value); |
3240 | g_variant_iter_next (iter: &tuple, format_string: "ao" , &array); |
3241 | |
3242 | i = 0; |
3243 | while (g_variant_iter_loop (iter: array, format_string: "o" , &str)) |
3244 | g_assert_cmpstr (str, ==, test_strs[i++]); |
3245 | g_assert_cmpuint (i, ==, 3); |
3246 | |
3247 | g_variant_iter_free (iter: array); |
3248 | |
3249 | /* start over */ |
3250 | g_variant_iter_init (iter: &tuple, value); |
3251 | g_variant_iter_next (iter: &tuple, format_string: "ao" , &array); |
3252 | |
3253 | i = 0; |
3254 | while (g_variant_iter_loop (iter: array, format_string: "&o" , &str)) |
3255 | g_assert_cmpstr (str, ==, test_strs[i++]); |
3256 | g_assert_cmpuint (i, ==, 3); |
3257 | |
3258 | g_variant_iter_free (iter: array); |
3259 | |
3260 | g_variant_iter_next (iter: &tuple, format_string: "^a&o" , &strv); |
3261 | g_variant_iter_next (iter: &tuple, format_string: "^ao" , &my_strv); |
3262 | |
3263 | g_assert_cmpstrv (strv, strvector); |
3264 | g_assert_cmpstrv (my_strv, strvector); |
3265 | |
3266 | g_variant_unref (value); |
3267 | g_strfreev (str_array: my_strv); |
3268 | g_free (mem: strv); |
3269 | } |
3270 | |
3271 | { |
3272 | const gchar *strvector[] = { "i" , "ii" , "iii" , "iv" , "v" , "vi" , NULL }; |
3273 | GVariantBuilder builder; |
3274 | GVariantIter iter; |
3275 | GVariantIter *i2; |
3276 | GVariantIter *i3; |
3277 | GVariant *value; |
3278 | GVariant *sub; |
3279 | gchar **strv; |
3280 | gsize i; |
3281 | |
3282 | g_variant_builder_init (builder: &builder, G_VARIANT_TYPE ("aas" )); |
3283 | g_variant_builder_open (builder: &builder, G_VARIANT_TYPE ("as" )); |
3284 | for (i = 0; i < 6; i++) |
3285 | if (i & 1) |
3286 | g_variant_builder_add (builder: &builder, format_string: "s" , strvector[i]); |
3287 | else |
3288 | g_variant_builder_add (builder: &builder, format_string: "&s" , strvector[i]); |
3289 | g_variant_builder_close (builder: &builder); |
3290 | g_variant_builder_add (builder: &builder, format_string: "^as" , strvector); |
3291 | g_variant_builder_add (builder: &builder, format_string: "^as" , strvector); |
3292 | value = g_variant_new (format_string: "aas" , &builder); |
3293 | |
3294 | g_variant_iter_init (iter: &iter, value); |
3295 | while (g_variant_iter_loop (iter: &iter, format_string: "^as" , &strv)) |
3296 | for (i = 0; i < 6; i++) |
3297 | g_assert_cmpstr (strv[i], ==, strvector[i]); |
3298 | |
3299 | g_variant_iter_init (iter: &iter, value); |
3300 | while (g_variant_iter_loop (iter: &iter, format_string: "^a&s" , &strv)) |
3301 | for (i = 0; i < 6; i++) |
3302 | g_assert_cmpstr (strv[i], ==, strvector[i]); |
3303 | |
3304 | g_variant_iter_init (iter: &iter, value); |
3305 | while (g_variant_iter_loop (iter: &iter, format_string: "as" , &i2)) |
3306 | { |
3307 | gchar *str; |
3308 | |
3309 | i = 0; |
3310 | while (g_variant_iter_loop (iter: i2, format_string: "s" , &str)) |
3311 | g_assert_cmpstr (str, ==, strvector[i++]); |
3312 | g_assert_cmpuint (i, ==, 6); |
3313 | } |
3314 | |
3315 | g_variant_iter_init (iter: &iter, value); |
3316 | i3 = g_variant_iter_copy (iter: &iter); |
3317 | while (g_variant_iter_loop (iter: &iter, format_string: "@as" , &sub)) |
3318 | { |
3319 | gchar *str = g_variant_print (value: sub, TRUE); |
3320 | g_assert_cmpstr (str, ==, |
3321 | "['i', 'ii', 'iii', 'iv', 'v', 'vi']" ); |
3322 | g_free (mem: str); |
3323 | } |
3324 | |
3325 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL, |
3326 | pattern: "*NULL has already been returned*" ); |
3327 | g_variant_iter_next_value (iter: &iter); |
3328 | g_test_assert_expected_messages (); |
3329 | |
3330 | while (g_variant_iter_loop (iter: i3, format_string: "*" , &sub)) |
3331 | { |
3332 | gchar *str = g_variant_print (value: sub, TRUE); |
3333 | g_assert_cmpstr (str, ==, |
3334 | "['i', 'ii', 'iii', 'iv', 'v', 'vi']" ); |
3335 | g_free (mem: str); |
3336 | } |
3337 | |
3338 | g_variant_iter_free (iter: i3); |
3339 | |
3340 | for (i = 0; i < g_variant_n_children (value); i++) |
3341 | { |
3342 | gsize j; |
3343 | |
3344 | g_variant_get_child (value, index_: i, format_string: "*" , &sub); |
3345 | |
3346 | for (j = 0; j < g_variant_n_children (value: sub); j++) |
3347 | { |
3348 | const gchar *str = NULL; |
3349 | GVariant *cval; |
3350 | |
3351 | g_variant_get_child (value: sub, index_: j, format_string: "&s" , &str); |
3352 | g_assert_cmpstr (str, ==, strvector[j]); |
3353 | |
3354 | cval = g_variant_get_child_value (value: sub, index_: j); |
3355 | g_variant_get (value: cval, format_string: "&s" , &str); |
3356 | g_assert_cmpstr (str, ==, strvector[j]); |
3357 | g_variant_unref (value: cval); |
3358 | } |
3359 | |
3360 | g_variant_unref (value: sub); |
3361 | } |
3362 | |
3363 | g_variant_unref (value); |
3364 | } |
3365 | |
3366 | { |
3367 | gboolean justs[10]; |
3368 | GVariant *value; |
3369 | |
3370 | GVariant *vval; |
3371 | guchar byteval; |
3372 | gboolean bval; |
3373 | gint16 i16val; |
3374 | guint16 u16val; |
3375 | gint32 i32val; |
3376 | guint32 u32val; |
3377 | gint64 i64val; |
3378 | guint64 u64val; |
3379 | gdouble dval; |
3380 | gint32 hval; |
3381 | |
3382 | /* test all 'nothing' */ |
3383 | value = g_variant_new (format_string: "(mymbmnmqmimumxmtmhmdmv)" , |
3384 | FALSE, 'a', |
3385 | FALSE, TRUE, |
3386 | FALSE, (gint16) 123, |
3387 | FALSE, (guint16) 123, |
3388 | FALSE, (gint32) 123, |
3389 | FALSE, (guint32) 123, |
3390 | FALSE, (gint64) 123, |
3391 | FALSE, (guint64) 123, |
3392 | FALSE, (gint32) -1, |
3393 | FALSE, (gdouble) 37.5, |
3394 | NULL); |
3395 | |
3396 | /* both NULL */ |
3397 | g_variant_get (value, format_string: "(mymbmnmqmimumxmtmhmdmv)" , |
3398 | NULL, NULL, |
3399 | NULL, NULL, |
3400 | NULL, NULL, |
3401 | NULL, NULL, |
3402 | NULL, NULL, |
3403 | NULL, NULL, |
3404 | NULL, NULL, |
3405 | NULL, NULL, |
3406 | NULL, NULL, |
3407 | NULL, NULL, |
3408 | NULL); |
3409 | |
3410 | /* NULL values */ |
3411 | memset (s: justs, c: 1, n: sizeof justs); |
3412 | g_variant_get (value, format_string: "(mymbmnmqmimumxmtmhmdmv)" , |
3413 | &justs[0], NULL, |
3414 | &justs[1], NULL, |
3415 | &justs[2], NULL, |
3416 | &justs[3], NULL, |
3417 | &justs[4], NULL, |
3418 | &justs[5], NULL, |
3419 | &justs[6], NULL, |
3420 | &justs[7], NULL, |
3421 | &justs[8], NULL, |
3422 | &justs[9], NULL, |
3423 | NULL); |
3424 | g_assert_true (!(justs[0] || justs[1] || justs[2] || justs[3] || justs[4] || |
3425 | justs[5] || justs[6] || justs[7] || justs[8] || justs[9])); |
3426 | |
3427 | /* both non-NULL */ |
3428 | memset (s: justs, c: 1, n: sizeof justs); |
3429 | byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88; |
3430 | vval = (void *) 1; |
3431 | bval = TRUE; |
3432 | dval = 88.88; |
3433 | g_variant_get (value, format_string: "(mymbmnmqmimumxmtmhmdmv)" , |
3434 | &justs[0], &byteval, |
3435 | &justs[1], &bval, |
3436 | &justs[2], &i16val, |
3437 | &justs[3], &u16val, |
3438 | &justs[4], &i32val, |
3439 | &justs[5], &u32val, |
3440 | &justs[6], &i64val, |
3441 | &justs[7], &u64val, |
3442 | &justs[8], &hval, |
3443 | &justs[9], &dval, |
3444 | &vval); |
3445 | g_assert_true (!(justs[0] || justs[1] || justs[2] || justs[3] || justs[4] || |
3446 | justs[5] || justs[6] || justs[7] || justs[8] || justs[9])); |
3447 | g_assert_true (byteval == '\0' && bval == FALSE); |
3448 | g_assert_true (i16val == 0 && u16val == 0 && i32val == 0 && |
3449 | u32val == 0 && i64val == 0 && u64val == 0 && |
3450 | hval == 0 && dval == 0.0); |
3451 | g_assert_null (vval); |
3452 | |
3453 | /* NULL justs */ |
3454 | byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88; |
3455 | vval = (void *) 1; |
3456 | bval = TRUE; |
3457 | dval = 88.88; |
3458 | g_variant_get (value, format_string: "(mymbmnmqmimumxmtmhmdmv)" , |
3459 | NULL, &byteval, |
3460 | NULL, &bval, |
3461 | NULL, &i16val, |
3462 | NULL, &u16val, |
3463 | NULL, &i32val, |
3464 | NULL, &u32val, |
3465 | NULL, &i64val, |
3466 | NULL, &u64val, |
3467 | NULL, &hval, |
3468 | NULL, &dval, |
3469 | &vval); |
3470 | g_assert_true (byteval == '\0' && bval == FALSE); |
3471 | g_assert_true (i16val == 0 && u16val == 0 && i32val == 0 && |
3472 | u32val == 0 && i64val == 0 && u64val == 0 && |
3473 | hval == 0 && dval == 0.0); |
3474 | g_assert_null (vval); |
3475 | |
3476 | g_variant_unref (value); |
3477 | |
3478 | |
3479 | /* test all 'just' */ |
3480 | value = g_variant_new (format_string: "(mymbmnmqmimumxmtmhmdmv)" , |
3481 | TRUE, 'a', |
3482 | TRUE, TRUE, |
3483 | TRUE, (gint16) 123, |
3484 | TRUE, (guint16) 123, |
3485 | TRUE, (gint32) 123, |
3486 | TRUE, (guint32) 123, |
3487 | TRUE, (gint64) 123, |
3488 | TRUE, (guint64) 123, |
3489 | TRUE, (gint32) -1, |
3490 | TRUE, (gdouble) 37.5, |
3491 | g_variant_new (format_string: "()" )); |
3492 | |
3493 | /* both NULL */ |
3494 | g_variant_get (value, format_string: "(mymbmnmqmimumxmtmhmdmv)" , |
3495 | NULL, NULL, |
3496 | NULL, NULL, |
3497 | NULL, NULL, |
3498 | NULL, NULL, |
3499 | NULL, NULL, |
3500 | NULL, NULL, |
3501 | NULL, NULL, |
3502 | NULL, NULL, |
3503 | NULL, NULL, |
3504 | NULL, NULL, |
3505 | NULL); |
3506 | |
3507 | /* NULL values */ |
3508 | memset (s: justs, c: 0, n: sizeof justs); |
3509 | g_variant_get (value, format_string: "(mymbmnmqmimumxmtmhmdmv)" , |
3510 | &justs[0], NULL, |
3511 | &justs[1], NULL, |
3512 | &justs[2], NULL, |
3513 | &justs[3], NULL, |
3514 | &justs[4], NULL, |
3515 | &justs[5], NULL, |
3516 | &justs[6], NULL, |
3517 | &justs[7], NULL, |
3518 | &justs[8], NULL, |
3519 | &justs[9], NULL, |
3520 | NULL); |
3521 | g_assert_true (justs[0] && justs[1] && justs[2] && justs[3] && justs[4] && |
3522 | justs[5] && justs[6] && justs[7] && justs[8] && justs[9]); |
3523 | |
3524 | /* both non-NULL */ |
3525 | memset (s: justs, c: 0, n: sizeof justs); |
3526 | byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88; |
3527 | vval = (void *) 1; |
3528 | bval = FALSE; |
3529 | dval = 88.88; |
3530 | g_variant_get (value, format_string: "(mymbmnmqmimumxmtmhmdmv)" , |
3531 | &justs[0], &byteval, |
3532 | &justs[1], &bval, |
3533 | &justs[2], &i16val, |
3534 | &justs[3], &u16val, |
3535 | &justs[4], &i32val, |
3536 | &justs[5], &u32val, |
3537 | &justs[6], &i64val, |
3538 | &justs[7], &u64val, |
3539 | &justs[8], &hval, |
3540 | &justs[9], &dval, |
3541 | &vval); |
3542 | g_assert_true (justs[0] && justs[1] && justs[2] && justs[3] && justs[4] && |
3543 | justs[5] && justs[6] && justs[7] && justs[8] && justs[9]); |
3544 | g_assert_true (byteval == 'a' && bval == TRUE); |
3545 | g_assert_true (i16val == 123 && u16val == 123 && i32val == 123 && |
3546 | u32val == 123 && i64val == 123 && u64val == 123 && |
3547 | hval == -1 && dval == 37.5); |
3548 | g_assert_true (g_variant_is_of_type (vval, G_VARIANT_TYPE_UNIT)); |
3549 | g_variant_unref (value: vval); |
3550 | |
3551 | /* NULL justs */ |
3552 | byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88; |
3553 | vval = (void *) 1; |
3554 | bval = TRUE; |
3555 | dval = 88.88; |
3556 | g_variant_get (value, format_string: "(mymbmnmqmimumxmtmhmdmv)" , |
3557 | NULL, &byteval, |
3558 | NULL, &bval, |
3559 | NULL, &i16val, |
3560 | NULL, &u16val, |
3561 | NULL, &i32val, |
3562 | NULL, &u32val, |
3563 | NULL, &i64val, |
3564 | NULL, &u64val, |
3565 | NULL, &hval, |
3566 | NULL, &dval, |
3567 | &vval); |
3568 | g_assert_true (byteval == 'a' && bval == TRUE); |
3569 | g_assert_true (i16val == 123 && u16val == 123 && i32val == 123 && |
3570 | u32val == 123 && i64val == 123 && u64val == 123 && |
3571 | hval == -1 && dval == 37.5); |
3572 | g_assert_true (g_variant_is_of_type (vval, G_VARIANT_TYPE_UNIT)); |
3573 | g_variant_unref (value: vval); |
3574 | |
3575 | g_variant_unref (value); |
3576 | } |
3577 | |
3578 | { |
3579 | GVariant *value; |
3580 | gchar *str; |
3581 | |
3582 | value = g_variant_new (format_string: "(masas)" , NULL, NULL); |
3583 | g_variant_ref_sink (value); |
3584 | |
3585 | str = g_variant_print (value, TRUE); |
3586 | g_assert_cmpstr (str, ==, "(@mas nothing, @as [])" ); |
3587 | g_variant_unref (value); |
3588 | g_free (mem: str); |
3589 | |
3590 | do_failed_test (test: "/gvariant/varargs/subprocess/empty-array" , |
3591 | pattern: "*which type of empty array*" ); |
3592 | } |
3593 | |
3594 | g_variant_type_info_assert_no_infos (); |
3595 | } |
3596 | |
3597 | static void |
3598 | hash_get (GVariant *value, |
3599 | const gchar *format, |
3600 | ...) |
3601 | { |
3602 | const gchar *endptr = NULL; |
3603 | gboolean hash; |
3604 | va_list ap; |
3605 | |
3606 | hash = g_str_has_suffix (str: format, suffix: "#" ); |
3607 | |
3608 | va_start (ap, format); |
3609 | g_variant_get_va (value, format_string: format, endptr: hash ? &endptr : NULL, app: &ap); |
3610 | va_end (ap); |
3611 | |
3612 | if (hash) |
3613 | g_assert_cmpint (*endptr, ==, '#'); |
3614 | } |
3615 | |
3616 | static GVariant * |
3617 | hash_new (const gchar *format, |
3618 | ...) |
3619 | { |
3620 | const gchar *endptr = NULL; |
3621 | GVariant *value; |
3622 | gboolean hash; |
3623 | va_list ap; |
3624 | |
3625 | hash = g_str_has_suffix (str: format, suffix: "#" ); |
3626 | |
3627 | va_start (ap, format); |
3628 | value = g_variant_new_va (format_string: format, endptr: hash ? &endptr : NULL, app: &ap); |
3629 | va_end (ap); |
3630 | |
3631 | if (hash) |
3632 | g_assert_cmpint (*endptr, ==, '#'); |
3633 | |
3634 | return value; |
3635 | } |
3636 | |
3637 | static void |
3638 | test_valist (void) |
3639 | { |
3640 | GVariant *value; |
3641 | gint32 x; |
3642 | |
3643 | x = 0; |
3644 | value = hash_new (format: "i" , 234); |
3645 | hash_get (value, format: "i" , &x); |
3646 | g_assert_cmpint (x, ==, 234); |
3647 | g_variant_unref (value); |
3648 | |
3649 | x = 0; |
3650 | value = hash_new (format: "i#" , 234); |
3651 | hash_get (value, format: "i#" , &x); |
3652 | g_assert_cmpint (x, ==, 234); |
3653 | g_variant_unref (value); |
3654 | |
3655 | g_variant_type_info_assert_no_infos (); |
3656 | } |
3657 | |
3658 | static void |
3659 | test_builder_memory (void) |
3660 | { |
3661 | GVariantBuilder *hb; |
3662 | GVariantBuilder sb; |
3663 | |
3664 | hb = g_variant_builder_new (G_VARIANT_TYPE_ARRAY); |
3665 | g_variant_builder_open (builder: hb, G_VARIANT_TYPE_ARRAY); |
3666 | g_variant_builder_open (builder: hb, G_VARIANT_TYPE_ARRAY); |
3667 | g_variant_builder_open (builder: hb, G_VARIANT_TYPE_ARRAY); |
3668 | g_variant_builder_add (builder: hb, format_string: "s" , "some value" ); |
3669 | g_variant_builder_ref (builder: hb); |
3670 | g_variant_builder_unref (builder: hb); |
3671 | g_variant_builder_unref (builder: hb); |
3672 | |
3673 | hb = g_variant_builder_new (G_VARIANT_TYPE_ARRAY); |
3674 | g_variant_builder_unref (builder: hb); |
3675 | |
3676 | hb = g_variant_builder_new (G_VARIANT_TYPE_ARRAY); |
3677 | g_variant_builder_clear (builder: hb); |
3678 | g_variant_builder_unref (builder: hb); |
3679 | |
3680 | g_variant_builder_init (builder: &sb, G_VARIANT_TYPE_ARRAY); |
3681 | g_variant_builder_open (builder: &sb, G_VARIANT_TYPE_ARRAY); |
3682 | g_variant_builder_open (builder: &sb, G_VARIANT_TYPE_ARRAY); |
3683 | g_variant_builder_add (builder: &sb, format_string: "s" , "some value" ); |
3684 | g_variant_builder_clear (builder: &sb); |
3685 | |
3686 | g_variant_type_info_assert_no_infos (); |
3687 | } |
3688 | |
3689 | static void |
3690 | test_hashing (void) |
3691 | { |
3692 | GVariant *items[4096]; |
3693 | GHashTable *table; |
3694 | gsize i; |
3695 | |
3696 | table = g_hash_table_new_full (hash_func: g_variant_hash, key_equal_func: g_variant_equal, |
3697 | key_destroy_func: (GDestroyNotify ) g_variant_unref, |
3698 | NULL); |
3699 | |
3700 | for (i = 0; i < G_N_ELEMENTS (items); i++) |
3701 | { |
3702 | TreeInstance *tree; |
3703 | gsize j; |
3704 | |
3705 | again: |
3706 | tree = tree_instance_new (NULL, depth: 0); |
3707 | items[i] = tree_instance_get_gvariant (tree); |
3708 | tree_instance_free (instance: tree); |
3709 | |
3710 | for (j = 0; j < i; j++) |
3711 | if (g_variant_equal (one: items[i], two: items[j])) |
3712 | { |
3713 | g_variant_unref (value: items[i]); |
3714 | goto again; |
3715 | } |
3716 | |
3717 | g_hash_table_insert (hash_table: table, |
3718 | key: g_variant_ref_sink (value: items[i]), |
3719 | GINT_TO_POINTER (i)); |
3720 | } |
3721 | |
3722 | for (i = 0; i < G_N_ELEMENTS (items); i++) |
3723 | { |
3724 | gpointer result; |
3725 | |
3726 | result = g_hash_table_lookup (hash_table: table, key: items[i]); |
3727 | g_assert_cmpint (GPOINTER_TO_INT (result), ==, i); |
3728 | } |
3729 | |
3730 | g_hash_table_unref (hash_table: table); |
3731 | |
3732 | g_variant_type_info_assert_no_infos (); |
3733 | } |
3734 | |
3735 | static void |
3736 | test_gv_byteswap (void) |
3737 | { |
3738 | #if G_BYTE_ORDER == G_LITTLE_ENDIAN |
3739 | # define native16(x) x, 0 |
3740 | # define swapped16(x) 0, x |
3741 | #else |
3742 | # define native16(x) 0, x |
3743 | # define swapped16(x) x, 0 |
3744 | #endif |
3745 | /* all kinds of of crazy randomised testing already performed on the |
3746 | * byteswapper in the /gvariant/serialiser/byteswap test and all kinds |
3747 | * of crazy randomised testing performed against the serialiser |
3748 | * normalisation functions in the /gvariant/serialiser/fuzz/ tests. |
3749 | * |
3750 | * just test a few simple cases here to make sure they each work |
3751 | */ |
3752 | guchar validbytes[] = { 'a', '\0', swapped16(66), 2, |
3753 | 0, |
3754 | 'b', '\0', swapped16(77), 2, |
3755 | 5, 11 }; |
3756 | guchar corruptbytes[] = { 'a', '\0', swapped16(66), 2, |
3757 | 0, |
3758 | 'b', '\0', swapped16(77), 2, |
3759 | 6, 11 }; |
3760 | guint valid_data[4], corrupt_data[4]; |
3761 | GVariant *value, *swapped; |
3762 | gchar *string, *string2; |
3763 | |
3764 | memcpy (dest: valid_data, src: validbytes, n: sizeof validbytes); |
3765 | memcpy (dest: corrupt_data, src: corruptbytes, n: sizeof corruptbytes); |
3766 | |
3767 | /* trusted */ |
3768 | value = g_variant_new_from_data (G_VARIANT_TYPE ("a(sn)" ), |
3769 | data: valid_data, size: sizeof validbytes, TRUE, |
3770 | NULL, NULL); |
3771 | swapped = g_variant_byteswap (value); |
3772 | g_variant_unref (value); |
3773 | g_assert_cmpuint (g_variant_get_size (swapped), ==, 13); |
3774 | string = g_variant_print (value: swapped, FALSE); |
3775 | g_variant_unref (value: swapped); |
3776 | g_assert_cmpstr (string, ==, "[('a', 66), ('b', 77)]" ); |
3777 | g_free (mem: string); |
3778 | |
3779 | /* untrusted but valid */ |
3780 | value = g_variant_new_from_data (G_VARIANT_TYPE ("a(sn)" ), |
3781 | data: valid_data, size: sizeof validbytes, FALSE, |
3782 | NULL, NULL); |
3783 | swapped = g_variant_byteswap (value); |
3784 | g_variant_unref (value); |
3785 | g_assert_cmpuint (g_variant_get_size (swapped), ==, 13); |
3786 | string = g_variant_print (value: swapped, FALSE); |
3787 | g_variant_unref (value: swapped); |
3788 | g_assert_cmpstr (string, ==, "[('a', 66), ('b', 77)]" ); |
3789 | g_free (mem: string); |
3790 | |
3791 | /* untrusted, invalid */ |
3792 | value = g_variant_new_from_data (G_VARIANT_TYPE ("a(sn)" ), |
3793 | data: corrupt_data, size: sizeof corruptbytes, FALSE, |
3794 | NULL, NULL); |
3795 | string = g_variant_print (value, FALSE); |
3796 | swapped = g_variant_byteswap (value); |
3797 | g_variant_unref (value); |
3798 | g_assert_cmpuint (g_variant_get_size (swapped), ==, 13); |
3799 | value = g_variant_byteswap (value: swapped); |
3800 | g_variant_unref (value: swapped); |
3801 | string2 = g_variant_print (value, FALSE); |
3802 | g_assert_cmpuint (g_variant_get_size (value), ==, 13); |
3803 | g_variant_unref (value); |
3804 | g_assert_cmpstr (string, ==, string2); |
3805 | g_free (mem: string2); |
3806 | g_free (mem: string); |
3807 | } |
3808 | |
3809 | static void |
3810 | test_parser (void) |
3811 | { |
3812 | TreeInstance *tree; |
3813 | GVariant *parsed; |
3814 | GVariant *value; |
3815 | gchar *pt, *p; |
3816 | gchar *res; |
3817 | |
3818 | tree = tree_instance_new (NULL, depth: 3); |
3819 | value = tree_instance_get_gvariant (tree); |
3820 | tree_instance_free (instance: tree); |
3821 | |
3822 | pt = g_variant_print (value, TRUE); |
3823 | p = g_variant_print (value, FALSE); |
3824 | |
3825 | parsed = g_variant_parse (NULL, text: pt, NULL, NULL, NULL); |
3826 | res = g_variant_print (value: parsed, FALSE); |
3827 | g_assert_cmpstr (p, ==, res); |
3828 | g_variant_unref (value: parsed); |
3829 | g_free (mem: res); |
3830 | |
3831 | parsed = g_variant_parse (type: g_variant_get_type (value), text: p, |
3832 | NULL, NULL, NULL); |
3833 | res = g_variant_print (value: parsed, TRUE); |
3834 | g_assert_cmpstr (pt, ==, res); |
3835 | g_variant_unref (value: parsed); |
3836 | g_free (mem: res); |
3837 | |
3838 | g_variant_unref (value); |
3839 | g_free (mem: pt); |
3840 | g_free (mem: p); |
3841 | } |
3842 | |
3843 | static void |
3844 | test_parses (void) |
3845 | { |
3846 | gsize i; |
3847 | |
3848 | for (i = 0; i < 100; i++) |
3849 | { |
3850 | test_parser (); |
3851 | } |
3852 | |
3853 | /* mini test */ |
3854 | { |
3855 | GError *error = NULL; |
3856 | gchar str[128]; |
3857 | GVariant *val; |
3858 | gchar *p, *p2; |
3859 | |
3860 | for (i = 0; i < 127; i++) |
3861 | str[i] = i + 1; |
3862 | str[i] = 0; |
3863 | |
3864 | val = g_variant_new_string (string: str); |
3865 | p = g_variant_print (value: val, FALSE); |
3866 | g_variant_unref (value: val); |
3867 | |
3868 | val = g_variant_parse (NULL, text: p, NULL, NULL, error: &error); |
3869 | p2 = g_variant_print (value: val, FALSE); |
3870 | |
3871 | g_assert_cmpstr (str, ==, g_variant_get_string (val, NULL)); |
3872 | g_assert_cmpstr (p, ==, p2); |
3873 | |
3874 | g_variant_unref (value: val); |
3875 | g_free (mem: p2); |
3876 | g_free (mem: p); |
3877 | } |
3878 | |
3879 | /* another mini test */ |
3880 | { |
3881 | const gchar *end; |
3882 | GVariant *value; |
3883 | |
3884 | value = g_variant_parse (G_VARIANT_TYPE_INT32, text: "1 2 3" , NULL, endptr: &end, NULL); |
3885 | g_assert_cmpint (g_variant_get_int32 (value), ==, 1); |
3886 | /* make sure endptr returning works */ |
3887 | g_assert_cmpstr (end, ==, " 2 3" ); |
3888 | g_variant_unref (value); |
3889 | } |
3890 | |
3891 | /* unicode mini test */ |
3892 | { |
3893 | /* ał𝄞 */ |
3894 | const gchar orig[] = "a\xc5\x82\xf0\x9d\x84\x9e \t\n" ; |
3895 | GVariant *value; |
3896 | gchar *printed; |
3897 | |
3898 | value = g_variant_new_string (string: orig); |
3899 | printed = g_variant_print (value, FALSE); |
3900 | g_variant_unref (value); |
3901 | |
3902 | g_assert_cmpstr (printed, ==, "'a\xc5\x82\xf0\x9d\x84\x9e \\t\\n'" ); |
3903 | value = g_variant_parse (NULL, text: printed, NULL, NULL, NULL); |
3904 | g_assert_cmpstr (g_variant_get_string (value, NULL), ==, orig); |
3905 | g_variant_unref (value); |
3906 | g_free (mem: printed); |
3907 | } |
3908 | |
3909 | /* escapes */ |
3910 | { |
3911 | const gchar orig[] = " \342\200\254 \360\220\210\240 \a \b \f \n \r \t \v " ; |
3912 | GVariant *value; |
3913 | gchar *printed; |
3914 | |
3915 | value = g_variant_new_string (string: orig); |
3916 | printed = g_variant_print (value, FALSE); |
3917 | g_variant_unref (value); |
3918 | |
3919 | g_assert_cmpstr (printed, ==, "' \\u202c \\U00010220 \\a \\b \\f \\n \\r \\t \\v '" ); |
3920 | value = g_variant_parse (NULL, text: printed, NULL, NULL, NULL); |
3921 | g_assert_cmpstr (g_variant_get_string (value, NULL), ==, orig); |
3922 | g_variant_unref (value); |
3923 | g_free (mem: printed); |
3924 | } |
3925 | |
3926 | /* pattern coalese of `MN` and `*` is `MN` */ |
3927 | { |
3928 | GVariant *value = NULL; |
3929 | GError *error = NULL; |
3930 | |
3931 | value = g_variant_parse (NULL, text: "[[0], [], [nothing]]" , NULL, NULL, error: &error); |
3932 | g_assert_no_error (error); |
3933 | g_assert_cmpstr (g_variant_get_type_string (value), ==, "aami" ); |
3934 | g_variant_unref (value); |
3935 | } |
3936 | |
3937 | #ifndef _MSC_VER |
3938 | /* inf/nan strings are C99 features which Visual C++ does not support */ |
3939 | /* inf/nan mini test */ |
3940 | { |
3941 | const gchar *tests[] = { "inf" , "-inf" , "nan" }; |
3942 | GVariant *value; |
3943 | gchar *printed; |
3944 | gchar *printed_down; |
3945 | gsize i; |
3946 | |
3947 | for (i = 0; i < G_N_ELEMENTS (tests); i++) |
3948 | { |
3949 | GError *error = NULL; |
3950 | value = g_variant_parse (NULL, text: tests[i], NULL, NULL, error: &error); |
3951 | printed = g_variant_print (value, FALSE); |
3952 | /* Canonicalize to lowercase; https://bugzilla.gnome.org/show_bug.cgi?id=704585 */ |
3953 | printed_down = g_ascii_strdown (str: printed, len: -1); |
3954 | g_assert_true (g_str_has_prefix (printed_down, tests[i])); |
3955 | g_free (mem: printed); |
3956 | g_free (mem: printed_down); |
3957 | g_variant_unref (value); |
3958 | } |
3959 | } |
3960 | #endif |
3961 | |
3962 | g_variant_type_info_assert_no_infos (); |
3963 | } |
3964 | |
3965 | static void |
3966 | test_parse_failures (void) |
3967 | { |
3968 | const gchar *test[] = { |
3969 | "[1, 2," , "6:" , "expected value" , |
3970 | "" , "0:" , "expected value" , |
3971 | "(1, 2," , "6:" , "expected value" , |
3972 | "<1" , "2:" , "expected '>'" , |
3973 | "[]" , "0-2:" , "unable to infer" , |
3974 | "(," , "1:" , "expected value" , |
3975 | "[4,'']" , "1-2,3-5:" , "common type" , |
3976 | "[4, '', 5]" , "1-2,4-6:" , "common type" , |
3977 | "['', 4, 5]" , "1-3,5-6:" , "common type" , |
3978 | "[4, 5, '']" , "1-2,7-9:" , "common type" , |
3979 | "[[4], [], ['']]" , "1-4,10-14:" , "common type" , |
3980 | "[[], [4], ['']]" , "5-8,10-14:" , "common type" , |
3981 | "just" , "4:" , "expected value" , |
3982 | "nothing" , "0-7:" , "unable to infer" , |
3983 | "just [4, '']" , "6-7,9-11:" , "common type" , |
3984 | "[[4,'']]" , "2-3,4-6:" , "common type" , |
3985 | "([4,''],)" , "2-3,4-6:" , "common type" , |
3986 | "(4)" , "2:" , "','" , |
3987 | "{}" , "0-2:" , "unable to infer" , |
3988 | "{[1,2],[3,4]}" , "0-13:" , "basic types" , |
3989 | "{[1,2]:[3,4]}" , "0-13:" , "basic types" , |
3990 | "justt" , "0-5:" , "unknown keyword" , |
3991 | "nothng" , "0-6:" , "unknown keyword" , |
3992 | "uint33" , "0-6:" , "unknown keyword" , |
3993 | "@mi just ''" , "9-11:" , "can not parse as" , |
3994 | "@ai ['']" , "5-7:" , "can not parse as" , |
3995 | "@(i) ('',)" , "6-8:" , "can not parse as" , |
3996 | "[[], 5]" , "1-3,5-6:" , "common type" , |
3997 | "[[5], 5]" , "1-4,6-7:" , "common type" , |
3998 | "5 5" , "2:" , "expected end of input" , |
3999 | "[5, [5, '']]" , "5-6,8-10:" , "common type" , |
4000 | "@i just 5" , "3-9:" , "can not parse as" , |
4001 | "@i nothing" , "3-10:" , "can not parse as" , |
4002 | "@i []" , "3-5:" , "can not parse as" , |
4003 | "@i ()" , "3-5:" , "can not parse as" , |
4004 | "@ai (4,)" , "4-8:" , "can not parse as" , |
4005 | "@(i) []" , "5-7:" , "can not parse as" , |
4006 | "(5 5)" , "3:" , "expected ','" , |
4007 | "[5 5]" , "3:" , "expected ',' or ']'" , |
4008 | "(5, 5 5)" , "6:" , "expected ',' or ')'" , |
4009 | "[5, 5 5]" , "6:" , "expected ',' or ']'" , |
4010 | "<@i []>" , "4-6:" , "can not parse as" , |
4011 | "<[5 5]>" , "4:" , "expected ',' or ']'" , |
4012 | "{[4,''],5}" , "2-3,4-6:" , "common type" , |
4013 | "{5,[4,'']}" , "4-5,6-8:" , "common type" , |
4014 | "@i {1,2}" , "3-8:" , "can not parse as" , |
4015 | "{@i '', 5}" , "4-6:" , "can not parse as" , |
4016 | "{5, @i ''}" , "7-9:" , "can not parse as" , |
4017 | "@ai {}" , "4-6:" , "can not parse as" , |
4018 | "{@i '': 5}" , "4-6:" , "can not parse as" , |
4019 | "{5: @i ''}" , "7-9:" , "can not parse as" , |
4020 | "{<4,5}" , "3:" , "expected '>'" , |
4021 | "{4,<5}" , "5:" , "expected '>'" , |
4022 | "{4,5,6}" , "4:" , "expected '}'" , |
4023 | "{5 5}" , "3:" , "expected ':' or ','" , |
4024 | "{4: 5: 6}" , "5:" , "expected ',' or '}'" , |
4025 | "{4:5,<6:7}" , "7:" , "expected '>'" , |
4026 | "{4:5,6:<7}" , "9:" , "expected '>'" , |
4027 | "{4:5,6 7}" , "7:" , "expected ':'" , |
4028 | "@o 'foo'" , "3-8:" , "object path" , |
4029 | "@g 'zzz'" , "3-8:" , "signature" , |
4030 | "@i true" , "3-7:" , "can not parse as" , |
4031 | "@z 4" , "0-2:" , "invalid type" , |
4032 | "@a* []" , "0-3:" , "definite" , |
4033 | "@ai [3 3]" , "7:" , "expected ',' or ']'" , |
4034 | "18446744073709551616" , "0-20:" , "too big for any type" , |
4035 | "-18446744073709551616" , "0-21:" , "too big for any type" , |
4036 | "byte 256" , "5-8:" , "out of range for type" , |
4037 | "byte -1" , "5-7:" , "out of range for type" , |
4038 | "int16 32768" , "6-11:" , "out of range for type" , |
4039 | "int16 -32769" , "6-12:" , "out of range for type" , |
4040 | "uint16 -1" , "7-9:" , "out of range for type" , |
4041 | "uint16 65536" , "7-12:" , "out of range for type" , |
4042 | "2147483648" , "0-10:" , "out of range for type" , |
4043 | "-2147483649" , "0-11:" , "out of range for type" , |
4044 | "uint32 -1" , "7-9:" , "out of range for type" , |
4045 | "uint32 4294967296" , "7-17:" , "out of range for type" , |
4046 | "@x 9223372036854775808" , "3-22:" , "out of range for type" , |
4047 | "@x -9223372036854775809" , "3-23:" , "out of range for type" , |
4048 | "@t -1" , "3-5:" , "out of range for type" , |
4049 | "@t 18446744073709551616" , "3-23:" , "too big for any type" , |
4050 | "handle 2147483648" , "7-17:" , "out of range for type" , |
4051 | "handle -2147483649" , "7-18:" , "out of range for type" , |
4052 | "1.798e308" , "0-9:" , "too big for any type" , |
4053 | "37.5a488" , "4-5:" , "invalid character" , |
4054 | "0x7ffgf" , "5-6:" , "invalid character" , |
4055 | "07758" , "4-5:" , "invalid character" , |
4056 | "123a5" , "3-4:" , "invalid character" , |
4057 | "@ai 123" , "4-7:" , "can not parse as" , |
4058 | "'\"\\'" , "0-4:" , "unterminated string" , |
4059 | "'\"\\'\\" , "0-5:" , "unterminated string" , |
4060 | "boolean 4" , "8-9:" , "can not parse as" , |
4061 | "int32 true" , "6-10:" , "can not parse as" , |
4062 | "[double 5, int32 5]" , "1-9,11-18:" , "common type" , |
4063 | "string 4" , "7-8:" , "can not parse as" , |
4064 | "\x0a" , "1:" , "expected value" , |
4065 | "((" , "2:" , "expected value" , |
4066 | "(b" , "1:" , "expected value" , |
4067 | "b'" , "0-2:" , "unterminated string constant" , |
4068 | "b\"" , "0-2:" , "unterminated string constant" , |
4069 | "b'a" , "0-3:" , "unterminated string constant" , |
4070 | "b\"a" , "0-3:" , "unterminated string constant" , |
4071 | "b'\\" , "0-3:" , "unterminated string constant" , |
4072 | "b\"\\" , "0-3:" , "unterminated string constant" , |
4073 | "b'\\'" , "0-4:" , "unterminated string constant" , |
4074 | "b\"\\\"" , "0-4:" , "unterminated string constant" , |
4075 | "b'\\'a" , "0-5:" , "unterminated string constant" , |
4076 | "b\"\\\"a" , "0-5:" , "unterminated string constant" , |
4077 | "'\\u-ff4'" , "3:" , "invalid 4-character unicode escape" , |
4078 | "'\\u+ff4'" , "3:" , "invalid 4-character unicode escape" , |
4079 | "'\\u'" , "3:" , "invalid 4-character unicode escape" , |
4080 | "'\\u0'" , "3-4:" , "invalid 4-character unicode escape" , |
4081 | "'\\uHELLO'" , "3:" , "invalid 4-character unicode escape" , |
4082 | "'\\u ff4'" , "3:" , "invalid 4-character unicode escape" , |
4083 | "'\\u012'" , "3-6:" , "invalid 4-character unicode escape" , |
4084 | "'\\u0xff4'" , "3-4:" , "invalid 4-character unicode escape" , |
4085 | "'\\U-ff4'" , "3:" , "invalid 8-character unicode escape" , |
4086 | "'\\U+ff4'" , "3:" , "invalid 8-character unicode escape" , |
4087 | "'\\U'" , "3:" , "invalid 8-character unicode escape" , |
4088 | "'\\U0'" , "3-4:" , "invalid 8-character unicode escape" , |
4089 | "'\\UHELLO'" , "3:" , "invalid 8-character unicode escape" , |
4090 | "'\\U ff4'" , "3:" , "invalid 8-character unicode escape" , |
4091 | "'\\U0123456'" , "3-10:" , "invalid 8-character unicode escape" , |
4092 | "'\\U0xff4'" , "3-4:" , "invalid 8-character unicode escape" , |
4093 | }; |
4094 | guint i; |
4095 | |
4096 | for (i = 0; i < G_N_ELEMENTS (test); i += 3) |
4097 | { |
4098 | GError *error1 = NULL, *error2 = NULL; |
4099 | GVariant *value; |
4100 | |
4101 | /* Copy the test string and drop its nul terminator, then use the @limit |
4102 | * parameter of g_variant_parse() to set the length. This allows valgrind |
4103 | * to catch 1-byte heap buffer overflows. */ |
4104 | gsize test_len = MAX (strlen (test[i]), 1); |
4105 | gchar *test_blob = g_malloc0 (n_bytes: test_len); /* no nul terminator */ |
4106 | |
4107 | memcpy (dest: test_blob, src: test[i], n: test_len); |
4108 | value = g_variant_parse (NULL, text: test_blob, limit: test_blob + test_len, NULL, error: &error1); |
4109 | g_assert_null (value); |
4110 | |
4111 | g_free (mem: test_blob); |
4112 | |
4113 | if (!strstr (haystack: error1->message, needle: test[i+2])) |
4114 | g_error ("test %u: Can't find '%s' in '%s'" , i / 3, |
4115 | test[i+2], error1->message); |
4116 | |
4117 | if (!g_str_has_prefix (str: error1->message, prefix: test[i+1])) |
4118 | g_error ("test %u: Expected location '%s' in '%s'" , i / 3, |
4119 | test[i+1], error1->message); |
4120 | |
4121 | /* Test again with the nul terminator this time. The behaviour should be |
4122 | * the same. */ |
4123 | value = g_variant_parse (NULL, text: test[i], NULL, NULL, error: &error2); |
4124 | g_assert_null (value); |
4125 | |
4126 | g_assert_cmpint (error1->domain, ==, error2->domain); |
4127 | g_assert_cmpint (error1->code, ==, error2->code); |
4128 | g_assert_cmpstr (error1->message, ==, error2->message); |
4129 | |
4130 | g_clear_error (err: &error1); |
4131 | g_clear_error (err: &error2); |
4132 | } |
4133 | } |
4134 | |
4135 | /* Test that parsing GVariant text format integers works at the boundaries of |
4136 | * those integer types. We’re especially interested in the handling of the most |
4137 | * negative numbers, since those can’t be represented in sign + absolute value |
4138 | * form. */ |
4139 | static void |
4140 | test_parser_integer_bounds (void) |
4141 | { |
4142 | GVariant *value = NULL; |
4143 | GError *local_error = NULL; |
4144 | |
4145 | #define test_bound(TYPE, type, text, expected_value) \ |
4146 | value = g_variant_parse (G_VARIANT_TYPE_##TYPE, text, NULL, NULL, &local_error); \ |
4147 | g_assert_no_error (local_error); \ |
4148 | g_assert_nonnull (value); \ |
4149 | g_assert_true (g_variant_is_of_type (value, G_VARIANT_TYPE_##TYPE)); \ |
4150 | g_assert_cmpint (g_variant_get_##type (value), ==, expected_value); \ |
4151 | g_variant_unref (value) |
4152 | |
4153 | test_bound (BYTE, byte, "0" , 0); |
4154 | test_bound (BYTE, byte, "255" , G_MAXUINT8); |
4155 | test_bound (INT16, int16, "-32768" , G_MININT16); |
4156 | test_bound (INT16, int16, "32767" , G_MAXINT16); |
4157 | test_bound (INT32, int32, "-2147483648" , G_MININT32); |
4158 | test_bound (INT32, int32, "2147483647" , G_MAXINT32); |
4159 | test_bound (INT64, int64, "-9223372036854775808" , G_MININT64); |
4160 | test_bound (INT64, int64, "9223372036854775807" , G_MAXINT64); |
4161 | test_bound (HANDLE, handle, "-2147483648" , G_MININT32); |
4162 | test_bound (HANDLE, handle, "2147483647" , G_MAXINT32); |
4163 | |
4164 | #undef test_bound |
4165 | } |
4166 | |
4167 | /* Test that #GVariants which recurse too deeply are rejected. */ |
4168 | static void |
4169 | test_parser_recursion (void) |
4170 | { |
4171 | GVariant *value = NULL; |
4172 | GError *local_error = NULL; |
4173 | const guint recursion_depth = G_VARIANT_MAX_RECURSION_DEPTH + 1; |
4174 | gchar *silly_dict = g_malloc0 (n_bytes: recursion_depth * 2 + 1); |
4175 | gsize i; |
4176 | |
4177 | for (i = 0; i < recursion_depth; i++) |
4178 | { |
4179 | silly_dict[i] = '{'; |
4180 | silly_dict[recursion_depth * 2 - i - 1] = '}'; |
4181 | } |
4182 | |
4183 | value = g_variant_parse (NULL, text: silly_dict, NULL, NULL, error: &local_error); |
4184 | g_assert_error (local_error, G_VARIANT_PARSE_ERROR, G_VARIANT_PARSE_ERROR_RECURSION); |
4185 | g_assert_null (value); |
4186 | g_error_free (error: local_error); |
4187 | g_free (mem: silly_dict); |
4188 | } |
4189 | |
4190 | static void |
4191 | test_parse_bad_format_char (void) |
4192 | { |
4193 | g_variant_new_parsed (format: "%z" ); |
4194 | |
4195 | g_assert_not_reached (); |
4196 | } |
4197 | |
4198 | static void |
4199 | test_parse_bad_format_string (void) |
4200 | { |
4201 | g_variant_new_parsed (format: "uint32 %i" , 2); |
4202 | |
4203 | g_assert_not_reached (); |
4204 | } |
4205 | |
4206 | static void |
4207 | test_parse_bad_args (void) |
4208 | { |
4209 | g_variant_new_parsed (format: "%@i" , g_variant_new_uint32 (value: 2)); |
4210 | |
4211 | g_assert_not_reached (); |
4212 | } |
4213 | |
4214 | static void |
4215 | test_parse_positional (void) |
4216 | { |
4217 | GVariant *value; |
4218 | check_and_free (value: g_variant_new_parsed (format: "[('one', 1), (%s, 2)," |
4219 | " ('three', %i)]" , "two" , 3), |
4220 | str: "[('one', 1), ('two', 2), ('three', 3)]" ); |
4221 | value = g_variant_new_parsed (format: "[('one', 1), (%s, 2)," |
4222 | " ('three', %u)]" , "two" , 3); |
4223 | g_assert_true (g_variant_is_of_type (value, G_VARIANT_TYPE ("a(su)" ))); |
4224 | check_and_free (value, str: "[('one', 1), ('two', 2), ('three', 3)]" ); |
4225 | check_and_free (value: g_variant_new_parsed (format: "{%s:%i}" , "one" , 1), str: "{'one': 1}" ); |
4226 | |
4227 | if (g_test_undefined ()) |
4228 | { |
4229 | do_failed_test (test: "/gvariant/parse/subprocess/bad-format-char" , |
4230 | pattern: "*GVariant format string*" ); |
4231 | |
4232 | do_failed_test (test: "/gvariant/parse/subprocess/bad-format-string" , |
4233 | pattern: "*can not parse as*" ); |
4234 | |
4235 | do_failed_test (test: "/gvariant/parse/subprocess/bad-args" , |
4236 | pattern: "*expected GVariant of type 'i'*" ); |
4237 | } |
4238 | } |
4239 | |
4240 | static void |
4241 | test_floating (void) |
4242 | { |
4243 | GVariant *value; |
4244 | |
4245 | value = g_variant_new_int32 (value: 42); |
4246 | g_assert_true (g_variant_is_floating (value)); |
4247 | g_variant_ref_sink (value); |
4248 | g_assert_true (!g_variant_is_floating (value)); |
4249 | g_variant_unref (value); |
4250 | } |
4251 | |
4252 | static void |
4253 | test_bytestring (void) |
4254 | { |
4255 | const gchar *test_string = "foo,bar,baz,quux,\xffoooo" ; |
4256 | GVariant *value; |
4257 | gchar **strv; |
4258 | gchar *str; |
4259 | const gchar *const_str; |
4260 | GVariant *untrusted_empty; |
4261 | |
4262 | strv = g_strsplit (string: test_string, delimiter: "," , max_tokens: 0); |
4263 | |
4264 | value = g_variant_new_bytestring_array (strv: (const gchar **) strv, length: -1); |
4265 | g_assert_true (g_variant_is_floating (value)); |
4266 | g_strfreev (str_array: strv); |
4267 | |
4268 | str = g_variant_print (value, FALSE); |
4269 | g_variant_unref (value); |
4270 | |
4271 | value = g_variant_parse (NULL, text: str, NULL, NULL, NULL); |
4272 | g_free (mem: str); |
4273 | |
4274 | strv = g_variant_dup_bytestring_array (value, NULL); |
4275 | g_variant_unref (value); |
4276 | |
4277 | str = g_strjoinv (separator: "," , str_array: strv); |
4278 | g_strfreev (str_array: strv); |
4279 | |
4280 | g_assert_cmpstr (str, ==, test_string); |
4281 | g_free (mem: str); |
4282 | |
4283 | strv = g_strsplit (string: test_string, delimiter: "," , max_tokens: 0); |
4284 | value = g_variant_new (format_string: "(^aay^a&ay^ay^&ay)" , |
4285 | strv, strv, strv[0], strv[0]); |
4286 | g_strfreev (str_array: strv); |
4287 | |
4288 | g_variant_get_child (value, index_: 0, format_string: "^a&ay" , &strv); |
4289 | str = g_strjoinv (separator: "," , str_array: strv); |
4290 | g_free (mem: strv); |
4291 | g_assert_cmpstr (str, ==, test_string); |
4292 | g_free (mem: str); |
4293 | |
4294 | g_variant_get_child (value, index_: 0, format_string: "^aay" , &strv); |
4295 | str = g_strjoinv (separator: "," , str_array: strv); |
4296 | g_strfreev (str_array: strv); |
4297 | g_assert_cmpstr (str, ==, test_string); |
4298 | g_free (mem: str); |
4299 | |
4300 | g_variant_get_child (value, index_: 1, format_string: "^a&ay" , &strv); |
4301 | str = g_strjoinv (separator: "," , str_array: strv); |
4302 | g_free (mem: strv); |
4303 | g_assert_cmpstr (str, ==, test_string); |
4304 | g_free (mem: str); |
4305 | |
4306 | g_variant_get_child (value, index_: 1, format_string: "^aay" , &strv); |
4307 | str = g_strjoinv (separator: "," , str_array: strv); |
4308 | g_strfreev (str_array: strv); |
4309 | g_assert_cmpstr (str, ==, test_string); |
4310 | g_free (mem: str); |
4311 | |
4312 | g_variant_get_child (value, index_: 2, format_string: "^ay" , &str); |
4313 | g_assert_cmpstr (str, ==, "foo" ); |
4314 | g_free (mem: str); |
4315 | |
4316 | g_variant_get_child (value, index_: 2, format_string: "^&ay" , &str); |
4317 | g_assert_cmpstr (str, ==, "foo" ); |
4318 | |
4319 | g_variant_get_child (value, index_: 3, format_string: "^ay" , &str); |
4320 | g_assert_cmpstr (str, ==, "foo" ); |
4321 | g_free (mem: str); |
4322 | |
4323 | g_variant_get_child (value, index_: 3, format_string: "^&ay" , &str); |
4324 | g_assert_cmpstr (str, ==, "foo" ); |
4325 | g_variant_unref (value); |
4326 | |
4327 | untrusted_empty = g_variant_new_from_data (G_VARIANT_TYPE ("ay" ), NULL, size: 0, FALSE, NULL, NULL); |
4328 | value = g_variant_get_normal_form (value: untrusted_empty); |
4329 | const_str = g_variant_get_bytestring (value); |
4330 | (void) const_str; |
4331 | g_variant_unref (value); |
4332 | g_variant_unref (value: untrusted_empty); |
4333 | } |
4334 | |
4335 | static void |
4336 | test_lookup_value (void) |
4337 | { |
4338 | struct { |
4339 | const gchar *dict, *key, *value; |
4340 | } cases[] = { |
4341 | { "@a{ss} {'x': 'y'}" , "x" , "'y'" }, |
4342 | { "@a{ss} {'x': 'y'}" , "y" , NULL }, |
4343 | { "@a{os} {'/x': 'y'}" , "/x" , "'y'" }, |
4344 | { "@a{os} {'/x': 'y'}" , "/y" , NULL }, |
4345 | { "@a{sv} {'x': <'y'>}" , "x" , "'y'" }, |
4346 | { "@a{sv} {'x': <5>}" , "x" , "5" }, |
4347 | { "@a{sv} {'x': <'y'>}" , "y" , NULL } |
4348 | }; |
4349 | gsize i; |
4350 | |
4351 | for (i = 0; i < G_N_ELEMENTS (cases); i++) |
4352 | { |
4353 | GVariant *dictionary; |
4354 | GVariant *value; |
4355 | gchar *p; |
4356 | |
4357 | dictionary = g_variant_parse (NULL, text: cases[i].dict, NULL, NULL, NULL); |
4358 | value = g_variant_lookup_value (dictionary, key: cases[i].key, NULL); |
4359 | g_variant_unref (value: dictionary); |
4360 | |
4361 | if (value == NULL && cases[i].value == NULL) |
4362 | continue; |
4363 | |
4364 | g_assert_true (value && cases[i].value); |
4365 | p = g_variant_print (value, FALSE); |
4366 | g_assert_cmpstr (cases[i].value, ==, p); |
4367 | g_variant_unref (value); |
4368 | g_free (mem: p); |
4369 | } |
4370 | } |
4371 | |
4372 | static void |
4373 | test_lookup (void) |
4374 | { |
4375 | const gchar *str; |
4376 | GVariant *dict; |
4377 | gboolean ok; |
4378 | gint num; |
4379 | |
4380 | dict = g_variant_parse (NULL, |
4381 | text: "{'a': <5>, 'b': <'c'>}" , |
4382 | NULL, NULL, NULL); |
4383 | |
4384 | ok = g_variant_lookup (dictionary: dict, key: "a" , format_string: "i" , &num); |
4385 | g_assert_true (ok); |
4386 | g_assert_cmpint (num, ==, 5); |
4387 | |
4388 | ok = g_variant_lookup (dictionary: dict, key: "a" , format_string: "&s" , &str); |
4389 | g_assert_false (ok); |
4390 | |
4391 | ok = g_variant_lookup (dictionary: dict, key: "q" , format_string: "&s" , &str); |
4392 | g_assert_false (ok); |
4393 | |
4394 | ok = g_variant_lookup (dictionary: dict, key: "b" , format_string: "i" , &num); |
4395 | g_assert_false (ok); |
4396 | |
4397 | ok = g_variant_lookup (dictionary: dict, key: "b" , format_string: "&s" , &str); |
4398 | g_assert_true (ok); |
4399 | g_assert_cmpstr (str, ==, "c" ); |
4400 | |
4401 | ok = g_variant_lookup (dictionary: dict, key: "q" , format_string: "&s" , &str); |
4402 | g_assert_false (ok); |
4403 | |
4404 | g_variant_unref (value: dict); |
4405 | } |
4406 | |
4407 | static GVariant * |
4408 | untrusted (GVariant *a) |
4409 | { |
4410 | GVariant *b; |
4411 | const GVariantType *type; |
4412 | GBytes *bytes; |
4413 | |
4414 | type = g_variant_get_type (value: a); |
4415 | bytes = g_variant_get_data_as_bytes (value: a); |
4416 | b = g_variant_new_from_bytes (type, bytes, FALSE); |
4417 | g_bytes_unref (bytes); |
4418 | g_variant_unref (value: a); |
4419 | |
4420 | return b; |
4421 | } |
4422 | |
4423 | static void |
4424 | test_compare (void) |
4425 | { |
4426 | GVariant *a; |
4427 | GVariant *b; |
4428 | |
4429 | a = untrusted (a: g_variant_new_byte (value: 5)); |
4430 | b = g_variant_new_byte (value: 6); |
4431 | g_assert_cmpint (g_variant_compare (a, b), <, 0); |
4432 | g_variant_unref (value: a); |
4433 | g_variant_unref (value: b); |
4434 | a = untrusted (a: g_variant_new_int16 (G_MININT16)); |
4435 | b = g_variant_new_int16 (G_MAXINT16); |
4436 | g_assert_cmpint (g_variant_compare (a, b), <, 0); |
4437 | g_variant_unref (value: a); |
4438 | g_variant_unref (value: b); |
4439 | a = untrusted (a: g_variant_new_uint16 (value: 0)); |
4440 | b = g_variant_new_uint16 (G_MAXUINT16); |
4441 | g_assert_cmpint (g_variant_compare (a, b), <, 0); |
4442 | g_variant_unref (value: a); |
4443 | g_variant_unref (value: b); |
4444 | a = untrusted (a: g_variant_new_int32 (G_MININT32)); |
4445 | b = g_variant_new_int32 (G_MAXINT32); |
4446 | g_assert_cmpint (g_variant_compare (a, b), <, 0); |
4447 | g_variant_unref (value: a); |
4448 | g_variant_unref (value: b); |
4449 | a = untrusted (a: g_variant_new_uint32 (value: 0)); |
4450 | b = g_variant_new_uint32 (G_MAXUINT32); |
4451 | g_assert_cmpint (g_variant_compare (a, b), <, 0); |
4452 | g_variant_unref (value: a); |
4453 | g_variant_unref (value: b); |
4454 | a = untrusted (a: g_variant_new_int64 (G_MININT64)); |
4455 | b = g_variant_new_int64 (G_MAXINT64); |
4456 | g_assert_cmpint (g_variant_compare (a, b), <, 0); |
4457 | g_variant_unref (value: a); |
4458 | g_variant_unref (value: b); |
4459 | a = untrusted (a: g_variant_new_uint64 (value: 0)); |
4460 | b = g_variant_new_uint64 (G_MAXUINT64); |
4461 | g_assert_cmpint (g_variant_compare (a, b), <, 0); |
4462 | g_variant_unref (value: a); |
4463 | g_variant_unref (value: b); |
4464 | a = untrusted (a: g_variant_new_double (G_MINDOUBLE)); |
4465 | b = g_variant_new_double (G_MAXDOUBLE); |
4466 | g_assert_cmpint (g_variant_compare (a, b), <, 0); |
4467 | g_variant_unref (value: a); |
4468 | g_variant_unref (value: b); |
4469 | a = untrusted (a: g_variant_new_string (string: "abc" )); |
4470 | b = g_variant_new_string (string: "abd" ); |
4471 | g_assert_cmpint (g_variant_compare (a, b), <, 0); |
4472 | g_variant_unref (value: a); |
4473 | g_variant_unref (value: b); |
4474 | a = untrusted (a: g_variant_new_object_path (object_path: "/abc" )); |
4475 | b = g_variant_new_object_path (object_path: "/abd" ); |
4476 | g_assert_cmpint (g_variant_compare (a, b), <, 0); |
4477 | g_variant_unref (value: a); |
4478 | g_variant_unref (value: b); |
4479 | a = untrusted (a: g_variant_new_signature (signature: "g" )); |
4480 | b = g_variant_new_signature (signature: "o" ); |
4481 | g_assert_cmpint (g_variant_compare (a, b), <, 0); |
4482 | g_variant_unref (value: a); |
4483 | g_variant_unref (value: b); |
4484 | a = untrusted (a: g_variant_new_boolean (FALSE)); |
4485 | b = g_variant_new_boolean (TRUE); |
4486 | g_assert_cmpint (g_variant_compare (a, b), <, 0); |
4487 | g_variant_unref (value: a); |
4488 | g_variant_unref (value: b); |
4489 | } |
4490 | |
4491 | static void |
4492 | test_equal (void) |
4493 | { |
4494 | GVariant *a; |
4495 | GVariant *b; |
4496 | |
4497 | a = untrusted (a: g_variant_new_byte (value: 5)); |
4498 | b = g_variant_get_normal_form (value: a); |
4499 | g_assert_cmpvariant (a, b); |
4500 | g_variant_unref (value: a); |
4501 | g_variant_unref (value: b); |
4502 | a = untrusted (a: g_variant_new_int16 (G_MININT16)); |
4503 | b = g_variant_get_normal_form (value: a); |
4504 | g_assert_cmpvariant (a, b); |
4505 | g_variant_unref (value: a); |
4506 | g_variant_unref (value: b); |
4507 | a = untrusted (a: g_variant_new_uint16 (value: 0)); |
4508 | b = g_variant_get_normal_form (value: a); |
4509 | g_assert_cmpvariant (a, b); |
4510 | g_variant_unref (value: a); |
4511 | g_variant_unref (value: b); |
4512 | a = untrusted (a: g_variant_new_int32 (G_MININT32)); |
4513 | b = g_variant_get_normal_form (value: a); |
4514 | g_assert_cmpvariant (a, b); |
4515 | g_variant_unref (value: a); |
4516 | g_variant_unref (value: b); |
4517 | a = untrusted (a: g_variant_new_uint32 (value: 0)); |
4518 | b = g_variant_get_normal_form (value: a); |
4519 | g_assert_cmpvariant (a, b); |
4520 | g_variant_unref (value: a); |
4521 | g_variant_unref (value: b); |
4522 | a = untrusted (a: g_variant_new_int64 (G_MININT64)); |
4523 | b = g_variant_get_normal_form (value: a); |
4524 | g_assert_cmpvariant (a, b); |
4525 | g_variant_unref (value: a); |
4526 | g_variant_unref (value: b); |
4527 | a = untrusted (a: g_variant_new_uint64 (value: 0)); |
4528 | b = g_variant_get_normal_form (value: a); |
4529 | g_assert_cmpvariant (a, b); |
4530 | g_variant_unref (value: a); |
4531 | g_variant_unref (value: b); |
4532 | a = untrusted (a: g_variant_new_double (G_MINDOUBLE)); |
4533 | b = g_variant_get_normal_form (value: a); |
4534 | g_assert_cmpvariant (a, b); |
4535 | g_variant_unref (value: a); |
4536 | g_variant_unref (value: b); |
4537 | a = untrusted (a: g_variant_new_string (string: "abc" )); |
4538 | g_assert_cmpvariant (a, a); |
4539 | b = g_variant_get_normal_form (value: a); |
4540 | g_assert_cmpvariant (a, b); |
4541 | g_variant_unref (value: a); |
4542 | g_variant_unref (value: b); |
4543 | a = untrusted (a: g_variant_new_object_path (object_path: "/abc" )); |
4544 | g_assert_cmpvariant (a, a); |
4545 | b = g_variant_get_normal_form (value: a); |
4546 | a = untrusted (a); |
4547 | g_assert_cmpvariant (a, b); |
4548 | g_variant_unref (value: a); |
4549 | g_variant_unref (value: b); |
4550 | a = untrusted (a: g_variant_new_signature (signature: "g" )); |
4551 | g_assert_cmpvariant (a, a); |
4552 | b = g_variant_get_normal_form (value: a); |
4553 | a = untrusted (a); |
4554 | g_assert_cmpvariant (a, b); |
4555 | g_variant_unref (value: a); |
4556 | g_variant_unref (value: b); |
4557 | a = untrusted (a: g_variant_new_boolean (FALSE)); |
4558 | b = g_variant_get_normal_form (value: a); |
4559 | g_assert_cmpvariant (a, b); |
4560 | g_variant_unref (value: a); |
4561 | g_variant_unref (value: b); |
4562 | } |
4563 | |
4564 | static void |
4565 | test_fixed_array (void) |
4566 | { |
4567 | GVariant *a; |
4568 | gint32 values[5]; |
4569 | const gint32 *elts; |
4570 | gsize n_elts; |
4571 | gsize i; |
4572 | |
4573 | n_elts = 0; |
4574 | a = g_variant_new_parsed (format: "[1,2,3,4,5]" ); |
4575 | elts = g_variant_get_fixed_array (value: a, n_elements: &n_elts, element_size: sizeof (gint32)); |
4576 | g_assert_cmpuint (n_elts, ==, 5); |
4577 | for (i = 0; i < 5; i++) |
4578 | g_assert_cmpint (elts[i], ==, i + 1); |
4579 | g_variant_unref (value: a); |
4580 | |
4581 | n_elts = 0; |
4582 | for (i = 0; i < 5; i++) |
4583 | values[i] = i + 1; |
4584 | a = g_variant_new_fixed_array (G_VARIANT_TYPE_INT32, elements: values, |
4585 | G_N_ELEMENTS (values), element_size: sizeof (values[0])); |
4586 | g_assert_cmpstr (g_variant_get_type_string (a), ==, "ai" ); |
4587 | elts = g_variant_get_fixed_array (value: a, n_elements: &n_elts, element_size: sizeof (gint32)); |
4588 | g_assert_cmpuint (n_elts, ==, 5); |
4589 | for (i = 0; i < 5; i++) |
4590 | g_assert_cmpint (elts[i], ==, i + 1); |
4591 | g_variant_unref (value: a); |
4592 | } |
4593 | |
4594 | static void |
4595 | test_check_format_string (void) |
4596 | { |
4597 | GVariant *value; |
4598 | |
4599 | value = g_variant_new (format_string: "(sas)" , "foo" , NULL); |
4600 | g_variant_ref_sink (value); |
4601 | |
4602 | g_assert_true (g_variant_check_format_string (value, "(s*)" , TRUE)); |
4603 | g_assert_true (g_variant_check_format_string (value, "(s*)" , FALSE)); |
4604 | g_assert_false (g_variant_check_format_string (value, "(u*)" , TRUE)); |
4605 | g_assert_false (g_variant_check_format_string (value, "(u*)" , FALSE)); |
4606 | |
4607 | g_assert_true (g_variant_check_format_string (value, "(&s*)" , FALSE)); |
4608 | g_test_expect_message (log_domain: "GLib" , log_level: G_LOG_LEVEL_CRITICAL, pattern: "*contains a '&' character*" ); |
4609 | g_assert_false (g_variant_check_format_string (value, "(&s*)" , TRUE)); |
4610 | g_test_assert_expected_messages (); |
4611 | |
4612 | g_assert_true (g_variant_check_format_string (value, "(s^as)" , TRUE)); |
4613 | g_assert_true (g_variant_check_format_string (value, "(s^as)" , FALSE)); |
4614 | |
4615 | g_test_expect_message (log_domain: "GLib" , log_level: G_LOG_LEVEL_CRITICAL, pattern: "*contains a '&' character*" ); |
4616 | g_assert_false (g_variant_check_format_string (value, "(s^a&s)" , TRUE)); |
4617 | g_test_assert_expected_messages (); |
4618 | g_assert_true (g_variant_check_format_string (value, "(s^a&s)" , FALSE)); |
4619 | |
4620 | g_variant_unref (value); |
4621 | |
4622 | /* Do it again with a type that will let us put a '&' after a '^' */ |
4623 | value = g_variant_new (format_string: "(say)" , "foo" , NULL); |
4624 | g_variant_ref_sink (value); |
4625 | |
4626 | g_assert_true (g_variant_check_format_string (value, "(s*)" , TRUE)); |
4627 | g_assert_true (g_variant_check_format_string (value, "(s*)" , FALSE)); |
4628 | g_assert_false (g_variant_check_format_string (value, "(u*)" , TRUE)); |
4629 | g_assert_false (g_variant_check_format_string (value, "(u*)" , FALSE)); |
4630 | |
4631 | g_assert_true (g_variant_check_format_string (value, "(&s*)" , FALSE)); |
4632 | g_test_expect_message (log_domain: "GLib" , log_level: G_LOG_LEVEL_CRITICAL, pattern: "*contains a '&' character*" ); |
4633 | g_assert_false (g_variant_check_format_string (value, "(&s*)" , TRUE)); |
4634 | g_test_assert_expected_messages (); |
4635 | |
4636 | g_assert_true (g_variant_check_format_string (value, "(s^ay)" , TRUE)); |
4637 | g_assert_true (g_variant_check_format_string (value, "(s^ay)" , FALSE)); |
4638 | |
4639 | g_test_expect_message (log_domain: "GLib" , log_level: G_LOG_LEVEL_CRITICAL, pattern: "*contains a '&' character*" ); |
4640 | g_assert_false (g_variant_check_format_string (value, "(s^&ay)" , TRUE)); |
4641 | g_test_assert_expected_messages (); |
4642 | g_assert_true (g_variant_check_format_string (value, "(s^&ay)" , FALSE)); |
4643 | |
4644 | g_assert_true (g_variant_check_format_string (value, "r" , FALSE)); |
4645 | g_assert_true (g_variant_check_format_string (value, "(?a?)" , FALSE)); |
4646 | |
4647 | g_variant_unref (value); |
4648 | } |
4649 | |
4650 | static void |
4651 | verify_gvariant_checksum (const gchar *sha256, |
4652 | GVariant *v) |
4653 | |
4654 | { |
4655 | gchar *checksum; |
4656 | checksum = g_compute_checksum_for_data (checksum_type: G_CHECKSUM_SHA256, |
4657 | data: g_variant_get_data (value: v), |
4658 | length: g_variant_get_size (value: v)); |
4659 | g_assert_cmpstr (sha256, ==, checksum); |
4660 | g_free (mem: checksum); |
4661 | } |
4662 | |
4663 | static void |
4664 | verify_gvariant_checksum_va (const gchar *sha256, |
4665 | const gchar *fmt, |
4666 | ...) |
4667 | { |
4668 | va_list args; |
4669 | GVariant *v; |
4670 | |
4671 | va_start (args, fmt); |
4672 | |
4673 | v = g_variant_new_va (format_string: fmt, NULL, app: &args); |
4674 | g_variant_ref_sink (value: v); |
4675 | #if G_BYTE_ORDER == G_BIG_ENDIAN |
4676 | { |
4677 | GVariant *byteswapped = g_variant_byteswap (v); |
4678 | g_variant_unref (v); |
4679 | v = byteswapped; |
4680 | } |
4681 | #endif |
4682 | |
4683 | va_end (args); |
4684 | |
4685 | verify_gvariant_checksum (sha256, v); |
4686 | |
4687 | g_variant_unref (value: v); |
4688 | } |
4689 | |
4690 | static void |
4691 | test_checksum_basic (void) |
4692 | { |
4693 | verify_gvariant_checksum_va (sha256: "e8a4b2ee7ede79a3afb332b5b6cc3d952a65fd8cffb897f5d18016577c33d7cc" , |
4694 | fmt: "u" , 42); |
4695 | verify_gvariant_checksum_va (sha256: "c53e363c33b00cfce298229ee83856b8a98c2e6126cab13f65899f62473b0df5" , |
4696 | fmt: "s" , "moocow" ); |
4697 | verify_gvariant_checksum_va (sha256: "2b4c342f5433ebe591a1da77e013d1b72475562d48578dca8b84bac6651c3cb9" , |
4698 | fmt: "y" , 9); |
4699 | verify_gvariant_checksum_va (sha256: "12a3ae445661ce5dee78d0650d33362dec29c4f82af05e7e57fb595bbbacf0ca" , |
4700 | fmt: "t" , G_MAXUINT64); |
4701 | verify_gvariant_checksum_va (sha256: "e25a59b24440eb6c833aa79c93b9840e6eab6966add0dacf31df7e9e7000f5b3" , |
4702 | fmt: "d" , 3.14159); |
4703 | verify_gvariant_checksum_va (sha256: "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a" , |
4704 | fmt: "b" , TRUE); |
4705 | verify_gvariant_checksum_va (sha256: "ca2fd00fa001190744c15c317643ab092e7048ce086a243e2be9437c898de1bb" , |
4706 | fmt: "q" , G_MAXUINT16); |
4707 | } |
4708 | |
4709 | static void |
4710 | test_checksum_nested (void) |
4711 | { |
4712 | static const char* const strv[] = {"foo" , "bar" , "baz" , NULL}; |
4713 | |
4714 | verify_gvariant_checksum_va (sha256: "31fbc92f08fddaca716188fe4b5d44ae122fc6306fd3c6925af53cfa47ea596d" , |
4715 | fmt: "(uu)" , 41, 43); |
4716 | verify_gvariant_checksum_va (sha256: "01759d683cead856d1d386d59af0578841698a424a265345ad5413122f220de8" , |
4717 | fmt: "(su)" , "moocow" , 79); |
4718 | verify_gvariant_checksum_va (sha256: "52b3ae95f19b3e642ea1d01185aea14a09004c1d1712672644427403a8a0afe6" , |
4719 | fmt: "(qyst)" , G_MAXUINT16, 9, "moocow" , G_MAXUINT64); |
4720 | verify_gvariant_checksum_va (sha256: "6fc6f4524161c3ae0d316812d7088e3fcd372023edaea2d7821093be40ae1060" , |
4721 | fmt: "(@ay)" , g_variant_new_bytestring (string: "\xFF\xFF\xFF" )); |
4722 | verify_gvariant_checksum_va (sha256: "572aca386e1a983dd23bb6eb6e3dfa72eef9ca7c7744581aa800e18d7d9d0b0b" , |
4723 | fmt: "(^as)" , strv); |
4724 | verify_gvariant_checksum_va (sha256: "4bddf6174c791bb44fc6a4106573031690064df34b741033a0122ed8dc05bcf3" , |
4725 | fmt: "(yvu)" , 254, g_variant_new (format_string: "(^as)" , strv), 42); |
4726 | } |
4727 | |
4728 | static void |
4729 | test_gbytes (void) |
4730 | { |
4731 | GVariant *a; |
4732 | GVariant *tuple; |
4733 | GBytes *bytes; |
4734 | GBytes *bytes2; |
4735 | const guint8 values[5] = { 1, 2, 3, 4, 5 }; |
4736 | const guint8 *elts; |
4737 | gsize n_elts; |
4738 | gsize i; |
4739 | |
4740 | bytes = g_bytes_new (data: &values, size: 5); |
4741 | a = g_variant_new_from_bytes (G_VARIANT_TYPE_BYTESTRING, bytes, TRUE); |
4742 | g_bytes_unref (bytes); |
4743 | n_elts = 0; |
4744 | elts = g_variant_get_fixed_array (value: a, n_elements: &n_elts, element_size: sizeof (guint8)); |
4745 | g_assert_cmpuint (n_elts, ==, 5); |
4746 | for (i = 0; i < 5; i++) |
4747 | g_assert_cmpuint (elts[i], ==, i + 1); |
4748 | |
4749 | bytes2 = g_variant_get_data_as_bytes (value: a); |
4750 | g_variant_unref (value: a); |
4751 | |
4752 | bytes = g_bytes_new (data: &values, size: 5); |
4753 | g_assert_true (g_bytes_equal (bytes, bytes2)); |
4754 | g_bytes_unref (bytes); |
4755 | g_bytes_unref (bytes: bytes2); |
4756 | |
4757 | tuple = g_variant_new_parsed (format: "['foo', 'bar']" ); |
4758 | bytes = g_variant_get_data_as_bytes (value: tuple); /* force serialisation */ |
4759 | a = g_variant_get_child_value (value: tuple, index_: 1); |
4760 | bytes2 = g_variant_get_data_as_bytes (value: a); |
4761 | g_assert_false (g_bytes_equal (bytes, bytes2)); |
4762 | |
4763 | g_bytes_unref (bytes); |
4764 | g_bytes_unref (bytes: bytes2); |
4765 | g_variant_unref (value: a); |
4766 | g_variant_unref (value: tuple); |
4767 | } |
4768 | |
4769 | typedef struct { |
4770 | const GVariantType *type; |
4771 | const gchar *in; |
4772 | const gchar *out; |
4773 | } ContextTest; |
4774 | |
4775 | static void |
4776 | test_print_context (void) |
4777 | { |
4778 | ContextTest tests[] = { |
4779 | { NULL, "(1, 2, 3, 'abc" , " ^^^^" }, |
4780 | { NULL, "[1, 2, 3, 'str']" , " ^ ^^^^^" }, |
4781 | { G_VARIANT_TYPE_UINT16, "{ 'abc':'def' }" , " ^^^^^^^^^^^^^^^" }, |
4782 | { NULL, "<5" , " ^" }, |
4783 | { NULL, "'ab\\ux'" , " ^ " }, |
4784 | { NULL, "'ab\\U00efx'" , " ^^^^ " } |
4785 | }; |
4786 | GVariant *v; |
4787 | gchar *s; |
4788 | gsize i; |
4789 | GError *error = NULL; |
4790 | |
4791 | for (i = 0; i < G_N_ELEMENTS (tests); i++) |
4792 | { |
4793 | v = g_variant_parse (type: tests[i].type, text: tests[i].in, NULL, NULL, error: &error); |
4794 | g_assert_null (v); |
4795 | s = g_variant_parse_error_print_context (error, source_str: tests[i].in); |
4796 | g_assert_nonnull (strstr (s, tests[i].out)); |
4797 | g_free (mem: s); |
4798 | g_clear_error (err: &error); |
4799 | } |
4800 | } |
4801 | |
4802 | static void |
4803 | test_error_quark (void) |
4804 | { |
4805 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
4806 | g_assert_cmpuint (g_variant_parser_get_error_quark (), ==, g_variant_parse_error_quark ()); |
4807 | G_GNUC_END_IGNORE_DEPRECATIONS |
4808 | } |
4809 | |
4810 | static void |
4811 | test_stack_builder_init (void) |
4812 | { |
4813 | GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_BYTESTRING); |
4814 | GVariant *variant; |
4815 | |
4816 | g_variant_builder_add_value (builder: &builder, value: g_variant_new_byte (value: 'g')); |
4817 | g_variant_builder_add_value (builder: &builder, value: g_variant_new_byte (value: 'l')); |
4818 | g_variant_builder_add_value (builder: &builder, value: g_variant_new_byte (value: 'i')); |
4819 | g_variant_builder_add_value (builder: &builder, value: g_variant_new_byte (value: 'b')); |
4820 | g_variant_builder_add_value (builder: &builder, value: g_variant_new_byte (value: '\0')); |
4821 | |
4822 | variant = g_variant_ref_sink (value: g_variant_builder_end (builder: &builder)); |
4823 | g_assert_nonnull (variant); |
4824 | g_assert_true (g_variant_type_equal (g_variant_get_type (variant), |
4825 | G_VARIANT_TYPE_BYTESTRING)); |
4826 | g_assert_cmpuint (g_variant_n_children (variant), ==, 5); |
4827 | g_assert_cmpstr (g_variant_get_bytestring (variant), ==, "glib" ); |
4828 | g_variant_unref (value: variant); |
4829 | } |
4830 | |
4831 | static GVariant * |
4832 | get_asv (void) |
4833 | { |
4834 | GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT); |
4835 | |
4836 | g_variant_builder_add (builder: &builder, format_string: "{s@v}" , "foo" , g_variant_new_variant (value: g_variant_new_string (string: "FOO" ))); |
4837 | g_variant_builder_add (builder: &builder, format_string: "{s@v}" , "bar" , g_variant_new_variant (value: g_variant_new_string (string: "BAR" ))); |
4838 | |
4839 | return g_variant_ref_sink (value: g_variant_builder_end (builder: &builder)); |
4840 | } |
4841 | |
4842 | static void |
4843 | test_stack_dict_init (void) |
4844 | { |
4845 | GVariant *asv = get_asv (); |
4846 | GVariantDict dict = G_VARIANT_DICT_INIT (asv); |
4847 | GVariant *variant; |
4848 | GVariantIter iter; |
4849 | gchar *key; |
4850 | GVariant *value; |
4851 | |
4852 | g_variant_dict_insert_value (dict: &dict, key: "baz" , value: g_variant_new_string (string: "BAZ" )); |
4853 | g_variant_dict_insert_value (dict: &dict, key: "quux" , value: g_variant_new_string (string: "QUUX" )); |
4854 | |
4855 | variant = g_variant_ref_sink (value: g_variant_dict_end (dict: &dict)); |
4856 | g_assert_nonnull (variant); |
4857 | g_assert_true (g_variant_type_equal (g_variant_get_type (variant), |
4858 | G_VARIANT_TYPE_VARDICT)); |
4859 | g_assert_cmpuint (g_variant_n_children (variant), ==, 4); |
4860 | |
4861 | g_variant_iter_init (iter: &iter, value: variant); |
4862 | while (g_variant_iter_next (iter: &iter, format_string: "{sv}" , &key, &value)) |
4863 | { |
4864 | gchar *strup = g_ascii_strup (str: key, len: -1); |
4865 | |
4866 | g_assert_cmpstr (strup, ==, g_variant_get_string (value, NULL)); |
4867 | g_free (mem: key); |
4868 | g_free (mem: strup); |
4869 | g_variant_unref (value); |
4870 | } |
4871 | |
4872 | g_variant_unref (value: asv); |
4873 | g_variant_unref (value: variant); |
4874 | } |
4875 | |
4876 | /* Test checking arbitrary binary data for normal form. This time, it’s a tuple |
4877 | * with invalid element ends. */ |
4878 | static void |
4879 | test_normal_checking_tuples (void) |
4880 | { |
4881 | const guint8 data[] = { |
4882 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, |
4883 | 'a', '(', 'a', 'o', 'a', 'o', 'a', 'a', 'o', 'a', 'a', 'o', ')' |
4884 | }; |
4885 | gsize size = sizeof (data); |
4886 | GVariant *variant = NULL; |
4887 | GVariant *normal_variant = NULL; |
4888 | |
4889 | variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size, |
4890 | FALSE, NULL, NULL); |
4891 | g_assert_nonnull (variant); |
4892 | |
4893 | normal_variant = g_variant_get_normal_form (value: variant); |
4894 | g_assert_nonnull (normal_variant); |
4895 | |
4896 | g_variant_unref (value: normal_variant); |
4897 | g_variant_unref (value: variant); |
4898 | } |
4899 | |
4900 | /* Check that deeply nested variants are not considered in normal form when |
4901 | * deserialised from untrusted data.*/ |
4902 | static void |
4903 | test_recursion_limits_variant_in_variant (void) |
4904 | { |
4905 | GVariant *wrapper_variant = NULL; |
4906 | gsize i; |
4907 | GBytes *bytes = NULL; |
4908 | GVariant *deserialised_variant = NULL; |
4909 | |
4910 | /* Construct a hierarchy of variants, containing a single string. This is just |
4911 | * below the maximum recursion level, as a series of nested variant types. */ |
4912 | wrapper_variant = g_variant_new_string (string: "hello" ); |
4913 | |
4914 | for (i = 0; i < G_VARIANT_MAX_RECURSION_DEPTH - 1; i++) |
4915 | wrapper_variant = g_variant_new_variant (g_steal_pointer (&wrapper_variant)); |
4916 | |
4917 | /* Serialise and deserialise it as untrusted data, to force normalisation. */ |
4918 | bytes = g_variant_get_data_as_bytes (value: wrapper_variant); |
4919 | deserialised_variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARIANT, |
4920 | bytes, FALSE); |
4921 | g_assert_nonnull (deserialised_variant); |
4922 | g_assert_true (g_variant_is_normal_form (deserialised_variant)); |
4923 | |
4924 | g_bytes_unref (bytes); |
4925 | g_variant_unref (value: deserialised_variant); |
4926 | |
4927 | /* Wrap it once more. Normalisation should now fail. */ |
4928 | wrapper_variant = g_variant_new_variant (g_steal_pointer (&wrapper_variant)); |
4929 | |
4930 | bytes = g_variant_get_data_as_bytes (value: wrapper_variant); |
4931 | deserialised_variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARIANT, |
4932 | bytes, FALSE); |
4933 | g_assert_nonnull (deserialised_variant); |
4934 | g_assert_false (g_variant_is_normal_form (deserialised_variant)); |
4935 | |
4936 | g_variant_unref (value: deserialised_variant); |
4937 | |
4938 | /* Deserialise it again, but trusted this time. This should succeed. */ |
4939 | deserialised_variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARIANT, |
4940 | bytes, TRUE); |
4941 | g_assert_nonnull (deserialised_variant); |
4942 | g_assert_true (g_variant_is_normal_form (deserialised_variant)); |
4943 | |
4944 | g_bytes_unref (bytes); |
4945 | g_variant_unref (value: deserialised_variant); |
4946 | g_variant_unref (value: wrapper_variant); |
4947 | } |
4948 | |
4949 | /* Check that deeply nested arrays are not considered in normal form when |
4950 | * deserialised from untrusted data after being wrapped in a variant. This is |
4951 | * worth testing, because neither the deeply nested array, nor the variant, |
4952 | * have a static #GVariantType which is too deep — only when nested together do |
4953 | * they become too deep. */ |
4954 | static void |
4955 | test_recursion_limits_array_in_variant (void) |
4956 | { |
4957 | GVariant *child_variant = NULL; |
4958 | GVariant *wrapper_variant = NULL; |
4959 | gsize i; |
4960 | GBytes *bytes = NULL; |
4961 | GVariant *deserialised_variant = NULL; |
4962 | |
4963 | /* Construct a hierarchy of arrays, containing a single string. This is just |
4964 | * below the maximum recursion level, all in a single definite type. */ |
4965 | child_variant = g_variant_new_string (string: "hello" ); |
4966 | |
4967 | for (i = 0; i < G_VARIANT_MAX_RECURSION_DEPTH - 1; i++) |
4968 | child_variant = g_variant_new_array (NULL, children: &child_variant, n_children: 1); |
4969 | |
4970 | /* Serialise and deserialise it as untrusted data, to force normalisation. */ |
4971 | bytes = g_variant_get_data_as_bytes (value: child_variant); |
4972 | deserialised_variant = g_variant_new_from_bytes (type: g_variant_get_type (value: child_variant), |
4973 | bytes, FALSE); |
4974 | g_assert_nonnull (deserialised_variant); |
4975 | g_assert_true (g_variant_is_normal_form (deserialised_variant)); |
4976 | |
4977 | g_bytes_unref (bytes); |
4978 | g_variant_unref (value: deserialised_variant); |
4979 | |
4980 | /* Wrap it in a variant. Normalisation should now fail. */ |
4981 | wrapper_variant = g_variant_new_variant (g_steal_pointer (&child_variant)); |
4982 | |
4983 | bytes = g_variant_get_data_as_bytes (value: wrapper_variant); |
4984 | deserialised_variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARIANT, |
4985 | bytes, FALSE); |
4986 | g_assert_nonnull (deserialised_variant); |
4987 | g_assert_false (g_variant_is_normal_form (deserialised_variant)); |
4988 | |
4989 | g_variant_unref (value: deserialised_variant); |
4990 | |
4991 | /* Deserialise it again, but trusted this time. This should succeed. */ |
4992 | deserialised_variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARIANT, |
4993 | bytes, TRUE); |
4994 | g_assert_nonnull (deserialised_variant); |
4995 | g_assert_true (g_variant_is_normal_form (deserialised_variant)); |
4996 | |
4997 | g_bytes_unref (bytes); |
4998 | g_variant_unref (value: deserialised_variant); |
4999 | g_variant_unref (value: wrapper_variant); |
5000 | } |
5001 | |
5002 | /* Test that an array with invalidly large values in its offset table is |
5003 | * normalised successfully without looping infinitely. */ |
5004 | static void |
5005 | test_normal_checking_array_offsets (void) |
5006 | { |
5007 | const guint8 data[] = { |
5008 | 0x07, 0xe5, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, |
5009 | 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'g', |
5010 | }; |
5011 | gsize size = sizeof (data); |
5012 | GVariant *variant = NULL; |
5013 | GVariant *normal_variant = NULL; |
5014 | |
5015 | variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size, |
5016 | FALSE, NULL, NULL); |
5017 | g_assert_nonnull (variant); |
5018 | |
5019 | normal_variant = g_variant_get_normal_form (value: variant); |
5020 | g_assert_nonnull (normal_variant); |
5021 | |
5022 | g_variant_unref (value: normal_variant); |
5023 | g_variant_unref (value: variant); |
5024 | } |
5025 | |
5026 | /* Test that a tuple with invalidly large values in its offset table is |
5027 | * normalised successfully without looping infinitely. */ |
5028 | static void |
5029 | test_normal_checking_tuple_offsets (void) |
5030 | { |
5031 | const guint8 data[] = { |
5032 | 0x07, 0xe5, 0x00, 0x07, 0x00, 0x07, |
5033 | '(', 'a', 's', 'a', 's', 'a', 's', 'a', 's', 'a', 's', 'a', 's', ')', |
5034 | }; |
5035 | gsize size = sizeof (data); |
5036 | GVariant *variant = NULL; |
5037 | GVariant *normal_variant = NULL; |
5038 | |
5039 | variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size, |
5040 | FALSE, NULL, NULL); |
5041 | g_assert_nonnull (variant); |
5042 | |
5043 | normal_variant = g_variant_get_normal_form (value: variant); |
5044 | g_assert_nonnull (normal_variant); |
5045 | |
5046 | g_variant_unref (value: normal_variant); |
5047 | g_variant_unref (value: variant); |
5048 | } |
5049 | |
5050 | /* Test that an empty object path is normalised successfully to the base object |
5051 | * path, ‘/’. */ |
5052 | static void |
5053 | test_normal_checking_empty_object_path (void) |
5054 | { |
5055 | const guint8 data[] = { |
5056 | 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, |
5057 | '(', 'h', '(', 'a', 'i', 'a', 'b', 'i', 'o', ')', ')', |
5058 | }; |
5059 | gsize size = sizeof (data); |
5060 | GVariant *variant = NULL; |
5061 | GVariant *normal_variant = NULL; |
5062 | |
5063 | variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size, |
5064 | FALSE, NULL, NULL); |
5065 | g_assert_nonnull (variant); |
5066 | |
5067 | normal_variant = g_variant_get_normal_form (value: variant); |
5068 | g_assert_nonnull (normal_variant); |
5069 | |
5070 | g_variant_unref (value: normal_variant); |
5071 | g_variant_unref (value: variant); |
5072 | } |
5073 | |
5074 | /* Test that constructing a #GVariant from data which is not correctly aligned |
5075 | * for the variant type is OK, by loading a variant from data at various offsets |
5076 | * which are aligned and unaligned. When unaligned, a slow construction path |
5077 | * should be taken. */ |
5078 | static void |
5079 | test_unaligned_construction (void) |
5080 | { |
5081 | const guint8 data[] = { |
5082 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
5083 | 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, |
5084 | }; |
5085 | GVariant *variant = NULL; |
5086 | GVariant *normal_variant = NULL; |
5087 | gsize i, offset; |
5088 | const struct { |
5089 | const GVariantType *type; |
5090 | gsize size; |
5091 | gsize max_offset; |
5092 | } vectors[] = { |
5093 | { G_VARIANT_TYPE_UINT64, sizeof (guint64), sizeof (guint64) }, |
5094 | { G_VARIANT_TYPE_UINT32, sizeof (guint32), sizeof (guint32) }, |
5095 | { G_VARIANT_TYPE_UINT16, sizeof (guint16), sizeof (guint16) }, |
5096 | { G_VARIANT_TYPE_BYTE, sizeof (guint8), 3 }, |
5097 | }; |
5098 | |
5099 | G_STATIC_ASSERT (sizeof (guint64) * 2 <= sizeof (data)); |
5100 | |
5101 | for (i = 0; i < G_N_ELEMENTS (vectors); i++) |
5102 | { |
5103 | for (offset = 0; offset < vectors[i].max_offset; offset++) |
5104 | { |
5105 | variant = g_variant_new_from_data (type: vectors[i].type, data: data + offset, |
5106 | size: vectors[i].size, |
5107 | FALSE, NULL, NULL); |
5108 | g_assert_nonnull (variant); |
5109 | |
5110 | normal_variant = g_variant_get_normal_form (value: variant); |
5111 | g_assert_nonnull (normal_variant); |
5112 | |
5113 | g_variant_unref (value: normal_variant); |
5114 | g_variant_unref (value: variant); |
5115 | } |
5116 | } |
5117 | } |
5118 | |
5119 | int |
5120 | main (int argc, char **argv) |
5121 | { |
5122 | guint i; |
5123 | |
5124 | g_test_init (argc: &argc, argv: &argv, NULL); |
5125 | g_test_bug_base (uri_pattern: "" ); |
5126 | |
5127 | g_test_add_func (testpath: "/gvariant/type" , test_func: test_gvarianttype); |
5128 | g_test_add_func (testpath: "/gvariant/type/string-scan/recursion/tuple" , |
5129 | test_func: test_gvarianttype_string_scan_recursion_tuple); |
5130 | g_test_add_func (testpath: "/gvariant/type/string-scan/recursion/array" , |
5131 | test_func: test_gvarianttype_string_scan_recursion_array); |
5132 | g_test_add_func (testpath: "/gvariant/typeinfo" , test_func: test_gvarianttypeinfo); |
5133 | g_test_add_func (testpath: "/gvariant/serialiser/maybe" , test_func: test_maybes); |
5134 | g_test_add_func (testpath: "/gvariant/serialiser/array" , test_func: test_arrays); |
5135 | g_test_add_func (testpath: "/gvariant/serialiser/tuple" , test_func: test_tuples); |
5136 | g_test_add_func (testpath: "/gvariant/serialiser/variant" , test_func: test_variants); |
5137 | g_test_add_func (testpath: "/gvariant/serialiser/strings" , test_func: test_strings); |
5138 | g_test_add_func (testpath: "/gvariant/serialiser/byteswap" , test_func: test_byteswaps); |
5139 | g_test_add_func (testpath: "/gvariant/serialiser/children" , test_func: test_serialiser_children); |
5140 | |
5141 | for (i = 1; i <= 20; i += 4) |
5142 | { |
5143 | char *testname; |
5144 | |
5145 | testname = g_strdup_printf (format: "/gvariant/serialiser/fuzz/%u%%" , i); |
5146 | g_test_add_data_func (testpath: testname, GINT_TO_POINTER (i), |
5147 | test_func: (gpointer) test_fuzzes); |
5148 | g_free (mem: testname); |
5149 | } |
5150 | |
5151 | g_test_add_func (testpath: "/gvariant/string" , test_func: test_string); |
5152 | g_test_add_func (testpath: "/gvariant/utf8" , test_func: test_utf8); |
5153 | g_test_add_func (testpath: "/gvariant/containers" , test_func: test_containers); |
5154 | g_test_add_func (testpath: "/gvariant/format-strings" , test_func: test_format_strings); |
5155 | g_test_add_func (testpath: "/gvariant/invalid-varargs" , test_func: test_invalid_varargs); |
5156 | g_test_add_func (testpath: "/gvariant/varargs" , test_func: test_varargs); |
5157 | g_test_add_func (testpath: "/gvariant/varargs/subprocess/empty-array" , test_func: test_varargs_empty_array); |
5158 | g_test_add_func (testpath: "/gvariant/valist" , test_func: test_valist); |
5159 | g_test_add_func (testpath: "/gvariant/builder-memory" , test_func: test_builder_memory); |
5160 | g_test_add_func (testpath: "/gvariant/hashing" , test_func: test_hashing); |
5161 | g_test_add_func (testpath: "/gvariant/byteswap" , test_func: test_gv_byteswap); |
5162 | g_test_add_func (testpath: "/gvariant/parser" , test_func: test_parses); |
5163 | g_test_add_func (testpath: "/gvariant/parser/integer-bounds" , test_func: test_parser_integer_bounds); |
5164 | g_test_add_func (testpath: "/gvariant/parser/recursion" , test_func: test_parser_recursion); |
5165 | g_test_add_func (testpath: "/gvariant/parse-failures" , test_func: test_parse_failures); |
5166 | g_test_add_func (testpath: "/gvariant/parse-positional" , test_func: test_parse_positional); |
5167 | g_test_add_func (testpath: "/gvariant/parse/subprocess/bad-format-char" , test_func: test_parse_bad_format_char); |
5168 | g_test_add_func (testpath: "/gvariant/parse/subprocess/bad-format-string" , test_func: test_parse_bad_format_string); |
5169 | g_test_add_func (testpath: "/gvariant/parse/subprocess/bad-args" , test_func: test_parse_bad_args); |
5170 | g_test_add_func (testpath: "/gvariant/floating" , test_func: test_floating); |
5171 | g_test_add_func (testpath: "/gvariant/bytestring" , test_func: test_bytestring); |
5172 | g_test_add_func (testpath: "/gvariant/lookup-value" , test_func: test_lookup_value); |
5173 | g_test_add_func (testpath: "/gvariant/lookup" , test_func: test_lookup); |
5174 | g_test_add_func (testpath: "/gvariant/compare" , test_func: test_compare); |
5175 | g_test_add_func (testpath: "/gvariant/equal" , test_func: test_equal); |
5176 | g_test_add_func (testpath: "/gvariant/fixed-array" , test_func: test_fixed_array); |
5177 | g_test_add_func (testpath: "/gvariant/check-format-string" , test_func: test_check_format_string); |
5178 | |
5179 | g_test_add_func (testpath: "/gvariant/checksum-basic" , test_func: test_checksum_basic); |
5180 | g_test_add_func (testpath: "/gvariant/checksum-nested" , test_func: test_checksum_nested); |
5181 | |
5182 | g_test_add_func (testpath: "/gvariant/gbytes" , test_func: test_gbytes); |
5183 | g_test_add_func (testpath: "/gvariant/print-context" , test_func: test_print_context); |
5184 | g_test_add_func (testpath: "/gvariant/error-quark" , test_func: test_error_quark); |
5185 | |
5186 | g_test_add_func (testpath: "/gvariant/stack-builder-init" , test_func: test_stack_builder_init); |
5187 | g_test_add_func (testpath: "/gvariant/stack-dict-init" , test_func: test_stack_dict_init); |
5188 | |
5189 | g_test_add_func (testpath: "/gvariant/normal-checking/tuples" , |
5190 | test_func: test_normal_checking_tuples); |
5191 | g_test_add_func (testpath: "/gvariant/normal-checking/array-offsets" , |
5192 | test_func: test_normal_checking_array_offsets); |
5193 | g_test_add_func (testpath: "/gvariant/normal-checking/tuple-offsets" , |
5194 | test_func: test_normal_checking_tuple_offsets); |
5195 | g_test_add_func (testpath: "/gvariant/normal-checking/empty-object-path" , |
5196 | test_func: test_normal_checking_empty_object_path); |
5197 | |
5198 | g_test_add_func (testpath: "/gvariant/recursion-limits/variant-in-variant" , |
5199 | test_func: test_recursion_limits_variant_in_variant); |
5200 | g_test_add_func (testpath: "/gvariant/recursion-limits/array-in-variant" , |
5201 | test_func: test_recursion_limits_array_in_variant); |
5202 | |
5203 | g_test_add_func (testpath: "/gvariant/unaligned-construction" , |
5204 | test_func: test_unaligned_construction); |
5205 | |
5206 | return g_test_run (); |
5207 | } |
5208 | |