GVariantBuilder: allow for stack allocation
[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 <string.h>
15 #include <glib.h>
16
17 #define BASIC "bynqiuxthdsog?"
18 #define N_BASIC (G_N_ELEMENTS (BASIC) - 1)
19
20 #define INVALIDS "cefjklpwz&@^$"
21 #define N_INVALIDS (G_N_ELEMENTS (INVALIDS) - 1)
22
23 static gboolean
24 randomly (gdouble prob)
25 {
26   return g_test_rand_double_range (0, 1) < prob;
27 }
28
29 /* corecursion */
30 static GVariantType *
31 append_tuple_type_string (GString *, GString *, gboolean, gint);
32
33 /* append a random GVariantType to a GString
34  * append a description of the type to another GString
35  * return what the type is
36  */
37 static GVariantType *
38 append_type_string (GString  *string,
39                     GString  *description,
40                     gboolean  definite,
41                     gint      depth)
42 {
43   if (!depth-- || randomly (0.3))
44     {
45       gchar b = BASIC[g_test_rand_int_range (0, N_BASIC - definite)];
46       g_string_append_c (string, b);
47       g_string_append_c (description, b);
48
49       switch (b)
50         {
51         case 'b':
52           return g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN);
53         case 'y':
54           return g_variant_type_copy (G_VARIANT_TYPE_BYTE);
55         case 'n':
56           return g_variant_type_copy (G_VARIANT_TYPE_INT16);
57         case 'q':
58           return g_variant_type_copy (G_VARIANT_TYPE_UINT16);
59         case 'i':
60           return g_variant_type_copy (G_VARIANT_TYPE_INT32);
61         case 'u':
62           return g_variant_type_copy (G_VARIANT_TYPE_UINT32);
63         case 'x':
64           return g_variant_type_copy (G_VARIANT_TYPE_INT64);
65         case 't':
66           return g_variant_type_copy (G_VARIANT_TYPE_UINT64);
67         case 'h':
68           return g_variant_type_copy (G_VARIANT_TYPE_HANDLE);
69         case 'd':
70           return g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
71         case 's':
72           return g_variant_type_copy (G_VARIANT_TYPE_STRING);
73         case 'o':
74           return g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH);
75         case 'g':
76           return g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE);
77         case '?':
78           return g_variant_type_copy (G_VARIANT_TYPE_BASIC);
79         default:
80           g_assert_not_reached ();
81         }
82     }
83   else
84     {
85       GVariantType *result;
86
87       switch (g_test_rand_int_range (0, definite ? 5 : 7))
88         {
89         case 0:
90           {
91             GVariantType *element;
92
93             g_string_append_c (string, 'a');
94             g_string_append (description, "a of ");
95             element = append_type_string (string, description,
96                                           definite, depth);
97             result = g_variant_type_new_array (element);
98             g_variant_type_free (element);
99           }
100
101           g_assert (g_variant_type_is_array (result));
102           break;
103
104         case 1:
105           {
106             GVariantType *element;
107
108             g_string_append_c (string, 'm');
109             g_string_append (description, "m of ");
110             element = append_type_string (string, description,
111                                           definite, depth);
112             result = g_variant_type_new_maybe (element);
113             g_variant_type_free (element);
114           }
115
116           g_assert (g_variant_type_is_maybe (result));
117           break;
118
119         case 2:
120           result = append_tuple_type_string (string, description,
121                                              definite, depth);
122
123           g_assert (g_variant_type_is_tuple (result));
124           break;
125
126         case 3:
127           {
128             GVariantType *key, *value;
129
130             g_string_append_c (string, '{');
131             g_string_append (description, "e of [");
132             key = append_type_string (string, description, definite, 0);
133             g_string_append (description, ", ");
134             value = append_type_string (string, description, definite, depth);
135             g_string_append_c (description, ']');
136             g_string_append_c (string, '}');
137             result = g_variant_type_new_dict_entry (key, value);
138             g_variant_type_free (key);
139             g_variant_type_free (value);
140           }
141
142           g_assert (g_variant_type_is_dict_entry (result));
143           break;
144
145         case 4:
146           g_string_append_c (string, 'v');
147           g_string_append_c (description, 'V');
148           result = g_variant_type_copy (G_VARIANT_TYPE_VARIANT);
149           g_assert (g_variant_type_equal (result, G_VARIANT_TYPE_VARIANT));
150           break;
151
152         case 5:
153           g_string_append_c (string, '*');
154           g_string_append_c (description, 'S');
155           result = g_variant_type_copy (G_VARIANT_TYPE_ANY);
156           g_assert (g_variant_type_equal (result, G_VARIANT_TYPE_ANY));
157           break;
158
159         case 6:
160           g_string_append_c (string, 'r');
161           g_string_append_c (description, 'R');
162           result = g_variant_type_copy (G_VARIANT_TYPE_TUPLE);
163           g_assert (g_variant_type_is_tuple (result));
164           break;
165
166         default:
167           g_assert_not_reached ();
168         }
169
170       return result;
171     }
172 }
173
174 static GVariantType *
175 append_tuple_type_string (GString  *string,
176                           GString  *description,
177                           gboolean  definite,
178                           gint      depth)
179 {
180   GVariantType *result, *other_result;
181   GVariantType **types;
182   gint size;
183   gint i;
184
185   g_string_append_c (string, '(');
186   g_string_append (description, "t of [");
187
188   size = g_test_rand_int_range (0, 20);
189   types = g_new (GVariantType *, size + 1);
190
191   for (i = 0; i < size; i++)
192     {
193       types[i] = append_type_string (string, description, definite, depth);
194
195       if (i < size - 1)
196         g_string_append (description, ", ");
197     }
198
199   types[i] = NULL;
200
201   g_string_append_c (description, ']');
202   g_string_append_c (string, ')');
203
204   result = g_variant_type_new_tuple ((gpointer) types, size);
205   other_result = g_variant_type_new_tuple ((gpointer) types, -1);
206   g_assert (g_variant_type_equal (result, other_result));
207   g_variant_type_free (other_result);
208   for (i = 0; i < size; i++)
209     g_variant_type_free (types[i]);
210   g_free (types);
211
212   return result;
213 }
214
215 /* given a valid type string, make it invalid */
216 static gchar *
217 invalid_mutation (const gchar *type_string)
218 {
219   gboolean have_parens, have_braces;
220
221   /* it's valid, so '(' implies ')' and same for '{' and '}' */
222   have_parens = strchr (type_string, '(') != NULL;
223   have_braces = strchr (type_string, '{') != NULL;
224
225   if (have_parens && have_braces && randomly (0.3))
226     {
227       /* swap a paren and a brace */
228       gchar *pp, *bp;
229       gint np, nb;
230       gchar p, b;
231       gchar *new;
232
233       new = g_strdup (type_string);
234
235       if (randomly (0.5))
236         p = '(', b = '{';
237       else
238         p = ')', b = '}';
239
240       np = nb = 0;
241       pp = bp = new - 1;
242
243       /* count number of parens/braces */
244       while ((pp = strchr (pp + 1, p))) np++;
245       while ((bp = strchr (bp + 1, b))) nb++;
246
247       /* randomly pick one of each */
248       np = g_test_rand_int_range (0, np) + 1;
249       nb = g_test_rand_int_range (0, nb) + 1;
250
251       /* find it */
252       pp = bp = new - 1;
253       while (np--) pp = strchr (pp + 1, p);
254       while (nb--) bp = strchr (bp + 1, b);
255
256       /* swap */
257       g_assert (*bp == b && *pp == p);
258       *bp = p;
259       *pp = b;
260
261       return new;
262     }
263
264   if ((have_parens || have_braces) && randomly (0.3))
265     {
266       /* drop a paren/brace */
267       gchar *new;
268       gchar *pp;
269       gint np;
270       gchar p;
271
272       if (have_parens)
273         if (randomly (0.5)) p = '('; else p = ')';
274       else
275         if (randomly (0.5)) p = '{'; else p = '}';
276
277       new = g_strdup (type_string);
278
279       np = 0;
280       pp = new - 1;
281       while ((pp = strchr (pp + 1, p))) np++;
282       np = g_test_rand_int_range (0, np) + 1;
283       pp = new - 1;
284       while (np--) pp = strchr (pp + 1, p);
285       g_assert (*pp == p);
286
287       while (*pp)
288         {
289           *pp = *(pp + 1);
290           pp++;
291         }
292
293       return new;
294     }
295
296   /* else, perform a random mutation at a random point */
297   {
298     gint length, n;
299     gchar *new;
300     gchar p;
301
302     if (randomly (0.3))
303       {
304         /* insert a paren/brace */
305         if (randomly (0.5))
306           if (randomly (0.5)) p = '('; else p = ')';
307         else
308           if (randomly (0.5)) p = '{'; else p = '}';
309       }
310     else if (randomly (0.5))
311       {
312         /* insert junk */
313         p = INVALIDS[g_test_rand_int_range (0, N_INVALIDS)];
314       }
315     else
316       {
317         /* truncate */
318         p = '\0';
319       }
320
321
322     length = strlen (type_string);
323     new = g_malloc (length + 2);
324     n = g_test_rand_int_range (0, length);
325     memcpy (new, type_string, n);
326     new[n] = p;
327     memcpy (new + n + 1, type_string + n, length - n);
328     new[length + 1] = '\0';
329
330     return new;
331   }
332 }
333
334 /* describe a type using the same language as is generated
335  * while generating the type with append_type_string
336  */
337 static gchar *
338 describe_type (const GVariantType *type)
339 {
340   gchar *result;
341
342   if (g_variant_type_is_container (type))
343     {
344       g_assert (!g_variant_type_is_basic (type));
345
346       if (g_variant_type_is_array (type))
347         {
348           gchar *subtype = describe_type (g_variant_type_element (type));
349           result = g_strdup_printf ("a of %s", subtype);
350           g_free (subtype);
351         }
352       else if (g_variant_type_is_maybe (type))
353         {
354           gchar *subtype = describe_type (g_variant_type_element (type));
355           result = g_strdup_printf ("m of %s", subtype);
356           g_free (subtype);
357         }
358       else if (g_variant_type_is_tuple (type))
359         {
360           if (!g_variant_type_equal (type, G_VARIANT_TYPE_TUPLE))
361             {
362               const GVariantType *sub;
363               GString *string;
364               gint length;
365               gint i;
366
367               string = g_string_new ("t of [");
368
369               length = g_variant_type_n_items (type);
370               sub = g_variant_type_first (type);
371               for (i = 0; i < length; i++)
372                 {
373                   gchar *subtype = describe_type (sub);
374                   g_string_append (string, subtype);
375                   g_free (subtype);
376
377                   if ((sub = g_variant_type_next (sub)))
378                     g_string_append (string, ", ");
379                 }
380               g_assert (sub == NULL);
381               g_string_append_c (string, ']');
382
383               result = g_string_free (string, FALSE);
384             }
385           else
386             result = g_strdup ("R");
387         }
388       else if (g_variant_type_is_dict_entry (type))
389         {
390           gchar *key, *value, *key2, *value2;
391
392           key = describe_type (g_variant_type_key (type));
393           value = describe_type (g_variant_type_value (type));
394           key2 = describe_type (g_variant_type_first (type));
395           value2 = describe_type (
396             g_variant_type_next (g_variant_type_first (type)));
397           g_assert (g_variant_type_next (g_variant_type_next (
398             g_variant_type_first (type))) == NULL);
399           g_assert_cmpstr (key, ==, key2);
400           g_assert_cmpstr (value, ==, value2);
401           result = g_strjoin ("", "e of [", key, ", ", value, "]", NULL);
402           g_free (key2);
403           g_free (value2);
404           g_free (key);
405           g_free (value);
406         }
407       else if (g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT))
408         {
409           result = g_strdup ("V");
410         }
411       else
412         g_assert_not_reached ();
413     }
414   else
415     {
416       if (g_variant_type_is_definite (type))
417         {
418           g_assert (g_variant_type_is_basic (type));
419
420           if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
421             result = g_strdup ("b");
422           else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
423             result = g_strdup ("y");
424           else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
425             result = g_strdup ("n");
426           else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
427             result = g_strdup ("q");
428           else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
429             result = g_strdup ("i");
430           else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
431             result = g_strdup ("u");
432           else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
433             result = g_strdup ("x");
434           else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
435             result = g_strdup ("t");
436           else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
437             result = g_strdup ("h");
438           else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
439             result = g_strdup ("d");
440           else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
441             result = g_strdup ("s");
442           else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
443             result = g_strdup ("o");
444           else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
445             result = g_strdup ("g");
446           else
447             g_assert_not_reached ();
448         }
449       else
450         {
451           if (g_variant_type_equal (type, G_VARIANT_TYPE_ANY))
452             {
453               result = g_strdup ("S");
454             }
455           else if (g_variant_type_equal (type, G_VARIANT_TYPE_BASIC))
456             {
457               result = g_strdup ("?");
458             }
459           else
460             g_assert_not_reached ();
461         }
462     }
463
464   return result;
465 }
466
467 /* given a type string, replace one of the indefinite type characters in
468  * it with a matching type (possibly the same type).
469  */
470 static gchar *
471 generate_subtype (const gchar *type_string)
472 {
473   GVariantType *replacement;
474   GString *result, *junk;
475   gint length, n = 0, l;
476
477   result = g_string_new (NULL);
478   junk = g_string_new (NULL);
479
480   /* count the number of indefinite type characters */
481   for (length = 0; type_string[length]; length++)
482     n += type_string[length] == 'r' ||
483          type_string[length] == '?' ||
484          type_string[length] == '*';
485   /* length now is strlen (type_string) */
486
487   /* pick one at random to replace */
488   n = g_test_rand_int_range (0, n) + 1;
489
490   /* find it */
491   l = -1;
492   while (n--) l += strcspn (type_string + l + 1, "r?*") + 1;
493   g_assert (type_string[l] == 'r' ||
494             type_string[l] == '?' ||
495             type_string[l] == '*');
496
497   /* store up to that point in a GString */
498   g_string_append_len (result, type_string, l);
499
500   /* then store the replacement in the GString */
501   if (type_string[l] == 'r')
502     replacement = append_tuple_type_string (result, junk, FALSE, 3);
503
504   else if (type_string[l] == '?')
505     replacement = append_type_string (result, junk, FALSE, 0);
506
507   else if (type_string[l] == '*')
508     replacement = append_type_string (result, junk, FALSE, 3);
509
510   else
511     g_assert_not_reached ();
512
513   /* ensure the replacement has the proper type */
514   g_assert (g_variant_type_is_subtype_of (replacement,
515                                           (gpointer) &type_string[l]));
516
517   /* store the rest from the original type string */
518   g_string_append (result, type_string + l + 1);
519
520   g_variant_type_free (replacement);
521   g_string_free (junk, TRUE);
522
523   return g_string_free (result, FALSE);
524 }
525
526 struct typestack
527 {
528   const GVariantType *type;
529   struct typestack *parent;
530 };
531
532 /* given an indefinite type string, replace one of the indefinite
533  * characters in it with a matching type and ensure that the result is a
534  * subtype of the original.  repeat.
535  */
536 static void
537 subtype_check (const gchar      *type_string,
538                struct typestack *parent_ts)
539 {
540   struct typestack ts, *node;
541   gchar *subtype;
542   gint depth = 0;
543
544   subtype = generate_subtype (type_string);
545
546   ts.type = G_VARIANT_TYPE (subtype);
547   ts.parent = parent_ts;
548
549   for (node = &ts; node; node = node->parent)
550     {
551       /* this type should be a subtype of each parent type */
552       g_assert (g_variant_type_is_subtype_of (ts.type, node->type));
553
554       /* it should only be a supertype when it is exactly equal */
555       g_assert (g_variant_type_is_subtype_of (node->type, ts.type) ==
556                 g_variant_type_equal (ts.type, node->type));
557
558       depth++;
559     }
560
561   if (!g_variant_type_is_definite (ts.type) && depth < 5)
562     {
563       /* the type is still indefinite and we haven't repeated too many
564        * times.  go once more.
565        */
566
567       subtype_check (subtype, &ts);
568     }
569
570   g_free (subtype);
571 }
572
573 static void
574 test_gvarianttype (void)
575 {
576   gint i;
577
578   for (i = 0; i < 2000; i++)
579     {
580       GString *type_string, *description;
581       GVariantType *type, *other_type;
582       const GVariantType *ctype;
583       gchar *invalid;
584       gchar *desc;
585
586       type_string = g_string_new (NULL);
587       description = g_string_new (NULL);
588
589       /* generate a random type, its type string and a description
590        *
591        * exercises type constructor functions and g_variant_type_copy()
592        */
593       type = append_type_string (type_string, description, FALSE, 6);
594
595       /* convert the type string to a type and ensure that it is equal
596        * to the one produced with the type constructor routines
597        */
598       ctype = G_VARIANT_TYPE (type_string->str);
599       g_assert (g_variant_type_equal (ctype, type));
600       g_assert (g_variant_type_is_subtype_of (ctype, type));
601       g_assert (g_variant_type_is_subtype_of (type, ctype));
602
603       /* check if the type is indefinite */
604       if (!g_variant_type_is_definite (type))
605         {
606           struct typestack ts = { type, NULL };
607
608           /* if it is indefinite, then replace one of the indefinite
609            * characters with a matching type and ensure that the result
610            * is a subtype of the original type.  repeat.
611            */
612           subtype_check (type_string->str, &ts);
613         }
614       else
615         /* ensure that no indefinite characters appear */
616         g_assert (strcspn (type_string->str, "r?*") == type_string->len);
617
618
619       /* describe the type.
620        *
621        * exercises the type iterator interface
622        */
623       desc = describe_type (type);
624
625       /* make sure the description matches */
626       g_assert_cmpstr (desc, ==, description->str);
627       g_free (desc);
628
629       /* make an invalid mutation to the type and make sure the type
630        * validation routines catch it */
631       invalid = invalid_mutation (type_string->str);
632       g_assert (g_variant_type_string_is_valid (type_string->str));
633       g_assert (!g_variant_type_string_is_valid (invalid));
634       g_free (invalid);
635
636       /* concatenate another type to the type string and ensure that
637        * the result is recognised as being invalid
638        */
639       other_type = append_type_string (type_string, description, FALSE, 2);
640
641       g_string_free (description, TRUE);
642       g_string_free (type_string, TRUE);
643       g_variant_type_free (other_type);
644       g_variant_type_free (type);
645     }
646 }
647
648 #undef  G_GNUC_INTERNAL
649 #define G_GNUC_INTERNAL static
650
651 #define DISABLE_VISIBILITY
652 #define GLIB_COMPILATION
653 #include <glib/gvarianttypeinfo.c>
654
655 #define ALIGNED(x, y)   (((x + (y - 1)) / y) * y)
656
657 /* do our own calculation of the fixed_size and alignment of a type
658  * using a simple algorithm to make sure the "fancy" one in the
659  * implementation is correct.
660  */
661 static void
662 calculate_type_info (const GVariantType *type,
663                      gsize              *fixed_size,
664                      guint              *alignment)
665 {
666   if (g_variant_type_is_array (type) ||
667       g_variant_type_is_maybe (type))
668     {
669       calculate_type_info (g_variant_type_element (type), NULL, alignment);
670
671       if (fixed_size)
672         *fixed_size = 0;
673     }
674   else if (g_variant_type_is_tuple (type) ||
675            g_variant_type_is_dict_entry (type))
676     {
677       if (g_variant_type_n_items (type))
678         {
679           const GVariantType *sub;
680           gboolean variable;
681           gsize size;
682           guint al;
683
684           variable = FALSE;
685           size = 0;
686           al = 0;
687
688           sub = g_variant_type_first (type);
689           do
690             {
691               gsize this_fs;
692               guint this_al;
693
694               calculate_type_info (sub, &this_fs, &this_al);
695
696               al = MAX (al, this_al);
697
698               if (!this_fs)
699                 {
700                   variable = TRUE;
701                   size = 0;
702                 }
703
704               if (!variable)
705                 {
706                   size = ALIGNED (size, this_al);
707                   size += this_fs;
708                 }
709             }
710           while ((sub = g_variant_type_next (sub)));
711
712           size = ALIGNED (size, al);
713
714           if (alignment)
715             *alignment = al;
716
717           if (fixed_size)
718             *fixed_size = size;
719         }
720       else
721         {
722           if (fixed_size)
723             *fixed_size = 1;
724
725           if (alignment)
726             *alignment = 1;
727         }
728     }
729   else
730     {
731       gint fs, al;
732
733       if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN) ||
734           g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
735         {
736           al = fs = 1;
737         }
738
739       else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16) ||
740                g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
741         {
742           al = fs = 2;
743         }
744
745       else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32) ||
746                g_variant_type_equal (type, G_VARIANT_TYPE_UINT32) ||
747                g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
748         {
749           al = fs = 4;
750         }
751
752       else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64) ||
753                g_variant_type_equal (type, G_VARIANT_TYPE_UINT64) ||
754                g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
755         {
756           al = fs = 8;
757         }
758       else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING) ||
759                g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH) ||
760                g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
761         {
762           al = 1;
763           fs = 0;
764         }
765       else if (g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT))
766         {
767           al = 8;
768           fs = 0;
769         }
770       else
771         g_assert_not_reached ();
772
773       if (fixed_size)
774         *fixed_size = fs;
775
776       if (alignment)
777         *alignment = al;
778     }
779 }
780
781 /* same as the describe_type() function above, but iterates over
782  * typeinfo instead of types.
783  */
784 static gchar *
785 describe_info (GVariantTypeInfo *info)
786 {
787   gchar *result;
788
789   switch (g_variant_type_info_get_type_char (info))
790     {
791     case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
792       {
793         gchar *element;
794
795         element = describe_info (g_variant_type_info_element (info));
796         result = g_strdup_printf ("m of %s", element);
797         g_free (element);
798       }
799       break;
800
801     case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
802       {
803         gchar *element;
804
805         element = describe_info (g_variant_type_info_element (info));
806         result = g_strdup_printf ("a of %s", element);
807         g_free (element);
808       }
809       break;
810
811     case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
812       {
813         const gchar *sep = "";
814         GString *string;
815         gint length;
816         gint i;
817
818         string = g_string_new ("t of [");
819         length = g_variant_type_info_n_members (info);
820
821         for (i = 0; i < length; i++)
822           {
823             const GVariantMemberInfo *minfo;
824             gchar *subtype;
825
826             g_string_append (string, sep);
827             sep = ", ";
828
829             minfo = g_variant_type_info_member_info (info, i);
830             subtype = describe_info (minfo->type_info);
831             g_string_append (string, subtype);
832             g_free (subtype);
833           }
834
835         g_string_append_c (string, ']');
836
837         result = g_string_free (string, FALSE);
838       }
839       break;
840
841     case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
842       {
843         const GVariantMemberInfo *keyinfo, *valueinfo;
844         gchar *key, *value;
845
846         g_assert_cmpint (g_variant_type_info_n_members (info), ==, 2);
847         keyinfo = g_variant_type_info_member_info (info, 0);
848         valueinfo = g_variant_type_info_member_info (info, 1);
849         key = describe_info (keyinfo->type_info);
850         value = describe_info (valueinfo->type_info);
851         result = g_strjoin ("", "e of [", key, ", ", value, "]", NULL);
852         g_free (key);
853         g_free (value);
854       }
855       break;
856
857     case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
858       result = g_strdup ("V");
859       break;
860
861     default:
862       result = g_strdup (g_variant_type_info_get_type_string (info));
863       g_assert_cmpint (strlen (result), ==, 1);
864       break;
865     }
866
867   return result;
868 }
869
870 /* check that the O(1) method of calculating offsets meshes with the
871  * results of simple iteration.
872  */
873 static void
874 check_offsets (GVariantTypeInfo   *info,
875                const GVariantType *type)
876 {
877   gint flavour;
878   gint length;
879
880   length = g_variant_type_info_n_members (info);
881   g_assert_cmpint (length, ==, g_variant_type_n_items (type));
882
883   /* the 'flavour' is the low order bits of the ending point of
884    * variable-size items in the tuple.  this lets us test that the type
885    * info is correct for various starting alignments.
886    */
887   for (flavour = 0; flavour < 8; flavour++)
888     {
889       const GVariantType *subtype;
890       gsize last_offset_index;
891       gsize last_offset;
892       gsize position;
893       gint i;
894
895       subtype = g_variant_type_first (type);
896       last_offset_index = -1;
897       last_offset = 0;
898       position = 0;
899
900       /* go through the tuple, keeping track of our position */
901       for (i = 0; i < length; i++)
902         {
903           gsize fixed_size;
904           guint alignment;
905
906           calculate_type_info (subtype, &fixed_size, &alignment);
907
908           position = ALIGNED (position, alignment);
909
910           /* compare our current aligned position (ie: the start of this
911            * item) to the start offset that would be calculated if we
912            * used the type info
913            */
914           {
915             const GVariantMemberInfo *member;
916             gsize start;
917
918             member = g_variant_type_info_member_info (info, i);
919             g_assert_cmpint (member->i, ==, last_offset_index);
920
921             /* do the calculation using the typeinfo */
922             start = last_offset;
923             start += member->a;
924             start &= member->b;
925             start |= member->c;
926
927             /* did we reach the same spot? */
928             g_assert_cmpint (start, ==, position);
929           }
930
931           if (fixed_size)
932             {
933               /* fixed size.  add that size. */
934               position += fixed_size;
935             }
936           else
937             {
938               /* variable size.  do the flavouring. */
939               while ((position & 0x7) != flavour)
940                 position++;
941
942               /* and store the offset, just like it would be in the
943                * serialised data.
944                */
945               last_offset = position;
946               last_offset_index++;
947             }
948
949           /* next type */
950           subtype = g_variant_type_next (subtype);
951         }
952
953       /* make sure we used up exactly all the types */
954       g_assert (subtype == NULL);
955     }
956 }
957
958 static void
959 test_gvarianttypeinfo (void)
960 {
961   gint i;
962
963   for (i = 0; i < 2000; i++)
964     {
965       GString *type_string, *description;
966       gsize fixed_size1, fixed_size2;
967       guint alignment1, alignment2;
968       GVariantTypeInfo *info;
969       GVariantType *type;
970       gchar *desc;
971
972       type_string = g_string_new (NULL);
973       description = g_string_new (NULL);
974
975       /* random type */
976       type = append_type_string (type_string, description, TRUE, 6);
977
978       /* create a typeinfo for it */
979       info = g_variant_type_info_get (type);
980
981       /* make sure the typeinfo has the right type string */
982       g_assert_cmpstr (g_variant_type_info_get_type_string (info), ==,
983                        type_string->str);
984
985       /* calculate the alignment and fixed size, compare to the
986        * typeinfo's calculations
987        */
988       calculate_type_info (type, &fixed_size1, &alignment1);
989       g_variant_type_info_query (info, &alignment2, &fixed_size2);
990       g_assert_cmpint (fixed_size1, ==, fixed_size2);
991       g_assert_cmpint (alignment1, ==, alignment2 + 1);
992
993       /* test the iteration functions over typeinfo structures by
994        * "describing" the typeinfo and verifying equality.
995        */
996       desc = describe_info (info);
997       g_assert_cmpstr (desc, ==, description->str);
998
999       /* do extra checks for containers */
1000       if (g_variant_type_is_array (type) ||
1001           g_variant_type_is_maybe (type))
1002         {
1003           const GVariantType *element;
1004           gsize efs1, efs2;
1005           guint ea1, ea2;
1006
1007           element = g_variant_type_element (type);
1008           calculate_type_info (element, &efs1, &ea1);
1009           g_variant_type_info_query_element (info, &ea2, &efs2);
1010           g_assert_cmpint (efs1, ==, efs2);
1011           g_assert_cmpint (ea1, ==, ea2 + 1);
1012
1013           g_assert_cmpint (ea1, ==, alignment1);
1014           g_assert_cmpint (0, ==, fixed_size1);
1015         }
1016       else if (g_variant_type_is_tuple (type) ||
1017                g_variant_type_is_dict_entry (type))
1018         {
1019           /* make sure the "magic constants" are working */
1020           check_offsets (info, type);
1021         }
1022
1023       g_string_free (type_string, TRUE);
1024       g_string_free (description, TRUE);
1025       g_variant_type_info_unref (info);
1026       g_variant_type_free (type);
1027       g_free (desc);
1028     }
1029
1030   assert_no_type_infos ();
1031 }
1032
1033 #include <glib/gvariant-serialiser.c>
1034
1035 #define MAX_FIXED_MULTIPLIER    256
1036 #define MAX_INSTANCE_SIZE       1024
1037 #define MAX_ARRAY_CHILDREN      128
1038 #define MAX_TUPLE_CHILDREN      128
1039
1040 /* this function generates a random type such that all characteristics
1041  * that are "interesting" to the serialiser are tested.
1042  *
1043  * this basically means:
1044  *   - test different alignments
1045  *   - test variable sized items and fixed sized items
1046  *   - test different fixed sizes
1047  */
1048 static gchar *
1049 random_type_string (void)
1050 {
1051   const guchar base_types[] = "ynix";
1052   guchar base_type;
1053
1054   base_type = base_types[g_test_rand_int_range (0, 4)];
1055
1056   if (g_test_rand_bit ())
1057     /* construct a fixed-sized type */
1058     {
1059       char type_string[MAX_FIXED_MULTIPLIER];
1060       guint multiplier;
1061       guint i = 0;
1062
1063       multiplier = g_test_rand_int_range (1, sizeof type_string - 1);
1064
1065       type_string[i++] = '(';
1066       while (multiplier--)
1067         type_string[i++] = base_type;
1068       type_string[i++] = ')';
1069
1070       return g_strndup (type_string, i);
1071     }
1072   else
1073     /* construct a variable-sized type */
1074     {
1075       char type_string[2] = { 'a', base_type };
1076
1077       return g_strndup (type_string, 2);
1078     }
1079 }
1080
1081 typedef struct
1082 {
1083   GVariantTypeInfo *type_info;
1084   guint alignment;
1085   gsize size;
1086   gboolean is_fixed_sized;
1087
1088   guint32 seed;
1089
1090 #define INSTANCE_MAGIC    1287582829
1091   guint magic;
1092 } RandomInstance;
1093
1094 static RandomInstance *
1095 random_instance (GVariantTypeInfo *type_info)
1096 {
1097   RandomInstance *instance;
1098
1099   instance = g_slice_new (RandomInstance);
1100
1101   if (type_info == NULL)
1102     {
1103       gchar *str = random_type_string ();
1104       instance->type_info = g_variant_type_info_get (G_VARIANT_TYPE (str));
1105       g_free (str);
1106     }
1107   else
1108     instance->type_info = g_variant_type_info_ref (type_info);
1109
1110   instance->seed = g_test_rand_int ();
1111
1112   g_variant_type_info_query (instance->type_info,
1113                              &instance->alignment,
1114                              &instance->size);
1115
1116   instance->is_fixed_sized = instance->size != 0;
1117
1118   if (!instance->is_fixed_sized)
1119     instance->size = g_test_rand_int_range (0, MAX_INSTANCE_SIZE);
1120
1121   instance->magic = INSTANCE_MAGIC;
1122
1123   return instance;
1124 }
1125
1126 static void
1127 random_instance_free (RandomInstance *instance)
1128 {
1129   g_variant_type_info_unref (instance->type_info);
1130   g_slice_free (RandomInstance, instance);
1131 }
1132
1133 static void
1134 append_instance_size (RandomInstance *instance,
1135                       gsize          *offset)
1136 {
1137   *offset += (-*offset) & instance->alignment;
1138   *offset += instance->size;
1139 }
1140
1141 static void
1142 random_instance_write (RandomInstance *instance,
1143                        guchar         *buffer)
1144 {
1145   GRand *rand;
1146   gint i;
1147
1148   g_assert_cmpint ((gsize) buffer & instance->alignment, ==, 0);
1149
1150   rand = g_rand_new_with_seed (instance->seed);
1151   for (i = 0; i < instance->size; i++)
1152     buffer[i] = g_rand_int (rand);
1153   g_rand_free (rand);
1154 }
1155
1156 static void
1157 append_instance_data (RandomInstance  *instance,
1158                       guchar         **buffer)
1159 {
1160   while (((gsize) *buffer) & instance->alignment)
1161     *(*buffer)++ = '\0';
1162
1163   random_instance_write (instance, *buffer);
1164   *buffer += instance->size;
1165 }
1166
1167 static gboolean
1168 random_instance_assert (RandomInstance *instance,
1169                         guchar         *buffer,
1170                         gsize           size)
1171 {
1172   GRand *rand;
1173   gint i;
1174
1175   g_assert_cmpint ((gsize) buffer & instance->alignment, ==, 0);
1176   g_assert_cmpint (size, ==, instance->size);
1177
1178   rand = g_rand_new_with_seed (instance->seed);
1179   for (i = 0; i < instance->size; i++)
1180     {
1181       guchar byte = g_rand_int (rand);
1182
1183       g_assert (buffer[i] == byte);
1184     }
1185   g_rand_free (rand);
1186
1187   return i == instance->size;
1188 }
1189
1190 static gboolean
1191 random_instance_check (RandomInstance *instance,
1192                        guchar         *buffer,
1193                        gsize           size)
1194 {
1195   GRand *rand;
1196   gint i;
1197
1198   g_assert_cmpint ((gsize) buffer & instance->alignment, ==, 0);
1199
1200   if (size != instance->size)
1201     return FALSE;
1202
1203   rand = g_rand_new_with_seed (instance->seed);
1204   for (i = 0; i < instance->size; i++)
1205     if (buffer[i] != (guchar) g_rand_int (rand))
1206       break;
1207   g_rand_free (rand);
1208
1209   return i == instance->size;
1210 }
1211
1212 static void
1213 random_instance_filler (GVariantSerialised *serialised,
1214                         gpointer            data)
1215 {
1216   RandomInstance *instance = data;
1217
1218   g_assert (instance->magic == INSTANCE_MAGIC);
1219
1220   if (serialised->type_info == NULL)
1221     serialised->type_info = instance->type_info;
1222
1223   if (serialised->size == 0)
1224     serialised->size = instance->size;
1225
1226   g_assert (serialised->type_info == instance->type_info);
1227   g_assert (serialised->size == instance->size);
1228
1229   if (serialised->data)
1230     random_instance_write (instance, serialised->data);
1231 }
1232
1233 static gsize
1234 calculate_offset_size (gsize body_size,
1235                        gsize n_offsets)
1236 {
1237   if (body_size == 0)
1238     return 0;
1239
1240   if (body_size + n_offsets <= G_MAXUINT8)
1241     return 1;
1242
1243   if (body_size + 2 * n_offsets <= G_MAXUINT16)
1244     return 2;
1245
1246   if (body_size + 4 * n_offsets <= G_MAXUINT32)
1247     return 4;
1248
1249   /* the test case won't generate anything bigger */
1250   g_assert_not_reached ();
1251 }
1252
1253 static gpointer
1254 flavoured_malloc (gsize size, gsize flavour)
1255 {
1256   g_assert (flavour < 8);
1257
1258   if (size == 0)
1259     return NULL;
1260
1261   return g_malloc (size + flavour) + flavour;
1262 }
1263
1264 static void
1265 flavoured_free (gpointer data)
1266 {
1267   g_free ((gpointer) (((gsize) data) & ~7));
1268 }
1269
1270 static void
1271 append_offset (guchar **offset_ptr,
1272                gsize    offset,
1273                guint    offset_size)
1274 {
1275   union
1276   {
1277     guchar bytes[sizeof (gsize)];
1278     gsize integer;
1279   } tmpvalue;
1280
1281   tmpvalue.integer = GSIZE_TO_LE (offset);
1282   memcpy (*offset_ptr, tmpvalue.bytes, offset_size);
1283   *offset_ptr += offset_size;
1284 }
1285
1286 static void
1287 prepend_offset (guchar **offset_ptr,
1288                 gsize    offset,
1289                 guint    offset_size)
1290 {
1291   union
1292   {
1293     guchar bytes[sizeof (gsize)];
1294     gsize integer;
1295   } tmpvalue;
1296
1297   *offset_ptr -= offset_size;
1298   tmpvalue.integer = GSIZE_TO_LE (offset);
1299   memcpy (*offset_ptr, tmpvalue.bytes, offset_size);
1300 }
1301
1302 static void
1303 test_maybe (void)
1304 {
1305   GVariantTypeInfo *type_info;
1306   RandomInstance *instance;
1307   gsize needed_size;
1308   guchar *data;
1309
1310   instance = random_instance (NULL);
1311
1312   {
1313     const gchar *element;
1314     gchar *tmp;
1315
1316     element = g_variant_type_info_get_type_string (instance->type_info);
1317     tmp = g_strdup_printf ("m%s", element);
1318     type_info = g_variant_type_info_get (G_VARIANT_TYPE (tmp));
1319     g_free (tmp);
1320   }
1321
1322   needed_size = g_variant_serialiser_needed_size (type_info,
1323                                                   random_instance_filler,
1324                                                   NULL, 0);
1325   g_assert_cmpint (needed_size, ==, 0);
1326
1327   needed_size = g_variant_serialiser_needed_size (type_info,
1328                                                   random_instance_filler,
1329                                                   (gpointer *) &instance, 1);
1330
1331   if (instance->is_fixed_sized)
1332     g_assert_cmpint (needed_size, ==, instance->size);
1333   else
1334     g_assert_cmpint (needed_size, ==, instance->size + 1);
1335
1336   {
1337     guchar *ptr;
1338
1339     ptr = data = g_malloc (needed_size);
1340     append_instance_data (instance, &ptr);
1341
1342     if (!instance->is_fixed_sized)
1343       *ptr++ = '\0';
1344
1345     g_assert_cmpint (ptr - data, ==, needed_size);
1346   }
1347
1348   {
1349     guint alignment;
1350     guint flavour;
1351
1352     alignment = instance->alignment + 1;
1353
1354     for (flavour = 0; flavour < 8; flavour += alignment)
1355       {
1356         GVariantSerialised serialised;
1357         GVariantSerialised child;
1358
1359         serialised.type_info = type_info;
1360         serialised.data = flavoured_malloc (needed_size, flavour);
1361         serialised.size = needed_size;
1362
1363         g_variant_serialiser_serialise (serialised,
1364                                         random_instance_filler,
1365                                         (gpointer *) &instance, 1);
1366         child = g_variant_serialised_get_child (serialised, 0);
1367         g_assert (child.type_info == instance->type_info);
1368         random_instance_assert (instance, child.data, child.size);
1369         g_variant_type_info_unref (child.type_info);
1370         flavoured_free (serialised.data);
1371       }
1372   }
1373
1374   g_variant_type_info_unref (type_info);
1375   random_instance_free (instance);
1376   g_free (data);
1377 }
1378
1379 static void
1380 test_maybes (void)
1381 {
1382   guint i;
1383
1384   for (i = 0; i < 1000; i++)
1385     test_maybe ();
1386
1387   assert_no_type_infos ();
1388 }
1389
1390 static void
1391 test_array (void)
1392 {
1393   GVariantTypeInfo *element_info;
1394   GVariantTypeInfo *array_info;
1395   RandomInstance **instances;
1396   gsize needed_size;
1397   gsize offset_size;
1398   guint n_children;
1399   guchar *data;
1400
1401   {
1402     gchar *element_type, *array_type;
1403
1404     element_type = random_type_string ();
1405     array_type = g_strdup_printf ("a%s", element_type);
1406
1407     element_info = g_variant_type_info_get (G_VARIANT_TYPE (element_type));
1408     array_info = g_variant_type_info_get (G_VARIANT_TYPE (array_type));
1409     g_assert (g_variant_type_info_element (array_info) == element_info);
1410
1411     g_free (element_type);
1412     g_free (array_type);
1413   }
1414
1415   {
1416     guint i;
1417
1418     n_children = g_test_rand_int_range (0, MAX_ARRAY_CHILDREN);
1419     instances = g_new (RandomInstance *, n_children);
1420     for (i = 0; i < n_children; i++)
1421       instances[i] = random_instance (element_info);
1422   }
1423
1424   needed_size = g_variant_serialiser_needed_size (array_info,
1425                                                   random_instance_filler,
1426                                                   (gpointer *) instances,
1427                                                   n_children);
1428
1429   {
1430     gsize element_fixed_size;
1431     gsize body_size = 0;
1432     guint i;
1433
1434     for (i = 0; i < n_children; i++)
1435       append_instance_size (instances[i], &body_size);
1436
1437     g_variant_type_info_query (element_info, NULL, &element_fixed_size);
1438
1439     if (!element_fixed_size)
1440       {
1441         offset_size = calculate_offset_size (body_size, n_children);
1442
1443         if (offset_size == 0)
1444           offset_size = 1;
1445       }
1446     else
1447       offset_size = 0;
1448
1449     g_assert_cmpint (needed_size, ==, body_size + n_children * offset_size);
1450   }
1451
1452   {
1453     guchar *offset_ptr, *body_ptr;
1454     guint i;
1455
1456     body_ptr = data = g_malloc (needed_size);
1457     offset_ptr = body_ptr + needed_size - offset_size * n_children;
1458
1459     for (i = 0; i < n_children; i++)
1460       {
1461         append_instance_data (instances[i], &body_ptr);
1462         append_offset (&offset_ptr, body_ptr - data, offset_size);
1463       }
1464
1465     g_assert (body_ptr == data + needed_size - offset_size * n_children);
1466     g_assert (offset_ptr == data + needed_size);
1467   }
1468
1469   {
1470     guint alignment;
1471     gsize flavour;
1472     guint i;
1473
1474     g_variant_type_info_query (array_info, &alignment, NULL);
1475     alignment++;
1476
1477     for (flavour = 0; flavour < 8; flavour += alignment)
1478       {
1479         GVariantSerialised serialised;
1480
1481         serialised.type_info = array_info;
1482         serialised.data = flavoured_malloc (needed_size, flavour);
1483         serialised.size = needed_size;
1484
1485         g_variant_serialiser_serialise (serialised, random_instance_filler,
1486                                         (gpointer *) instances, n_children);
1487
1488         g_assert (memcmp (serialised.data, data, serialised.size) == 0);
1489         g_assert (g_variant_serialised_n_children (serialised) == n_children);
1490
1491         for (i = 0; i < n_children; i++)
1492           {
1493             GVariantSerialised child;
1494
1495             child = g_variant_serialised_get_child (serialised, i);
1496             g_assert (child.type_info == instances[i]->type_info);
1497             random_instance_assert (instances[i], child.data, child.size);
1498             g_variant_type_info_unref (child.type_info);
1499           }
1500
1501         flavoured_free (serialised.data);
1502       }
1503   }
1504
1505   {
1506     guint i;
1507
1508     for (i = 0; i < n_children; i++)
1509       random_instance_free (instances[i]);
1510     g_free (instances);
1511   }
1512
1513   g_variant_type_info_unref (element_info);
1514   g_variant_type_info_unref (array_info);
1515   g_free (data);
1516 }
1517
1518 static void
1519 test_arrays (void)
1520 {
1521   guint i;
1522
1523   for (i = 0; i < 100; i++)
1524     test_array ();
1525
1526   assert_no_type_infos ();
1527 }
1528
1529 static void
1530 test_tuple (void)
1531 {
1532   GVariantTypeInfo *type_info;
1533   RandomInstance **instances;
1534   gboolean fixed_size;
1535   gsize needed_size;
1536   gsize offset_size;
1537   guint n_children;
1538   guint alignment;
1539   guchar *data;
1540
1541   n_children = g_test_rand_int_range (0, MAX_TUPLE_CHILDREN);
1542   instances = g_new (RandomInstance *, n_children);
1543
1544   {
1545     GString *type_string;
1546     guint i;
1547
1548     fixed_size = TRUE;
1549     alignment = 0;
1550
1551     type_string = g_string_new ("(");
1552     for (i = 0; i < n_children; i++)
1553       {
1554         const gchar *str;
1555
1556         instances[i] = random_instance (NULL);
1557
1558         alignment |= instances[i]->alignment;
1559         if (!instances[i]->is_fixed_sized)
1560           fixed_size = FALSE;
1561
1562         str = g_variant_type_info_get_type_string (instances[i]->type_info);
1563         g_string_append (type_string, str);
1564       }
1565     g_string_append_c (type_string, ')');
1566
1567     type_info = g_variant_type_info_get (G_VARIANT_TYPE (type_string->str));
1568     g_string_free (type_string, TRUE);
1569   }
1570
1571   needed_size = g_variant_serialiser_needed_size (type_info,
1572                                                   random_instance_filler,
1573                                                   (gpointer *) instances,
1574                                                   n_children);
1575   {
1576     gsize body_size = 0;
1577     gsize offsets = 0;
1578     guint i;
1579
1580     for (i = 0; i < n_children; i++)
1581       {
1582         append_instance_size (instances[i], &body_size);
1583
1584         if (i != n_children - 1 && !instances[i]->is_fixed_sized)
1585           offsets++;
1586       }
1587
1588     if (fixed_size)
1589       {
1590         body_size += (-body_size) & alignment;
1591
1592         g_assert ((body_size == 0) == (n_children == 0));
1593         if (n_children == 0)
1594           body_size = 1;
1595       }
1596
1597     offset_size = calculate_offset_size (body_size, offsets);
1598     g_assert_cmpint (needed_size, ==, body_size + offsets * offset_size);
1599   }
1600
1601   {
1602     guchar *body_ptr;
1603     guchar *ofs_ptr;
1604     guint i;
1605
1606     body_ptr = data = g_malloc (needed_size);
1607     ofs_ptr = body_ptr + needed_size;
1608
1609     for (i = 0; i < n_children; i++)
1610       {
1611         append_instance_data (instances[i], &body_ptr);
1612
1613         if (i != n_children - 1 && !instances[i]->is_fixed_sized)
1614           prepend_offset (&ofs_ptr, body_ptr - data, offset_size);
1615       }
1616
1617     if (fixed_size)
1618       {
1619         while (((gsize) body_ptr) & alignment)
1620           *body_ptr++ = '\0';
1621
1622         g_assert ((body_ptr == data) == (n_children == 0));
1623         if (n_children == 0)
1624           *body_ptr++ = '\0';
1625
1626       }
1627
1628
1629     g_assert (body_ptr == ofs_ptr);
1630   }
1631
1632   {
1633     gsize flavour;
1634     guint i;
1635
1636     alignment++;
1637
1638     for (flavour = 0; flavour < 8; flavour += alignment)
1639       {
1640         GVariantSerialised serialised;
1641
1642         serialised.type_info = type_info;
1643         serialised.data = flavoured_malloc (needed_size, flavour);
1644         serialised.size = needed_size;
1645
1646         g_variant_serialiser_serialise (serialised, random_instance_filler,
1647                                         (gpointer *) instances, n_children);
1648
1649         g_assert (memcmp (serialised.data, data, serialised.size) == 0);
1650         g_assert (g_variant_serialised_n_children (serialised) == n_children);
1651
1652         for (i = 0; i < n_children; i++)
1653           {
1654             GVariantSerialised child;
1655
1656             child = g_variant_serialised_get_child (serialised, i);
1657             g_assert (child.type_info == instances[i]->type_info);
1658             random_instance_assert (instances[i], child.data, child.size);
1659             g_variant_type_info_unref (child.type_info);
1660           }
1661
1662         flavoured_free (serialised.data);
1663       }
1664   }
1665
1666   {
1667     guint i;
1668
1669     for (i = 0; i < n_children; i++)
1670       random_instance_free (instances[i]);
1671     g_free (instances);
1672   }
1673
1674   g_variant_type_info_unref (type_info);
1675   g_free (data);
1676 }
1677
1678 static void
1679 test_tuples (void)
1680 {
1681   guint i;
1682
1683   for (i = 0; i < 100; i++)
1684     test_tuple ();
1685
1686   assert_no_type_infos ();
1687 }
1688
1689 static void
1690 test_variant (void)
1691 {
1692   GVariantTypeInfo *type_info;
1693   RandomInstance *instance;
1694   const gchar *type_string;
1695   gsize needed_size;
1696   guchar *data;
1697   gsize len;
1698
1699   type_info = g_variant_type_info_get (G_VARIANT_TYPE_VARIANT);
1700   instance = random_instance (NULL);
1701
1702   type_string = g_variant_type_info_get_type_string (instance->type_info);
1703   len = strlen (type_string);
1704
1705   needed_size = g_variant_serialiser_needed_size (type_info,
1706                                                   random_instance_filler,
1707                                                   (gpointer *) &instance, 1);
1708
1709   g_assert_cmpint (needed_size, ==, instance->size + 1 + len);
1710
1711   {
1712     guchar *ptr;
1713
1714     ptr = data = g_malloc (needed_size);
1715     append_instance_data (instance, &ptr);
1716     *ptr++ = '\0';
1717     memcpy (ptr, type_string, len);
1718     ptr += len;
1719
1720     g_assert (data + needed_size == ptr);
1721   }
1722
1723   {
1724     /* variants are 8-aligned, so no extra flavouring */
1725     GVariantSerialised serialised;
1726     GVariantSerialised child;
1727
1728     serialised.type_info = type_info;
1729     serialised.data = flavoured_malloc (needed_size, 0);
1730     serialised.size = needed_size;
1731
1732     g_variant_serialiser_serialise (serialised, random_instance_filler,
1733                                     (gpointer *) &instance, 1);
1734
1735     g_assert (memcmp (serialised.data, data, serialised.size) == 0);
1736     g_assert (g_variant_serialised_n_children (serialised) == 1);
1737
1738     child = g_variant_serialised_get_child (serialised, 0);
1739     g_assert (child.type_info == instance->type_info);
1740     random_instance_check (instance, child.data, child.size);
1741
1742     g_variant_type_info_unref (child.type_info);
1743     flavoured_free (serialised.data);
1744   }
1745
1746   g_variant_type_info_unref (type_info);
1747   random_instance_free (instance);
1748   g_free (data);
1749 }
1750
1751 static void
1752 test_variants (void)
1753 {
1754   guint i;
1755
1756   for (i = 0; i < 100; i++)
1757     test_variant ();
1758
1759   assert_no_type_infos ();
1760 }
1761
1762 static void
1763 test_strings (void)
1764 {
1765   struct {
1766     guint flags;
1767     guint size;
1768     gconstpointer data;
1769   } test_cases[] = {
1770 #define is_nval           0
1771 #define is_string         1
1772 #define is_objpath        is_string | 2
1773 #define is_sig            is_string | 4
1774     { is_sig,       1, "" },
1775     { is_nval,      0, NULL },
1776     { is_string,   13, "hello world!" },
1777     { is_nval,     13, "hello world\0" },
1778     { is_nval,     13, "hello\0world!" },
1779     { is_nval,     12, "hello world!" },
1780
1781     { is_objpath,   2, "/" },
1782     { is_objpath,   3, "/a" },
1783     { is_string,    3, "//" },
1784     { is_objpath,  11, "/some/path" },
1785     { is_string,   12, "/some/path/" },
1786     { is_nval,     11, "/some\0path" },
1787     { is_string,   11, "/some\\path" },
1788     { is_string,   12, "/some//path" },
1789     { is_string,   12, "/some-/path" },
1790
1791     { is_sig,       2, "i" },
1792     { is_sig,       2, "s" },
1793     { is_sig,       5, "(si)" },
1794     { is_string,    4, "(si" },
1795     { is_string,    2, "*" },
1796     { is_sig,       3, "ai" },
1797     { is_string,    3, "mi" },
1798     { is_string,    2, "r" },
1799     { is_sig,      15, "(yyy{sv}ssiai)" },
1800     { is_string,   16, "(yyy{yv}ssiai))" },
1801     { is_string,   15, "(yyy{vv}ssiai)" },
1802     { is_string,   15, "(yyy{sv)ssiai}" }
1803   };
1804   guint i;
1805
1806   for (i = 0; i < G_N_ELEMENTS (test_cases); i++)
1807     {
1808       guint flags;
1809
1810       flags = g_variant_serialiser_is_string (test_cases[i].data,
1811                                               test_cases[i].size)
1812         ? 1 : 0;
1813
1814       flags |= g_variant_serialiser_is_object_path (test_cases[i].data,
1815                                                     test_cases[i].size)
1816         ? 2 : 0;
1817
1818       flags |= g_variant_serialiser_is_signature (test_cases[i].data,
1819                                                   test_cases[i].size)
1820         ? 4 : 0;
1821
1822       g_assert (flags == test_cases[i].flags);
1823     }
1824 }
1825
1826 typedef struct _TreeInstance TreeInstance;
1827 struct _TreeInstance
1828 {
1829   GVariantTypeInfo *info;
1830
1831   TreeInstance **children;
1832   gsize n_children;
1833
1834   union {
1835     guint64 integer;
1836     gdouble floating;
1837     gchar string[32];
1838   } data;
1839   gsize data_size;
1840 };
1841
1842 static GVariantType *
1843 make_random_definite_type (int depth)
1844 {
1845   GString *description;
1846   GString *type_string;
1847   GVariantType *type;
1848
1849   description = g_string_new (NULL);
1850   type_string = g_string_new (NULL);
1851   type = append_type_string (type_string, description, TRUE, depth);
1852   g_string_free (description, TRUE);
1853   g_string_free (type_string, TRUE);
1854
1855   return type;
1856 }
1857
1858 static void
1859 make_random_string (gchar              *string,
1860                     gsize               size,
1861                     const GVariantType *type)
1862 {
1863   gint i;
1864
1865   /* create strings that are valid signature strings */
1866 #define good_chars "bynqiuxthdsog"
1867
1868   for (i = 0; i < size - 1; i++)
1869     string[i] = good_chars[g_test_rand_int_range (0, strlen (good_chars))];
1870   string[i] = '\0';
1871
1872   /* in case we need an object path, prefix a '/' */
1873   if (*g_variant_type_peek_string (type) == 'o')
1874     string[0] = '/';
1875
1876 #undef good_chars
1877 }
1878
1879 static TreeInstance *
1880 tree_instance_new (const GVariantType *type,
1881                    int                 depth)
1882 {
1883   const GVariantType *child_type = NULL;
1884   GVariantType *mytype = NULL;
1885   TreeInstance *instance;
1886   gboolean is_tuple_type;
1887
1888   if (type == NULL)
1889     type = mytype = make_random_definite_type (depth);
1890
1891   instance = g_slice_new (TreeInstance);
1892   instance->info = g_variant_type_info_get (type);
1893   instance->children = NULL;
1894   instance->n_children = 0;
1895   instance->data_size = 0;
1896
1897   is_tuple_type = FALSE;
1898
1899   switch (*g_variant_type_peek_string (type))
1900     {
1901     case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
1902       instance->n_children = g_test_rand_int_range (0, 2);
1903       child_type = g_variant_type_element (type);
1904       break;
1905
1906     case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
1907       instance->n_children = g_test_rand_int_range (0, MAX_ARRAY_CHILDREN);
1908       child_type = g_variant_type_element (type);
1909       break;
1910
1911     case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
1912     case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
1913       instance->n_children = g_variant_type_n_items (type);
1914       child_type = g_variant_type_first (type);
1915       is_tuple_type = TRUE;
1916       break;
1917
1918     case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
1919       instance->n_children = 1;
1920       child_type = NULL;
1921       break;
1922
1923     case 'b':
1924       instance->data.integer = g_test_rand_int_range (0, 2);
1925       instance->data_size = 1;
1926       break;
1927
1928     case 'y':
1929       instance->data.integer = g_test_rand_int ();
1930       instance->data_size = 1;
1931       break;
1932
1933     case 'n': case 'q':
1934       instance->data.integer = g_test_rand_int ();
1935       instance->data_size = 2;
1936       break;
1937
1938     case 'i': case 'u': case 'h':
1939       instance->data.integer = g_test_rand_int ();
1940       instance->data_size = 4;
1941       break;
1942
1943     case 'x': case 't': case 'd':
1944       instance->data.integer = g_test_rand_int ();
1945       instance->data.integer <<= 32;
1946       instance->data.integer |= (guint32) g_test_rand_int ();
1947       instance->data_size = 8;
1948       break;
1949
1950     case 's': case 'o': case 'g':
1951       instance->data_size = g_test_rand_int_range (10, 20);
1952       make_random_string (instance->data.string, instance->data_size, type);
1953       break;
1954     }
1955
1956   if (instance->data_size == 0)
1957     /* no data -> it is a container */
1958     {
1959       guint i;
1960
1961       instance->children = g_new (TreeInstance *, instance->n_children);
1962
1963       for (i = 0; i < instance->n_children; i++)
1964         {
1965           instance->children[i] = tree_instance_new (child_type, depth - 1);
1966
1967           if (is_tuple_type)
1968             child_type = g_variant_type_next (child_type);
1969         }
1970
1971       g_assert (!is_tuple_type || child_type == NULL);
1972     }
1973
1974   g_variant_type_free (mytype);
1975
1976   return instance;
1977 }
1978
1979 static void
1980 tree_instance_free (TreeInstance *instance)
1981 {
1982   gint i;
1983
1984   g_variant_type_info_unref (instance->info);
1985   for (i = 0; i < instance->n_children; i++)
1986     tree_instance_free (instance->children[i]);
1987   g_free (instance->children);
1988   g_slice_free (TreeInstance, instance);
1989 }
1990
1991 static gboolean i_am_writing_byteswapped;
1992
1993 static void
1994 tree_filler (GVariantSerialised *serialised,
1995              gpointer            data)
1996 {
1997   TreeInstance *instance = data;
1998
1999   if (serialised->type_info == NULL)
2000     serialised->type_info = instance->info;
2001
2002   if (instance->data_size == 0)
2003     /* is a container */
2004     {
2005       if (serialised->size == 0)
2006         serialised->size =
2007           g_variant_serialiser_needed_size (instance->info, tree_filler,
2008                                             (gpointer *) instance->children,
2009                                             instance->n_children);
2010
2011       if (serialised->data)
2012         g_variant_serialiser_serialise (*serialised, tree_filler,
2013                                         (gpointer *) instance->children,
2014                                         instance->n_children);
2015     }
2016   else
2017     /* it is a leaf */
2018     {
2019       if (serialised->size == 0)
2020         serialised->size = instance->data_size;
2021
2022       if (serialised->data)
2023         {
2024           switch (instance->data_size)
2025             {
2026             case 1:
2027               *serialised->data = instance->data.integer;
2028               break;
2029
2030             case 2:
2031               {
2032                 guint16 value = instance->data.integer;
2033
2034                 if (i_am_writing_byteswapped)
2035                   value = GUINT16_SWAP_LE_BE (value);
2036
2037                 *(guint16 *) serialised->data = value;
2038               }
2039               break;
2040
2041             case 4:
2042               {
2043                 guint32 value = instance->data.integer;
2044
2045                 if (i_am_writing_byteswapped)
2046                   value = GUINT32_SWAP_LE_BE (value);
2047
2048                 *(guint32 *) serialised->data = value;
2049               }
2050               break;
2051
2052             case 8:
2053               {
2054                 guint64 value = instance->data.integer;
2055
2056                 if (i_am_writing_byteswapped)
2057                   value = GUINT64_SWAP_LE_BE (value);
2058
2059                 *(guint64 *) serialised->data = value;
2060               }
2061               break;
2062
2063             default:
2064               memcpy (serialised->data,
2065                       instance->data.string,
2066                       instance->data_size);
2067               break;
2068             }
2069         }
2070     }
2071 }
2072
2073 static gboolean
2074 check_tree (TreeInstance       *instance,
2075             GVariantSerialised  serialised)
2076 {
2077   if (instance->info != serialised.type_info)
2078     return FALSE;
2079
2080   if (instance->data_size == 0)
2081     /* is a container */
2082     {
2083       gint i;
2084
2085       if (g_variant_serialised_n_children (serialised) !=
2086           instance->n_children)
2087         return FALSE;
2088
2089       for (i = 0; i < instance->n_children; i++)
2090         {
2091           GVariantSerialised child;
2092           gpointer data = NULL;
2093           gboolean ok;
2094
2095           child = g_variant_serialised_get_child (serialised, i);
2096           if (child.size && child.data == NULL)
2097             child.data = data = g_malloc0 (child.size);
2098           ok = check_tree (instance->children[i], child);
2099           g_variant_type_info_unref (child.type_info);
2100           g_free (data);
2101
2102           if (!ok)
2103             return FALSE;
2104         }
2105
2106       return TRUE;
2107     }
2108   else
2109     /* it is a leaf */
2110     {
2111       switch (instance->data_size)
2112         {
2113         case 1:
2114           g_assert (serialised.size == 1);
2115           return *(guint8 *) serialised.data ==
2116                   (guint8) instance->data.integer;
2117
2118         case 2:
2119           g_assert (serialised.size == 2);
2120           return *(guint16 *) serialised.data ==
2121                   (guint16) instance->data.integer;
2122
2123         case 4:
2124           g_assert (serialised.size == 4);
2125           return *(guint32 *) serialised.data ==
2126                   (guint32) instance->data.integer;
2127
2128         case 8:
2129           g_assert (serialised.size == 8);
2130           return *(guint64 *) serialised.data ==
2131                   (guint64) instance->data.integer;
2132
2133         default:
2134           if (serialised.size != instance->data_size)
2135             return FALSE;
2136
2137           return memcmp (serialised.data,
2138                          instance->data.string,
2139                          instance->data_size) == 0;
2140         }
2141     }
2142 }
2143
2144 static void
2145 serialise_tree (TreeInstance       *tree,
2146                 GVariantSerialised *serialised)
2147 {
2148   GVariantSerialised empty = {  };
2149
2150   *serialised = empty;
2151   tree_filler (serialised, tree);
2152   serialised->data = g_malloc (serialised->size);
2153   tree_filler (serialised, tree);
2154 }
2155
2156 static void
2157 test_byteswap (void)
2158 {
2159   GVariantSerialised one, two;
2160   TreeInstance *tree;
2161
2162   tree = tree_instance_new (NULL, 3);
2163   serialise_tree (tree, &one);
2164
2165   i_am_writing_byteswapped = TRUE;
2166   serialise_tree (tree, &two);
2167   i_am_writing_byteswapped = FALSE;
2168
2169   g_variant_serialised_byteswap (two);
2170
2171   g_assert_cmpint (one.size, ==, two.size);
2172   g_assert (memcmp (one.data, two.data, one.size) == 0);
2173
2174   tree_instance_free (tree);
2175   g_free (one.data);
2176   g_free (two.data);
2177 }
2178
2179 static void
2180 test_byteswaps (void)
2181 {
2182   int i;
2183
2184   for (i = 0; i < 200; i++)
2185     test_byteswap ();
2186
2187   assert_no_type_infos ();
2188 }
2189
2190 static void
2191 test_fuzz (gdouble *fuzziness)
2192 {
2193   GVariantSerialised serialised;
2194   TreeInstance *tree;
2195
2196   /* make an instance */
2197   tree = tree_instance_new (NULL, 3);
2198
2199   /* serialise it */
2200   serialise_tree (tree, &serialised);
2201
2202   g_assert (g_variant_serialised_is_normal (serialised));
2203   g_assert (check_tree (tree, serialised));
2204
2205   if (serialised.size)
2206     {
2207       gboolean fuzzed = FALSE;
2208       gboolean a, b;
2209
2210       while (!fuzzed)
2211         {
2212           gint i;
2213
2214           for (i = 0; i < serialised.size; i++)
2215             if (randomly (*fuzziness))
2216               {
2217                 serialised.data[i] += g_test_rand_int_range (1, 256);
2218                 fuzzed = TRUE;
2219               }
2220         }
2221
2222       /* at least one byte in the serialised data has changed.
2223        *
2224        * this means that at least one of the following is true:
2225        *
2226        *    - the serialised data now represents a different value:
2227        *        check_tree() will return FALSE
2228        *
2229        *    - the serialised data is in non-normal form:
2230        *        g_variant_serialiser_is_normal() will return FALSE
2231        *
2232        * we always do both checks to increase exposure of the serialiser
2233        * to corrupt data.
2234        */
2235       a = g_variant_serialised_is_normal (serialised);
2236       b = check_tree (tree, serialised);
2237
2238       g_assert (!a || !b);
2239     }
2240
2241   tree_instance_free (tree);
2242   g_free (serialised.data);
2243 }
2244
2245
2246 static void
2247 test_fuzzes (gpointer data)
2248 {
2249   gdouble fuzziness;
2250   int i;
2251
2252   fuzziness = GPOINTER_TO_INT (data) / 100.;
2253
2254   for (i = 0; i < 200; i++)
2255     test_fuzz (&fuzziness);
2256
2257   assert_no_type_infos ();
2258 }
2259
2260 static GVariant *
2261 tree_instance_get_gvariant (TreeInstance *tree)
2262 {
2263   const GVariantType *type;
2264   GVariant *result;
2265
2266   type = (GVariantType *) g_variant_type_info_get_type_string (tree->info);
2267
2268   switch (g_variant_type_info_get_type_char (tree->info))
2269     {
2270     case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
2271       {
2272         const GVariantType *child_type;
2273         GVariant *child;
2274
2275         if (tree->n_children)
2276           child = tree_instance_get_gvariant (tree->children[0]);
2277         else
2278           child = NULL;
2279
2280         child_type = g_variant_type_element (type);
2281
2282         if (child != NULL && randomly (0.5))
2283           child_type = NULL;
2284
2285         result = g_variant_new_maybe (child_type, child);
2286       }
2287       break;
2288
2289     case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
2290       {
2291         const GVariantType *child_type;
2292         GVariant **children;
2293         gint i;
2294
2295         children = g_new (GVariant *, tree->n_children);
2296         for (i = 0; i < tree->n_children; i++)
2297           children[i] = tree_instance_get_gvariant (tree->children[i]);
2298
2299         child_type = g_variant_type_element (type);
2300
2301         if (i > 0 && randomly (0.5))
2302           child_type = NULL;
2303
2304         result = g_variant_new_array (child_type, children, tree->n_children);
2305         g_free (children);
2306       }
2307       break;
2308
2309     case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
2310       {
2311         GVariant **children;
2312         gint i;
2313
2314         children = g_new (GVariant *, tree->n_children);
2315         for (i = 0; i < tree->n_children; i++)
2316           children[i] = tree_instance_get_gvariant (tree->children[i]);
2317
2318         result = g_variant_new_tuple (children, tree->n_children);
2319         g_free (children);
2320       }
2321       break;
2322
2323     case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
2324       {
2325         GVariant *key, *val;
2326
2327         g_assert (tree->n_children == 2);
2328
2329         key = tree_instance_get_gvariant (tree->children[0]);
2330         val = tree_instance_get_gvariant (tree->children[1]);
2331
2332         result = g_variant_new_dict_entry (key, val);
2333       }
2334       break;
2335
2336     case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
2337       {
2338         GVariant *value;
2339
2340         g_assert (tree->n_children == 1);
2341
2342         value = tree_instance_get_gvariant (tree->children[0]);
2343         result = g_variant_new_variant (value);
2344       }
2345       break;
2346
2347     case 'b':
2348       result = g_variant_new_boolean (tree->data.integer > 0);
2349       break;
2350
2351     case 'y':
2352       result = g_variant_new_byte (tree->data.integer);
2353       break;
2354
2355     case 'n':
2356       result = g_variant_new_int16 (tree->data.integer);
2357       break;
2358
2359     case 'q':
2360       result = g_variant_new_uint16 (tree->data.integer);
2361       break;
2362
2363     case 'i':
2364       result = g_variant_new_int32 (tree->data.integer);
2365       break;
2366
2367     case 'u':
2368       result = g_variant_new_uint32 (tree->data.integer);
2369       break;
2370
2371     case 'x':
2372       result = g_variant_new_int64 (tree->data.integer);
2373       break;
2374
2375     case 't':
2376       result = g_variant_new_uint64 (tree->data.integer);
2377       break;
2378
2379     case 'h':
2380       result = g_variant_new_handle (tree->data.integer);
2381       break;
2382
2383     case 'd':
2384       result = g_variant_new_double (tree->data.floating);
2385       break;
2386
2387     case 's':
2388       result = g_variant_new_string (tree->data.string);
2389       break;
2390
2391     case 'o':
2392       result = g_variant_new_object_path (tree->data.string);
2393       break;
2394
2395     case 'g':
2396       result = g_variant_new_signature (tree->data.string);
2397       break;
2398
2399     default:
2400       g_assert_not_reached ();
2401     }
2402
2403   return result;
2404 }
2405
2406 static gboolean
2407 tree_instance_check_gvariant (TreeInstance *tree,
2408                               GVariant     *value)
2409 {
2410   const GVariantType *type;
2411
2412   type = (GVariantType *) g_variant_type_info_get_type_string (tree->info);
2413   g_assert (g_variant_is_of_type (value, type));
2414
2415   switch (g_variant_type_info_get_type_char (tree->info))
2416     {
2417     case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
2418       {
2419         GVariant *child;
2420         gboolean equal;
2421
2422         child = g_variant_get_maybe (value);
2423
2424         if (child != NULL && tree->n_children == 1)
2425           equal = tree_instance_check_gvariant (tree->children[0], child);
2426         else if (child == NULL && tree->n_children == 0)
2427           equal = TRUE;
2428         else
2429           equal = FALSE;
2430
2431         if (child != NULL)
2432           g_variant_unref (child);
2433
2434         return equal;
2435       }
2436       break;
2437
2438     case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
2439     case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
2440     case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
2441       {
2442         gsize i;
2443
2444         if (g_variant_n_children (value) != tree->n_children)
2445           return FALSE;
2446
2447         for (i = 0; i < tree->n_children; i++)
2448           {
2449             GVariant *child;
2450             gboolean equal;
2451
2452             child = g_variant_get_child_value (value, i);
2453             equal = tree_instance_check_gvariant (tree->children[i], child);
2454             g_variant_unref (child);
2455
2456             if (!equal)
2457               return FALSE;
2458           }
2459
2460         return TRUE;
2461       }
2462       break;
2463
2464     case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
2465       {
2466         const gchar *str1, *str2;
2467         GVariant *child;
2468         gboolean equal;
2469
2470         child = g_variant_get_variant (value);
2471         str1 = g_variant_get_type_string (child);
2472         str2 = g_variant_type_info_get_type_string (tree->children[0]->info);
2473
2474         /* can't pointer-compare str1 and str2 since one comes from the
2475          * real GVariantTypeInfo and one comes from our private copy...
2476          */
2477         equal = strcmp (str1, str2) == 0 &&
2478                 tree_instance_check_gvariant (tree->children[0], child);
2479
2480         g_variant_unref (child);
2481
2482         return equal;
2483       }
2484       break;
2485
2486     case 'b':
2487       return g_variant_get_boolean (value) == tree->data.integer;
2488
2489     case 'y':
2490       return g_variant_get_byte (value) == (guchar) tree->data.integer;
2491
2492     case 'n':
2493       return g_variant_get_int16 (value) == (gint16) tree->data.integer;
2494
2495     case 'q':
2496       return g_variant_get_uint16 (value) == (guint16) tree->data.integer;
2497
2498     case 'i':
2499       return g_variant_get_int32 (value) == (gint32) tree->data.integer;
2500
2501     case 'u':
2502       return g_variant_get_uint32 (value) == (guint32) tree->data.integer;
2503
2504     case 'x':
2505       return g_variant_get_int64 (value) == (gint64) tree->data.integer;
2506
2507     case 't':
2508       return g_variant_get_uint64 (value) == (guint64) tree->data.integer;
2509
2510     case 'h':
2511       return g_variant_get_handle (value) == (gint32) tree->data.integer;
2512
2513     case 'd':
2514       {
2515         gdouble floating = g_variant_get_double (value);
2516
2517         return memcmp (&floating, &tree->data.floating, sizeof floating) == 0;
2518       }
2519
2520     case 's':
2521     case 'o':
2522     case 'g':
2523       return strcmp (g_variant_get_string (value, NULL),
2524                      tree->data.string) == 0;
2525
2526     default:
2527       g_assert_not_reached ();
2528     }
2529 }
2530
2531 static void
2532 tree_instance_build_gvariant (TreeInstance    *tree,
2533                               GVariantBuilder *builder)
2534 {
2535   const GVariantType *type;
2536
2537   type = (GVariantType *) g_variant_type_info_get_type_string (tree->info);
2538
2539   if (g_variant_type_is_container (type))
2540     {
2541       gsize i;
2542
2543       g_variant_builder_open (builder, type);
2544
2545       for (i = 0; i < tree->n_children; i++)
2546         tree_instance_build_gvariant (tree->children[i], builder);
2547
2548       g_variant_builder_close (builder);
2549     }
2550   else
2551     g_variant_builder_add_value (builder, tree_instance_get_gvariant (tree));
2552 }
2553
2554
2555 static gboolean
2556 tree_instance_check_iter (TreeInstance *tree,
2557                           GVariantIter *iter)
2558 {
2559   GVariant *value;
2560
2561   value = g_variant_iter_next_value (iter);
2562
2563   if (g_variant_is_container (value))
2564     {
2565       gsize i;
2566
2567       iter = g_variant_iter_new (value);
2568       g_variant_unref (value);
2569
2570       if (g_variant_iter_n_children (iter) != tree->n_children)
2571         {
2572           g_variant_iter_free (iter);
2573           return FALSE;
2574         }
2575
2576       for (i = 0; i < tree->n_children; i++)
2577         if (!tree_instance_check_iter (tree->children[i], iter))
2578           {
2579             g_variant_iter_free (iter);
2580             return FALSE;
2581           }
2582
2583       g_assert (g_variant_iter_next_value (iter) == NULL);
2584       g_variant_iter_free (iter);
2585
2586       return TRUE;
2587     }
2588
2589   else
2590     {
2591       gboolean equal;
2592
2593       equal = tree_instance_check_gvariant (tree, value);
2594       g_variant_unref (value);
2595
2596       return equal;
2597     }
2598 }
2599
2600 static void
2601 test_container (void)
2602 {
2603   TreeInstance *tree;
2604   GVariant *value;
2605   gchar *s1, *s2;
2606
2607   tree = tree_instance_new (NULL, 3);
2608   value = g_variant_ref_sink (tree_instance_get_gvariant (tree));
2609
2610   s1 = g_variant_print (value, TRUE);
2611   g_assert (tree_instance_check_gvariant (tree, value));
2612
2613   g_variant_get_data (value);
2614
2615   s2 = g_variant_print (value, TRUE);
2616   g_assert (tree_instance_check_gvariant (tree, value));
2617
2618   g_assert_cmpstr (s1, ==, s2);
2619
2620   if (g_variant_is_container (value))
2621     {
2622       GVariantBuilder builder;
2623       GVariantIter iter;
2624       GVariant *built;
2625       GVariant *val;
2626       gchar *s3;
2627
2628       g_variant_builder_init (&builder, G_VARIANT_TYPE_VARIANT);
2629       tree_instance_build_gvariant (tree, &builder);
2630       built = g_variant_builder_end (&builder);
2631       g_variant_ref_sink (built);
2632       g_variant_get_data (built);
2633       val = g_variant_get_variant (built);
2634
2635       s3 = g_variant_print (val, TRUE);
2636       g_assert_cmpstr (s1, ==, s3);
2637
2638       g_variant_iter_init (&iter, built);
2639       g_assert (tree_instance_check_iter (tree, &iter));
2640       g_assert (g_variant_iter_next_value (&iter) == NULL);
2641
2642       g_variant_unref (built);
2643       g_variant_unref (val);
2644       g_free (s3);
2645     }
2646
2647   tree_instance_free (tree);
2648   g_variant_unref (value);
2649   g_free (s2);
2650   g_free (s1);
2651 }
2652
2653 static void
2654 test_containers (void)
2655 {
2656   gint i;
2657
2658   for (i = 0; i < 100; i++)
2659     {
2660       test_container ();
2661     }
2662 }
2663
2664 int
2665 main (int argc, char **argv)
2666 {
2667   gint i;
2668
2669   g_test_init (&argc, &argv, NULL);
2670
2671   g_test_add_func ("/gvariant/type", test_gvarianttype);
2672   g_test_add_func ("/gvariant/typeinfo", test_gvarianttypeinfo);
2673   g_test_add_func ("/gvariant/serialiser/maybe", test_maybes);
2674   g_test_add_func ("/gvariant/serialiser/array", test_arrays);
2675   g_test_add_func ("/gvariant/serialiser/tuple", test_tuples);
2676   g_test_add_func ("/gvariant/serialiser/variant", test_variants);
2677   g_test_add_func ("/gvariant/serialiser/strings", test_strings);
2678   g_test_add_func ("/gvariant/serialiser/byteswap", test_byteswaps);
2679
2680   for (i = 1; i <= 20; i += 4)
2681     {
2682       char *testname;
2683
2684       testname = g_strdup_printf ("/gvariant/serialiser/fuzz/%d%%", i);
2685       g_test_add_data_func (testname, GINT_TO_POINTER (i),
2686                             (gpointer) test_fuzzes);
2687       g_free (testname);
2688     }
2689
2690   g_test_add_func ("/gvariant/containers", test_containers);
2691
2692   return g_test_run ();
2693 }