GVariant variable arguments, tests, cleanups
[platform/upstream/glib.git] / glib / tests / gvariant.c
1 /*
2  * Copyright © 2010 Codethink Limited
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the licence, or (at your option) any later version.
8  *
9  * See the included COPYING file for more information.
10  *
11  * Author: Ryan Lortie <desrt@desrt.ca>
12  */
13
14 #include <glib/gvariant-internal.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <glib.h>
18
19 #define BASIC "bynqiuxthdsog?"
20 #define N_BASIC (G_N_ELEMENTS (BASIC) - 1)
21
22 #define INVALIDS "cefjklpwz&@^$"
23 #define N_INVALIDS (G_N_ELEMENTS (INVALIDS) - 1)
24
25 static gboolean
26 randomly (gdouble prob)
27 {
28   return g_test_rand_double_range (0, 1) < prob;
29 }
30
31 /* corecursion */
32 static GVariantType *
33 append_tuple_type_string (GString *, GString *, gboolean, gint);
34
35 /* append a random GVariantType to a GString
36  * append a description of the type to another GString
37  * return what the type is
38  */
39 static GVariantType *
40 append_type_string (GString  *string,
41                     GString  *description,
42                     gboolean  definite,
43                     gint      depth)
44 {
45   if (!depth-- || randomly (0.3))
46     {
47       gchar b = BASIC[g_test_rand_int_range (0, N_BASIC - definite)];
48       g_string_append_c (string, b);
49       g_string_append_c (description, b);
50
51       switch (b)
52         {
53         case 'b':
54           return g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN);
55         case 'y':
56           return g_variant_type_copy (G_VARIANT_TYPE_BYTE);
57         case 'n':
58           return g_variant_type_copy (G_VARIANT_TYPE_INT16);
59         case 'q':
60           return g_variant_type_copy (G_VARIANT_TYPE_UINT16);
61         case 'i':
62           return g_variant_type_copy (G_VARIANT_TYPE_INT32);
63         case 'u':
64           return g_variant_type_copy (G_VARIANT_TYPE_UINT32);
65         case 'x':
66           return g_variant_type_copy (G_VARIANT_TYPE_INT64);
67         case 't':
68           return g_variant_type_copy (G_VARIANT_TYPE_UINT64);
69         case 'h':
70           return g_variant_type_copy (G_VARIANT_TYPE_HANDLE);
71         case 'd':
72           return g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
73         case 's':
74           return g_variant_type_copy (G_VARIANT_TYPE_STRING);
75         case 'o':
76           return g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH);
77         case 'g':
78           return g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE);
79         case '?':
80           return g_variant_type_copy (G_VARIANT_TYPE_BASIC);
81         default:
82           g_assert_not_reached ();
83         }
84     }
85   else
86     {
87       GVariantType *result;
88
89       switch (g_test_rand_int_range (0, definite ? 5 : 7))
90         {
91         case 0:
92           {
93             GVariantType *element;
94
95             g_string_append_c (string, 'a');
96             g_string_append (description, "a of ");
97             element = append_type_string (string, description,
98                                           definite, depth);
99             result = g_variant_type_new_array (element);
100             g_variant_type_free (element);
101           }
102
103           g_assert (g_variant_type_is_array (result));
104           break;
105
106         case 1:
107           {
108             GVariantType *element;
109
110             g_string_append_c (string, 'm');
111             g_string_append (description, "m of ");
112             element = append_type_string (string, description,
113                                           definite, depth);
114             result = g_variant_type_new_maybe (element);
115             g_variant_type_free (element);
116           }
117
118           g_assert (g_variant_type_is_maybe (result));
119           break;
120
121         case 2:
122           result = append_tuple_type_string (string, description,
123                                              definite, depth);
124
125           g_assert (g_variant_type_is_tuple (result));
126           break;
127
128         case 3:
129           {
130             GVariantType *key, *value;
131
132             g_string_append_c (string, '{');
133             g_string_append (description, "e of [");
134             key = append_type_string (string, description, definite, 0);
135             g_string_append (description, ", ");
136             value = append_type_string (string, description, definite, depth);
137             g_string_append_c (description, ']');
138             g_string_append_c (string, '}');
139             result = g_variant_type_new_dict_entry (key, value);
140             g_variant_type_free (key);
141             g_variant_type_free (value);
142           }
143
144           g_assert (g_variant_type_is_dict_entry (result));
145           break;
146
147         case 4:
148           g_string_append_c (string, 'v');
149           g_string_append_c (description, 'V');
150           result = g_variant_type_copy (G_VARIANT_TYPE_VARIANT);
151           g_assert (g_variant_type_equal (result, G_VARIANT_TYPE_VARIANT));
152           break;
153
154         case 5:
155           g_string_append_c (string, '*');
156           g_string_append_c (description, 'S');
157           result = g_variant_type_copy (G_VARIANT_TYPE_ANY);
158           g_assert (g_variant_type_equal (result, G_VARIANT_TYPE_ANY));
159           break;
160
161         case 6:
162           g_string_append_c (string, 'r');
163           g_string_append_c (description, 'R');
164           result = g_variant_type_copy (G_VARIANT_TYPE_TUPLE);
165           g_assert (g_variant_type_is_tuple (result));
166           break;
167
168         default:
169           g_assert_not_reached ();
170         }
171
172       return result;
173     }
174 }
175
176 static GVariantType *
177 append_tuple_type_string (GString  *string,
178                           GString  *description,
179                           gboolean  definite,
180                           gint      depth)
181 {
182   GVariantType *result, *other_result;
183   GVariantType **types;
184   gint size;
185   gint i;
186
187   g_string_append_c (string, '(');
188   g_string_append (description, "t of [");
189
190   size = g_test_rand_int_range (0, 20);
191   types = g_new (GVariantType *, size + 1);
192
193   for (i = 0; i < size; i++)
194     {
195       types[i] = append_type_string (string, description, definite, depth);
196
197       if (i < size - 1)
198         g_string_append (description, ", ");
199     }
200
201   types[i] = NULL;
202
203   g_string_append_c (description, ']');
204   g_string_append_c (string, ')');
205
206   result = g_variant_type_new_tuple ((gpointer) types, size);
207   other_result = g_variant_type_new_tuple ((gpointer) types, -1);
208   g_assert (g_variant_type_equal (result, other_result));
209   g_variant_type_free (other_result);
210   for (i = 0; i < size; i++)
211     g_variant_type_free (types[i]);
212   g_free (types);
213
214   return result;
215 }
216
217 /* given a valid type string, make it invalid */
218 static gchar *
219 invalid_mutation (const gchar *type_string)
220 {
221   gboolean have_parens, have_braces;
222
223   /* it's valid, so '(' implies ')' and same for '{' and '}' */
224   have_parens = strchr (type_string, '(') != NULL;
225   have_braces = strchr (type_string, '{') != NULL;
226
227   if (have_parens && have_braces && randomly (0.3))
228     {
229       /* swap a paren and a brace */
230       gchar *pp, *bp;
231       gint np, nb;
232       gchar p, b;
233       gchar *new;
234
235       new = g_strdup (type_string);
236
237       if (randomly (0.5))
238         p = '(', b = '{';
239       else
240         p = ')', b = '}';
241
242       np = nb = 0;
243       pp = bp = new - 1;
244
245       /* count number of parens/braces */
246       while ((pp = strchr (pp + 1, p))) np++;
247       while ((bp = strchr (bp + 1, b))) nb++;
248
249       /* randomly pick one of each */
250       np = g_test_rand_int_range (0, np) + 1;
251       nb = g_test_rand_int_range (0, nb) + 1;
252
253       /* find it */
254       pp = bp = new - 1;
255       while (np--) pp = strchr (pp + 1, p);
256       while (nb--) bp = strchr (bp + 1, b);
257
258       /* swap */
259       g_assert (*bp == b && *pp == p);
260       *bp = p;
261       *pp = b;
262
263       return new;
264     }
265
266   if ((have_parens || have_braces) && randomly (0.3))
267     {
268       /* drop a paren/brace */
269       gchar *new;
270       gchar *pp;
271       gint np;
272       gchar p;
273
274       if (have_parens)
275         if (randomly (0.5)) p = '('; else p = ')';
276       else
277         if (randomly (0.5)) p = '{'; else p = '}';
278
279       new = g_strdup (type_string);
280
281       np = 0;
282       pp = new - 1;
283       while ((pp = strchr (pp + 1, p))) np++;
284       np = g_test_rand_int_range (0, np) + 1;
285       pp = new - 1;
286       while (np--) pp = strchr (pp + 1, p);
287       g_assert (*pp == p);
288
289       while (*pp)
290         {
291           *pp = *(pp + 1);
292           pp++;
293         }
294
295       return new;
296     }
297
298   /* else, perform a random mutation at a random point */
299   {
300     gint length, n;
301     gchar *new;
302     gchar p;
303
304     if (randomly (0.3))
305       {
306         /* insert a paren/brace */
307         if (randomly (0.5))
308           if (randomly (0.5)) p = '('; else p = ')';
309         else
310           if (randomly (0.5)) p = '{'; else p = '}';
311       }
312     else if (randomly (0.5))
313       {
314         /* insert junk */
315         p = INVALIDS[g_test_rand_int_range (0, N_INVALIDS)];
316       }
317     else
318       {
319         /* truncate */
320         p = '\0';
321       }
322
323
324     length = strlen (type_string);
325     new = g_malloc (length + 2);
326     n = g_test_rand_int_range (0, length);
327     memcpy (new, type_string, n);
328     new[n] = p;
329     memcpy (new + n + 1, type_string + n, length - n);
330     new[length + 1] = '\0';
331
332     return new;
333   }
334 }
335
336 /* describe a type using the same language as is generated
337  * while generating the type with append_type_string
338  */
339 static gchar *
340 describe_type (const GVariantType *type)
341 {
342   gchar *result;
343
344   if (g_variant_type_is_container (type))
345     {
346       g_assert (!g_variant_type_is_basic (type));
347
348       if (g_variant_type_is_array (type))
349         {
350           gchar *subtype = describe_type (g_variant_type_element (type));
351           result = g_strdup_printf ("a of %s", subtype);
352           g_free (subtype);
353         }
354       else if (g_variant_type_is_maybe (type))
355         {
356           gchar *subtype = describe_type (g_variant_type_element (type));
357           result = g_strdup_printf ("m of %s", subtype);
358           g_free (subtype);
359         }
360       else if (g_variant_type_is_tuple (type))
361         {
362           if (!g_variant_type_equal (type, G_VARIANT_TYPE_TUPLE))
363             {
364               const GVariantType *sub;
365               GString *string;
366               gint length;
367               gint i;
368
369               string = g_string_new ("t of [");
370
371               length = g_variant_type_n_items (type);
372               sub = g_variant_type_first (type);
373               for (i = 0; i < length; i++)
374                 {
375                   gchar *subtype = describe_type (sub);
376                   g_string_append (string, subtype);
377                   g_free (subtype);
378
379                   if ((sub = g_variant_type_next (sub)))
380                     g_string_append (string, ", ");
381                 }
382               g_assert (sub == NULL);
383               g_string_append_c (string, ']');
384
385               result = g_string_free (string, FALSE);
386             }
387           else
388             result = g_strdup ("R");
389         }
390       else if (g_variant_type_is_dict_entry (type))
391         {
392           gchar *key, *value, *key2, *value2;
393
394           key = describe_type (g_variant_type_key (type));
395           value = describe_type (g_variant_type_value (type));
396           key2 = describe_type (g_variant_type_first (type));
397           value2 = describe_type (
398             g_variant_type_next (g_variant_type_first (type)));
399           g_assert (g_variant_type_next (g_variant_type_next (
400             g_variant_type_first (type))) == NULL);
401           g_assert_cmpstr (key, ==, key2);
402           g_assert_cmpstr (value, ==, value2);
403           result = g_strjoin ("", "e of [", key, ", ", value, "]", NULL);
404           g_free (key2);
405           g_free (value2);
406           g_free (key);
407           g_free (value);
408         }
409       else if (g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT))
410         {
411           result = g_strdup ("V");
412         }
413       else
414         g_assert_not_reached ();
415     }
416   else
417     {
418       if (g_variant_type_is_definite (type))
419         {
420           g_assert (g_variant_type_is_basic (type));
421
422           if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
423             result = g_strdup ("b");
424           else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
425             result = g_strdup ("y");
426           else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
427             result = g_strdup ("n");
428           else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
429             result = g_strdup ("q");
430           else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
431             result = g_strdup ("i");
432           else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
433             result = g_strdup ("u");
434           else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
435             result = g_strdup ("x");
436           else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
437             result = g_strdup ("t");
438           else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
439             result = g_strdup ("h");
440           else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
441             result = g_strdup ("d");
442           else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
443             result = g_strdup ("s");
444           else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
445             result = g_strdup ("o");
446           else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
447             result = g_strdup ("g");
448           else
449             g_assert_not_reached ();
450         }
451       else
452         {
453           if (g_variant_type_equal (type, G_VARIANT_TYPE_ANY))
454             {
455               result = g_strdup ("S");
456             }
457           else if (g_variant_type_equal (type, G_VARIANT_TYPE_BASIC))
458             {
459               result = g_strdup ("?");
460             }
461           else
462             g_assert_not_reached ();
463         }
464     }
465
466   return result;
467 }
468
469 /* given a type string, replace one of the indefinite type characters in
470  * it with a matching type (possibly the same type).
471  */
472 static gchar *
473 generate_subtype (const gchar *type_string)
474 {
475   GVariantType *replacement;
476   GString *result, *junk;
477   gint length, n = 0, l;
478
479   result = g_string_new (NULL);
480   junk = g_string_new (NULL);
481
482   /* count the number of indefinite type characters */
483   for (length = 0; type_string[length]; length++)
484     n += type_string[length] == 'r' ||
485          type_string[length] == '?' ||
486          type_string[length] == '*';
487   /* length now is strlen (type_string) */
488
489   /* pick one at random to replace */
490   n = g_test_rand_int_range (0, n) + 1;
491
492   /* find it */
493   l = -1;
494   while (n--) l += strcspn (type_string + l + 1, "r?*") + 1;
495   g_assert (type_string[l] == 'r' ||
496             type_string[l] == '?' ||
497             type_string[l] == '*');
498
499   /* store up to that point in a GString */
500   g_string_append_len (result, type_string, l);
501
502   /* then store the replacement in the GString */
503   if (type_string[l] == 'r')
504     replacement = append_tuple_type_string (result, junk, FALSE, 3);
505
506   else if (type_string[l] == '?')
507     replacement = append_type_string (result, junk, FALSE, 0);
508
509   else if (type_string[l] == '*')
510     replacement = append_type_string (result, junk, FALSE, 3);
511
512   else
513     g_assert_not_reached ();
514
515   /* ensure the replacement has the proper type */
516   g_assert (g_variant_type_is_subtype_of (replacement,
517                                           (gpointer) &type_string[l]));
518
519   /* store the rest from the original type string */
520   g_string_append (result, type_string + l + 1);
521
522   g_variant_type_free (replacement);
523   g_string_free (junk, TRUE);
524
525   return g_string_free (result, FALSE);
526 }
527
528 struct typestack
529 {
530   const GVariantType *type;
531   struct typestack *parent;
532 };
533
534 /* given an indefinite type string, replace one of the indefinite
535  * characters in it with a matching type and ensure that the result is a
536  * subtype of the original.  repeat.
537  */
538 static void
539 subtype_check (const gchar      *type_string,
540                struct typestack *parent_ts)
541 {
542   struct typestack ts, *node;
543   gchar *subtype;
544   gint depth = 0;
545
546   subtype = generate_subtype (type_string);
547
548   ts.type = G_VARIANT_TYPE (subtype);
549   ts.parent = parent_ts;
550
551   for (node = &ts; node; node = node->parent)
552     {
553       /* this type should be a subtype of each parent type */
554       g_assert (g_variant_type_is_subtype_of (ts.type, node->type));
555
556       /* it should only be a supertype when it is exactly equal */
557       g_assert (g_variant_type_is_subtype_of (node->type, ts.type) ==
558                 g_variant_type_equal (ts.type, node->type));
559
560       depth++;
561     }
562
563   if (!g_variant_type_is_definite (ts.type) && depth < 5)
564     {
565       /* the type is still indefinite and we haven't repeated too many
566        * times.  go once more.
567        */
568
569       subtype_check (subtype, &ts);
570     }
571
572   g_free (subtype);
573 }
574
575 static void
576 test_gvarianttype (void)
577 {
578   gint i;
579
580   for (i = 0; i < 2000; i++)
581     {
582       GString *type_string, *description;
583       GVariantType *type, *other_type;
584       const GVariantType *ctype;
585       gchar *invalid;
586       gchar *desc;
587
588       type_string = g_string_new (NULL);
589       description = g_string_new (NULL);
590
591       /* generate a random type, its type string and a description
592        *
593        * exercises type constructor functions and g_variant_type_copy()
594        */
595       type = append_type_string (type_string, description, FALSE, 6);
596
597       /* convert the type string to a type and ensure that it is equal
598        * to the one produced with the type constructor routines
599        */
600       ctype = G_VARIANT_TYPE (type_string->str);
601       g_assert (g_variant_type_equal (ctype, type));
602       g_assert (g_variant_type_is_subtype_of (ctype, type));
603       g_assert (g_variant_type_is_subtype_of (type, ctype));
604
605       /* check if the type is indefinite */
606       if (!g_variant_type_is_definite (type))
607         {
608           struct typestack ts = { type, NULL };
609
610           /* if it is indefinite, then replace one of the indefinite
611            * characters with a matching type and ensure that the result
612            * is a subtype of the original type.  repeat.
613            */
614           subtype_check (type_string->str, &ts);
615         }
616       else
617         /* ensure that no indefinite characters appear */
618         g_assert (strcspn (type_string->str, "r?*") == type_string->len);
619
620
621       /* describe the type.
622        *
623        * exercises the type iterator interface
624        */
625       desc = describe_type (type);
626
627       /* make sure the description matches */
628       g_assert_cmpstr (desc, ==, description->str);
629       g_free (desc);
630
631       /* make an invalid mutation to the type and make sure the type
632        * validation routines catch it */
633       invalid = invalid_mutation (type_string->str);
634       g_assert (g_variant_type_string_is_valid (type_string->str));
635       g_assert (!g_variant_type_string_is_valid (invalid));
636       g_free (invalid);
637
638       /* concatenate another type to the type string and ensure that
639        * the result is recognised as being invalid
640        */
641       other_type = append_type_string (type_string, description, FALSE, 2);
642
643       g_string_free (description, TRUE);
644       g_string_free (type_string, TRUE);
645       g_variant_type_free (other_type);
646       g_variant_type_free (type);
647     }
648 }
649
650 #define ALIGNED(x, y)   (((x + (y - 1)) / y) * y)
651
652 /* do our own calculation of the fixed_size and alignment of a type
653  * using a simple algorithm to make sure the "fancy" one in the
654  * implementation is correct.
655  */
656 static void
657 calculate_type_info (const GVariantType *type,
658                      gsize              *fixed_size,
659                      guint              *alignment)
660 {
661   if (g_variant_type_is_array (type) ||
662       g_variant_type_is_maybe (type))
663     {
664       calculate_type_info (g_variant_type_element (type), NULL, alignment);
665
666       if (fixed_size)
667         *fixed_size = 0;
668     }
669   else if (g_variant_type_is_tuple (type) ||
670            g_variant_type_is_dict_entry (type))
671     {
672       if (g_variant_type_n_items (type))
673         {
674           const GVariantType *sub;
675           gboolean variable;
676           gsize size;
677           guint al;
678
679           variable = FALSE;
680           size = 0;
681           al = 0;
682
683           sub = g_variant_type_first (type);
684           do
685             {
686               gsize this_fs;
687               guint this_al;
688
689               calculate_type_info (sub, &this_fs, &this_al);
690
691               al = MAX (al, this_al);
692
693               if (!this_fs)
694                 {
695                   variable = TRUE;
696                   size = 0;
697                 }
698
699               if (!variable)
700                 {
701                   size = ALIGNED (size, this_al);
702                   size += this_fs;
703                 }
704             }
705           while ((sub = g_variant_type_next (sub)));
706
707           size = ALIGNED (size, al);
708
709           if (alignment)
710             *alignment = al;
711
712           if (fixed_size)
713             *fixed_size = size;
714         }
715       else
716         {
717           if (fixed_size)
718             *fixed_size = 1;
719
720           if (alignment)
721             *alignment = 1;
722         }
723     }
724   else
725     {
726       gint fs, al;
727
728       if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN) ||
729           g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
730         {
731           al = fs = 1;
732         }
733
734       else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16) ||
735                g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
736         {
737           al = fs = 2;
738         }
739
740       else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32) ||
741                g_variant_type_equal (type, G_VARIANT_TYPE_UINT32) ||
742                g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
743         {
744           al = fs = 4;
745         }
746
747       else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64) ||
748                g_variant_type_equal (type, G_VARIANT_TYPE_UINT64) ||
749                g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
750         {
751           al = fs = 8;
752         }
753       else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING) ||
754                g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH) ||
755                g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
756         {
757           al = 1;
758           fs = 0;
759         }
760       else if (g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT))
761         {
762           al = 8;
763           fs = 0;
764         }
765       else
766         g_assert_not_reached ();
767
768       if (fixed_size)
769         *fixed_size = fs;
770
771       if (alignment)
772         *alignment = al;
773     }
774 }
775
776 /* same as the describe_type() function above, but iterates over
777  * typeinfo instead of types.
778  */
779 static gchar *
780 describe_info (GVariantTypeInfo *info)
781 {
782   gchar *result;
783
784   switch (g_variant_type_info_get_type_char (info))
785     {
786     case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
787       {
788         gchar *element;
789
790         element = describe_info (g_variant_type_info_element (info));
791         result = g_strdup_printf ("m of %s", element);
792         g_free (element);
793       }
794       break;
795
796     case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
797       {
798         gchar *element;
799
800         element = describe_info (g_variant_type_info_element (info));
801         result = g_strdup_printf ("a of %s", element);
802         g_free (element);
803       }
804       break;
805
806     case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
807       {
808         const gchar *sep = "";
809         GString *string;
810         gint length;
811         gint i;
812
813         string = g_string_new ("t of [");
814         length = g_variant_type_info_n_members (info);
815
816         for (i = 0; i < length; i++)
817           {
818             const GVariantMemberInfo *minfo;
819             gchar *subtype;
820
821             g_string_append (string, sep);
822             sep = ", ";
823
824             minfo = g_variant_type_info_member_info (info, i);
825             subtype = describe_info (minfo->type_info);
826             g_string_append (string, subtype);
827             g_free (subtype);
828           }
829
830         g_string_append_c (string, ']');
831
832         result = g_string_free (string, FALSE);
833       }
834       break;
835
836     case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
837       {
838         const GVariantMemberInfo *keyinfo, *valueinfo;
839         gchar *key, *value;
840
841         g_assert_cmpint (g_variant_type_info_n_members (info), ==, 2);
842         keyinfo = g_variant_type_info_member_info (info, 0);
843         valueinfo = g_variant_type_info_member_info (info, 1);
844         key = describe_info (keyinfo->type_info);
845         value = describe_info (valueinfo->type_info);
846         result = g_strjoin ("", "e of [", key, ", ", value, "]", NULL);
847         g_free (key);
848         g_free (value);
849       }
850       break;
851
852     case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
853       result = g_strdup ("V");
854       break;
855
856     default:
857       result = g_strdup (g_variant_type_info_get_type_string (info));
858       g_assert_cmpint (strlen (result), ==, 1);
859       break;
860     }
861
862   return result;
863 }
864
865 /* check that the O(1) method of calculating offsets meshes with the
866  * results of simple iteration.
867  */
868 static void
869 check_offsets (GVariantTypeInfo   *info,
870                const GVariantType *type)
871 {
872   gint flavour;
873   gint length;
874
875   length = g_variant_type_info_n_members (info);
876   g_assert_cmpint (length, ==, g_variant_type_n_items (type));
877
878   /* the 'flavour' is the low order bits of the ending point of
879    * variable-size items in the tuple.  this lets us test that the type
880    * info is correct for various starting alignments.
881    */
882   for (flavour = 0; flavour < 8; flavour++)
883     {
884       const GVariantType *subtype;
885       gsize last_offset_index;
886       gsize last_offset;
887       gsize position;
888       gint i;
889
890       subtype = g_variant_type_first (type);
891       last_offset_index = -1;
892       last_offset = 0;
893       position = 0;
894
895       /* go through the tuple, keeping track of our position */
896       for (i = 0; i < length; i++)
897         {
898           gsize fixed_size;
899           guint alignment;
900
901           calculate_type_info (subtype, &fixed_size, &alignment);
902
903           position = ALIGNED (position, alignment);
904
905           /* compare our current aligned position (ie: the start of this
906            * item) to the start offset that would be calculated if we
907            * used the type info
908            */
909           {
910             const GVariantMemberInfo *member;
911             gsize start;
912
913             member = g_variant_type_info_member_info (info, i);
914             g_assert_cmpint (member->i, ==, last_offset_index);
915
916             /* do the calculation using the typeinfo */
917             start = last_offset;
918             start += member->a;
919             start &= member->b;
920             start |= member->c;
921
922             /* did we reach the same spot? */
923             g_assert_cmpint (start, ==, position);
924           }
925
926           if (fixed_size)
927             {
928               /* fixed size.  add that size. */
929               position += fixed_size;
930             }
931           else
932             {
933               /* variable size.  do the flavouring. */
934               while ((position & 0x7) != flavour)
935                 position++;
936
937               /* and store the offset, just like it would be in the
938                * serialised data.
939                */
940               last_offset = position;
941               last_offset_index++;
942             }
943
944           /* next type */
945           subtype = g_variant_type_next (subtype);
946         }
947
948       /* make sure we used up exactly all the types */
949       g_assert (subtype == NULL);
950     }
951 }
952
953 static void
954 test_gvarianttypeinfo (void)
955 {
956   gint i;
957
958   for (i = 0; i < 2000; i++)
959     {
960       GString *type_string, *description;
961       gsize fixed_size1, fixed_size2;
962       guint alignment1, alignment2;
963       GVariantTypeInfo *info;
964       GVariantType *type;
965       gchar *desc;
966
967       type_string = g_string_new (NULL);
968       description = g_string_new (NULL);
969
970       /* random type */
971       type = append_type_string (type_string, description, TRUE, 6);
972
973       /* create a typeinfo for it */
974       info = g_variant_type_info_get (type);
975
976       /* make sure the typeinfo has the right type string */
977       g_assert_cmpstr (g_variant_type_info_get_type_string (info), ==,
978                        type_string->str);
979
980       /* calculate the alignment and fixed size, compare to the
981        * typeinfo's calculations
982        */
983       calculate_type_info (type, &fixed_size1, &alignment1);
984       g_variant_type_info_query (info, &alignment2, &fixed_size2);
985       g_assert_cmpint (fixed_size1, ==, fixed_size2);
986       g_assert_cmpint (alignment1, ==, alignment2 + 1);
987
988       /* test the iteration functions over typeinfo structures by
989        * "describing" the typeinfo and verifying equality.
990        */
991       desc = describe_info (info);
992       g_assert_cmpstr (desc, ==, description->str);
993
994       /* do extra checks for containers */
995       if (g_variant_type_is_array (type) ||
996           g_variant_type_is_maybe (type))
997         {
998           const GVariantType *element;
999           gsize efs1, efs2;
1000           guint ea1, ea2;
1001
1002           element = g_variant_type_element (type);
1003           calculate_type_info (element, &efs1, &ea1);
1004           g_variant_type_info_query_element (info, &ea2, &efs2);
1005           g_assert_cmpint (efs1, ==, efs2);
1006           g_assert_cmpint (ea1, ==, ea2 + 1);
1007
1008           g_assert_cmpint (ea1, ==, alignment1);
1009           g_assert_cmpint (0, ==, fixed_size1);
1010         }
1011       else if (g_variant_type_is_tuple (type) ||
1012                g_variant_type_is_dict_entry (type))
1013         {
1014           /* make sure the "magic constants" are working */
1015           check_offsets (info, type);
1016         }
1017
1018       g_string_free (type_string, TRUE);
1019       g_string_free (description, TRUE);
1020       g_variant_type_info_unref (info);
1021       g_variant_type_free (type);
1022       g_free (desc);
1023     }
1024
1025   g_variant_type_info_assert_no_infos ();
1026 }
1027
1028 #define MAX_FIXED_MULTIPLIER    256
1029 #define MAX_INSTANCE_SIZE       1024
1030 #define MAX_ARRAY_CHILDREN      128
1031 #define MAX_TUPLE_CHILDREN      128
1032
1033 /* this function generates a random type such that all characteristics
1034  * that are "interesting" to the serialiser are tested.
1035  *
1036  * this basically means:
1037  *   - test different alignments
1038  *   - test variable sized items and fixed sized items
1039  *   - test different fixed sizes
1040  */
1041 static gchar *
1042 random_type_string (void)
1043 {
1044   const guchar base_types[] = "ynix";
1045   guchar base_type;
1046
1047   base_type = base_types[g_test_rand_int_range (0, 4)];
1048
1049   if (g_test_rand_bit ())
1050     /* construct a fixed-sized type */
1051     {
1052       char type_string[MAX_FIXED_MULTIPLIER];
1053       guint multiplier;
1054       guint i = 0;
1055
1056       multiplier = g_test_rand_int_range (1, sizeof type_string - 1);
1057
1058       type_string[i++] = '(';
1059       while (multiplier--)
1060         type_string[i++] = base_type;
1061       type_string[i++] = ')';
1062
1063       return g_strndup (type_string, i);
1064     }
1065   else
1066     /* construct a variable-sized type */
1067     {
1068       char type_string[2] = { 'a', base_type };
1069
1070       return g_strndup (type_string, 2);
1071     }
1072 }
1073
1074 typedef struct
1075 {
1076   GVariantTypeInfo *type_info;
1077   guint alignment;
1078   gsize size;
1079   gboolean is_fixed_sized;
1080
1081   guint32 seed;
1082
1083 #define INSTANCE_MAGIC    1287582829
1084   guint magic;
1085 } RandomInstance;
1086
1087 static RandomInstance *
1088 random_instance (GVariantTypeInfo *type_info)
1089 {
1090   RandomInstance *instance;
1091
1092   instance = g_slice_new (RandomInstance);
1093
1094   if (type_info == NULL)
1095     {
1096       gchar *str = random_type_string ();
1097       instance->type_info = g_variant_type_info_get (G_VARIANT_TYPE (str));
1098       g_free (str);
1099     }
1100   else
1101     instance->type_info = g_variant_type_info_ref (type_info);
1102
1103   instance->seed = g_test_rand_int ();
1104
1105   g_variant_type_info_query (instance->type_info,
1106                              &instance->alignment,
1107                              &instance->size);
1108
1109   instance->is_fixed_sized = instance->size != 0;
1110
1111   if (!instance->is_fixed_sized)
1112     instance->size = g_test_rand_int_range (0, MAX_INSTANCE_SIZE);
1113
1114   instance->magic = INSTANCE_MAGIC;
1115
1116   return instance;
1117 }
1118
1119 static void
1120 random_instance_free (RandomInstance *instance)
1121 {
1122   g_variant_type_info_unref (instance->type_info);
1123   g_slice_free (RandomInstance, instance);
1124 }
1125
1126 static void
1127 append_instance_size (RandomInstance *instance,
1128                       gsize          *offset)
1129 {
1130   *offset += (-*offset) & instance->alignment;
1131   *offset += instance->size;
1132 }
1133
1134 static void
1135 random_instance_write (RandomInstance *instance,
1136                        guchar         *buffer)
1137 {
1138   GRand *rand;
1139   gint i;
1140
1141   g_assert_cmpint ((gsize) buffer & instance->alignment, ==, 0);
1142
1143   rand = g_rand_new_with_seed (instance->seed);
1144   for (i = 0; i < instance->size; i++)
1145     buffer[i] = g_rand_int (rand);
1146   g_rand_free (rand);
1147 }
1148
1149 static void
1150 append_instance_data (RandomInstance  *instance,
1151                       guchar         **buffer)
1152 {
1153   while (((gsize) *buffer) & instance->alignment)
1154     *(*buffer)++ = '\0';
1155
1156   random_instance_write (instance, *buffer);
1157   *buffer += instance->size;
1158 }
1159
1160 static gboolean
1161 random_instance_assert (RandomInstance *instance,
1162                         guchar         *buffer,
1163                         gsize           size)
1164 {
1165   GRand *rand;
1166   gint i;
1167
1168   g_assert_cmpint ((gsize) buffer & instance->alignment, ==, 0);
1169   g_assert_cmpint (size, ==, instance->size);
1170
1171   rand = g_rand_new_with_seed (instance->seed);
1172   for (i = 0; i < instance->size; i++)
1173     {
1174       guchar byte = g_rand_int (rand);
1175
1176       g_assert (buffer[i] == byte);
1177     }
1178   g_rand_free (rand);
1179
1180   return i == instance->size;
1181 }
1182
1183 static gboolean
1184 random_instance_check (RandomInstance *instance,
1185                        guchar         *buffer,
1186                        gsize           size)
1187 {
1188   GRand *rand;
1189   gint i;
1190
1191   g_assert_cmpint ((gsize) buffer & instance->alignment, ==, 0);
1192
1193   if (size != instance->size)
1194     return FALSE;
1195
1196   rand = g_rand_new_with_seed (instance->seed);
1197   for (i = 0; i < instance->size; i++)
1198     if (buffer[i] != (guchar) g_rand_int (rand))
1199       break;
1200   g_rand_free (rand);
1201
1202   return i == instance->size;
1203 }
1204
1205 static void
1206 random_instance_filler (GVariantSerialised *serialised,
1207                         gpointer            data)
1208 {
1209   RandomInstance *instance = data;
1210
1211   g_assert (instance->magic == INSTANCE_MAGIC);
1212
1213   if (serialised->type_info == NULL)
1214     serialised->type_info = instance->type_info;
1215
1216   if (serialised->size == 0)
1217     serialised->size = instance->size;
1218
1219   g_assert (serialised->type_info == instance->type_info);
1220   g_assert (serialised->size == instance->size);
1221
1222   if (serialised->data)
1223     random_instance_write (instance, serialised->data);
1224 }
1225
1226 static gsize
1227 calculate_offset_size (gsize body_size,
1228                        gsize n_offsets)
1229 {
1230   if (body_size == 0)
1231     return 0;
1232
1233   if (body_size + n_offsets <= G_MAXUINT8)
1234     return 1;
1235
1236   if (body_size + 2 * n_offsets <= G_MAXUINT16)
1237     return 2;
1238
1239   if (body_size + 4 * n_offsets <= G_MAXUINT32)
1240     return 4;
1241
1242   /* the test case won't generate anything bigger */
1243   g_assert_not_reached ();
1244 }
1245
1246 static gpointer
1247 flavoured_malloc (gsize size, gsize flavour)
1248 {
1249   g_assert (flavour < 8);
1250
1251   if (size == 0)
1252     return NULL;
1253
1254   return g_malloc (size + flavour) + flavour;
1255 }
1256
1257 static void
1258 flavoured_free (gpointer data)
1259 {
1260   g_free ((gpointer) (((gsize) data) & ~7));
1261 }
1262
1263 static void
1264 append_offset (guchar **offset_ptr,
1265                gsize    offset,
1266                guint    offset_size)
1267 {
1268   union
1269   {
1270     guchar bytes[sizeof (gsize)];
1271     gsize integer;
1272   } tmpvalue;
1273
1274   tmpvalue.integer = GSIZE_TO_LE (offset);
1275   memcpy (*offset_ptr, tmpvalue.bytes, offset_size);
1276   *offset_ptr += offset_size;
1277 }
1278
1279 static void
1280 prepend_offset (guchar **offset_ptr,
1281                 gsize    offset,
1282                 guint    offset_size)
1283 {
1284   union
1285   {
1286     guchar bytes[sizeof (gsize)];
1287     gsize integer;
1288   } tmpvalue;
1289
1290   *offset_ptr -= offset_size;
1291   tmpvalue.integer = GSIZE_TO_LE (offset);
1292   memcpy (*offset_ptr, tmpvalue.bytes, offset_size);
1293 }
1294
1295 static void
1296 test_maybe (void)
1297 {
1298   GVariantTypeInfo *type_info;
1299   RandomInstance *instance;
1300   gsize needed_size;
1301   guchar *data;
1302
1303   instance = random_instance (NULL);
1304
1305   {
1306     const gchar *element;
1307     gchar *tmp;
1308
1309     element = g_variant_type_info_get_type_string (instance->type_info);
1310     tmp = g_strdup_printf ("m%s", element);
1311     type_info = g_variant_type_info_get (G_VARIANT_TYPE (tmp));
1312     g_free (tmp);
1313   }
1314
1315   needed_size = g_variant_serialiser_needed_size (type_info,
1316                                                   random_instance_filler,
1317                                                   NULL, 0);
1318   g_assert_cmpint (needed_size, ==, 0);
1319
1320   needed_size = g_variant_serialiser_needed_size (type_info,
1321                                                   random_instance_filler,
1322                                                   (gpointer *) &instance, 1);
1323
1324   if (instance->is_fixed_sized)
1325     g_assert_cmpint (needed_size, ==, instance->size);
1326   else
1327     g_assert_cmpint (needed_size, ==, instance->size + 1);
1328
1329   {
1330     guchar *ptr;
1331
1332     ptr = data = g_malloc (needed_size);
1333     append_instance_data (instance, &ptr);
1334
1335     if (!instance->is_fixed_sized)
1336       *ptr++ = '\0';
1337
1338     g_assert_cmpint (ptr - data, ==, needed_size);
1339   }
1340
1341   {
1342     guint alignment;
1343     guint flavour;
1344
1345     alignment = instance->alignment + 1;
1346
1347     for (flavour = 0; flavour < 8; flavour += alignment)
1348       {
1349         GVariantSerialised serialised;
1350         GVariantSerialised child;
1351
1352         serialised.type_info = type_info;
1353         serialised.data = flavoured_malloc (needed_size, flavour);
1354         serialised.size = needed_size;
1355
1356         g_variant_serialiser_serialise (serialised,
1357                                         random_instance_filler,
1358                                         (gpointer *) &instance, 1);
1359         child = g_variant_serialised_get_child (serialised, 0);
1360         g_assert (child.type_info == instance->type_info);
1361         random_instance_assert (instance, child.data, child.size);
1362         g_variant_type_info_unref (child.type_info);
1363         flavoured_free (serialised.data);
1364       }
1365   }
1366
1367   g_variant_type_info_unref (type_info);
1368   random_instance_free (instance);
1369   g_free (data);
1370 }
1371
1372 static void
1373 test_maybes (void)
1374 {
1375   guint i;
1376
1377   for (i = 0; i < 1000; i++)
1378     test_maybe ();
1379
1380   g_variant_type_info_assert_no_infos ();
1381 }
1382
1383 static void
1384 test_array (void)
1385 {
1386   GVariantTypeInfo *element_info;
1387   GVariantTypeInfo *array_info;
1388   RandomInstance **instances;
1389   gsize needed_size;
1390   gsize offset_size;
1391   guint n_children;
1392   guchar *data;
1393
1394   {
1395     gchar *element_type, *array_type;
1396
1397     element_type = random_type_string ();
1398     array_type = g_strdup_printf ("a%s", element_type);
1399
1400     element_info = g_variant_type_info_get (G_VARIANT_TYPE (element_type));
1401     array_info = g_variant_type_info_get (G_VARIANT_TYPE (array_type));
1402     g_assert (g_variant_type_info_element (array_info) == element_info);
1403
1404     g_free (element_type);
1405     g_free (array_type);
1406   }
1407
1408   {
1409     guint i;
1410
1411     n_children = g_test_rand_int_range (0, MAX_ARRAY_CHILDREN);
1412     instances = g_new (RandomInstance *, n_children);
1413     for (i = 0; i < n_children; i++)
1414       instances[i] = random_instance (element_info);
1415   }
1416
1417   needed_size = g_variant_serialiser_needed_size (array_info,
1418                                                   random_instance_filler,
1419                                                   (gpointer *) instances,
1420                                                   n_children);
1421
1422   {
1423     gsize element_fixed_size;
1424     gsize body_size = 0;
1425     guint i;
1426
1427     for (i = 0; i < n_children; i++)
1428       append_instance_size (instances[i], &body_size);
1429
1430     g_variant_type_info_query (element_info, NULL, &element_fixed_size);
1431
1432     if (!element_fixed_size)
1433       {
1434         offset_size = calculate_offset_size (body_size, n_children);
1435
1436         if (offset_size == 0)
1437           offset_size = 1;
1438       }
1439     else
1440       offset_size = 0;
1441
1442     g_assert_cmpint (needed_size, ==, body_size + n_children * offset_size);
1443   }
1444
1445   {
1446     guchar *offset_ptr, *body_ptr;
1447     guint i;
1448
1449     body_ptr = data = g_malloc (needed_size);
1450     offset_ptr = body_ptr + needed_size - offset_size * n_children;
1451
1452     for (i = 0; i < n_children; i++)
1453       {
1454         append_instance_data (instances[i], &body_ptr);
1455         append_offset (&offset_ptr, body_ptr - data, offset_size);
1456       }
1457
1458     g_assert (body_ptr == data + needed_size - offset_size * n_children);
1459     g_assert (offset_ptr == data + needed_size);
1460   }
1461
1462   {
1463     guint alignment;
1464     gsize flavour;
1465     guint i;
1466
1467     g_variant_type_info_query (array_info, &alignment, NULL);
1468     alignment++;
1469
1470     for (flavour = 0; flavour < 8; flavour += alignment)
1471       {
1472         GVariantSerialised serialised;
1473
1474         serialised.type_info = array_info;
1475         serialised.data = flavoured_malloc (needed_size, flavour);
1476         serialised.size = needed_size;
1477
1478         g_variant_serialiser_serialise (serialised, random_instance_filler,
1479                                         (gpointer *) instances, n_children);
1480
1481         g_assert (memcmp (serialised.data, data, serialised.size) == 0);
1482         g_assert (g_variant_serialised_n_children (serialised) == n_children);
1483
1484         for (i = 0; i < n_children; i++)
1485           {
1486             GVariantSerialised child;
1487
1488             child = g_variant_serialised_get_child (serialised, i);
1489             g_assert (child.type_info == instances[i]->type_info);
1490             random_instance_assert (instances[i], child.data, child.size);
1491             g_variant_type_info_unref (child.type_info);
1492           }
1493
1494         flavoured_free (serialised.data);
1495       }
1496   }
1497
1498   {
1499     guint i;
1500
1501     for (i = 0; i < n_children; i++)
1502       random_instance_free (instances[i]);
1503     g_free (instances);
1504   }
1505
1506   g_variant_type_info_unref (element_info);
1507   g_variant_type_info_unref (array_info);
1508   g_free (data);
1509 }
1510
1511 static void
1512 test_arrays (void)
1513 {
1514   guint i;
1515
1516   for (i = 0; i < 100; i++)
1517     test_array ();
1518
1519   g_variant_type_info_assert_no_infos ();
1520 }
1521
1522 static void
1523 test_tuple (void)
1524 {
1525   GVariantTypeInfo *type_info;
1526   RandomInstance **instances;
1527   gboolean fixed_size;
1528   gsize needed_size;
1529   gsize offset_size;
1530   guint n_children;
1531   guint alignment;
1532   guchar *data;
1533
1534   n_children = g_test_rand_int_range (0, MAX_TUPLE_CHILDREN);
1535   instances = g_new (RandomInstance *, n_children);
1536
1537   {
1538     GString *type_string;
1539     guint i;
1540
1541     fixed_size = TRUE;
1542     alignment = 0;
1543
1544     type_string = g_string_new ("(");
1545     for (i = 0; i < n_children; i++)
1546       {
1547         const gchar *str;
1548
1549         instances[i] = random_instance (NULL);
1550
1551         alignment |= instances[i]->alignment;
1552         if (!instances[i]->is_fixed_sized)
1553           fixed_size = FALSE;
1554
1555         str = g_variant_type_info_get_type_string (instances[i]->type_info);
1556         g_string_append (type_string, str);
1557       }
1558     g_string_append_c (type_string, ')');
1559
1560     type_info = g_variant_type_info_get (G_VARIANT_TYPE (type_string->str));
1561     g_string_free (type_string, TRUE);
1562   }
1563
1564   needed_size = g_variant_serialiser_needed_size (type_info,
1565                                                   random_instance_filler,
1566                                                   (gpointer *) instances,
1567                                                   n_children);
1568   {
1569     gsize body_size = 0;
1570     gsize offsets = 0;
1571     guint i;
1572
1573     for (i = 0; i < n_children; i++)
1574       {
1575         append_instance_size (instances[i], &body_size);
1576
1577         if (i != n_children - 1 && !instances[i]->is_fixed_sized)
1578           offsets++;
1579       }
1580
1581     if (fixed_size)
1582       {
1583         body_size += (-body_size) & alignment;
1584
1585         g_assert ((body_size == 0) == (n_children == 0));
1586         if (n_children == 0)
1587           body_size = 1;
1588       }
1589
1590     offset_size = calculate_offset_size (body_size, offsets);
1591     g_assert_cmpint (needed_size, ==, body_size + offsets * offset_size);
1592   }
1593
1594   {
1595     guchar *body_ptr;
1596     guchar *ofs_ptr;
1597     guint i;
1598
1599     body_ptr = data = g_malloc (needed_size);
1600     ofs_ptr = body_ptr + needed_size;
1601
1602     for (i = 0; i < n_children; i++)
1603       {
1604         append_instance_data (instances[i], &body_ptr);
1605
1606         if (i != n_children - 1 && !instances[i]->is_fixed_sized)
1607           prepend_offset (&ofs_ptr, body_ptr - data, offset_size);
1608       }
1609
1610     if (fixed_size)
1611       {
1612         while (((gsize) body_ptr) & alignment)
1613           *body_ptr++ = '\0';
1614
1615         g_assert ((body_ptr == data) == (n_children == 0));
1616         if (n_children == 0)
1617           *body_ptr++ = '\0';
1618
1619       }
1620
1621
1622     g_assert (body_ptr == ofs_ptr);
1623   }
1624
1625   {
1626     gsize flavour;
1627     guint i;
1628
1629     alignment++;
1630
1631     for (flavour = 0; flavour < 8; flavour += alignment)
1632       {
1633         GVariantSerialised serialised;
1634
1635         serialised.type_info = type_info;
1636         serialised.data = flavoured_malloc (needed_size, flavour);
1637         serialised.size = needed_size;
1638
1639         g_variant_serialiser_serialise (serialised, random_instance_filler,
1640                                         (gpointer *) instances, n_children);
1641
1642         g_assert (memcmp (serialised.data, data, serialised.size) == 0);
1643         g_assert (g_variant_serialised_n_children (serialised) == n_children);
1644
1645         for (i = 0; i < n_children; i++)
1646           {
1647             GVariantSerialised child;
1648
1649             child = g_variant_serialised_get_child (serialised, i);
1650             g_assert (child.type_info == instances[i]->type_info);
1651             random_instance_assert (instances[i], child.data, child.size);
1652             g_variant_type_info_unref (child.type_info);
1653           }
1654
1655         flavoured_free (serialised.data);
1656       }
1657   }
1658
1659   {
1660     guint i;
1661
1662     for (i = 0; i < n_children; i++)
1663       random_instance_free (instances[i]);
1664     g_free (instances);
1665   }
1666
1667   g_variant_type_info_unref (type_info);
1668   g_free (data);
1669 }
1670
1671 static void
1672 test_tuples (void)
1673 {
1674   guint i;
1675
1676   for (i = 0; i < 100; i++)
1677     test_tuple ();
1678
1679   g_variant_type_info_assert_no_infos ();
1680 }
1681
1682 static void
1683 test_variant (void)
1684 {
1685   GVariantTypeInfo *type_info;
1686   RandomInstance *instance;
1687   const gchar *type_string;
1688   gsize needed_size;
1689   guchar *data;
1690   gsize len;
1691
1692   type_info = g_variant_type_info_get (G_VARIANT_TYPE_VARIANT);
1693   instance = random_instance (NULL);
1694
1695   type_string = g_variant_type_info_get_type_string (instance->type_info);
1696   len = strlen (type_string);
1697
1698   needed_size = g_variant_serialiser_needed_size (type_info,
1699                                                   random_instance_filler,
1700                                                   (gpointer *) &instance, 1);
1701
1702   g_assert_cmpint (needed_size, ==, instance->size + 1 + len);
1703
1704   {
1705     guchar *ptr;
1706
1707     ptr = data = g_malloc (needed_size);
1708     append_instance_data (instance, &ptr);
1709     *ptr++ = '\0';
1710     memcpy (ptr, type_string, len);
1711     ptr += len;
1712
1713     g_assert (data + needed_size == ptr);
1714   }
1715
1716   {
1717     /* variants are 8-aligned, so no extra flavouring */
1718     GVariantSerialised serialised;
1719     GVariantSerialised child;
1720
1721     serialised.type_info = type_info;
1722     serialised.data = flavoured_malloc (needed_size, 0);
1723     serialised.size = needed_size;
1724
1725     g_variant_serialiser_serialise (serialised, random_instance_filler,
1726                                     (gpointer *) &instance, 1);
1727
1728     g_assert (memcmp (serialised.data, data, serialised.size) == 0);
1729     g_assert (g_variant_serialised_n_children (serialised) == 1);
1730
1731     child = g_variant_serialised_get_child (serialised, 0);
1732     g_assert (child.type_info == instance->type_info);
1733     random_instance_check (instance, child.data, child.size);
1734
1735     g_variant_type_info_unref (child.type_info);
1736     flavoured_free (serialised.data);
1737   }
1738
1739   g_variant_type_info_unref (type_info);
1740   random_instance_free (instance);
1741   g_free (data);
1742 }
1743
1744 static void
1745 test_variants (void)
1746 {
1747   guint i;
1748
1749   for (i = 0; i < 100; i++)
1750     test_variant ();
1751
1752   g_variant_type_info_assert_no_infos ();
1753 }
1754
1755 static void
1756 test_strings (void)
1757 {
1758   struct {
1759     guint flags;
1760     guint size;
1761     gconstpointer data;
1762   } test_cases[] = {
1763 #define is_nval           0
1764 #define is_string         1
1765 #define is_objpath        is_string | 2
1766 #define is_sig            is_string | 4
1767     { is_sig,       1, "" },
1768     { is_nval,      0, NULL },
1769     { is_string,   13, "hello world!" },
1770     { is_nval,     13, "hello world\0" },
1771     { is_nval,     13, "hello\0world!" },
1772     { is_nval,     12, "hello world!" },
1773
1774     { is_objpath,   2, "/" },
1775     { is_objpath,   3, "/a" },
1776     { is_string,    3, "//" },
1777     { is_objpath,  11, "/some/path" },
1778     { is_string,   12, "/some/path/" },
1779     { is_nval,     11, "/some\0path" },
1780     { is_string,   11, "/some\\path" },
1781     { is_string,   12, "/some//path" },
1782     { is_string,   12, "/some-/path" },
1783
1784     { is_sig,       2, "i" },
1785     { is_sig,       2, "s" },
1786     { is_sig,       5, "(si)" },
1787     { is_string,    4, "(si" },
1788     { is_string,    2, "*" },
1789     { is_sig,       3, "ai" },
1790     { is_string,    3, "mi" },
1791     { is_string,    2, "r" },
1792     { is_sig,      15, "(yyy{sv}ssiai)" },
1793     { is_string,   16, "(yyy{yv}ssiai))" },
1794     { is_string,   15, "(yyy{vv}ssiai)" },
1795     { is_string,   15, "(yyy{sv)ssiai}" }
1796   };
1797   guint i;
1798
1799   for (i = 0; i < G_N_ELEMENTS (test_cases); i++)
1800     {
1801       guint flags;
1802
1803       flags = g_variant_serialiser_is_string (test_cases[i].data,
1804                                               test_cases[i].size)
1805         ? 1 : 0;
1806
1807       flags |= g_variant_serialiser_is_object_path (test_cases[i].data,
1808                                                     test_cases[i].size)
1809         ? 2 : 0;
1810
1811       flags |= g_variant_serialiser_is_signature (test_cases[i].data,
1812                                                   test_cases[i].size)
1813         ? 4 : 0;
1814
1815       g_assert (flags == test_cases[i].flags);
1816     }
1817 }
1818
1819 typedef struct _TreeInstance TreeInstance;
1820 struct _TreeInstance
1821 {
1822   GVariantTypeInfo *info;
1823
1824   TreeInstance **children;
1825   gsize n_children;
1826
1827   union {
1828     guint64 integer;
1829     gdouble floating;
1830     gchar string[32];
1831   } data;
1832   gsize data_size;
1833 };
1834
1835 static GVariantType *
1836 make_random_definite_type (int depth)
1837 {
1838   GString *description;
1839   GString *type_string;
1840   GVariantType *type;
1841
1842   description = g_string_new (NULL);
1843   type_string = g_string_new (NULL);
1844   type = append_type_string (type_string, description, TRUE, depth);
1845   g_string_free (description, TRUE);
1846   g_string_free (type_string, TRUE);
1847
1848   return type;
1849 }
1850
1851 static void
1852 make_random_string (gchar              *string,
1853                     gsize               size,
1854                     const GVariantType *type)
1855 {
1856   gint i;
1857
1858   /* create strings that are valid signature strings */
1859 #define good_chars "bynqiuxthdsog"
1860
1861   for (i = 0; i < size - 1; i++)
1862     string[i] = good_chars[g_test_rand_int_range (0, strlen (good_chars))];
1863   string[i] = '\0';
1864
1865   /* in case we need an object path, prefix a '/' */
1866   if (*g_variant_type_peek_string (type) == 'o')
1867     string[0] = '/';
1868
1869 #undef good_chars
1870 }
1871
1872 static TreeInstance *
1873 tree_instance_new (const GVariantType *type,
1874                    int                 depth)
1875 {
1876   const GVariantType *child_type = NULL;
1877   GVariantType *mytype = NULL;
1878   TreeInstance *instance;
1879   gboolean is_tuple_type;
1880
1881   if (type == NULL)
1882     type = mytype = make_random_definite_type (depth);
1883
1884   instance = g_slice_new (TreeInstance);
1885   instance->info = g_variant_type_info_get (type);
1886   instance->children = NULL;
1887   instance->n_children = 0;
1888   instance->data_size = 0;
1889
1890   is_tuple_type = FALSE;
1891
1892   switch (*g_variant_type_peek_string (type))
1893     {
1894     case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
1895       instance->n_children = g_test_rand_int_range (0, 2);
1896       child_type = g_variant_type_element (type);
1897       break;
1898
1899     case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
1900       instance->n_children = g_test_rand_int_range (0, MAX_ARRAY_CHILDREN);
1901       child_type = g_variant_type_element (type);
1902       break;
1903
1904     case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
1905     case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
1906       instance->n_children = g_variant_type_n_items (type);
1907       child_type = g_variant_type_first (type);
1908       is_tuple_type = TRUE;
1909       break;
1910
1911     case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
1912       instance->n_children = 1;
1913       child_type = NULL;
1914       break;
1915
1916     case 'b':
1917       instance->data.integer = g_test_rand_int_range (0, 2);
1918       instance->data_size = 1;
1919       break;
1920
1921     case 'y':
1922       instance->data.integer = g_test_rand_int ();
1923       instance->data_size = 1;
1924       break;
1925
1926     case 'n': case 'q':
1927       instance->data.integer = g_test_rand_int ();
1928       instance->data_size = 2;
1929       break;
1930
1931     case 'i': case 'u': case 'h':
1932       instance->data.integer = g_test_rand_int ();
1933       instance->data_size = 4;
1934       break;
1935
1936     case 'x': case 't': case 'd':
1937       instance->data.integer = g_test_rand_int ();
1938       instance->data.integer <<= 32;
1939       instance->data.integer |= (guint32) g_test_rand_int ();
1940       instance->data_size = 8;
1941       break;
1942
1943     case 's': case 'o': case 'g':
1944       instance->data_size = g_test_rand_int_range (10, 20);
1945       make_random_string (instance->data.string, instance->data_size, type);
1946       break;
1947     }
1948
1949   if (instance->data_size == 0)
1950     /* no data -> it is a container */
1951     {
1952       guint i;
1953
1954       instance->children = g_new (TreeInstance *, instance->n_children);
1955
1956       for (i = 0; i < instance->n_children; i++)
1957         {
1958           instance->children[i] = tree_instance_new (child_type, depth - 1);
1959
1960           if (is_tuple_type)
1961             child_type = g_variant_type_next (child_type);
1962         }
1963
1964       g_assert (!is_tuple_type || child_type == NULL);
1965     }
1966
1967   g_variant_type_free (mytype);
1968
1969   return instance;
1970 }
1971
1972 static void
1973 tree_instance_free (TreeInstance *instance)
1974 {
1975   gint i;
1976
1977   g_variant_type_info_unref (instance->info);
1978   for (i = 0; i < instance->n_children; i++)
1979     tree_instance_free (instance->children[i]);
1980   g_free (instance->children);
1981   g_slice_free (TreeInstance, instance);
1982 }
1983
1984 static gboolean i_am_writing_byteswapped;
1985
1986 static void
1987 tree_filler (GVariantSerialised *serialised,
1988              gpointer            data)
1989 {
1990   TreeInstance *instance = data;
1991
1992   if (serialised->type_info == NULL)
1993     serialised->type_info = instance->info;
1994
1995   if (instance->data_size == 0)
1996     /* is a container */
1997     {
1998       if (serialised->size == 0)
1999         serialised->size =
2000           g_variant_serialiser_needed_size (instance->info, tree_filler,
2001                                             (gpointer *) instance->children,
2002                                             instance->n_children);
2003
2004       if (serialised->data)
2005         g_variant_serialiser_serialise (*serialised, tree_filler,
2006                                         (gpointer *) instance->children,
2007                                         instance->n_children);
2008     }
2009   else
2010     /* it is a leaf */
2011     {
2012       if (serialised->size == 0)
2013         serialised->size = instance->data_size;
2014
2015       if (serialised->data)
2016         {
2017           switch (instance->data_size)
2018             {
2019             case 1:
2020               *serialised->data = instance->data.integer;
2021               break;
2022
2023             case 2:
2024               {
2025                 guint16 value = instance->data.integer;
2026
2027                 if (i_am_writing_byteswapped)
2028                   value = GUINT16_SWAP_LE_BE (value);
2029
2030                 *(guint16 *) serialised->data = value;
2031               }
2032               break;
2033
2034             case 4:
2035               {
2036                 guint32 value = instance->data.integer;
2037
2038                 if (i_am_writing_byteswapped)
2039                   value = GUINT32_SWAP_LE_BE (value);
2040
2041                 *(guint32 *) serialised->data = value;
2042               }
2043               break;
2044
2045             case 8:
2046               {
2047                 guint64 value = instance->data.integer;
2048
2049                 if (i_am_writing_byteswapped)
2050                   value = GUINT64_SWAP_LE_BE (value);
2051
2052                 *(guint64 *) serialised->data = value;
2053               }
2054               break;
2055
2056             default:
2057               memcpy (serialised->data,
2058                       instance->data.string,
2059                       instance->data_size);
2060               break;
2061             }
2062         }
2063     }
2064 }
2065
2066 static gboolean
2067 check_tree (TreeInstance       *instance,
2068             GVariantSerialised  serialised)
2069 {
2070   if (instance->info != serialised.type_info)
2071     return FALSE;
2072
2073   if (instance->data_size == 0)
2074     /* is a container */
2075     {
2076       gint i;
2077
2078       if (g_variant_serialised_n_children (serialised) !=
2079           instance->n_children)
2080         return FALSE;
2081
2082       for (i = 0; i < instance->n_children; i++)
2083         {
2084           GVariantSerialised child;
2085           gpointer data = NULL;
2086           gboolean ok;
2087
2088           child = g_variant_serialised_get_child (serialised, i);
2089           if (child.size && child.data == NULL)
2090             child.data = data = g_malloc0 (child.size);
2091           ok = check_tree (instance->children[i], child);
2092           g_variant_type_info_unref (child.type_info);
2093           g_free (data);
2094
2095           if (!ok)
2096             return FALSE;
2097         }
2098
2099       return TRUE;
2100     }
2101   else
2102     /* it is a leaf */
2103     {
2104       switch (instance->data_size)
2105         {
2106         case 1:
2107           g_assert (serialised.size == 1);
2108           return *(guint8 *) serialised.data ==
2109                   (guint8) instance->data.integer;
2110
2111         case 2:
2112           g_assert (serialised.size == 2);
2113           return *(guint16 *) serialised.data ==
2114                   (guint16) instance->data.integer;
2115
2116         case 4:
2117           g_assert (serialised.size == 4);
2118           return *(guint32 *) serialised.data ==
2119                   (guint32) instance->data.integer;
2120
2121         case 8:
2122           g_assert (serialised.size == 8);
2123           return *(guint64 *) serialised.data ==
2124                   (guint64) instance->data.integer;
2125
2126         default:
2127           if (serialised.size != instance->data_size)
2128             return FALSE;
2129
2130           return memcmp (serialised.data,
2131                          instance->data.string,
2132                          instance->data_size) == 0;
2133         }
2134     }
2135 }
2136
2137 static void
2138 serialise_tree (TreeInstance       *tree,
2139                 GVariantSerialised *serialised)
2140 {
2141   GVariantSerialised empty = {  };
2142
2143   *serialised = empty;
2144   tree_filler (serialised, tree);
2145   serialised->data = g_malloc (serialised->size);
2146   tree_filler (serialised, tree);
2147 }
2148
2149 static void
2150 test_byteswap (void)
2151 {
2152   GVariantSerialised one, two;
2153   TreeInstance *tree;
2154
2155   tree = tree_instance_new (NULL, 3);
2156   serialise_tree (tree, &one);
2157
2158   i_am_writing_byteswapped = TRUE;
2159   serialise_tree (tree, &two);
2160   i_am_writing_byteswapped = FALSE;
2161
2162   g_variant_serialised_byteswap (two);
2163
2164   g_assert_cmpint (one.size, ==, two.size);
2165   g_assert (memcmp (one.data, two.data, one.size) == 0);
2166
2167   tree_instance_free (tree);
2168   g_free (one.data);
2169   g_free (two.data);
2170 }
2171
2172 static void
2173 test_byteswaps (void)
2174 {
2175   int i;
2176
2177   for (i = 0; i < 200; i++)
2178     test_byteswap ();
2179
2180   g_variant_type_info_assert_no_infos ();
2181 }
2182
2183 static void
2184 test_fuzz (gdouble *fuzziness)
2185 {
2186   GVariantSerialised serialised;
2187   TreeInstance *tree;
2188
2189   /* make an instance */
2190   tree = tree_instance_new (NULL, 3);
2191
2192   /* serialise it */
2193   serialise_tree (tree, &serialised);
2194
2195   g_assert (g_variant_serialised_is_normal (serialised));
2196   g_assert (check_tree (tree, serialised));
2197
2198   if (serialised.size)
2199     {
2200       gboolean fuzzed = FALSE;
2201       gboolean a, b;
2202
2203       while (!fuzzed)
2204         {
2205           gint i;
2206
2207           for (i = 0; i < serialised.size; i++)
2208             if (randomly (*fuzziness))
2209               {
2210                 serialised.data[i] += g_test_rand_int_range (1, 256);
2211                 fuzzed = TRUE;
2212               }
2213         }
2214
2215       /* at least one byte in the serialised data has changed.
2216        *
2217        * this means that at least one of the following is true:
2218        *
2219        *    - the serialised data now represents a different value:
2220        *        check_tree() will return FALSE
2221        *
2222        *    - the serialised data is in non-normal form:
2223        *        g_variant_serialiser_is_normal() will return FALSE
2224        *
2225        * we always do both checks to increase exposure of the serialiser
2226        * to corrupt data.
2227        */
2228       a = g_variant_serialised_is_normal (serialised);
2229       b = check_tree (tree, serialised);
2230
2231       g_assert (!a || !b);
2232     }
2233
2234   tree_instance_free (tree);
2235   g_free (serialised.data);
2236 }
2237
2238
2239 static void
2240 test_fuzzes (gpointer data)
2241 {
2242   gdouble fuzziness;
2243   int i;
2244
2245   fuzziness = GPOINTER_TO_INT (data) / 100.;
2246
2247   for (i = 0; i < 200; i++)
2248     test_fuzz (&fuzziness);
2249
2250   g_variant_type_info_assert_no_infos ();
2251 }
2252
2253 static GVariant *
2254 tree_instance_get_gvariant (TreeInstance *tree)
2255 {
2256   const GVariantType *type;
2257   GVariant *result;
2258
2259   type = (GVariantType *) g_variant_type_info_get_type_string (tree->info);
2260
2261   switch (g_variant_type_info_get_type_char (tree->info))
2262     {
2263     case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
2264       {
2265         const GVariantType *child_type;
2266         GVariant *child;
2267
2268         if (tree->n_children)
2269           child = tree_instance_get_gvariant (tree->children[0]);
2270         else
2271           child = NULL;
2272
2273         child_type = g_variant_type_element (type);
2274
2275         if (child != NULL && randomly (0.5))
2276           child_type = NULL;
2277
2278         result = g_variant_new_maybe (child_type, child);
2279       }
2280       break;
2281
2282     case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
2283       {
2284         const GVariantType *child_type;
2285         GVariant **children;
2286         gint i;
2287
2288         children = g_new (GVariant *, tree->n_children);
2289         for (i = 0; i < tree->n_children; i++)
2290           children[i] = tree_instance_get_gvariant (tree->children[i]);
2291
2292         child_type = g_variant_type_element (type);
2293
2294         if (i > 0 && randomly (0.5))
2295           child_type = NULL;
2296
2297         result = g_variant_new_array (child_type, children, tree->n_children);
2298         g_free (children);
2299       }
2300       break;
2301
2302     case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
2303       {
2304         GVariant **children;
2305         gint i;
2306
2307         children = g_new (GVariant *, tree->n_children);
2308         for (i = 0; i < tree->n_children; i++)
2309           children[i] = tree_instance_get_gvariant (tree->children[i]);
2310
2311         result = g_variant_new_tuple (children, tree->n_children);
2312         g_free (children);
2313       }
2314       break;
2315
2316     case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
2317       {
2318         GVariant *key, *val;
2319
2320         g_assert (tree->n_children == 2);
2321
2322         key = tree_instance_get_gvariant (tree->children[0]);
2323         val = tree_instance_get_gvariant (tree->children[1]);
2324
2325         result = g_variant_new_dict_entry (key, val);
2326       }
2327       break;
2328
2329     case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
2330       {
2331         GVariant *value;
2332
2333         g_assert (tree->n_children == 1);
2334
2335         value = tree_instance_get_gvariant (tree->children[0]);
2336         result = g_variant_new_variant (value);
2337       }
2338       break;
2339
2340     case 'b':
2341       result = g_variant_new_boolean (tree->data.integer > 0);
2342       break;
2343
2344     case 'y':
2345       result = g_variant_new_byte (tree->data.integer);
2346       break;
2347
2348     case 'n':
2349       result = g_variant_new_int16 (tree->data.integer);
2350       break;
2351
2352     case 'q':
2353       result = g_variant_new_uint16 (tree->data.integer);
2354       break;
2355
2356     case 'i':
2357       result = g_variant_new_int32 (tree->data.integer);
2358       break;
2359
2360     case 'u':
2361       result = g_variant_new_uint32 (tree->data.integer);
2362       break;
2363
2364     case 'x':
2365       result = g_variant_new_int64 (tree->data.integer);
2366       break;
2367
2368     case 't':
2369       result = g_variant_new_uint64 (tree->data.integer);
2370       break;
2371
2372     case 'h':
2373       result = g_variant_new_handle (tree->data.integer);
2374       break;
2375
2376     case 'd':
2377       result = g_variant_new_double (tree->data.floating);
2378       break;
2379
2380     case 's':
2381       result = g_variant_new_string (tree->data.string);
2382       break;
2383
2384     case 'o':
2385       result = g_variant_new_object_path (tree->data.string);
2386       break;
2387
2388     case 'g':
2389       result = g_variant_new_signature (tree->data.string);
2390       break;
2391
2392     default:
2393       g_assert_not_reached ();
2394     }
2395
2396   return result;
2397 }
2398
2399 static gboolean
2400 tree_instance_check_gvariant (TreeInstance *tree,
2401                               GVariant     *value)
2402 {
2403   const GVariantType *type;
2404
2405   type = (GVariantType *) g_variant_type_info_get_type_string (tree->info);
2406   g_assert (g_variant_is_of_type (value, type));
2407
2408   switch (g_variant_type_info_get_type_char (tree->info))
2409     {
2410     case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
2411       {
2412         GVariant *child;
2413         gboolean equal;
2414
2415         child = g_variant_get_maybe (value);
2416
2417         if (child != NULL && tree->n_children == 1)
2418           equal = tree_instance_check_gvariant (tree->children[0], child);
2419         else if (child == NULL && tree->n_children == 0)
2420           equal = TRUE;
2421         else
2422           equal = FALSE;
2423
2424         if (child != NULL)
2425           g_variant_unref (child);
2426
2427         return equal;
2428       }
2429       break;
2430
2431     case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
2432     case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
2433     case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
2434       {
2435         gsize i;
2436
2437         if (g_variant_n_children (value) != tree->n_children)
2438           return FALSE;
2439
2440         for (i = 0; i < tree->n_children; i++)
2441           {
2442             GVariant *child;
2443             gboolean equal;
2444
2445             child = g_variant_get_child_value (value, i);
2446             equal = tree_instance_check_gvariant (tree->children[i], child);
2447             g_variant_unref (child);
2448
2449             if (!equal)
2450               return FALSE;
2451           }
2452
2453         return TRUE;
2454       }
2455       break;
2456
2457     case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
2458       {
2459         const gchar *str1, *str2;
2460         GVariant *child;
2461         gboolean equal;
2462
2463         child = g_variant_get_variant (value);
2464         str1 = g_variant_get_type_string (child);
2465         str2 = g_variant_type_info_get_type_string (tree->children[0]->info);
2466         /* GVariant only keeps one copy of type strings around */
2467         equal = str1 == str2 &&
2468                 tree_instance_check_gvariant (tree->children[0], child);
2469
2470         g_variant_unref (child);
2471
2472         return equal;
2473       }
2474       break;
2475
2476     case 'b':
2477       return g_variant_get_boolean (value) == tree->data.integer;
2478
2479     case 'y':
2480       return g_variant_get_byte (value) == (guchar) tree->data.integer;
2481
2482     case 'n':
2483       return g_variant_get_int16 (value) == (gint16) tree->data.integer;
2484
2485     case 'q':
2486       return g_variant_get_uint16 (value) == (guint16) tree->data.integer;
2487
2488     case 'i':
2489       return g_variant_get_int32 (value) == (gint32) tree->data.integer;
2490
2491     case 'u':
2492       return g_variant_get_uint32 (value) == (guint32) tree->data.integer;
2493
2494     case 'x':
2495       return g_variant_get_int64 (value) == (gint64) tree->data.integer;
2496
2497     case 't':
2498       return g_variant_get_uint64 (value) == (guint64) tree->data.integer;
2499
2500     case 'h':
2501       return g_variant_get_handle (value) == (gint32) tree->data.integer;
2502
2503     case 'd':
2504       {
2505         gdouble floating = g_variant_get_double (value);
2506
2507         return memcmp (&floating, &tree->data.floating, sizeof floating) == 0;
2508       }
2509
2510     case 's':
2511     case 'o':
2512     case 'g':
2513       return strcmp (g_variant_get_string (value, NULL),
2514                      tree->data.string) == 0;
2515
2516     default:
2517       g_assert_not_reached ();
2518     }
2519 }
2520
2521 static void
2522 tree_instance_build_gvariant (TreeInstance    *tree,
2523                               GVariantBuilder *builder,
2524                               gboolean         guess_ok)
2525 {
2526   const GVariantType *type;
2527
2528   type = (GVariantType *) g_variant_type_info_get_type_string (tree->info);
2529
2530   if (g_variant_type_is_container (type))
2531     {
2532       gsize i;
2533
2534       /* force GVariantBuilder to guess the type half the time */
2535       if (guess_ok && randomly (0.5))
2536         {
2537           if (g_variant_type_is_array (type) && tree->n_children)
2538             type = G_VARIANT_TYPE_ARRAY;
2539
2540           if (g_variant_type_is_maybe (type) && tree->n_children)
2541             type = G_VARIANT_TYPE_MAYBE;
2542
2543           if (g_variant_type_is_tuple (type))
2544             type = G_VARIANT_TYPE_TUPLE;
2545
2546           if (g_variant_type_is_dict_entry (type))
2547             type = G_VARIANT_TYPE_DICT_ENTRY;
2548         }
2549       else
2550         guess_ok = FALSE;
2551
2552       g_variant_builder_open (builder, type);
2553
2554       for (i = 0; i < tree->n_children; i++)
2555         tree_instance_build_gvariant (tree->children[i], builder, guess_ok);
2556
2557       g_variant_builder_close (builder);
2558     }
2559   else
2560     g_variant_builder_add_value (builder, tree_instance_get_gvariant (tree));
2561 }
2562
2563
2564 static gboolean
2565 tree_instance_check_iter (TreeInstance *tree,
2566                           GVariantIter *iter)
2567 {
2568   GVariant *value;
2569
2570   value = g_variant_iter_next_value (iter);
2571
2572   if (g_variant_is_container (value))
2573     {
2574       gsize i;
2575
2576       iter = g_variant_iter_new (value);
2577       g_variant_unref (value);
2578
2579       if (g_variant_iter_n_children (iter) != tree->n_children)
2580         {
2581           g_variant_iter_free (iter);
2582           return FALSE;
2583         }
2584
2585       for (i = 0; i < tree->n_children; i++)
2586         if (!tree_instance_check_iter (tree->children[i], iter))
2587           {
2588             g_variant_iter_free (iter);
2589             return FALSE;
2590           }
2591
2592       g_assert (g_variant_iter_next_value (iter) == NULL);
2593       g_variant_iter_free (iter);
2594
2595       return TRUE;
2596     }
2597
2598   else
2599     {
2600       gboolean equal;
2601
2602       equal = tree_instance_check_gvariant (tree, value);
2603       g_variant_unref (value);
2604
2605       return equal;
2606     }
2607 }
2608
2609 static void
2610 test_container (void)
2611 {
2612   TreeInstance *tree;
2613   GVariant *value;
2614   gchar *s1, *s2;
2615
2616   tree = tree_instance_new (NULL, 3);
2617   value = g_variant_ref_sink (tree_instance_get_gvariant (tree));
2618
2619   s1 = g_variant_print (value, TRUE);
2620   g_assert (tree_instance_check_gvariant (tree, value));
2621
2622   g_variant_get_data (value);
2623
2624   s2 = g_variant_print (value, TRUE);
2625   g_assert (tree_instance_check_gvariant (tree, value));
2626
2627   g_assert_cmpstr (s1, ==, s2);
2628
2629   if (g_variant_is_container (value))
2630     {
2631       GVariantBuilder builder;
2632       GVariantIter iter;
2633       GVariant *built;
2634       GVariant *val;
2635       gchar *s3;
2636
2637       g_variant_builder_init (&builder, G_VARIANT_TYPE_VARIANT);
2638       tree_instance_build_gvariant (tree, &builder, TRUE);
2639       built = g_variant_builder_end (&builder);
2640       g_variant_ref_sink (built);
2641       g_variant_get_data (built);
2642       val = g_variant_get_variant (built);
2643
2644       s3 = g_variant_print (val, TRUE);
2645       g_assert_cmpstr (s1, ==, s3);
2646
2647       g_variant_iter_init (&iter, built);
2648       g_assert (tree_instance_check_iter (tree, &iter));
2649       g_assert (g_variant_iter_next_value (&iter) == NULL);
2650
2651       g_variant_unref (built);
2652       g_variant_unref (val);
2653       g_free (s3);
2654     }
2655
2656   tree_instance_free (tree);
2657   g_variant_unref (value);
2658   g_free (s2);
2659   g_free (s1);
2660 }
2661
2662 static void
2663 test_containers (void)
2664 {
2665   gint i;
2666
2667   for (i = 0; i < 100; i++)
2668     {
2669       test_container ();
2670     }
2671
2672   g_variant_type_info_assert_no_infos ();
2673 }
2674
2675 static void
2676 test_format_strings (void)
2677 {
2678   GVariantType *type;
2679   const gchar *end;
2680
2681   g_assert (g_variant_format_string_scan ("i", NULL, &end) && *end == '\0');
2682   g_assert (g_variant_format_string_scan ("@i", NULL, &end) && *end == '\0');
2683   g_assert (g_variant_format_string_scan ("@ii", NULL, &end) && *end == 'i');
2684   g_assert (g_variant_format_string_scan ("^a&s", NULL, &end) && *end == '\0');
2685   g_assert (g_variant_format_string_scan ("(^as)", NULL, &end) &&
2686             *end == '\0');
2687   g_assert (!g_variant_format_string_scan ("(^s)", NULL, &end));
2688   g_assert (!g_variant_format_string_scan ("(^a)", NULL, &end));
2689   g_assert (!g_variant_format_string_scan ("(z)", NULL, &end));
2690   g_assert (!g_variant_format_string_scan ("az", NULL, &end));
2691   g_assert (!g_variant_format_string_scan ("{**}", NULL, &end));
2692   g_assert (!g_variant_format_string_scan ("{@**}", NULL, &end));
2693   g_assert (g_variant_format_string_scan ("{@y*}", NULL, &end) &&
2694             *end == '\0');
2695   g_assert (g_variant_format_string_scan ("{yv}", NULL, &end) &&
2696             *end == '\0');
2697   g_assert (!g_variant_format_string_scan ("{vv}", NULL, &end));
2698   g_assert (!g_variant_format_string_scan ("{y}", NULL, &end));
2699   g_assert (!g_variant_format_string_scan ("{yyy}", NULL, &end));
2700   g_assert (!g_variant_format_string_scan ("{ya}", NULL, &end));
2701   g_assert (g_variant_format_string_scan ("&s", NULL, &end) && *end == '\0');
2702   g_assert (!g_variant_format_string_scan ("&as", NULL, &end));
2703   g_assert (!g_variant_format_string_scan ("@z", NULL, &end));
2704   g_assert (!g_variant_format_string_scan ("az", NULL, &end));
2705   g_assert (!g_variant_format_string_scan ("a&s", NULL, &end));
2706
2707   type = g_variant_format_string_scan_type ("mm(@xy^a&s*?@?)", NULL, &end);
2708   g_assert (type && *end == '\0');
2709   g_assert (g_variant_type_equal (type, G_VARIANT_TYPE ("mm(xyas*?\?)")));
2710   g_variant_type_free (type);
2711
2712   type = g_variant_format_string_scan_type ("mm(@xy^a&*?@?)", NULL, NULL);
2713   g_assert (type == NULL);
2714 }
2715
2716 static void
2717 exit_on_abort (int signal)
2718 {
2719   exit (signal);
2720 }
2721
2722 static gboolean
2723 do_failed_test (const gchar *pattern)
2724 {
2725   if (g_test_trap_fork (1000000, G_TEST_TRAP_SILENCE_STDERR))
2726     {
2727       signal (SIGABRT, exit_on_abort);
2728       return TRUE;
2729     }
2730
2731   g_test_trap_assert_failed ();
2732   g_test_trap_assert_stderr (pattern);
2733
2734   return FALSE;
2735 }
2736
2737 static void
2738 test_invalid_varargs (void)
2739 {
2740   if (do_failed_test ("*not a valid GVariant format string*"))
2741     {
2742       g_variant_new ("z");
2743       abort ();
2744     }
2745
2746   if (do_failed_test ("*valid GVariant format string as a prefix*"))
2747     {
2748       const gchar *end;
2749
2750       g_variant_new_va ("z", &end, NULL);
2751       abort ();
2752     }
2753
2754   if (do_failed_test ("*type of `q' but * has a type of `y'*"))
2755     {
2756       g_variant_get (g_variant_new ("y", 'a'), "q");
2757       abort ();
2758     }
2759 }
2760
2761 static void
2762 check_and_free (GVariant    *value,
2763                 const gchar *str)
2764 {
2765   gchar *valstr = g_variant_print (value, FALSE);
2766   g_assert_cmpstr (str, ==, valstr);
2767   g_variant_unref (value);
2768   g_free (valstr);
2769 }
2770
2771 static void
2772 test_varargs (void)
2773 {
2774   {
2775     GVariantBuilder array;
2776
2777     g_variant_builder_init (&array, G_VARIANT_TYPE_ARRAY);
2778     g_variant_builder_add (&array, "{sv}", "size",
2779                            g_variant_new ("(ii)", 800, 600));
2780     g_variant_builder_add (&array, "{sv}", "title",
2781                            g_variant_new_string ("Test case"));
2782     g_variant_builder_add_value (&array,
2783       g_variant_new_dict_entry (g_variant_new_string ("temperature"),
2784                                 g_variant_new_variant (
2785                                   g_variant_new_double (37.5))));
2786     check_and_free (g_variant_new ("(ma{sv}m(a{sv})ma{sv}ii)",
2787                                    NULL, FALSE, NULL, &array, 7777, 8888),
2788                     "(Nothing, Nothing, {'size': <(800, 600)>, "
2789                                         "'title': <'Test case'>, "
2790                                         "'temperature': <37.5>}, "
2791                      "7777, 8888)");
2792
2793     check_and_free (g_variant_new ("(imimimmimmimmi)",
2794                                    123,
2795                                    FALSE, 321,
2796                                    TRUE, 123,
2797                                    FALSE, TRUE, 321,
2798                                    TRUE, FALSE, 321,
2799                                    TRUE, TRUE, 123),
2800                     "(123, Nothing, 123, Nothing, Just Nothing, 123)");
2801
2802     check_and_free (g_variant_new ("(ybnixd)",
2803                                    'a', 1, 22, 33, (guint64) 44, 5.5),
2804                     "(0x61, true, 22, 33, 44, 5.5)");
2805
2806     check_and_free (g_variant_new ("(@y?*rv)",
2807                                    g_variant_new ("y", 'a'),
2808                                    g_variant_new ("y", 'b'),
2809                                    g_variant_new ("y", 'c'),
2810                                    g_variant_new ("(y)", 'd'),
2811                                    g_variant_new ("y", 'e')),
2812                     "(0x61, 0x62, 0x63, (0x64,), <byte 0x65>)");
2813   }
2814
2815   {
2816     GVariantBuilder array;
2817     GVariantIter iter;
2818     GVariant *value;
2819     gchar *number;
2820     gboolean just;
2821     gint i, val;
2822
2823     g_variant_builder_init (&array, G_VARIANT_TYPE_ARRAY);
2824     for (i = 0; i < 100; i++)
2825       {
2826         number = g_strdup_printf ("%d", i);
2827         g_variant_builder_add (&array, "s", number);
2828         g_free (number);
2829       }
2830
2831     value = g_variant_builder_end (&array);
2832     g_variant_iter_init (&iter, value);
2833
2834     i = 0;
2835     while (g_variant_iter_loop (&iter, "s", &number))
2836       {
2837         gchar *check = g_strdup_printf ("%d", i++);
2838         g_assert_cmpstr (number, ==, check);
2839         g_free (check);
2840       }
2841     g_assert (number == NULL);
2842     g_assert (i == 100);
2843
2844     g_variant_unref (value);
2845
2846     g_variant_builder_init (&array, G_VARIANT_TYPE_ARRAY);
2847     for (i = 0; i < 100; i++)
2848       g_variant_builder_add (&array, "mi", i % 2 == 0, i);
2849     value = g_variant_builder_end (&array);
2850
2851     i = 0;
2852     g_variant_iter_init (&iter, value);
2853     while (g_variant_iter_loop (&iter, "mi", NULL, &val))
2854       g_assert (val == i++ || val == 0);
2855     g_assert (i == 100);
2856
2857     i = 0;
2858     g_variant_iter_init (&iter, value);
2859     while (g_variant_iter_loop (&iter, "mi", &just, &val))
2860       {
2861         gint this = i++;
2862
2863         if (this % 2 == 0)
2864           {
2865             g_assert (just);
2866             g_assert (val == this);
2867           }
2868         else
2869           {
2870             g_assert (!just);
2871             g_assert (val == 0);
2872           }
2873       }
2874     g_assert (i == 100);
2875
2876     g_variant_unref (value);
2877   }
2878
2879   {
2880     const gchar *strvector[] = {"/hello", "/world", NULL};
2881     const gchar *test_strs[] = {"/foo", "/bar", "/baz" };
2882     GVariantBuilder builder;
2883     GVariantIter *array;
2884     GVariantIter tuple;
2885     const gchar **strv;
2886     gchar **my_strv;
2887     GVariant *value;
2888     gchar *str;
2889     gint i;
2890
2891     g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
2892     g_variant_builder_add (&builder, "o", "/foo");
2893     g_variant_builder_add (&builder, "o", "/bar");
2894     g_variant_builder_add (&builder, "o", "/baz");
2895     value = g_variant_new("(ao^ao^a&o)", &builder, strvector, strvector);
2896     g_variant_iter_init (&tuple, value);
2897     g_variant_iter_next (&tuple, "ao", &array);
2898
2899     i = 0;
2900     while (g_variant_iter_loop (array, "o", &str))
2901       g_assert_cmpstr (str, ==, test_strs[i++]);
2902     g_assert (i == 3);
2903
2904     g_variant_iter_free (array);
2905
2906     /* start over */
2907     g_variant_iter_init (&tuple, value);
2908     g_variant_iter_next (&tuple, "ao", &array);
2909
2910     i = 0;
2911     while (g_variant_iter_loop (array, "&o", &str))
2912       g_assert_cmpstr (str, ==, test_strs[i++]);
2913     g_assert (i == 3);
2914
2915     g_variant_iter_free (array);
2916
2917     g_variant_iter_next (&tuple, "^a&o", &strv);
2918     g_variant_iter_next (&tuple, "^ao", &my_strv);
2919
2920     g_assert_cmpstr (strv[0], ==, "/hello");
2921     g_assert_cmpstr (strv[1], ==, "/world");
2922     g_assert (strv[2] == NULL);
2923     g_assert_cmpstr (my_strv[0], ==, "/hello");
2924     g_assert_cmpstr (my_strv[1], ==, "/world");
2925     g_assert (my_strv[2] == NULL);
2926
2927     g_variant_unref (value);
2928     g_strfreev (my_strv);
2929     g_free (strv);
2930   }
2931
2932   {
2933     const gchar *strvector[] = { "i", "ii", "iii", "iv", "v", "vi", NULL };
2934     GVariantBuilder builder;
2935     GVariantIter iter;
2936     GVariantIter *i2;
2937     GVariantIter *i3;
2938     GVariant *value;
2939     GVariant *sub;
2940     gchar **strv;
2941     gint i;
2942
2943     g_variant_builder_init (&builder, G_VARIANT_TYPE ("aag"));
2944     g_variant_builder_open (&builder, G_VARIANT_TYPE ("ag"));
2945     for (i = 0; i < 6; i++)
2946       if (i & 1)
2947         g_variant_builder_add (&builder, "g", strvector[i]);
2948       else
2949         g_variant_builder_add (&builder, "&g", strvector[i]);
2950     g_variant_builder_close (&builder);
2951     g_variant_builder_add (&builder, "^ag", strvector);
2952     g_variant_builder_add (&builder, "^ag", strvector);
2953     value = g_variant_new ("aag", &builder);
2954
2955     g_variant_iter_init (&iter, value);
2956     while (g_variant_iter_loop (&iter, "^ag", &strv))
2957       for (i = 0; i < 6; i++)
2958         g_assert_cmpstr (strv[i], ==, strvector[i]);
2959
2960     g_variant_iter_init (&iter, value);
2961     while (g_variant_iter_loop (&iter, "^a&g", &strv))
2962       for (i = 0; i < 6; i++)
2963         g_assert_cmpstr (strv[i], ==, strvector[i]);
2964
2965     g_variant_iter_init (&iter, value);
2966     while (g_variant_iter_loop (&iter, "ag", &i2))
2967       {
2968         gchar *str;
2969
2970         i = 0;
2971         while (g_variant_iter_loop (i2, "g", &str))
2972           g_assert_cmpstr (str, ==, strvector[i++]);
2973         g_assert (i == 6);
2974       }
2975
2976     g_variant_iter_init (&iter, value);
2977     i3 = g_variant_iter_copy (&iter);
2978     while (g_variant_iter_loop (&iter, "@ag", &sub))
2979       {
2980         gchar *str = g_variant_print (sub, TRUE);
2981         g_assert_cmpstr (str, ==,
2982                          "[signature 'i', 'ii', 'iii', 'iv', 'v', 'vi']");
2983         g_free (str);
2984       }
2985
2986   if (do_failed_test ("*NULL has already been returned*"))
2987     {
2988       g_variant_iter_next_value (&iter);
2989       abort ();
2990     }
2991
2992
2993     while (g_variant_iter_loop (i3, "*", &sub))
2994       {
2995         gchar *str = g_variant_print (sub, TRUE);
2996         g_assert_cmpstr (str, ==,
2997                          "[signature 'i', 'ii', 'iii', 'iv', 'v', 'vi']");
2998         g_free (str);
2999       }
3000
3001     g_variant_iter_free (i3);
3002
3003     for (i = 0; i < g_variant_n_children (value); i++)
3004       {
3005         gint j;
3006
3007         g_variant_get_child (value, i, "*", &sub);
3008
3009         for (j = 0; j < g_variant_n_children (sub); j++)
3010           {
3011             const gchar *str = NULL;
3012             GVariant *cval;
3013
3014             g_variant_get_child (sub, j, "&g", &str);
3015             g_assert_cmpstr (str, ==, strvector[j]);
3016
3017             cval = g_variant_get_child_value (sub, j);
3018             g_variant_get (cval, "&g", &str);
3019             g_assert_cmpstr (str, ==, strvector[j]);
3020             g_variant_unref (cval);
3021           }
3022
3023         g_variant_unref (sub);
3024       }
3025
3026     g_variant_unref (value);
3027   }
3028
3029   {
3030     gboolean justs[10];
3031     GVariant *value;
3032
3033     GVariant *vval;
3034     guchar byteval;
3035     gboolean bval;
3036     gint16 i16val;
3037     guint16 u16val;
3038     gint32 i32val;
3039     guint32 u32val;
3040     gint64 i64val;
3041     guint64 u64val;
3042     gdouble dval;
3043     gint32 hval;
3044
3045     /* test all 'Nothing' */
3046     value = g_variant_new ("(mymbmnmqmimumxmtmhmdmv)",
3047                            FALSE, 'a',
3048                            FALSE, TRUE,
3049                            FALSE, (gint16) 123,
3050                            FALSE, (guint16) 123,
3051                            FALSE, (gint32) 123,
3052                            FALSE, (guint32) 123,
3053                            FALSE, (gint64) 123,
3054                            FALSE, (guint64) 123,
3055                            FALSE, (gint32) -1,
3056                            FALSE, (gdouble) 37.5,
3057                            NULL);
3058
3059     /* both NULL */
3060     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3061                    NULL, NULL,
3062                    NULL, NULL,
3063                    NULL, NULL,
3064                    NULL, NULL,
3065                    NULL, NULL,
3066                    NULL, NULL,
3067                    NULL, NULL,
3068                    NULL, NULL,
3069                    NULL, NULL,
3070                    NULL, NULL,
3071                    NULL);
3072
3073     /* NULL values */
3074     memset (justs, 1, sizeof justs);
3075     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3076                    &justs[0], NULL,
3077                    &justs[1], NULL,
3078                    &justs[2], NULL,
3079                    &justs[3], NULL,
3080                    &justs[4], NULL,
3081                    &justs[5], NULL,
3082                    &justs[6], NULL,
3083                    &justs[7], NULL,
3084                    &justs[8], NULL,
3085                    &justs[9], NULL,
3086                    NULL);
3087     g_assert (!(justs[0] || justs[1] || justs[2] || justs[3] || justs[4] ||
3088                 justs[5] || justs[6] || justs[7] || justs[8] || justs[9]));
3089
3090     /* both non-NULL */
3091     memset (justs, 1, sizeof justs);
3092     byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88;
3093     vval = (void *) 1;
3094     bval = TRUE;
3095     dval = 88.88;
3096     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3097                    &justs[0], &byteval,
3098                    &justs[1], &bval,
3099                    &justs[2], &i16val,
3100                    &justs[3], &u16val,
3101                    &justs[4], &i32val,
3102                    &justs[5], &u32val,
3103                    &justs[6], &i64val,
3104                    &justs[7], &u64val,
3105                    &justs[8], &hval,
3106                    &justs[9], &dval,
3107                    &vval);
3108     g_assert (!(justs[0] || justs[1] || justs[2] || justs[3] || justs[4] ||
3109                 justs[5] || justs[6] || justs[7] || justs[8] || justs[9]));
3110     g_assert (byteval == '\0' && bval == FALSE);
3111     g_assert (i16val == 0 && u16val == 0 && i32val == 0 &&
3112               u32val == 0 && i64val == 0 && u64val == 0 &&
3113               hval == 0 && dval == 0.0);
3114     g_assert (vval == NULL);
3115
3116     /* NULL justs */
3117     byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88;
3118     vval = (void *) 1;
3119     bval = TRUE;
3120     dval = 88.88;
3121     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3122                    NULL, &byteval,
3123                    NULL, &bval,
3124                    NULL, &i16val,
3125                    NULL, &u16val,
3126                    NULL, &i32val,
3127                    NULL, &u32val,
3128                    NULL, &i64val,
3129                    NULL, &u64val,
3130                    NULL, &hval,
3131                    NULL, &dval,
3132                    &vval);
3133     g_assert (byteval == '\0' && bval == FALSE);
3134     g_assert (i16val == 0 && u16val == 0 && i32val == 0 &&
3135               u32val == 0 && i64val == 0 && u64val == 0 &&
3136               hval == 0 && dval == 0.0);
3137     g_assert (vval == NULL);
3138
3139     g_variant_unref (value);
3140
3141
3142     /* test all 'Just' */
3143     value = g_variant_new ("(mymbmnmqmimumxmtmhmdmv)",
3144                            TRUE, 'a',
3145                            TRUE, TRUE,
3146                            TRUE, (gint16) 123,
3147                            TRUE, (guint16) 123,
3148                            TRUE, (gint32) 123,
3149                            TRUE, (guint32) 123,
3150                            TRUE, (gint64) 123,
3151                            TRUE, (guint64) 123,
3152                            TRUE, (gint32) -1,
3153                            TRUE, (gdouble) 37.5,
3154                            g_variant_new ("()"));
3155
3156     /* both NULL */
3157     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3158                    NULL, NULL,
3159                    NULL, NULL,
3160                    NULL, NULL,
3161                    NULL, NULL,
3162                    NULL, NULL,
3163                    NULL, NULL,
3164                    NULL, NULL,
3165                    NULL, NULL,
3166                    NULL, NULL,
3167                    NULL, NULL,
3168                    NULL);
3169
3170     /* NULL values */
3171     memset (justs, 0, sizeof justs);
3172     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3173                    &justs[0], NULL,
3174                    &justs[1], NULL,
3175                    &justs[2], NULL,
3176                    &justs[3], NULL,
3177                    &justs[4], NULL,
3178                    &justs[5], NULL,
3179                    &justs[6], NULL,
3180                    &justs[7], NULL,
3181                    &justs[8], NULL,
3182                    &justs[9], NULL,
3183                    NULL);
3184     g_assert (justs[0] && justs[1] && justs[2] && justs[3] && justs[4] &&
3185               justs[5] && justs[6] && justs[7] && justs[8] && justs[9]);
3186
3187     /* both non-NULL */
3188     memset (justs, 0, sizeof justs);
3189     byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88;
3190     vval = (void *) 1;
3191     bval = FALSE;
3192     dval = 88.88;
3193     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3194                    &justs[0], &byteval,
3195                    &justs[1], &bval,
3196                    &justs[2], &i16val,
3197                    &justs[3], &u16val,
3198                    &justs[4], &i32val,
3199                    &justs[5], &u32val,
3200                    &justs[6], &i64val,
3201                    &justs[7], &u64val,
3202                    &justs[8], &hval,
3203                    &justs[9], &dval,
3204                    &vval);
3205     g_assert (justs[0] && justs[1] && justs[2] && justs[3] && justs[4] &&
3206               justs[5] && justs[6] && justs[7] && justs[8] && justs[9]);
3207     g_assert (byteval == 'a' && bval == TRUE);
3208     g_assert (i16val == 123 && u16val == 123 && i32val == 123 &&
3209               u32val == 123 && i64val == 123 && u64val == 123 &&
3210               hval == -1 && dval == 37.5);
3211     g_assert (g_variant_is_of_type (vval, G_VARIANT_TYPE_UNIT));
3212     g_variant_unref (vval);
3213
3214     /* NULL justs */
3215     byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88;
3216     vval = (void *) 1;
3217     bval = TRUE;
3218     dval = 88.88;
3219     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3220                    NULL, &byteval,
3221                    NULL, &bval,
3222                    NULL, &i16val,
3223                    NULL, &u16val,
3224                    NULL, &i32val,
3225                    NULL, &u32val,
3226                    NULL, &i64val,
3227                    NULL, &u64val,
3228                    NULL, &hval,
3229                    NULL, &dval,
3230                    &vval);
3231     g_assert (byteval == 'a' && bval == TRUE);
3232     g_assert (i16val == 123 && u16val == 123 && i32val == 123 &&
3233               u32val == 123 && i64val == 123 && u64val == 123 &&
3234               hval == -1 && dval == 37.5);
3235     g_assert (g_variant_is_of_type (vval, G_VARIANT_TYPE_UNIT));
3236     g_variant_unref (vval);
3237
3238     g_variant_unref (value);
3239   }
3240
3241   g_variant_type_info_assert_no_infos ();
3242 }
3243
3244 static void
3245 hash_get (GVariant    *value,
3246           const gchar *format,
3247           ...)
3248 {
3249   const gchar *endptr = NULL;
3250   gboolean hash;
3251   va_list ap;
3252
3253   hash = g_str_has_suffix (format, "#");
3254
3255   va_start (ap, format);
3256   g_variant_get_va (value, format, hash ? &endptr : NULL, &ap);
3257   va_end (ap);
3258
3259   if (hash)
3260     g_assert (*endptr == '#');
3261 }
3262
3263 static GVariant *
3264 hash_new (const gchar *format,
3265           ...)
3266 {
3267   const gchar *endptr = NULL;
3268   GVariant *value;
3269   gboolean hash;
3270   va_list ap;
3271
3272   hash = g_str_has_suffix (format, "#");
3273
3274   va_start (ap, format);
3275   value = g_variant_new_va (format, hash ? &endptr : NULL, &ap);
3276   va_end (ap);
3277
3278   if (hash)
3279     g_assert (*endptr == '#');
3280
3281   return value;
3282 }
3283
3284 static void
3285 test_valist (void)
3286 {
3287   GVariant *value;
3288   gint32 x;
3289
3290   x = 0;
3291   value = hash_new ("i", 234);
3292   hash_get (value, "i", &x);
3293   g_assert (x == 234);
3294   g_variant_unref (value);
3295
3296   x = 0;
3297   value = hash_new ("i#", 234);
3298   hash_get (value, "i#", &x);
3299   g_assert (x == 234);
3300   g_variant_unref (value);
3301
3302   g_variant_type_info_assert_no_infos ();
3303 }
3304
3305 static void
3306 test_builder_memory (void)
3307 {
3308   GVariantBuilder *hb;
3309   GVariantBuilder sb;
3310
3311   hb = g_variant_builder_new  (G_VARIANT_TYPE_ARRAY);
3312   g_variant_builder_open (hb, G_VARIANT_TYPE_ARRAY);
3313   g_variant_builder_open (hb, G_VARIANT_TYPE_ARRAY);
3314   g_variant_builder_open (hb, G_VARIANT_TYPE_ARRAY);
3315   g_variant_builder_add (hb, "s", "some value");
3316   g_variant_builder_ref (hb);
3317   g_variant_builder_unref (hb);
3318   g_variant_builder_unref (hb);
3319
3320   hb = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
3321   g_variant_builder_unref (hb);
3322
3323   hb = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
3324   g_variant_builder_clear (hb);
3325   g_variant_builder_unref (hb);
3326
3327   g_variant_builder_init (&sb, G_VARIANT_TYPE_ARRAY);
3328   g_variant_builder_open (&sb, G_VARIANT_TYPE_ARRAY);
3329   g_variant_builder_open (&sb, G_VARIANT_TYPE_ARRAY);
3330   g_variant_builder_add (&sb, "s", "some value");
3331   g_variant_builder_clear (&sb);
3332
3333   g_variant_type_info_assert_no_infos ();
3334 }
3335
3336 static void
3337 test_hashing (void)
3338 {
3339   const gint n_items = 4096;
3340   GVariant *items[n_items];
3341   GHashTable *table;
3342   gint i;
3343
3344   table = g_hash_table_new_full (g_variant_hash, g_variant_equal,
3345                                  (GDestroyNotify ) g_variant_unref,
3346                                  NULL);
3347
3348   for (i = 0; i < n_items; i++)
3349     {
3350       TreeInstance *tree;
3351       gint j;
3352
3353  again:
3354       tree = tree_instance_new (NULL, 0);
3355       items[i] = tree_instance_get_gvariant (tree);
3356       tree_instance_free (tree);
3357
3358       for (j = 0; j < i; j++)
3359         if (g_variant_equal (items[i], items[j]))
3360           {
3361             g_variant_unref (items[i]);
3362             goto again;
3363           }
3364
3365       g_hash_table_insert (table,
3366                            g_variant_ref_sink (items[i]),
3367                            GINT_TO_POINTER (i));
3368     }
3369
3370   for (i = 0; i < n_items; i++)
3371     {
3372       gpointer result;
3373
3374       result = g_hash_table_lookup (table, items[i]);
3375       g_assert_cmpint (GPOINTER_TO_INT (result), ==, i);
3376     }
3377
3378   g_hash_table_unref (table);
3379
3380   g_variant_type_info_assert_no_infos ();
3381 }
3382
3383 int
3384 main (int argc, char **argv)
3385 {
3386   gint i;
3387
3388   g_test_init (&argc, &argv, NULL);
3389
3390   g_test_add_func ("/gvariant/type", test_gvarianttype);
3391   g_test_add_func ("/gvariant/typeinfo", test_gvarianttypeinfo);
3392   g_test_add_func ("/gvariant/serialiser/maybe", test_maybes);
3393   g_test_add_func ("/gvariant/serialiser/array", test_arrays);
3394   g_test_add_func ("/gvariant/serialiser/tuple", test_tuples);
3395   g_test_add_func ("/gvariant/serialiser/variant", test_variants);
3396   g_test_add_func ("/gvariant/serialiser/strings", test_strings);
3397   g_test_add_func ("/gvariant/serialiser/byteswap", test_byteswaps);
3398
3399   for (i = 1; i <= 20; i += 4)
3400     {
3401       char *testname;
3402
3403       testname = g_strdup_printf ("/gvariant/serialiser/fuzz/%d%%", i);
3404       g_test_add_data_func (testname, GINT_TO_POINTER (i),
3405                             (gpointer) test_fuzzes);
3406       g_free (testname);
3407     }
3408
3409   g_test_add_func ("/gvariant/containers", test_containers);
3410   g_test_add_func ("/gvariant/format-strings", test_format_strings);
3411   g_test_add_func ("/gvariant/invalid-varargs", test_invalid_varargs);
3412   g_test_add_func ("/gvariant/varargs", test_varargs);
3413   g_test_add_func ("/gvariant/valist", test_valist);
3414   g_test_add_func ("/gvariant/builder-memory", test_builder_memory);
3415   g_test_add_func ("/gvariant/hashing", test_hashing);
3416
3417   return g_test_run ();
3418 }