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
38static gboolean
39randomly (gdouble prob)
40{
41 return g_test_rand_double_range (range_start: 0, range_end: 1) < prob;
42}
43
44/* corecursion */
45static GVariantType *
46append_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 */
52static GVariantType *
53append_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
189static GVariantType *
190append_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 */
230static gchar *
231invalid_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 */
351static gchar *
352describe_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 */
483static gchar *
484generate_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
540struct 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 */
550static void
551subtype_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
587static void
588test_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). */
665static void
666test_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. */
691static void
692test_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 */
720static void
721calculate_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 */
843static gchar *
844describe_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 */
931static void
932check_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
1015static void
1016test_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 */
1103static gchar *
1104random_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
1136typedef 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
1149static RandomInstance *
1150random_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
1181static void
1182random_instance_free (RandomInstance *instance)
1183{
1184 g_variant_type_info_unref (typeinfo: instance->type_info);
1185 g_slice_free (RandomInstance, instance);
1186}
1187
1188static void
1189append_instance_size (RandomInstance *instance,
1190 gsize *offset)
1191{
1192 *offset += (-*offset) & instance->alignment;
1193 *offset += instance->size;
1194}
1195
1196static void
1197random_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
1211static void
1212append_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
1222static gboolean
1223random_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
1245static gboolean
1246random_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
1267static void
1268random_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
1290static gsize
1291calculate_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
1310static gpointer
1311flavoured_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
1321static void
1322flavoured_free (gpointer data,
1323 gsize flavour)
1324{
1325 if (!data)
1326 return;
1327 g_free (mem: ((gchar *) data) - flavour);
1328}
1329
1330static gpointer
1331align_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
1349static void
1350align_free (gpointer mem)
1351{
1352 free (ptr: mem);
1353}
1354
1355static void
1356append_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
1371static void
1372prepend_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
1387static void
1388test_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
1465static void
1466test_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
1476static void
1477test_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
1607static void
1608test_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
1618static void
1619test_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
1770static void
1771test_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
1781static void
1782test_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
1854static void
1855test_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
1865static void
1866test_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
1931typedef struct _TreeInstance TreeInstance;
1932struct _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
1947static GVariantType *
1948make_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
1963static void
1964make_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
1984static TreeInstance *
1985tree_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
2089static void
2090tree_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
2101static gboolean i_am_writing_byteswapped;
2102
2103static void
2104tree_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
2185static gboolean
2186check_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
2256static void
2257serialise_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
2268static void
2269test_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
2291static void
2292test_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
2302static void
2303test_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
2342static void
2343test_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
2398static void
2399test_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
2412static GVariant *
2413tree_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
2558static gboolean
2559tree_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
2680static void
2681tree_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
2723static gboolean
2724tree_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
2768static void
2769test_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
2821static void
2822test_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
2841static void
2842test_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
2872static void
2873test_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
2885static void
2886test_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
2933static void
2934do_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
2942static void
2943test_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
2977static void
2978check_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
2987static void
2988test_varargs_empty_array (void)
2989{
2990 g_variant_new (format_string: "(a{s*})", NULL);
2991
2992 g_assert_not_reached ();
2993}
2994
2995static void
2996test_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
3597static void
3598hash_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
3616static GVariant *
3617hash_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
3637static void
3638test_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
3658static void
3659test_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
3689static void
3690test_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
3735static void
3736test_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
3809static void
3810test_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
3843static void
3844test_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
3965static void
3966test_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. */
4139static void
4140test_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. */
4168static void
4169test_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
4190static void
4191test_parse_bad_format_char (void)
4192{
4193 g_variant_new_parsed (format: "%z");
4194
4195 g_assert_not_reached ();
4196}
4197
4198static void
4199test_parse_bad_format_string (void)
4200{
4201 g_variant_new_parsed (format: "uint32 %i", 2);
4202
4203 g_assert_not_reached ();
4204}
4205
4206static void
4207test_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
4214static void
4215test_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
4240static void
4241test_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
4252static void
4253test_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
4335static void
4336test_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
4372static void
4373test_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
4407static GVariant *
4408untrusted (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
4423static void
4424test_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
4491static void
4492test_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
4564static void
4565test_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
4594static void
4595test_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
4650static void
4651verify_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
4663static void
4664verify_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
4690static void
4691test_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
4709static void
4710test_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
4728static void
4729test_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
4769typedef struct {
4770 const GVariantType *type;
4771 const gchar *in;
4772 const gchar *out;
4773} ContextTest;
4774
4775static void
4776test_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
4802static void
4803test_error_quark (void)
4804{
4805G_GNUC_BEGIN_IGNORE_DEPRECATIONS
4806 g_assert_cmpuint (g_variant_parser_get_error_quark (), ==, g_variant_parse_error_quark ());
4807G_GNUC_END_IGNORE_DEPRECATIONS
4808}
4809
4810static void
4811test_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
4831static GVariant *
4832get_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
4842static void
4843test_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. */
4878static void
4879test_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.*/
4902static void
4903test_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. */
4954static void
4955test_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. */
5004static void
5005test_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. */
5028static void
5029test_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, ‘/’. */
5052static void
5053test_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. */
5078static void
5079test_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
5119int
5120main (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

source code of gtk/subprojects/glib/glib/tests/gvariant.c