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