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