mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-27 22:46:15 +01:00
add testcase for GVariantType
This commit is contained in:
parent
0ccb288da1
commit
b4c0b10658
1
glib/tests/.gitignore
vendored
1
glib/tests/.gitignore
vendored
@ -1,5 +1,6 @@
|
|||||||
array-test
|
array-test
|
||||||
fileutils
|
fileutils
|
||||||
|
gvarianttype
|
||||||
hostutils
|
hostutils
|
||||||
keyfile
|
keyfile
|
||||||
markup-subparser
|
markup-subparser
|
||||||
|
@ -47,6 +47,9 @@ array_test_LDADD = $(progs_ldadd)
|
|||||||
TEST_PROGS += hostutils
|
TEST_PROGS += hostutils
|
||||||
hostutils_LDADD = $(progs_ldadd)
|
hostutils_LDADD = $(progs_ldadd)
|
||||||
|
|
||||||
|
TEST_PROGS += gvarianttype
|
||||||
|
gvarianttype_LDADD = $(progs_ldadd)
|
||||||
|
|
||||||
if OS_UNIX
|
if OS_UNIX
|
||||||
|
|
||||||
# some testing of gtester funcitonality
|
# some testing of gtester funcitonality
|
||||||
|
650
glib/tests/gvarianttype.c
Normal file
650
glib/tests/gvarianttype.c
Normal file
@ -0,0 +1,650 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2010 Codethink Limited
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the licence, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* See the included COPYING file for more information.
|
||||||
|
*
|
||||||
|
* Author: Ryan Lortie <desrt@desrt.ca>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#define BASIC "bynqiuxthdsog?"
|
||||||
|
#define N_BASIC (G_N_ELEMENTS (BASIC) - 1)
|
||||||
|
|
||||||
|
#define INVALIDS "cefjklpwz&@^$"
|
||||||
|
#define N_INVALIDS (G_N_ELEMENTS (INVALIDS) - 1)
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
randomly (gdouble prob)
|
||||||
|
{
|
||||||
|
return g_test_rand_double_range (0, 1) < prob;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* corecursion */
|
||||||
|
static GVariantType *append_tuple_type_string (GString *, GString *, gint);
|
||||||
|
|
||||||
|
/* append a random GVariantType to a GString
|
||||||
|
* append a description of the type to another GString
|
||||||
|
* return what the type is
|
||||||
|
*/
|
||||||
|
static GVariantType *
|
||||||
|
append_type_string (GString *string,
|
||||||
|
GString *description,
|
||||||
|
gint depth)
|
||||||
|
{
|
||||||
|
if (!depth-- || randomly (0.3))
|
||||||
|
{
|
||||||
|
gchar b = BASIC[g_test_rand_int_range (0, N_BASIC)];
|
||||||
|
g_string_append_c (string, b);
|
||||||
|
g_string_append_c (description, b);
|
||||||
|
|
||||||
|
switch (b)
|
||||||
|
{
|
||||||
|
case 'b':
|
||||||
|
return g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN);
|
||||||
|
case 'y':
|
||||||
|
return g_variant_type_copy (G_VARIANT_TYPE_BYTE);
|
||||||
|
case 'n':
|
||||||
|
return g_variant_type_copy (G_VARIANT_TYPE_INT16);
|
||||||
|
case 'q':
|
||||||
|
return g_variant_type_copy (G_VARIANT_TYPE_UINT16);
|
||||||
|
case 'i':
|
||||||
|
return g_variant_type_copy (G_VARIANT_TYPE_INT32);
|
||||||
|
case 'u':
|
||||||
|
return g_variant_type_copy (G_VARIANT_TYPE_UINT32);
|
||||||
|
case 'x':
|
||||||
|
return g_variant_type_copy (G_VARIANT_TYPE_INT64);
|
||||||
|
case 't':
|
||||||
|
return g_variant_type_copy (G_VARIANT_TYPE_UINT64);
|
||||||
|
case 'h':
|
||||||
|
return g_variant_type_copy (G_VARIANT_TYPE_HANDLE);
|
||||||
|
case 'd':
|
||||||
|
return g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
|
||||||
|
case 's':
|
||||||
|
return g_variant_type_copy (G_VARIANT_TYPE_STRING);
|
||||||
|
case 'o':
|
||||||
|
return g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH);
|
||||||
|
case 'g':
|
||||||
|
return g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE);
|
||||||
|
case '?':
|
||||||
|
return g_variant_type_copy (G_VARIANT_TYPE_BASIC);
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GVariantType *result;
|
||||||
|
|
||||||
|
switch (g_test_rand_int_range (0, 7))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
GVariantType *element;
|
||||||
|
|
||||||
|
g_string_append_c (string, 'a');
|
||||||
|
g_string_append (description, "a of ");
|
||||||
|
element = append_type_string (string, description, depth);
|
||||||
|
result = g_variant_type_new_array (element);
|
||||||
|
g_variant_type_free (element);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert (g_variant_type_is_array (result));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
GVariantType *element;
|
||||||
|
|
||||||
|
g_string_append_c (string, 'm');
|
||||||
|
g_string_append (description, "m of ");
|
||||||
|
element = append_type_string (string, description, depth);
|
||||||
|
result = g_variant_type_new_maybe (element);
|
||||||
|
g_variant_type_free (element);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert (g_variant_type_is_maybe (result));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
result = append_tuple_type_string (string, description, depth);
|
||||||
|
|
||||||
|
g_assert (g_variant_type_is_tuple (result));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
GVariantType *key, *value;
|
||||||
|
|
||||||
|
g_string_append_c (string, '{');
|
||||||
|
g_string_append (description, "e of [");
|
||||||
|
key = append_type_string (string, description, 0);
|
||||||
|
g_string_append (description, ", ");
|
||||||
|
value = append_type_string (string, description, depth);
|
||||||
|
g_string_append_c (description, ']');
|
||||||
|
g_string_append_c (string, '}');
|
||||||
|
result = g_variant_type_new_dict_entry (key, value);
|
||||||
|
g_variant_type_free (key);
|
||||||
|
g_variant_type_free (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert (g_variant_type_is_dict_entry (result));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
g_string_append_c (string, 'v');
|
||||||
|
g_string_append_c (description, 'V');
|
||||||
|
result = g_variant_type_copy (G_VARIANT_TYPE_VARIANT);
|
||||||
|
g_assert (g_variant_type_equal (result, G_VARIANT_TYPE_VARIANT));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
g_string_append_c (string, '*');
|
||||||
|
g_string_append_c (description, 'S');
|
||||||
|
result = g_variant_type_copy (G_VARIANT_TYPE_ANY);
|
||||||
|
g_assert (g_variant_type_equal (result, G_VARIANT_TYPE_ANY));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
g_string_append_c (string, 'r');
|
||||||
|
g_string_append_c (description, 'R');
|
||||||
|
result = g_variant_type_copy (G_VARIANT_TYPE_TUPLE);
|
||||||
|
g_assert (g_variant_type_is_tuple (result));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GVariantType *
|
||||||
|
append_tuple_type_string (GString *string,
|
||||||
|
GString *description,
|
||||||
|
gint depth)
|
||||||
|
{
|
||||||
|
GVariantType *result, *other_result;
|
||||||
|
GVariantType **types;
|
||||||
|
gint size;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
g_string_append_c (string, '(');
|
||||||
|
g_string_append (description, "t of [");
|
||||||
|
|
||||||
|
size = g_test_rand_int_range (0, 20);
|
||||||
|
types = g_new (GVariantType *, size + 1);
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
types[i] = append_type_string (string, description, depth);
|
||||||
|
|
||||||
|
if (i < size - 1)
|
||||||
|
g_string_append (description, ", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
types[i] = NULL;
|
||||||
|
|
||||||
|
g_string_append_c (description, ']');
|
||||||
|
g_string_append_c (string, ')');
|
||||||
|
|
||||||
|
result = g_variant_type_new_tuple ((gpointer) types, size);
|
||||||
|
other_result = g_variant_type_new_tuple ((gpointer) types, -1);
|
||||||
|
g_assert (g_variant_type_equal (result, other_result));
|
||||||
|
g_variant_type_free (other_result);
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
g_variant_type_free (types[i]);
|
||||||
|
g_free (types);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* given a valid type string, make it invalid */
|
||||||
|
static gchar *
|
||||||
|
invalid_mutation (const gchar *type_string)
|
||||||
|
{
|
||||||
|
gboolean have_parens, have_braces;
|
||||||
|
|
||||||
|
/* it's valid, so '(' implies ')' and same for '{' and '}' */
|
||||||
|
have_parens = strchr (type_string, '(') != NULL;
|
||||||
|
have_braces = strchr (type_string, '{') != NULL;
|
||||||
|
|
||||||
|
if (have_parens && have_braces && randomly (0.3))
|
||||||
|
{
|
||||||
|
/* swap a paren and a brace */
|
||||||
|
gchar *pp, *bp;
|
||||||
|
gint np, nb;
|
||||||
|
gchar p, b;
|
||||||
|
gchar *new;
|
||||||
|
|
||||||
|
new = g_strdup (type_string);
|
||||||
|
|
||||||
|
if (randomly (0.5))
|
||||||
|
p = '(', b = '{';
|
||||||
|
else
|
||||||
|
p = ')', b = '}';
|
||||||
|
|
||||||
|
np = nb = 0;
|
||||||
|
pp = bp = new - 1;
|
||||||
|
|
||||||
|
/* count number of parens/braces */
|
||||||
|
while ((pp = strchr (pp + 1, p))) np++;
|
||||||
|
while ((bp = strchr (bp + 1, b))) nb++;
|
||||||
|
|
||||||
|
/* randomly pick one of each */
|
||||||
|
np = g_test_rand_int_range (0, np) + 1;
|
||||||
|
nb = g_test_rand_int_range (0, nb) + 1;
|
||||||
|
|
||||||
|
/* find it */
|
||||||
|
pp = bp = new - 1;
|
||||||
|
while (np--) pp = strchr (pp + 1, p);
|
||||||
|
while (nb--) bp = strchr (bp + 1, b);
|
||||||
|
|
||||||
|
/* swap */
|
||||||
|
g_assert (*bp == b && *pp == p);
|
||||||
|
*bp = p;
|
||||||
|
*pp = b;
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((have_parens || have_braces) && randomly (0.3))
|
||||||
|
{
|
||||||
|
/* drop a paren/brace */
|
||||||
|
gchar *new;
|
||||||
|
gchar *pp;
|
||||||
|
gint np;
|
||||||
|
gchar p;
|
||||||
|
|
||||||
|
if (have_parens)
|
||||||
|
if (randomly (0.5)) p = '('; else p = ')';
|
||||||
|
else
|
||||||
|
if (randomly (0.5)) p = '{'; else p = '}';
|
||||||
|
|
||||||
|
new = g_strdup (type_string);
|
||||||
|
|
||||||
|
np = 0;
|
||||||
|
pp = new - 1;
|
||||||
|
while ((pp = strchr (pp + 1, p))) np++;
|
||||||
|
np = g_test_rand_int_range (0, np) + 1;
|
||||||
|
pp = new - 1;
|
||||||
|
while (np--) pp = strchr (pp + 1, p);
|
||||||
|
g_assert (*pp == p);
|
||||||
|
|
||||||
|
while (*pp)
|
||||||
|
{
|
||||||
|
*pp = *(pp + 1);
|
||||||
|
pp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* else, perform a random mutation at a random point */
|
||||||
|
{
|
||||||
|
gint length, n;
|
||||||
|
gchar *new;
|
||||||
|
gchar p;
|
||||||
|
|
||||||
|
if (randomly (0.3))
|
||||||
|
{
|
||||||
|
/* insert a paren/brace */
|
||||||
|
if (randomly (0.5))
|
||||||
|
if (randomly (0.5)) p = '('; else p = ')';
|
||||||
|
else
|
||||||
|
if (randomly (0.5)) p = '{'; else p = '}';
|
||||||
|
}
|
||||||
|
else if (randomly (0.5))
|
||||||
|
{
|
||||||
|
/* insert junk */
|
||||||
|
p = INVALIDS[g_test_rand_int_range (0, N_INVALIDS)];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* truncate */
|
||||||
|
p = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
length = strlen (type_string);
|
||||||
|
new = g_malloc (length + 2);
|
||||||
|
n = g_test_rand_int_range (0, length);
|
||||||
|
memcpy (new, type_string, n);
|
||||||
|
new[n] = p;
|
||||||
|
memcpy (new + n + 1, type_string + n, length - n);
|
||||||
|
new[length + 1] = '\0';
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* describe a type using the same language as is generated
|
||||||
|
* while generating the type with append_type_string
|
||||||
|
*/
|
||||||
|
static gchar *
|
||||||
|
describe_type (const GVariantType *type)
|
||||||
|
{
|
||||||
|
gchar *result;
|
||||||
|
|
||||||
|
if (g_variant_type_is_container (type))
|
||||||
|
{
|
||||||
|
g_assert (!g_variant_type_is_basic (type));
|
||||||
|
|
||||||
|
if (g_variant_type_is_array (type))
|
||||||
|
{
|
||||||
|
gchar *subtype = describe_type (g_variant_type_element (type));
|
||||||
|
result = g_strdup_printf ("a of %s", subtype);
|
||||||
|
g_free (subtype);
|
||||||
|
}
|
||||||
|
else if (g_variant_type_is_maybe (type))
|
||||||
|
{
|
||||||
|
gchar *subtype = describe_type (g_variant_type_element (type));
|
||||||
|
result = g_strdup_printf ("m of %s", subtype);
|
||||||
|
g_free (subtype);
|
||||||
|
}
|
||||||
|
else if (g_variant_type_is_tuple (type))
|
||||||
|
{
|
||||||
|
if (!g_variant_type_equal (type, G_VARIANT_TYPE_TUPLE))
|
||||||
|
{
|
||||||
|
const GVariantType *sub;
|
||||||
|
GString *string;
|
||||||
|
gint length;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
string = g_string_new ("t of [");
|
||||||
|
|
||||||
|
length = g_variant_type_n_items (type);
|
||||||
|
sub = g_variant_type_first (type);
|
||||||
|
for (i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
gchar *subtype = describe_type (sub);
|
||||||
|
g_string_append (string, subtype);
|
||||||
|
g_free (subtype);
|
||||||
|
|
||||||
|
if ((sub = g_variant_type_next (sub)))
|
||||||
|
g_string_append (string, ", ");
|
||||||
|
}
|
||||||
|
g_assert (sub == NULL);
|
||||||
|
g_string_append_c (string, ']');
|
||||||
|
|
||||||
|
result = g_string_free (string, FALSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result = g_strdup ("R");
|
||||||
|
}
|
||||||
|
else if (g_variant_type_is_dict_entry (type))
|
||||||
|
{
|
||||||
|
gchar *key, *value, *key2, *value2;
|
||||||
|
|
||||||
|
key = describe_type (g_variant_type_key (type));
|
||||||
|
value = describe_type (g_variant_type_value (type));
|
||||||
|
key2 = describe_type (g_variant_type_first (type));
|
||||||
|
value2 = describe_type (
|
||||||
|
g_variant_type_next (g_variant_type_first (type)));
|
||||||
|
g_assert (g_variant_type_next (g_variant_type_next (
|
||||||
|
g_variant_type_first (type))) == NULL);
|
||||||
|
g_assert_cmpstr (key, ==, key2);
|
||||||
|
g_assert_cmpstr (value, ==, value2);
|
||||||
|
result = g_strjoin ("", "e of [", key, ", ", value, "]", NULL);
|
||||||
|
g_free (key2);
|
||||||
|
g_free (value2);
|
||||||
|
g_free (key);
|
||||||
|
g_free (value);
|
||||||
|
}
|
||||||
|
else if (g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT))
|
||||||
|
{
|
||||||
|
result = g_strdup ("V");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (g_variant_type_is_definite (type))
|
||||||
|
{
|
||||||
|
g_assert (g_variant_type_is_basic (type));
|
||||||
|
|
||||||
|
if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
|
||||||
|
result = g_strdup ("b");
|
||||||
|
else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
|
||||||
|
result = g_strdup ("y");
|
||||||
|
else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
|
||||||
|
result = g_strdup ("n");
|
||||||
|
else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
|
||||||
|
result = g_strdup ("q");
|
||||||
|
else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
|
||||||
|
result = g_strdup ("i");
|
||||||
|
else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
|
||||||
|
result = g_strdup ("u");
|
||||||
|
else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
|
||||||
|
result = g_strdup ("x");
|
||||||
|
else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
|
||||||
|
result = g_strdup ("t");
|
||||||
|
else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
|
||||||
|
result = g_strdup ("h");
|
||||||
|
else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
|
||||||
|
result = g_strdup ("d");
|
||||||
|
else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
|
||||||
|
result = g_strdup ("s");
|
||||||
|
else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
|
||||||
|
result = g_strdup ("o");
|
||||||
|
else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
|
||||||
|
result = g_strdup ("g");
|
||||||
|
else
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (g_variant_type_equal (type, G_VARIANT_TYPE_ANY))
|
||||||
|
{
|
||||||
|
result = g_strdup ("S");
|
||||||
|
}
|
||||||
|
else if (g_variant_type_equal (type, G_VARIANT_TYPE_BASIC))
|
||||||
|
{
|
||||||
|
result = g_strdup ("?");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* given a type string, replace one of the indefinite type characters in
|
||||||
|
* it with a matching type (possibly the same type).
|
||||||
|
*/
|
||||||
|
static gchar *
|
||||||
|
generate_subtype (const gchar *type_string)
|
||||||
|
{
|
||||||
|
GVariantType *replacement;
|
||||||
|
GString *result, *junk;
|
||||||
|
gint length, n = 0, l;
|
||||||
|
|
||||||
|
result = g_string_new (NULL);
|
||||||
|
junk = g_string_new (NULL);
|
||||||
|
|
||||||
|
/* count the number of indefinite type characters */
|
||||||
|
for (length = 0; type_string[length]; length++)
|
||||||
|
n += type_string[length] == 'r' ||
|
||||||
|
type_string[length] == '?' ||
|
||||||
|
type_string[length] == '*';
|
||||||
|
/* length now is strlen (type_string) */
|
||||||
|
|
||||||
|
/* pick one at random to replace */
|
||||||
|
n = g_test_rand_int_range (0, n) + 1;
|
||||||
|
|
||||||
|
/* find it */
|
||||||
|
l = -1;
|
||||||
|
while (n--) l += strcspn (type_string + l + 1, "r?*") + 1;
|
||||||
|
g_assert (type_string[l] == 'r' ||
|
||||||
|
type_string[l] == '?' ||
|
||||||
|
type_string[l] == '*');
|
||||||
|
|
||||||
|
/* store up to that point in a GString */
|
||||||
|
g_string_append_len (result, type_string, l);
|
||||||
|
|
||||||
|
/* then store the replacement in the GString */
|
||||||
|
if (type_string[l] == 'r')
|
||||||
|
replacement = append_tuple_type_string (result, junk, 3);
|
||||||
|
|
||||||
|
else if (type_string[l] == '?')
|
||||||
|
replacement = append_type_string (result, junk, 0);
|
||||||
|
|
||||||
|
else if (type_string[l] == '*')
|
||||||
|
replacement = append_type_string (result, junk, 3);
|
||||||
|
|
||||||
|
else
|
||||||
|
g_assert_not_reached ();
|
||||||
|
|
||||||
|
/* ensure the replacement has the proper type */
|
||||||
|
g_assert (g_variant_type_is_subtype_of (replacement,
|
||||||
|
(gpointer) &type_string[l]));
|
||||||
|
|
||||||
|
/* store the rest from the original type string */
|
||||||
|
g_string_append (result, type_string + l + 1);
|
||||||
|
|
||||||
|
g_variant_type_free (replacement);
|
||||||
|
g_string_free (junk, TRUE);
|
||||||
|
|
||||||
|
return g_string_free (result, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct typestack
|
||||||
|
{
|
||||||
|
const GVariantType *type;
|
||||||
|
struct typestack *parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* given an indefinite type string, replace one of the indefinite
|
||||||
|
* characters in it with a matching type and ensure that the result is a
|
||||||
|
* subtype of the original. repeat.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
subtype_check (const gchar *type_string,
|
||||||
|
struct typestack *parent_ts)
|
||||||
|
{
|
||||||
|
struct typestack ts, *node;
|
||||||
|
gchar *subtype;
|
||||||
|
gint depth = 0;
|
||||||
|
|
||||||
|
subtype = generate_subtype (type_string);
|
||||||
|
|
||||||
|
ts.type = G_VARIANT_TYPE (subtype);
|
||||||
|
ts.parent = parent_ts;
|
||||||
|
|
||||||
|
for (node = &ts; node; node = node->parent)
|
||||||
|
{
|
||||||
|
/* this type should be a subtype of each parent type */
|
||||||
|
g_assert (g_variant_type_is_subtype_of (ts.type, node->type));
|
||||||
|
|
||||||
|
/* it should only be a supertype when it is exactly equal */
|
||||||
|
g_assert (g_variant_type_is_subtype_of (node->type, ts.type) ==
|
||||||
|
g_variant_type_equal (ts.type, node->type));
|
||||||
|
|
||||||
|
depth++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_variant_type_is_definite (ts.type) && depth < 5)
|
||||||
|
{
|
||||||
|
/* the type is still indefinite and we haven't repeated too many
|
||||||
|
* times. go once more.
|
||||||
|
*/
|
||||||
|
|
||||||
|
subtype_check (subtype, &ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (subtype);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_gvarianttype (void)
|
||||||
|
{
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
for (i = 0; i < 2000; i++)
|
||||||
|
{
|
||||||
|
GString *type_string, *description;
|
||||||
|
GVariantType *type, *other_type;
|
||||||
|
const GVariantType *ctype;
|
||||||
|
gchar *invalid;
|
||||||
|
gchar *desc;
|
||||||
|
|
||||||
|
type_string = g_string_new (NULL);
|
||||||
|
description = g_string_new (NULL);
|
||||||
|
|
||||||
|
/* generate a random type, its type string and a description
|
||||||
|
*
|
||||||
|
* exercises type constructor functions and g_variant_type_copy()
|
||||||
|
*/
|
||||||
|
type = append_type_string (type_string, description, 6);
|
||||||
|
|
||||||
|
/* convert the type string to a type and ensure that it is equal
|
||||||
|
* to the one produced with the type constructor routines
|
||||||
|
*/
|
||||||
|
ctype = G_VARIANT_TYPE (type_string->str);
|
||||||
|
g_assert (g_variant_type_equal (ctype, type));
|
||||||
|
g_assert (g_variant_type_is_subtype_of (ctype, type));
|
||||||
|
g_assert (g_variant_type_is_subtype_of (type, ctype));
|
||||||
|
|
||||||
|
/* check if the type is indefinite */
|
||||||
|
if (!g_variant_type_is_definite (type))
|
||||||
|
{
|
||||||
|
struct typestack ts = { type, NULL };
|
||||||
|
|
||||||
|
/* if it is indefinite, then replace one of the indefinite
|
||||||
|
* characters with a matching type and ensure that the result
|
||||||
|
* is a subtype of the original type. repeat.
|
||||||
|
*/
|
||||||
|
subtype_check (type_string->str, &ts);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* ensure that no indefinite characters appear */
|
||||||
|
g_assert (strcspn (type_string->str, "r?*") == type_string->len);
|
||||||
|
|
||||||
|
|
||||||
|
/* describe the type.
|
||||||
|
*
|
||||||
|
* exercises the type iterator interface
|
||||||
|
*/
|
||||||
|
desc = describe_type (type);
|
||||||
|
|
||||||
|
/* make sure the description matches */
|
||||||
|
g_assert_cmpstr (desc, ==, description->str);
|
||||||
|
g_free (desc);
|
||||||
|
|
||||||
|
/* make an invalid mutation to the type and make sure the type
|
||||||
|
* validation routines catch it */
|
||||||
|
invalid = invalid_mutation (type_string->str);
|
||||||
|
g_assert (g_variant_type_string_is_valid (type_string->str));
|
||||||
|
g_assert (!g_variant_type_string_is_valid (invalid));
|
||||||
|
g_free (invalid);
|
||||||
|
|
||||||
|
/* concatenate another type to the type string and ensure that
|
||||||
|
* the result is recognised as being invalid
|
||||||
|
*/
|
||||||
|
other_type = append_type_string (type_string, description, 2);
|
||||||
|
|
||||||
|
g_string_free (description, TRUE);
|
||||||
|
g_string_free (type_string, TRUE);
|
||||||
|
g_variant_type_free (other_type);
|
||||||
|
g_variant_type_free (type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
g_test_init (&argc, &argv, NULL);
|
||||||
|
|
||||||
|
g_test_add_func ("/gvariant/type", test_gvarianttype);
|
||||||
|
|
||||||
|
return g_test_run ();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user