2 * Copyright © 2010 Codethink Limited
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.
9 * See the included COPYING file for more information.
11 * Author: Ryan Lortie <desrt@desrt.ca>
17 #define BASIC "bynqiuxthdsog?"
18 #define N_BASIC (G_N_ELEMENTS (BASIC) - 1)
20 #define INVALIDS "cefjklpwz&@^$"
21 #define N_INVALIDS (G_N_ELEMENTS (INVALIDS) - 1)
24 randomly (gdouble prob)
26 return g_test_rand_double_range (0, 1) < prob;
31 append_tuple_type_string (GString *, GString *, gboolean, gint);
33 /* append a random GVariantType to a GString
34 * append a description of the type to another GString
35 * return what the type is
38 append_type_string (GString *string,
43 if (!depth-- || randomly (0.3))
45 gchar b = BASIC[g_test_rand_int_range (0, N_BASIC - definite)];
46 g_string_append_c (string, b);
47 g_string_append_c (description, b);
52 return g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN);
54 return g_variant_type_copy (G_VARIANT_TYPE_BYTE);
56 return g_variant_type_copy (G_VARIANT_TYPE_INT16);
58 return g_variant_type_copy (G_VARIANT_TYPE_UINT16);
60 return g_variant_type_copy (G_VARIANT_TYPE_INT32);
62 return g_variant_type_copy (G_VARIANT_TYPE_UINT32);
64 return g_variant_type_copy (G_VARIANT_TYPE_INT64);
66 return g_variant_type_copy (G_VARIANT_TYPE_UINT64);
68 return g_variant_type_copy (G_VARIANT_TYPE_HANDLE);
70 return g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
72 return g_variant_type_copy (G_VARIANT_TYPE_STRING);
74 return g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH);
76 return g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE);
78 return g_variant_type_copy (G_VARIANT_TYPE_BASIC);
80 g_assert_not_reached ();
87 switch (g_test_rand_int_range (0, definite ? 5 : 7))
91 GVariantType *element;
93 g_string_append_c (string, 'a');
94 g_string_append (description, "a of ");
95 element = append_type_string (string, description,
97 result = g_variant_type_new_array (element);
98 g_variant_type_free (element);
101 g_assert (g_variant_type_is_array (result));
106 GVariantType *element;
108 g_string_append_c (string, 'm');
109 g_string_append (description, "m of ");
110 element = append_type_string (string, description,
112 result = g_variant_type_new_maybe (element);
113 g_variant_type_free (element);
116 g_assert (g_variant_type_is_maybe (result));
120 result = append_tuple_type_string (string, description,
123 g_assert (g_variant_type_is_tuple (result));
128 GVariantType *key, *value;
130 g_string_append_c (string, '{');
131 g_string_append (description, "e of [");
132 key = append_type_string (string, description, definite, 0);
133 g_string_append (description, ", ");
134 value = append_type_string (string, description, definite, depth);
135 g_string_append_c (description, ']');
136 g_string_append_c (string, '}');
137 result = g_variant_type_new_dict_entry (key, value);
138 g_variant_type_free (key);
139 g_variant_type_free (value);
142 g_assert (g_variant_type_is_dict_entry (result));
146 g_string_append_c (string, 'v');
147 g_string_append_c (description, 'V');
148 result = g_variant_type_copy (G_VARIANT_TYPE_VARIANT);
149 g_assert (g_variant_type_equal (result, G_VARIANT_TYPE_VARIANT));
153 g_string_append_c (string, '*');
154 g_string_append_c (description, 'S');
155 result = g_variant_type_copy (G_VARIANT_TYPE_ANY);
156 g_assert (g_variant_type_equal (result, G_VARIANT_TYPE_ANY));
160 g_string_append_c (string, 'r');
161 g_string_append_c (description, 'R');
162 result = g_variant_type_copy (G_VARIANT_TYPE_TUPLE);
163 g_assert (g_variant_type_is_tuple (result));
167 g_assert_not_reached ();
174 static GVariantType *
175 append_tuple_type_string (GString *string,
176 GString *description,
180 GVariantType *result, *other_result;
181 GVariantType **types;
185 g_string_append_c (string, '(');
186 g_string_append (description, "t of [");
188 size = g_test_rand_int_range (0, 20);
189 types = g_new (GVariantType *, size + 1);
191 for (i = 0; i < size; i++)
193 types[i] = append_type_string (string, description, definite, depth);
196 g_string_append (description, ", ");
201 g_string_append_c (description, ']');
202 g_string_append_c (string, ')');
204 result = g_variant_type_new_tuple ((gpointer) types, size);
205 other_result = g_variant_type_new_tuple ((gpointer) types, -1);
206 g_assert (g_variant_type_equal (result, other_result));
207 g_variant_type_free (other_result);
208 for (i = 0; i < size; i++)
209 g_variant_type_free (types[i]);
215 /* given a valid type string, make it invalid */
217 invalid_mutation (const gchar *type_string)
219 gboolean have_parens, have_braces;
221 /* it's valid, so '(' implies ')' and same for '{' and '}' */
222 have_parens = strchr (type_string, '(') != NULL;
223 have_braces = strchr (type_string, '{') != NULL;
225 if (have_parens && have_braces && randomly (0.3))
227 /* swap a paren and a brace */
233 new = g_strdup (type_string);
243 /* count number of parens/braces */
244 while ((pp = strchr (pp + 1, p))) np++;
245 while ((bp = strchr (bp + 1, b))) nb++;
247 /* randomly pick one of each */
248 np = g_test_rand_int_range (0, np) + 1;
249 nb = g_test_rand_int_range (0, nb) + 1;
253 while (np--) pp = strchr (pp + 1, p);
254 while (nb--) bp = strchr (bp + 1, b);
257 g_assert (*bp == b && *pp == p);
264 if ((have_parens || have_braces) && randomly (0.3))
266 /* drop a paren/brace */
273 if (randomly (0.5)) p = '('; else p = ')';
275 if (randomly (0.5)) p = '{'; else p = '}';
277 new = g_strdup (type_string);
281 while ((pp = strchr (pp + 1, p))) np++;
282 np = g_test_rand_int_range (0, np) + 1;
284 while (np--) pp = strchr (pp + 1, p);
296 /* else, perform a random mutation at a random point */
304 /* insert a paren/brace */
306 if (randomly (0.5)) p = '('; else p = ')';
308 if (randomly (0.5)) p = '{'; else p = '}';
310 else if (randomly (0.5))
313 p = INVALIDS[g_test_rand_int_range (0, N_INVALIDS)];
322 length = strlen (type_string);
323 new = g_malloc (length + 2);
324 n = g_test_rand_int_range (0, length);
325 memcpy (new, type_string, n);
327 memcpy (new + n + 1, type_string + n, length - n);
328 new[length + 1] = '\0';
334 /* describe a type using the same language as is generated
335 * while generating the type with append_type_string
338 describe_type (const GVariantType *type)
342 if (g_variant_type_is_container (type))
344 g_assert (!g_variant_type_is_basic (type));
346 if (g_variant_type_is_array (type))
348 gchar *subtype = describe_type (g_variant_type_element (type));
349 result = g_strdup_printf ("a of %s", subtype);
352 else if (g_variant_type_is_maybe (type))
354 gchar *subtype = describe_type (g_variant_type_element (type));
355 result = g_strdup_printf ("m of %s", subtype);
358 else if (g_variant_type_is_tuple (type))
360 if (!g_variant_type_equal (type, G_VARIANT_TYPE_TUPLE))
362 const GVariantType *sub;
367 string = g_string_new ("t of [");
369 length = g_variant_type_n_items (type);
370 sub = g_variant_type_first (type);
371 for (i = 0; i < length; i++)
373 gchar *subtype = describe_type (sub);
374 g_string_append (string, subtype);
377 if ((sub = g_variant_type_next (sub)))
378 g_string_append (string, ", ");
380 g_assert (sub == NULL);
381 g_string_append_c (string, ']');
383 result = g_string_free (string, FALSE);
386 result = g_strdup ("R");
388 else if (g_variant_type_is_dict_entry (type))
390 gchar *key, *value, *key2, *value2;
392 key = describe_type (g_variant_type_key (type));
393 value = describe_type (g_variant_type_value (type));
394 key2 = describe_type (g_variant_type_first (type));
395 value2 = describe_type (
396 g_variant_type_next (g_variant_type_first (type)));
397 g_assert (g_variant_type_next (g_variant_type_next (
398 g_variant_type_first (type))) == NULL);
399 g_assert_cmpstr (key, ==, key2);
400 g_assert_cmpstr (value, ==, value2);
401 result = g_strjoin ("", "e of [", key, ", ", value, "]", NULL);
407 else if (g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT))
409 result = g_strdup ("V");
412 g_assert_not_reached ();
416 if (g_variant_type_is_definite (type))
418 g_assert (g_variant_type_is_basic (type));
420 if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
421 result = g_strdup ("b");
422 else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
423 result = g_strdup ("y");
424 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
425 result = g_strdup ("n");
426 else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
427 result = g_strdup ("q");
428 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
429 result = g_strdup ("i");
430 else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
431 result = g_strdup ("u");
432 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
433 result = g_strdup ("x");
434 else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
435 result = g_strdup ("t");
436 else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
437 result = g_strdup ("h");
438 else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
439 result = g_strdup ("d");
440 else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
441 result = g_strdup ("s");
442 else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
443 result = g_strdup ("o");
444 else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
445 result = g_strdup ("g");
447 g_assert_not_reached ();
451 if (g_variant_type_equal (type, G_VARIANT_TYPE_ANY))
453 result = g_strdup ("S");
455 else if (g_variant_type_equal (type, G_VARIANT_TYPE_BASIC))
457 result = g_strdup ("?");
460 g_assert_not_reached ();
467 /* given a type string, replace one of the indefinite type characters in
468 * it with a matching type (possibly the same type).
471 generate_subtype (const gchar *type_string)
473 GVariantType *replacement;
474 GString *result, *junk;
475 gint length, n = 0, l;
477 result = g_string_new (NULL);
478 junk = g_string_new (NULL);
480 /* count the number of indefinite type characters */
481 for (length = 0; type_string[length]; length++)
482 n += type_string[length] == 'r' ||
483 type_string[length] == '?' ||
484 type_string[length] == '*';
485 /* length now is strlen (type_string) */
487 /* pick one at random to replace */
488 n = g_test_rand_int_range (0, n) + 1;
492 while (n--) l += strcspn (type_string + l + 1, "r?*") + 1;
493 g_assert (type_string[l] == 'r' ||
494 type_string[l] == '?' ||
495 type_string[l] == '*');
497 /* store up to that point in a GString */
498 g_string_append_len (result, type_string, l);
500 /* then store the replacement in the GString */
501 if (type_string[l] == 'r')
502 replacement = append_tuple_type_string (result, junk, FALSE, 3);
504 else if (type_string[l] == '?')
505 replacement = append_type_string (result, junk, FALSE, 0);
507 else if (type_string[l] == '*')
508 replacement = append_type_string (result, junk, FALSE, 3);
511 g_assert_not_reached ();
513 /* ensure the replacement has the proper type */
514 g_assert (g_variant_type_is_subtype_of (replacement,
515 (gpointer) &type_string[l]));
517 /* store the rest from the original type string */
518 g_string_append (result, type_string + l + 1);
520 g_variant_type_free (replacement);
521 g_string_free (junk, TRUE);
523 return g_string_free (result, FALSE);
528 const GVariantType *type;
529 struct typestack *parent;
532 /* given an indefinite type string, replace one of the indefinite
533 * characters in it with a matching type and ensure that the result is a
534 * subtype of the original. repeat.
537 subtype_check (const gchar *type_string,
538 struct typestack *parent_ts)
540 struct typestack ts, *node;
544 subtype = generate_subtype (type_string);
546 ts.type = G_VARIANT_TYPE (subtype);
547 ts.parent = parent_ts;
549 for (node = &ts; node; node = node->parent)
551 /* this type should be a subtype of each parent type */
552 g_assert (g_variant_type_is_subtype_of (ts.type, node->type));
554 /* it should only be a supertype when it is exactly equal */
555 g_assert (g_variant_type_is_subtype_of (node->type, ts.type) ==
556 g_variant_type_equal (ts.type, node->type));
561 if (!g_variant_type_is_definite (ts.type) && depth < 5)
563 /* the type is still indefinite and we haven't repeated too many
564 * times. go once more.
567 subtype_check (subtype, &ts);
574 test_gvarianttype (void)
578 for (i = 0; i < 2000; i++)
580 GString *type_string, *description;
581 GVariantType *type, *other_type;
582 const GVariantType *ctype;
586 type_string = g_string_new (NULL);
587 description = g_string_new (NULL);
589 /* generate a random type, its type string and a description
591 * exercises type constructor functions and g_variant_type_copy()
593 type = append_type_string (type_string, description, FALSE, 6);
595 /* convert the type string to a type and ensure that it is equal
596 * to the one produced with the type constructor routines
598 ctype = G_VARIANT_TYPE (type_string->str);
599 g_assert (g_variant_type_equal (ctype, type));
600 g_assert (g_variant_type_is_subtype_of (ctype, type));
601 g_assert (g_variant_type_is_subtype_of (type, ctype));
603 /* check if the type is indefinite */
604 if (!g_variant_type_is_definite (type))
606 struct typestack ts = { type, NULL };
608 /* if it is indefinite, then replace one of the indefinite
609 * characters with a matching type and ensure that the result
610 * is a subtype of the original type. repeat.
612 subtype_check (type_string->str, &ts);
615 /* ensure that no indefinite characters appear */
616 g_assert (strcspn (type_string->str, "r?*") == type_string->len);
619 /* describe the type.
621 * exercises the type iterator interface
623 desc = describe_type (type);
625 /* make sure the description matches */
626 g_assert_cmpstr (desc, ==, description->str);
629 /* make an invalid mutation to the type and make sure the type
630 * validation routines catch it */
631 invalid = invalid_mutation (type_string->str);
632 g_assert (g_variant_type_string_is_valid (type_string->str));
633 g_assert (!g_variant_type_string_is_valid (invalid));
636 /* concatenate another type to the type string and ensure that
637 * the result is recognised as being invalid
639 other_type = append_type_string (type_string, description, FALSE, 2);
641 g_string_free (description, TRUE);
642 g_string_free (type_string, TRUE);
643 g_variant_type_free (other_type);
644 g_variant_type_free (type);
648 #undef G_GNUC_INTERNAL
649 #define G_GNUC_INTERNAL static
651 #define DISABLE_VISIBILITY
652 #include <glib/gvarianttypeinfo.c>
654 #define ALIGNED(x, y) (((x + (y - 1)) / y) * y)
656 /* do our own calculation of the fixed_size and alignment of a type
657 * using a simple algorithm to make sure the "fancy" one in the
658 * implementation is correct.
661 calculate_type_info (const GVariantType *type,
665 if (g_variant_type_is_array (type) ||
666 g_variant_type_is_maybe (type))
668 calculate_type_info (g_variant_type_element (type), NULL, alignment);
673 else if (g_variant_type_is_tuple (type) ||
674 g_variant_type_is_dict_entry (type))
676 if (g_variant_type_n_items (type))
678 const GVariantType *sub;
687 sub = g_variant_type_first (type);
693 calculate_type_info (sub, &this_fs, &this_al);
695 al = MAX (al, this_al);
705 size = ALIGNED (size, this_al);
709 while ((sub = g_variant_type_next (sub)));
711 size = ALIGNED (size, al);
732 if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN) ||
733 g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
738 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16) ||
739 g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
744 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32) ||
745 g_variant_type_equal (type, G_VARIANT_TYPE_UINT32) ||
746 g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
751 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64) ||
752 g_variant_type_equal (type, G_VARIANT_TYPE_UINT64) ||
753 g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
757 else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING) ||
758 g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH) ||
759 g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
764 else if (g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT))
770 g_assert_not_reached ();
780 /* same as the describe_type() function above, but iterates over
781 * typeinfo instead of types.
784 describe_info (GVariantTypeInfo *info)
788 switch (g_variant_type_info_get_type_char (info))
790 case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
794 element = describe_info (g_variant_type_info_element (info));
795 result = g_strdup_printf ("m of %s", element);
800 case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
804 element = describe_info (g_variant_type_info_element (info));
805 result = g_strdup_printf ("a of %s", element);
810 case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
812 const gchar *sep = "";
817 string = g_string_new ("t of [");
818 length = g_variant_type_info_n_members (info);
820 for (i = 0; i < length; i++)
822 const GVariantMemberInfo *minfo;
825 g_string_append (string, sep);
828 minfo = g_variant_type_info_member_info (info, i);
829 subtype = describe_info (minfo->type);
830 g_string_append (string, subtype);
834 g_string_append_c (string, ']');
836 result = g_string_free (string, FALSE);
840 case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
842 const GVariantMemberInfo *keyinfo, *valueinfo;
845 g_assert_cmpint (g_variant_type_info_n_members (info), ==, 2);
846 keyinfo = g_variant_type_info_member_info (info, 0);
847 valueinfo = g_variant_type_info_member_info (info, 1);
848 key = describe_info (keyinfo->type);
849 value = describe_info (valueinfo->type);
850 result = g_strjoin ("", "e of [", key, ", ", value, "]", NULL);
856 case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
857 result = g_strdup ("V");
861 result = g_strdup (g_variant_type_info_get_type_string (info));
862 g_assert_cmpint (strlen (result), ==, 1);
869 /* check that the O(1) method of calculating offsets meshes with the
870 * results of simple iteration.
873 check_offsets (GVariantTypeInfo *info,
874 const GVariantType *type)
879 length = g_variant_type_info_n_members (info);
880 g_assert_cmpint (length, ==, g_variant_type_n_items (type));
882 /* the 'flavour' is the low order bits of the ending point of
883 * variable-size items in the tuple. this lets us test that the type
884 * info is correct for various starting alignments.
886 for (flavour = 0; flavour < 8; flavour++)
888 const GVariantType *subtype;
889 gsize last_offset_index;
894 subtype = g_variant_type_first (type);
895 last_offset_index = -1;
899 /* go through the tuple, keeping track of our position */
900 for (i = 0; i < length; i++)
905 calculate_type_info (subtype, &fixed_size, &alignment);
907 position = ALIGNED (position, alignment);
909 /* compare our current aligned position (ie: the start of this
910 * item) to the start offset that would be calculated if we
914 const GVariantMemberInfo *member;
917 member = g_variant_type_info_member_info (info, i);
918 g_assert_cmpint (member->i, ==, last_offset_index);
920 /* do the calculation using the typeinfo */
926 /* did we reach the same spot? */
927 g_assert_cmpint (start, ==, position);
932 /* fixed size. add that size. */
933 position += fixed_size;
937 /* variable size. do the flavouring. */
938 while ((position & 0x7) != flavour)
941 /* and store the offset, just like it would be in the
944 last_offset = position;
949 subtype = g_variant_type_next (subtype);
952 /* make sure we used up exactly all the types */
953 g_assert (subtype == NULL);
958 test_gvarianttypeinfo (void)
962 for (i = 0; i < 2000; i++)
964 GString *type_string, *description;
965 gsize fixed_size1, fixed_size2;
966 guint alignment1, alignment2;
967 GVariantTypeInfo *info;
971 type_string = g_string_new (NULL);
972 description = g_string_new (NULL);
975 type = append_type_string (type_string, description, TRUE, 6);
977 /* create a typeinfo for it */
978 info = g_variant_type_info_get (type);
980 /* make sure the typeinfo has the right type string */
981 g_assert_cmpstr (g_variant_type_info_get_type_string (info), ==,
984 /* calculate the alignment and fixed size, compare to the
985 * typeinfo's calculations
987 calculate_type_info (type, &fixed_size1, &alignment1);
988 g_variant_type_info_query (info, &alignment2, &fixed_size2);
989 g_assert_cmpint (fixed_size1, ==, fixed_size2);
990 g_assert_cmpint (alignment1, ==, alignment2 + 1);
992 /* test the iteration functions over typeinfo structures by
993 * "describing" the typeinfo and verifying equality.
995 desc = describe_info (info);
996 g_assert_cmpstr (desc, ==, description->str);
998 /* do extra checks for containers */
999 if (g_variant_type_is_array (type) ||
1000 g_variant_type_is_maybe (type))
1002 const GVariantType *element;
1006 element = g_variant_type_element (type);
1007 calculate_type_info (element, &efs1, &ea1);
1008 g_variant_type_info_query_element (info, &ea2, &efs2);
1009 g_assert_cmpint (efs1, ==, efs2);
1010 g_assert_cmpint (ea1, ==, ea2 + 1);
1012 g_assert_cmpint (ea1, ==, alignment1);
1013 g_assert_cmpint (0, ==, fixed_size1);
1015 else if (g_variant_type_is_tuple (type) ||
1016 g_variant_type_is_dict_entry (type))
1018 /* make sure the "magic constants" are working */
1019 check_offsets (info, type);
1022 g_string_free (type_string, TRUE);
1023 g_string_free (description, TRUE);
1024 g_variant_type_info_unref (info);
1025 g_variant_type_free (type);
1031 main (int argc, char **argv)
1033 g_test_init (&argc, &argv, NULL);
1035 g_test_add_func ("/gvariant/type", test_gvarianttype);
1036 g_test_add_func ("/gvariant/typeinfo", test_gvarianttypeinfo);
1038 return g_test_run ();