* 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.
+ * version 2.1 of the License, or (at your option) any later version.
*
* See the included COPYING file for more information.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
+#include "config.h"
+
+#include <glib/gvariant-internal.h>
#include <string.h>
+#include <stdlib.h>
#include <glib.h>
#define BASIC "bynqiuxthdsog?"
#define INVALIDS "cefjklpwz&@^$"
#define N_INVALIDS (G_N_ELEMENTS (INVALIDS) - 1)
+/* see comment in gvariant-serialiser.c about this madness.
+ *
+ * we use this to get testing of non-strictly-aligned GVariant instances
+ * on machines that can tolerate it. it is necessary to support this
+ * because some systems have malloc() that returns non-8-aligned
+ * pointers. it is necessary to have special support in the tests
+ * because on most machines malloc() is 8-aligned.
+ */
+#define ALIGN_BITS (sizeof (struct { char a; union { \
+ guint64 x; void *y; gdouble z; } b; }) - 9)
+
static gboolean
randomly (gdouble prob)
{
*/
ctype = G_VARIANT_TYPE (type_string->str);
g_assert (g_variant_type_equal (ctype, type));
+ g_assert (g_variant_type_hash (ctype) == g_variant_type_hash (type));
g_assert (g_variant_type_is_subtype_of (ctype, type));
g_assert (g_variant_type_is_subtype_of (type, ctype));
}
}
-#undef G_GNUC_INTERNAL
-#define G_GNUC_INTERNAL static
-
-#define DISABLE_VISIBILITY
-#define GLIB_COMPILATION
-#include <glib/gvarianttypeinfo.c>
-
#define ALIGNED(x, y) (((x + (y - 1)) / y) * y)
/* do our own calculation of the fixed_size and alignment of a type
g_free (desc);
}
- assert_no_type_infos ();
+ g_variant_type_info_assert_no_infos ();
}
-#include <glib/gvariant-serialiser.c>
-
#define MAX_FIXED_MULTIPLIER 256
#define MAX_INSTANCE_SIZE 1024
#define MAX_ARRAY_CHILDREN 128
GRand *rand;
gint i;
- g_assert_cmpint ((gsize) buffer & instance->alignment, ==, 0);
+ g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0);
rand = g_rand_new_with_seed (instance->seed);
for (i = 0; i < instance->size; i++)
GRand *rand;
gint i;
- g_assert_cmpint ((gsize) buffer & instance->alignment, ==, 0);
+ g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0);
g_assert_cmpint (size, ==, instance->size);
rand = g_rand_new_with_seed (instance->seed);
GRand *rand;
gint i;
- g_assert_cmpint ((gsize) buffer & instance->alignment, ==, 0);
+ g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0);
if (size != instance->size)
return FALSE;
if (size == 0)
return NULL;
- return g_malloc (size + flavour) + flavour;
+ return ((gchar *) g_malloc (size + flavour)) + flavour;
+}
+
+static void
+flavoured_free (gpointer data,
+ gsize flavour)
+{
+ if (!data)
+ return;
+ g_free (((gchar *) data) - flavour);
+}
+
+static gpointer
+align_malloc (gsize size)
+{
+ gpointer mem;
+
+#ifdef HAVE_POSIX_MEMALIGN
+ if (posix_memalign (&mem, 8, size))
+ g_error ("posix_memalign failed");
+#else
+ /* NOTE: there may be platforms that lack posix_memalign() and also
+ * have malloc() that returns non-8-aligned. if so, we need to try
+ * harder here.
+ */
+ mem = malloc (size);
+#endif
+
+ return mem;
}
static void
-flavoured_free (gpointer data)
+align_free (gpointer mem)
{
- g_free ((gpointer) (((gsize) data) & ~7));
+ free (mem);
}
static void
{
guchar *ptr;
- ptr = data = g_malloc (needed_size);
+ ptr = data = align_malloc (needed_size);
append_instance_data (instance, &ptr);
if (!instance->is_fixed_sized)
guint alignment;
guint flavour;
- alignment = instance->alignment + 1;
+ alignment = (instance->alignment & ALIGN_BITS) + 1;
for (flavour = 0; flavour < 8; flavour += alignment)
{
g_assert (child.type_info == instance->type_info);
random_instance_assert (instance, child.data, child.size);
g_variant_type_info_unref (child.type_info);
- flavoured_free (serialised.data);
+ flavoured_free (serialised.data, flavour);
}
}
g_variant_type_info_unref (type_info);
random_instance_free (instance);
- g_free (data);
+ align_free (data);
}
static void
for (i = 0; i < 1000; i++)
test_maybe ();
- assert_no_type_infos ();
+ g_variant_type_info_assert_no_infos ();
}
static void
guchar *offset_ptr, *body_ptr;
guint i;
- body_ptr = data = g_malloc (needed_size);
+ body_ptr = data = align_malloc (needed_size);
offset_ptr = body_ptr + needed_size - offset_size * n_children;
for (i = 0; i < n_children; i++)
guint i;
g_variant_type_info_query (array_info, &alignment, NULL);
- alignment++;
+ alignment = (alignment & ALIGN_BITS) + 1;
for (flavour = 0; flavour < 8; flavour += alignment)
{
g_variant_serialiser_serialise (serialised, random_instance_filler,
(gpointer *) instances, n_children);
- g_assert (memcmp (serialised.data, data, serialised.size) == 0);
+ if (serialised.size)
+ g_assert (memcmp (serialised.data, data, serialised.size) == 0);
+
g_assert (g_variant_serialised_n_children (serialised) == n_children);
for (i = 0; i < n_children; i++)
g_variant_type_info_unref (child.type_info);
}
- flavoured_free (serialised.data);
+ flavoured_free (serialised.data, flavour);
}
}
g_variant_type_info_unref (element_info);
g_variant_type_info_unref (array_info);
- g_free (data);
+ align_free (data);
}
static void
for (i = 0; i < 100; i++)
test_array ();
- assert_no_type_infos ();
+ g_variant_type_info_assert_no_infos ();
}
static void
guchar *ofs_ptr;
guint i;
- body_ptr = data = g_malloc (needed_size);
+ body_ptr = data = align_malloc (needed_size);
ofs_ptr = body_ptr + needed_size;
for (i = 0; i < n_children; i++)
gsize flavour;
guint i;
- alignment++;
+ alignment = (alignment & ALIGN_BITS) + 1;
for (flavour = 0; flavour < 8; flavour += alignment)
{
g_variant_serialiser_serialise (serialised, random_instance_filler,
(gpointer *) instances, n_children);
- g_assert (memcmp (serialised.data, data, serialised.size) == 0);
+ if (serialised.size)
+ g_assert (memcmp (serialised.data, data, serialised.size) == 0);
+
g_assert (g_variant_serialised_n_children (serialised) == n_children);
for (i = 0; i < n_children; i++)
g_variant_type_info_unref (child.type_info);
}
- flavoured_free (serialised.data);
+ flavoured_free (serialised.data, flavour);
}
}
}
g_variant_type_info_unref (type_info);
- g_free (data);
+ align_free (data);
}
static void
for (i = 0; i < 100; i++)
test_tuple ();
- assert_no_type_infos ();
+ g_variant_type_info_assert_no_infos ();
}
static void
{
guchar *ptr;
- ptr = data = g_malloc (needed_size);
+ ptr = data = align_malloc (needed_size);
append_instance_data (instance, &ptr);
*ptr++ = '\0';
memcpy (ptr, type_string, len);
}
{
- /* variants are 8-aligned, so no extra flavouring */
- GVariantSerialised serialised;
- GVariantSerialised child;
+ gsize alignment;
+ gsize flavour;
- serialised.type_info = type_info;
- serialised.data = flavoured_malloc (needed_size, 0);
- serialised.size = needed_size;
+ /* variants are always 8-aligned */
+ alignment = ALIGN_BITS + 1;
- g_variant_serialiser_serialise (serialised, random_instance_filler,
- (gpointer *) &instance, 1);
+ for (flavour = 0; flavour < 8; flavour += alignment)
+ {
+ GVariantSerialised serialised;
+ GVariantSerialised child;
- g_assert (memcmp (serialised.data, data, serialised.size) == 0);
- g_assert (g_variant_serialised_n_children (serialised) == 1);
+ serialised.type_info = type_info;
+ serialised.data = flavoured_malloc (needed_size, flavour);
+ serialised.size = needed_size;
+
+ g_variant_serialiser_serialise (serialised, random_instance_filler,
+ (gpointer *) &instance, 1);
- child = g_variant_serialised_get_child (serialised, 0);
- g_assert (child.type_info == instance->type_info);
- random_instance_check (instance, child.data, child.size);
+ if (serialised.size)
+ g_assert (memcmp (serialised.data, data, serialised.size) == 0);
- g_variant_type_info_unref (child.type_info);
- flavoured_free (serialised.data);
+ g_assert (g_variant_serialised_n_children (serialised) == 1);
+
+ child = g_variant_serialised_get_child (serialised, 0);
+ g_assert (child.type_info == instance->type_info);
+ random_instance_check (instance, child.data, child.size);
+
+ g_variant_type_info_unref (child.type_info);
+ flavoured_free (serialised.data, flavour);
+ }
}
g_variant_type_info_unref (type_info);
random_instance_free (instance);
- g_free (data);
+ align_free (data);
}
static void
for (i = 0; i < 100; i++)
test_variant ();
- assert_no_type_infos ();
+ g_variant_type_info_assert_no_infos ();
}
static void
#define is_sig is_string | 4
{ is_sig, 1, "" },
{ is_nval, 0, NULL },
+ { is_nval, 13, "hello\xffworld!" },
{ is_string, 13, "hello world!" },
{ is_nval, 13, "hello world\0" },
{ is_nval, 13, "hello\0world!" },
{ is_nval, 12, "hello world!" },
+ { is_nval, 13, "hello world!\xff" },
{ is_objpath, 2, "/" },
{ is_objpath, 3, "/a" },
union {
guint64 integer;
gdouble floating;
- gchar string[32];
+ gchar string[200];
} data;
gsize data_size;
};
instance->data_size = 4;
break;
- case 'x': case 't': case 'd':
+ case 'x': case 't':
instance->data.integer = g_test_rand_int ();
instance->data.integer <<= 32;
instance->data.integer |= (guint32) g_test_rand_int ();
instance->data_size = 8;
break;
+ case 'd':
+ instance->data.floating = g_test_rand_double ();
+ instance->data_size = 8;
+ break;
+
case 's': case 'o': case 'g':
- instance->data_size = g_test_rand_int_range (10, 20);
+ instance->data_size = g_test_rand_int_range (10, 200);
make_random_string (instance->data.string, instance->data_size, type);
break;
}
serialise_tree (TreeInstance *tree,
GVariantSerialised *serialised)
{
- GVariantSerialised empty = { };
+ GVariantSerialised empty = {0, };
*serialised = empty;
tree_filler (serialised, tree);
g_variant_serialised_byteswap (two);
- g_assert_cmpint (one.size, ==, two.size);
- g_assert (memcmp (one.data, two.data, one.size) == 0);
+ g_assert_cmpmem (one.data, one.size, two.data, two.size);
tree_instance_free (tree);
g_free (one.data);
for (i = 0; i < 200; i++)
test_byteswap ();
- assert_no_type_infos ();
+ g_variant_type_info_assert_no_infos ();
}
static void
for (i = 0; i < 200; i++)
test_fuzz (&fuzziness);
- assert_no_type_infos ();
+ g_variant_type_info_assert_no_infos ();
}
static GVariant *
child = g_variant_get_variant (value);
str1 = g_variant_get_type_string (child);
str2 = g_variant_type_info_get_type_string (tree->children[0]->info);
-
- /* can't pointer-compare str1 and str2 since one comes from the
- * real GVariantTypeInfo and one comes from our private copy...
- */
- equal = strcmp (str1, str2) == 0 &&
+ /* GVariant only keeps one copy of type strings around */
+ equal = str1 == str2 &&
tree_instance_check_gvariant (tree->children[0], child);
g_variant_unref (child);
static void
tree_instance_build_gvariant (TreeInstance *tree,
- GVariantBuilder *builder)
+ GVariantBuilder *builder,
+ gboolean guess_ok)
{
const GVariantType *type;
{
gsize i;
- builder = g_variant_builder_open (builder, type);
+ /* force GVariantBuilder to guess the type half the time */
+ if (guess_ok && randomly (0.5))
+ {
+ if (g_variant_type_is_array (type) && tree->n_children)
+ type = G_VARIANT_TYPE_ARRAY;
+
+ if (g_variant_type_is_maybe (type) && tree->n_children)
+ type = G_VARIANT_TYPE_MAYBE;
+
+ if (g_variant_type_is_tuple (type))
+ type = G_VARIANT_TYPE_TUPLE;
+
+ if (g_variant_type_is_dict_entry (type))
+ type = G_VARIANT_TYPE_DICT_ENTRY;
+ }
+ else
+ guess_ok = FALSE;
+
+ g_variant_builder_open (builder, type);
for (i = 0; i < tree->n_children; i++)
- tree_instance_build_gvariant (tree->children[i], builder);
+ tree_instance_build_gvariant (tree->children[i], builder, guess_ok);
g_variant_builder_close (builder);
}
if (g_variant_is_container (value))
{
- GVariantBuilder *builder;
+ GVariantBuilder builder;
GVariantIter iter;
GVariant *built;
GVariant *val;
gchar *s3;
- builder = g_variant_builder_new (G_VARIANT_TYPE_VARIANT);
- tree_instance_build_gvariant (tree, builder);
- built = g_variant_builder_end (builder);
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARIANT);
+ tree_instance_build_gvariant (tree, &builder, TRUE);
+ built = g_variant_builder_end (&builder);
g_variant_ref_sink (built);
g_variant_get_data (built);
val = g_variant_get_variant (built);
}
static void
+test_string (void)
+{
+ /* Test some different methods of creating strings */
+ GVariant *v;
+
+ v = g_variant_new_string ("foo");
+ g_assert_cmpstr (g_variant_get_string (v, NULL), ==, "foo");
+ g_variant_unref (v);
+
+
+ v = g_variant_new_take_string (g_strdup ("foo"));
+ g_assert_cmpstr (g_variant_get_string (v, NULL), ==, "foo");
+ g_variant_unref (v);
+
+ v = g_variant_new_printf ("%s %d", "foo", 123);
+ g_assert_cmpstr (g_variant_get_string (v, NULL), ==, "foo 123");
+ g_variant_unref (v);
+}
+
+static void
+test_utf8 (void)
+{
+ const gchar invalid[] = "hello\xffworld";
+ GVariant *value;
+
+ /* ensure that the test data is not valid utf8... */
+ g_assert (!g_utf8_validate (invalid, -1, NULL));
+
+ /* load the data untrusted */
+ value = g_variant_new_from_data (G_VARIANT_TYPE_STRING,
+ invalid, sizeof invalid,
+ FALSE, NULL, NULL);
+
+ /* ensure that the problem is caught and we get valid UTF-8 */
+ g_assert (g_utf8_validate (g_variant_get_string (value, NULL), -1, NULL));
+ g_variant_unref (value);
+
+
+ /* now load it trusted */
+ value = g_variant_new_from_data (G_VARIANT_TYPE_STRING,
+ invalid, sizeof invalid,
+ TRUE, NULL, NULL);
+
+ /* ensure we get the invalid data (ie: make sure that time wasn't
+ * wasted on validating data that was marked as trusted)
+ */
+ g_assert (g_variant_get_string (value, NULL) == invalid);
+ g_variant_unref (value);
+}
+
+static void
test_containers (void)
{
gint i;
{
test_container ();
}
+
+ g_variant_type_info_assert_no_infos ();
+}
+
+static void
+test_format_strings (void)
+{
+ GVariantType *type;
+ const gchar *end;
+
+ g_assert (g_variant_format_string_scan ("i", NULL, &end) && *end == '\0');
+ g_assert (g_variant_format_string_scan ("@i", NULL, &end) && *end == '\0');
+ g_assert (g_variant_format_string_scan ("@ii", NULL, &end) && *end == 'i');
+ g_assert (g_variant_format_string_scan ("^a&s", NULL, &end) && *end == '\0');
+ g_assert (g_variant_format_string_scan ("(^as)", NULL, &end) &&
+ *end == '\0');
+ g_assert (!g_variant_format_string_scan ("(^s)", NULL, &end));
+ g_assert (!g_variant_format_string_scan ("(^a)", NULL, &end));
+ g_assert (!g_variant_format_string_scan ("(z)", NULL, &end));
+ g_assert (!g_variant_format_string_scan ("az", NULL, &end));
+ g_assert (!g_variant_format_string_scan ("{**}", NULL, &end));
+ g_assert (!g_variant_format_string_scan ("{@**}", NULL, &end));
+ g_assert (g_variant_format_string_scan ("{@y*}", NULL, &end) &&
+ *end == '\0');
+ g_assert (g_variant_format_string_scan ("{yv}", NULL, &end) &&
+ *end == '\0');
+ g_assert (!g_variant_format_string_scan ("{&?v}", NULL, &end));
+ g_assert (g_variant_format_string_scan ("{@?v}", NULL, &end) &&
+ *end == '\0');
+ g_assert (!g_variant_format_string_scan ("{&@sv}", NULL, &end));
+ g_assert (!g_variant_format_string_scan ("{@&sv}", NULL, &end));
+ g_assert (g_variant_format_string_scan ("{&sv}", NULL, &end) &&
+ *end == '\0');
+ g_assert (!g_variant_format_string_scan ("{vv}", NULL, &end));
+ g_assert (!g_variant_format_string_scan ("{y}", NULL, &end));
+ g_assert (!g_variant_format_string_scan ("{yyy}", NULL, &end));
+ g_assert (!g_variant_format_string_scan ("{ya}", NULL, &end));
+ g_assert (g_variant_format_string_scan ("&s", NULL, &end) && *end == '\0');
+ g_assert (!g_variant_format_string_scan ("&as", NULL, &end));
+ g_assert (!g_variant_format_string_scan ("@z", NULL, &end));
+ g_assert (!g_variant_format_string_scan ("az", NULL, &end));
+ g_assert (!g_variant_format_string_scan ("a&s", NULL, &end));
+
+ type = g_variant_format_string_scan_type ("mm(@xy^a&s*?@?)", NULL, &end);
+ g_assert (type && *end == '\0');
+ g_assert (g_variant_type_equal (type, G_VARIANT_TYPE ("mm(xyas*?\?)")));
+ g_variant_type_free (type);
+
+ type = g_variant_format_string_scan_type ("mm(@xy^a&*?@?)", NULL, NULL);
+ g_assert (type == NULL);
+}
+
+static void
+do_failed_test (const char *test,
+ const gchar *pattern)
+{
+ g_test_trap_subprocess (test, 1000000, 0);
+ g_test_trap_assert_failed ();
+ g_test_trap_assert_stderr (pattern);
+}
+
+static void
+test_invalid_varargs (void)
+{
+ GVariant *value;
+ const gchar *end;
+
+ if (!g_test_undefined ())
+ return;
+
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*GVariant format string*");
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*valid_format_string*");
+ value = g_variant_new ("z");
+ g_test_assert_expected_messages ();
+ g_assert (value == NULL);
+
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*valid GVariant format string as a prefix*");
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*valid_format_string*");
+ value = g_variant_new_va ("z", &end, NULL);
+ g_test_assert_expected_messages ();
+ g_assert (value == NULL);
+
+ value = g_variant_new ("y", 'a');
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*type of 'q' but * has a type of 'y'*");
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*valid_format_string*");
+ g_variant_get (value, "q");
+ g_test_assert_expected_messages ();
+ g_variant_unref (value);
+}
+
+static void
+check_and_free (GVariant *value,
+ const gchar *str)
+{
+ gchar *valstr = g_variant_print (value, FALSE);
+ g_assert_cmpstr (str, ==, valstr);
+ g_variant_unref (value);
+ g_free (valstr);
+}
+
+static void
+test_varargs_empty_array (void)
+{
+ g_variant_new ("(a{s*})", NULL);
+
+ g_assert_not_reached ();
+}
+
+static void
+test_varargs (void)
+{
+ {
+ GVariantBuilder array;
+
+ g_variant_builder_init (&array, G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add_parsed (&array, "{'size', <(%i, %i)> }", 800, 600);
+ g_variant_builder_add (&array, "{sv}", "title",
+ g_variant_new_string ("Test case"));
+ g_variant_builder_add_value (&array,
+ g_variant_new_dict_entry (g_variant_new_string ("temperature"),
+ g_variant_new_variant (
+ g_variant_new_double (37.5))));
+ check_and_free (g_variant_new ("(ma{sv}m(a{sv})ma{sv}ii)",
+ NULL, FALSE, NULL, &array, 7777, 8888),
+ "(nothing, nothing, {'size': <(800, 600)>, "
+ "'title': <'Test case'>, "
+ "'temperature': <37.5>}, "
+ "7777, 8888)");
+
+ check_and_free (g_variant_new ("(imimimmimmimmi)",
+ 123,
+ FALSE, 321,
+ TRUE, 123,
+ FALSE, TRUE, 321,
+ TRUE, FALSE, 321,
+ TRUE, TRUE, 123),
+ "(123, nothing, 123, nothing, just nothing, 123)");
+
+ check_and_free (g_variant_new ("(ybnixd)",
+ 'a', 1, 22, 33, (guint64) 44, 5.5),
+ "(0x61, true, 22, 33, 44, 5.5)");
+
+ check_and_free (g_variant_new ("(@y?*rv)",
+ g_variant_new ("y", 'a'),
+ g_variant_new ("y", 'b'),
+ g_variant_new ("y", 'c'),
+ g_variant_new ("(y)", 'd'),
+ g_variant_new ("y", 'e')),
+ "(0x61, 0x62, 0x63, (0x64,), <byte 0x65>)");
+ }
+
+ {
+ GVariantBuilder array;
+ GVariantIter iter;
+ GVariant *value;
+ gchar *number;
+ gboolean just;
+ gint i, val;
+
+ g_variant_builder_init (&array, G_VARIANT_TYPE_ARRAY);
+ for (i = 0; i < 100; i++)
+ {
+ number = g_strdup_printf ("%d", i);
+ g_variant_builder_add (&array, "s", number);
+ g_free (number);
+ }
+
+ value = g_variant_builder_end (&array);
+ g_variant_iter_init (&iter, value);
+
+ i = 0;
+ while (g_variant_iter_loop (&iter, "s", &number))
+ {
+ gchar *check = g_strdup_printf ("%d", i++);
+ g_assert_cmpstr (number, ==, check);
+ g_free (check);
+ }
+ g_assert (number == NULL);
+ g_assert (i == 100);
+
+ g_variant_unref (value);
+
+ g_variant_builder_init (&array, G_VARIANT_TYPE_ARRAY);
+ for (i = 0; i < 100; i++)
+ g_variant_builder_add (&array, "mi", i % 2 == 0, i);
+ value = g_variant_builder_end (&array);
+
+ i = 0;
+ g_variant_iter_init (&iter, value);
+ while (g_variant_iter_loop (&iter, "mi", NULL, &val))
+ g_assert (val == i++ || val == 0);
+ g_assert (i == 100);
+
+ i = 0;
+ g_variant_iter_init (&iter, value);
+ while (g_variant_iter_loop (&iter, "mi", &just, &val))
+ {
+ gint this = i++;
+
+ if (this % 2 == 0)
+ {
+ g_assert (just);
+ g_assert (val == this);
+ }
+ else
+ {
+ g_assert (!just);
+ g_assert (val == 0);
+ }
+ }
+ g_assert (i == 100);
+
+ g_variant_unref (value);
+ }
+
+ {
+ const gchar *strvector[] = {"/hello", "/world", NULL};
+ const gchar *test_strs[] = {"/foo", "/bar", "/baz" };
+ GVariantBuilder builder;
+ GVariantIter *array;
+ GVariantIter tuple;
+ const gchar **strv;
+ gchar **my_strv;
+ GVariant *value;
+ gchar *str;
+ gint i;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
+ g_variant_builder_add (&builder, "s", "/foo");
+ g_variant_builder_add (&builder, "s", "/bar");
+ g_variant_builder_add (&builder, "s", "/baz");
+ value = g_variant_new("(as^as^a&s)", &builder, strvector, strvector);
+ g_variant_iter_init (&tuple, value);
+ g_variant_iter_next (&tuple, "as", &array);
+
+ i = 0;
+ while (g_variant_iter_loop (array, "s", &str))
+ g_assert_cmpstr (str, ==, test_strs[i++]);
+ g_assert (i == 3);
+
+ g_variant_iter_free (array);
+
+ /* start over */
+ g_variant_iter_init (&tuple, value);
+ g_variant_iter_next (&tuple, "as", &array);
+
+ i = 0;
+ while (g_variant_iter_loop (array, "&s", &str))
+ g_assert_cmpstr (str, ==, test_strs[i++]);
+ g_assert (i == 3);
+
+ g_variant_iter_free (array);
+
+ g_variant_iter_next (&tuple, "^a&s", &strv);
+ g_variant_iter_next (&tuple, "^as", &my_strv);
+
+ g_assert_cmpstr (strv[0], ==, "/hello");
+ g_assert_cmpstr (strv[1], ==, "/world");
+ g_assert (strv[2] == NULL);
+ g_assert_cmpstr (my_strv[0], ==, "/hello");
+ g_assert_cmpstr (my_strv[1], ==, "/world");
+ g_assert (my_strv[2] == NULL);
+
+ g_variant_unref (value);
+ g_strfreev (my_strv);
+ g_free (strv);
+ }
+
+ {
+ const gchar *strvector[] = {"/hello", "/world", NULL};
+ const gchar *test_strs[] = {"/foo", "/bar", "/baz" };
+ GVariantBuilder builder;
+ GVariantIter *array;
+ GVariantIter tuple;
+ const gchar **strv;
+ gchar **my_strv;
+ GVariant *value;
+ gchar *str;
+ gint i;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_OBJECT_PATH_ARRAY);
+ g_variant_builder_add (&builder, "o", "/foo");
+ g_variant_builder_add (&builder, "o", "/bar");
+ g_variant_builder_add (&builder, "o", "/baz");
+ value = g_variant_new("(ao^ao^a&o)", &builder, strvector, strvector);
+ g_variant_iter_init (&tuple, value);
+ g_variant_iter_next (&tuple, "ao", &array);
+
+ i = 0;
+ while (g_variant_iter_loop (array, "o", &str))
+ g_assert_cmpstr (str, ==, test_strs[i++]);
+ g_assert (i == 3);
+
+ g_variant_iter_free (array);
+
+ /* start over */
+ g_variant_iter_init (&tuple, value);
+ g_variant_iter_next (&tuple, "ao", &array);
+
+ i = 0;
+ while (g_variant_iter_loop (array, "&o", &str))
+ g_assert_cmpstr (str, ==, test_strs[i++]);
+ g_assert (i == 3);
+
+ g_variant_iter_free (array);
+
+ g_variant_iter_next (&tuple, "^a&o", &strv);
+ g_variant_iter_next (&tuple, "^ao", &my_strv);
+
+ g_assert_cmpstr (strv[0], ==, "/hello");
+ g_assert_cmpstr (strv[1], ==, "/world");
+ g_assert (strv[2] == NULL);
+ g_assert_cmpstr (my_strv[0], ==, "/hello");
+ g_assert_cmpstr (my_strv[1], ==, "/world");
+ g_assert (my_strv[2] == NULL);
+
+ g_variant_unref (value);
+ g_strfreev (my_strv);
+ g_free (strv);
+ }
+
+ {
+ const gchar *strvector[] = { "i", "ii", "iii", "iv", "v", "vi", NULL };
+ GVariantBuilder builder;
+ GVariantIter iter;
+ GVariantIter *i2;
+ GVariantIter *i3;
+ GVariant *value;
+ GVariant *sub;
+ gchar **strv;
+ gint i;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("aas"));
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("as"));
+ for (i = 0; i < 6; i++)
+ if (i & 1)
+ g_variant_builder_add (&builder, "s", strvector[i]);
+ else
+ g_variant_builder_add (&builder, "&s", strvector[i]);
+ g_variant_builder_close (&builder);
+ g_variant_builder_add (&builder, "^as", strvector);
+ g_variant_builder_add (&builder, "^as", strvector);
+ value = g_variant_new ("aas", &builder);
+
+ g_variant_iter_init (&iter, value);
+ while (g_variant_iter_loop (&iter, "^as", &strv))
+ for (i = 0; i < 6; i++)
+ g_assert_cmpstr (strv[i], ==, strvector[i]);
+
+ g_variant_iter_init (&iter, value);
+ while (g_variant_iter_loop (&iter, "^a&s", &strv))
+ for (i = 0; i < 6; i++)
+ g_assert_cmpstr (strv[i], ==, strvector[i]);
+
+ g_variant_iter_init (&iter, value);
+ while (g_variant_iter_loop (&iter, "as", &i2))
+ {
+ gchar *str;
+
+ i = 0;
+ while (g_variant_iter_loop (i2, "s", &str))
+ g_assert_cmpstr (str, ==, strvector[i++]);
+ g_assert (i == 6);
+ }
+
+ g_variant_iter_init (&iter, value);
+ i3 = g_variant_iter_copy (&iter);
+ while (g_variant_iter_loop (&iter, "@as", &sub))
+ {
+ gchar *str = g_variant_print (sub, TRUE);
+ g_assert_cmpstr (str, ==,
+ "['i', 'ii', 'iii', 'iv', 'v', 'vi']");
+ g_free (str);
+ }
+
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*NULL has already been returned*");
+ g_variant_iter_next_value (&iter);
+ g_test_assert_expected_messages ();
+
+ while (g_variant_iter_loop (i3, "*", &sub))
+ {
+ gchar *str = g_variant_print (sub, TRUE);
+ g_assert_cmpstr (str, ==,
+ "['i', 'ii', 'iii', 'iv', 'v', 'vi']");
+ g_free (str);
+ }
+
+ g_variant_iter_free (i3);
+
+ for (i = 0; i < g_variant_n_children (value); i++)
+ {
+ gint j;
+
+ g_variant_get_child (value, i, "*", &sub);
+
+ for (j = 0; j < g_variant_n_children (sub); j++)
+ {
+ const gchar *str = NULL;
+ GVariant *cval;
+
+ g_variant_get_child (sub, j, "&s", &str);
+ g_assert_cmpstr (str, ==, strvector[j]);
+
+ cval = g_variant_get_child_value (sub, j);
+ g_variant_get (cval, "&s", &str);
+ g_assert_cmpstr (str, ==, strvector[j]);
+ g_variant_unref (cval);
+ }
+
+ g_variant_unref (sub);
+ }
+
+ g_variant_unref (value);
+ }
+
+ {
+ gboolean justs[10];
+ GVariant *value;
+
+ GVariant *vval;
+ guchar byteval;
+ gboolean bval;
+ gint16 i16val;
+ guint16 u16val;
+ gint32 i32val;
+ guint32 u32val;
+ gint64 i64val;
+ guint64 u64val;
+ gdouble dval;
+ gint32 hval;
+
+ /* test all 'nothing' */
+ value = g_variant_new ("(mymbmnmqmimumxmtmhmdmv)",
+ FALSE, 'a',
+ FALSE, TRUE,
+ FALSE, (gint16) 123,
+ FALSE, (guint16) 123,
+ FALSE, (gint32) 123,
+ FALSE, (guint32) 123,
+ FALSE, (gint64) 123,
+ FALSE, (guint64) 123,
+ FALSE, (gint32) -1,
+ FALSE, (gdouble) 37.5,
+ NULL);
+
+ /* both NULL */
+ g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL);
+
+ /* NULL values */
+ memset (justs, 1, sizeof justs);
+ g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
+ &justs[0], NULL,
+ &justs[1], NULL,
+ &justs[2], NULL,
+ &justs[3], NULL,
+ &justs[4], NULL,
+ &justs[5], NULL,
+ &justs[6], NULL,
+ &justs[7], NULL,
+ &justs[8], NULL,
+ &justs[9], NULL,
+ NULL);
+ g_assert (!(justs[0] || justs[1] || justs[2] || justs[3] || justs[4] ||
+ justs[5] || justs[6] || justs[7] || justs[8] || justs[9]));
+
+ /* both non-NULL */
+ memset (justs, 1, sizeof justs);
+ byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88;
+ vval = (void *) 1;
+ bval = TRUE;
+ dval = 88.88;
+ g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
+ &justs[0], &byteval,
+ &justs[1], &bval,
+ &justs[2], &i16val,
+ &justs[3], &u16val,
+ &justs[4], &i32val,
+ &justs[5], &u32val,
+ &justs[6], &i64val,
+ &justs[7], &u64val,
+ &justs[8], &hval,
+ &justs[9], &dval,
+ &vval);
+ g_assert (!(justs[0] || justs[1] || justs[2] || justs[3] || justs[4] ||
+ justs[5] || justs[6] || justs[7] || justs[8] || justs[9]));
+ g_assert (byteval == '\0' && bval == FALSE);
+ g_assert (i16val == 0 && u16val == 0 && i32val == 0 &&
+ u32val == 0 && i64val == 0 && u64val == 0 &&
+ hval == 0 && dval == 0.0);
+ g_assert (vval == NULL);
+
+ /* NULL justs */
+ byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88;
+ vval = (void *) 1;
+ bval = TRUE;
+ dval = 88.88;
+ g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
+ NULL, &byteval,
+ NULL, &bval,
+ NULL, &i16val,
+ NULL, &u16val,
+ NULL, &i32val,
+ NULL, &u32val,
+ NULL, &i64val,
+ NULL, &u64val,
+ NULL, &hval,
+ NULL, &dval,
+ &vval);
+ g_assert (byteval == '\0' && bval == FALSE);
+ g_assert (i16val == 0 && u16val == 0 && i32val == 0 &&
+ u32val == 0 && i64val == 0 && u64val == 0 &&
+ hval == 0 && dval == 0.0);
+ g_assert (vval == NULL);
+
+ g_variant_unref (value);
+
+
+ /* test all 'just' */
+ value = g_variant_new ("(mymbmnmqmimumxmtmhmdmv)",
+ TRUE, 'a',
+ TRUE, TRUE,
+ TRUE, (gint16) 123,
+ TRUE, (guint16) 123,
+ TRUE, (gint32) 123,
+ TRUE, (guint32) 123,
+ TRUE, (gint64) 123,
+ TRUE, (guint64) 123,
+ TRUE, (gint32) -1,
+ TRUE, (gdouble) 37.5,
+ g_variant_new ("()"));
+
+ /* both NULL */
+ g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL);
+
+ /* NULL values */
+ memset (justs, 0, sizeof justs);
+ g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
+ &justs[0], NULL,
+ &justs[1], NULL,
+ &justs[2], NULL,
+ &justs[3], NULL,
+ &justs[4], NULL,
+ &justs[5], NULL,
+ &justs[6], NULL,
+ &justs[7], NULL,
+ &justs[8], NULL,
+ &justs[9], NULL,
+ NULL);
+ g_assert (justs[0] && justs[1] && justs[2] && justs[3] && justs[4] &&
+ justs[5] && justs[6] && justs[7] && justs[8] && justs[9]);
+
+ /* both non-NULL */
+ memset (justs, 0, sizeof justs);
+ byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88;
+ vval = (void *) 1;
+ bval = FALSE;
+ dval = 88.88;
+ g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
+ &justs[0], &byteval,
+ &justs[1], &bval,
+ &justs[2], &i16val,
+ &justs[3], &u16val,
+ &justs[4], &i32val,
+ &justs[5], &u32val,
+ &justs[6], &i64val,
+ &justs[7], &u64val,
+ &justs[8], &hval,
+ &justs[9], &dval,
+ &vval);
+ g_assert (justs[0] && justs[1] && justs[2] && justs[3] && justs[4] &&
+ justs[5] && justs[6] && justs[7] && justs[8] && justs[9]);
+ g_assert (byteval == 'a' && bval == TRUE);
+ g_assert (i16val == 123 && u16val == 123 && i32val == 123 &&
+ u32val == 123 && i64val == 123 && u64val == 123 &&
+ hval == -1 && dval == 37.5);
+ g_assert (g_variant_is_of_type (vval, G_VARIANT_TYPE_UNIT));
+ g_variant_unref (vval);
+
+ /* NULL justs */
+ byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88;
+ vval = (void *) 1;
+ bval = TRUE;
+ dval = 88.88;
+ g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
+ NULL, &byteval,
+ NULL, &bval,
+ NULL, &i16val,
+ NULL, &u16val,
+ NULL, &i32val,
+ NULL, &u32val,
+ NULL, &i64val,
+ NULL, &u64val,
+ NULL, &hval,
+ NULL, &dval,
+ &vval);
+ g_assert (byteval == 'a' && bval == TRUE);
+ g_assert (i16val == 123 && u16val == 123 && i32val == 123 &&
+ u32val == 123 && i64val == 123 && u64val == 123 &&
+ hval == -1 && dval == 37.5);
+ g_assert (g_variant_is_of_type (vval, G_VARIANT_TYPE_UNIT));
+ g_variant_unref (vval);
+
+ g_variant_unref (value);
+ }
+
+ {
+ GVariant *value;
+ gchar *str;
+
+ value = g_variant_new ("(masas)", NULL, NULL);
+ g_variant_ref_sink (value);
+
+ str = g_variant_print (value, TRUE);
+ g_assert_cmpstr (str, ==, "(@mas nothing, @as [])");
+ g_variant_unref (value);
+ g_free (str);
+
+ do_failed_test ("/gvariant/varargs/subprocess/empty-array",
+ "*which type of empty array*");
+ }
+
+ g_variant_type_info_assert_no_infos ();
+}
+
+static void
+hash_get (GVariant *value,
+ const gchar *format,
+ ...)
+{
+ const gchar *endptr = NULL;
+ gboolean hash;
+ va_list ap;
+
+ hash = g_str_has_suffix (format, "#");
+
+ va_start (ap, format);
+ g_variant_get_va (value, format, hash ? &endptr : NULL, &ap);
+ va_end (ap);
+
+ if (hash)
+ g_assert (*endptr == '#');
+}
+
+static GVariant *
+hash_new (const gchar *format,
+ ...)
+{
+ const gchar *endptr = NULL;
+ GVariant *value;
+ gboolean hash;
+ va_list ap;
+
+ hash = g_str_has_suffix (format, "#");
+
+ va_start (ap, format);
+ value = g_variant_new_va (format, hash ? &endptr : NULL, &ap);
+ va_end (ap);
+
+ if (hash)
+ g_assert (*endptr == '#');
+
+ return value;
+}
+
+static void
+test_valist (void)
+{
+ GVariant *value;
+ gint32 x;
+
+ x = 0;
+ value = hash_new ("i", 234);
+ hash_get (value, "i", &x);
+ g_assert (x == 234);
+ g_variant_unref (value);
+
+ x = 0;
+ value = hash_new ("i#", 234);
+ hash_get (value, "i#", &x);
+ g_assert (x == 234);
+ g_variant_unref (value);
+
+ g_variant_type_info_assert_no_infos ();
+}
+
+static void
+test_builder_memory (void)
+{
+ GVariantBuilder *hb;
+ GVariantBuilder sb;
+
+ hb = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_open (hb, G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_open (hb, G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_open (hb, G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add (hb, "s", "some value");
+ g_variant_builder_ref (hb);
+ g_variant_builder_unref (hb);
+ g_variant_builder_unref (hb);
+
+ hb = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_unref (hb);
+
+ hb = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_clear (hb);
+ g_variant_builder_unref (hb);
+
+ g_variant_builder_init (&sb, G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_open (&sb, G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_open (&sb, G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add (&sb, "s", "some value");
+ g_variant_builder_clear (&sb);
+
+ g_variant_type_info_assert_no_infos ();
+}
+
+static void
+test_hashing (void)
+{
+ GVariant *items[4096];
+ GHashTable *table;
+ gint i;
+
+ table = g_hash_table_new_full (g_variant_hash, g_variant_equal,
+ (GDestroyNotify ) g_variant_unref,
+ NULL);
+
+ for (i = 0; i < G_N_ELEMENTS (items); i++)
+ {
+ TreeInstance *tree;
+ gint j;
+
+ again:
+ tree = tree_instance_new (NULL, 0);
+ items[i] = tree_instance_get_gvariant (tree);
+ tree_instance_free (tree);
+
+ for (j = 0; j < i; j++)
+ if (g_variant_equal (items[i], items[j]))
+ {
+ g_variant_unref (items[i]);
+ goto again;
+ }
+
+ g_hash_table_insert (table,
+ g_variant_ref_sink (items[i]),
+ GINT_TO_POINTER (i));
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (items); i++)
+ {
+ gpointer result;
+
+ result = g_hash_table_lookup (table, items[i]);
+ g_assert_cmpint (GPOINTER_TO_INT (result), ==, i);
+ }
+
+ g_hash_table_unref (table);
+
+ g_variant_type_info_assert_no_infos ();
+}
+
+static void
+test_gv_byteswap (void)
+{
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+# define native16(x) x, 0
+# define swapped16(x) 0, x
+#else
+# define native16(x) 0, x
+# define swapped16(x) x, 0
+#endif
+ /* all kinds of of crazy randomised testing already performed on the
+ * byteswapper in the /gvariant/serialiser/byteswap test and all kinds
+ * of crazy randomised testing performed against the serialiser
+ * normalisation functions in the /gvariant/serialiser/fuzz/ tests.
+ *
+ * just test a few simple cases here to make sure they each work
+ */
+ guchar validbytes[] = { 'a', '\0', swapped16(66), 2,
+ 0,
+ 'b', '\0', swapped16(77), 2,
+ 5, 11 };
+ guchar corruptbytes[] = { 'a', '\0', swapped16(66), 2,
+ 0,
+ 'b', '\0', swapped16(77), 2,
+ 6, 11 };
+ guint valid_data[4], corrupt_data[4];
+ GVariant *value, *swapped;
+ gchar *string, *string2;
+
+ memcpy (valid_data, validbytes, sizeof validbytes);
+ memcpy (corrupt_data, corruptbytes, sizeof corruptbytes);
+
+ /* trusted */
+ value = g_variant_new_from_data (G_VARIANT_TYPE ("a(sn)"),
+ valid_data, sizeof validbytes, TRUE,
+ NULL, NULL);
+ swapped = g_variant_byteswap (value);
+ g_variant_unref (value);
+ g_assert (g_variant_get_size (swapped) == 13);
+ string = g_variant_print (swapped, FALSE);
+ g_variant_unref (swapped);
+ g_assert_cmpstr (string, ==, "[('a', 66), ('b', 77)]");
+ g_free (string);
+
+ /* untrusted but valid */
+ value = g_variant_new_from_data (G_VARIANT_TYPE ("a(sn)"),
+ valid_data, sizeof validbytes, FALSE,
+ NULL, NULL);
+ swapped = g_variant_byteswap (value);
+ g_variant_unref (value);
+ g_assert (g_variant_get_size (swapped) == 13);
+ string = g_variant_print (swapped, FALSE);
+ g_variant_unref (swapped);
+ g_assert_cmpstr (string, ==, "[('a', 66), ('b', 77)]");
+ g_free (string);
+
+ /* untrusted, invalid */
+ value = g_variant_new_from_data (G_VARIANT_TYPE ("a(sn)"),
+ corrupt_data, sizeof corruptbytes, FALSE,
+ NULL, NULL);
+ string = g_variant_print (value, FALSE);
+ swapped = g_variant_byteswap (value);
+ g_variant_unref (value);
+ g_assert (g_variant_get_size (swapped) == 13);
+ value = g_variant_byteswap (swapped);
+ g_variant_unref (swapped);
+ string2 = g_variant_print (value, FALSE);
+ g_assert (g_variant_get_size (value) == 13);
+ g_variant_unref (value);
+ g_assert_cmpstr (string, ==, string2);
+ g_free (string2);
+ g_free (string);
+}
+
+static void
+test_parser (void)
+{
+ TreeInstance *tree;
+ GVariant *parsed;
+ GVariant *value;
+ gchar *pt, *p;
+ gchar *res;
+
+ tree = tree_instance_new (NULL, 3);
+ value = tree_instance_get_gvariant (tree);
+ tree_instance_free (tree);
+
+ pt = g_variant_print (value, TRUE);
+ p = g_variant_print (value, FALSE);
+
+ parsed = g_variant_parse (NULL, pt, NULL, NULL, NULL);
+ res = g_variant_print (parsed, FALSE);
+ g_assert_cmpstr (p, ==, res);
+ g_variant_unref (parsed);
+ g_free (res);
+
+ parsed = g_variant_parse (g_variant_get_type (value), p,
+ NULL, NULL, NULL);
+ res = g_variant_print (parsed, TRUE);
+ g_assert_cmpstr (pt, ==, res);
+ g_variant_unref (parsed);
+ g_free (res);
+
+ g_variant_unref (value);
+ g_free (pt);
+ g_free (p);
+}
+
+static void
+test_parses (void)
+{
+ gint i;
+
+ for (i = 0; i < 100; i++)
+ {
+ test_parser ();
+ }
+
+ /* mini test */
+ {
+ GError *error = NULL;
+ gchar str[128];
+ GVariant *val;
+ gchar *p, *p2;
+
+ for (i = 0; i < 127; i++)
+ str[i] = i + 1;
+ str[i] = 0;
+
+ val = g_variant_new_string (str);
+ p = g_variant_print (val, FALSE);
+ g_variant_unref (val);
+
+ val = g_variant_parse (NULL, p, NULL, NULL, &error);
+ p2 = g_variant_print (val, FALSE);
+
+ g_assert_cmpstr (str, ==, g_variant_get_string (val, NULL));
+ g_assert_cmpstr (p, ==, p2);
+
+ g_variant_unref (val);
+ g_free (p2);
+ g_free (p);
+ }
+
+ /* another mini test */
+ {
+ const gchar *end;
+ GVariant *value;
+
+ value = g_variant_parse (G_VARIANT_TYPE_INT32, "1 2 3", NULL, &end, NULL);
+ g_assert_cmpint (g_variant_get_int32 (value), ==, 1);
+ /* make sure endptr returning works */
+ g_assert_cmpstr (end, ==, " 2 3");
+ g_variant_unref (value);
+ }
+
+ /* unicode mini test */
+ {
+ /* ał𝄞 */
+ const gchar orig[] = "a\xc5\x82\xf0\x9d\x84\x9e \t\n";
+ GVariant *value;
+ gchar *printed;
+
+ value = g_variant_new_string (orig);
+ printed = g_variant_print (value, FALSE);
+ g_variant_unref (value);
+
+ g_assert_cmpstr (printed, ==, "'a\xc5\x82\xf0\x9d\x84\x9e \\t\\n'");
+ value = g_variant_parse (NULL, printed, NULL, NULL, NULL);
+ g_assert_cmpstr (g_variant_get_string (value, NULL), ==, orig);
+ g_variant_unref (value);
+ g_free (printed);
+ }
+
+ /* escapes */
+ {
+ const gchar orig[] = " \342\200\254 \360\220\210\240 \a \b \f \n \r \t \v ";
+ GVariant *value;
+ gchar *printed;
+
+ value = g_variant_new_string (orig);
+ printed = g_variant_print (value, FALSE);
+ g_variant_unref (value);
+
+ g_assert_cmpstr (printed, ==, "' \\u202c \\U00010220 \\a \\b \\f \\n \\r \\t \\v '");
+ value = g_variant_parse (NULL, printed, NULL, NULL, NULL);
+ g_assert_cmpstr (g_variant_get_string (value, NULL), ==, orig);
+ g_variant_unref (value);
+ g_free (printed);
+ }
+
+#ifndef _MSC_VER
+ /* inf/nan strings are C99 features which Visual C++ does not support */
+ /* inf/nan mini test */
+ {
+ const gchar *tests[] = { "inf", "-inf", "nan" };
+ GVariant *value;
+ gchar *printed;
+ gchar *printed_down;
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (tests); i++)
+ {
+ GError *error = NULL;
+ value = g_variant_parse (NULL, tests[i], NULL, NULL, &error);
+ printed = g_variant_print (value, FALSE);
+ /* Canonicalize to lowercase; https://bugzilla.gnome.org/show_bug.cgi?id=704585 */
+ printed_down = g_ascii_strdown (printed, -1);
+ g_assert (g_str_has_prefix (printed_down, tests[i]));
+ g_free (printed);
+ g_free (printed_down);
+ g_variant_unref (value);
+ }
+ }
+#endif
+
+ g_variant_type_info_assert_no_infos ();
+}
+
+static void
+test_parse_failures (void)
+{
+ const gchar *test[] = {
+ "[1, 2,", "6:", "expected value",
+ "", "0:", "expected value",
+ "(1, 2,", "6:", "expected value",
+ "<1", "2:", "expected '>'",
+ "[]", "0-2:", "unable to infer",
+ "(,", "1:", "expected value",
+ "[4,'']", "1-2,3-5:", "common type",
+ "[4, '', 5]", "1-2,4-6:", "common type",
+ "['', 4, 5]", "1-3,5-6:", "common type",
+ "[4, 5, '']", "1-2,7-9:", "common type",
+ "[[4], [], ['']]", "1-4,10-14:", "common type",
+ "[[], [4], ['']]", "5-8,10-14:", "common type",
+ "just", "4:", "expected value",
+ "nothing", "0-7:", "unable to infer",
+ "just [4, '']", "6-7,9-11:", "common type",
+ "[[4,'']]", "2-3,4-6:", "common type",
+ "([4,''],)", "2-3,4-6:", "common type",
+ "(4)", "2:", "','",
+ "{}", "0-2:", "unable to infer",
+ "{[1,2],[3,4]}", "0-13:", "basic types",
+ "{[1,2]:[3,4]}", "0-13:", "basic types",
+ "justt", "0-5:", "unknown keyword",
+ "nothng", "0-6:", "unknown keyword",
+ "uint33", "0-6:", "unknown keyword",
+ "@mi just ''", "9-11:", "can not parse as",
+ "@ai ['']", "5-7:", "can not parse as",
+ "@(i) ('',)", "6-8:", "can not parse as",
+ "[[], 5]", "1-3,5-6:", "common type",
+ "[[5], 5]", "1-4,6-7:", "common type",
+ "5 5", "2:", "expected end of input",
+ "[5, [5, '']]", "5-6,8-10:", "common type",
+ "@i just 5", "3-9:", "can not parse as",
+ "@i nothing", "3-10:", "can not parse as",
+ "@i []", "3-5:", "can not parse as",
+ "@i ()", "3-5:", "can not parse as",
+ "@ai (4,)", "4-8:", "can not parse as",
+ "@(i) []", "5-7:", "can not parse as",
+ "(5 5)", "3:", "expected ','",
+ "[5 5]", "3:", "expected ',' or ']'",
+ "(5, 5 5)", "6:", "expected ',' or ')'",
+ "[5, 5 5]", "6:", "expected ',' or ']'",
+ "<@i []>", "4-6:", "can not parse as",
+ "<[5 5]>", "4:", "expected ',' or ']'",
+ "{[4,''],5}", "2-3,4-6:", "common type",
+ "{5,[4,'']}", "4-5,6-8:", "common type",
+ "@i {1,2}", "3-8:", "can not parse as",
+ "{@i '', 5}", "4-6:", "can not parse as",
+ "{5, @i ''}", "7-9:", "can not parse as",
+ "@ai {}", "4-6:", "can not parse as",
+ "{@i '': 5}", "4-6:", "can not parse as",
+ "{5: @i ''}", "7-9:", "can not parse as",
+ "{<4,5}", "3:", "expected '>'",
+ "{4,<5}", "5:", "expected '>'",
+ "{4,5,6}", "4:", "expected '}'",
+ "{5 5}", "3:", "expected ':' or ','",
+ "{4: 5: 6}", "5:", "expected ',' or '}'",
+ "{4:5,<6:7}", "7:", "expected '>'",
+ "{4:5,6:<7}", "9:", "expected '>'",
+ "{4:5,6 7}", "7:", "expected ':'",
+ "@o 'foo'", "3-8:", "object path",
+ "@g 'zzz'", "3-8:", "signature",
+ "@i true", "3-7:", "can not parse as",
+ "@z 4", "0-2:", "invalid type",
+ "@a* []", "0-3:", "definite",
+ "@ai [3 3]", "7:", "expected ',' or ']'",
+ "18446744073709551616", "0-20:", "too big for any type",
+ "-18446744073709551616", "0-21:", "too big for any type",
+ "byte 256", "5-8:", "out of range for type",
+ "byte -1", "5-7:", "out of range for type",
+ "int16 32768", "6-11:", "out of range for type",
+ "int16 -32769", "6-12:", "out of range for type",
+ "uint16 -1", "7-9:", "out of range for type",
+ "uint16 65536", "7-12:", "out of range for type",
+ "2147483648", "0-10:", "out of range for type",
+ "-2147483649", "0-11:", "out of range for type",
+ "uint32 -1", "7-9:", "out of range for type",
+ "uint32 4294967296", "7-17:", "out of range for type",
+ "@x 9223372036854775808", "3-22:", "out of range for type",
+ "@x -9223372036854775809", "3-23:", "out of range for type",
+ "@t -1", "3-5:", "out of range for type",
+ "@t 18446744073709551616", "3-23:", "too big for any type",
+ "handle 2147483648", "7-17:", "out of range for type",
+ "handle -2147483649", "7-18:", "out of range for type",
+ "1.798e308", "0-9:", "too big for any type",
+ "37.5a488", "4-5:", "invalid character",
+ "0x7ffgf", "5-6:", "invalid character",
+ "07758", "4-5:", "invalid character",
+ "123a5", "3-4:", "invalid character",
+ "@ai 123", "4-7:", "can not parse as",
+ "'\"\\'", "0-4:", "unterminated string",
+ "'\"\\'\\", "0-5:", "unterminated string",
+ "boolean 4", "8-9:", "can not parse as",
+ "int32 true", "6-10:", "can not parse as",
+ "[double 5, int32 5]", "1-9,11-18:", "common type",
+ "string 4", "7-8:", "can not parse as"
+ };
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (test); i += 3)
+ {
+ GError *error = NULL;
+ GVariant *value;
+
+ value = g_variant_parse (NULL, test[i], NULL, NULL, &error);
+ g_assert (value == NULL);
+
+ if (!strstr (error->message, test[i+2]))
+ g_error ("test %d: Can't find '%s' in '%s'", i / 3,
+ test[i+2], error->message);
+
+ if (!g_str_has_prefix (error->message, test[i+1]))
+ g_error ("test %d: Expected location '%s' in '%s'", i / 3,
+ test[i+1], error->message);
+
+ g_error_free (error);
+ }
+}
+
+static void
+test_parse_bad_format_char (void)
+{
+ g_variant_new_parsed ("%z");
+
+ g_assert_not_reached ();
+}
+
+static void
+test_parse_bad_format_string (void)
+{
+ g_variant_new_parsed ("uint32 %i", 2);
+
+ g_assert_not_reached ();
+}
+
+static void
+test_parse_bad_args (void)
+{
+ g_variant_new_parsed ("%@i", g_variant_new_uint32 (2));
+
+ g_assert_not_reached ();
+}
+
+static void
+test_parse_positional (void)
+{
+ GVariant *value;
+ check_and_free (g_variant_new_parsed ("[('one', 1), (%s, 2),"
+ " ('three', %i)]", "two", 3),
+ "[('one', 1), ('two', 2), ('three', 3)]");
+ value = g_variant_new_parsed ("[('one', 1), (%s, 2),"
+ " ('three', %u)]", "two", 3);
+ g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE ("a(su)")));
+ check_and_free (value, "[('one', 1), ('two', 2), ('three', 3)]");
+ check_and_free (g_variant_new_parsed ("{%s:%i}", "one", 1), "{'one': 1}");
+
+ if (g_test_undefined ())
+ {
+ do_failed_test ("/gvariant/parse/subprocess/bad-format-char",
+ "*GVariant format string*");
+
+ do_failed_test ("/gvariant/parse/subprocess/bad-format-string",
+ "*can not parse as*");
+
+ do_failed_test ("/gvariant/parse/subprocess/bad-args",
+ "*expected GVariant of type 'i'*");
+ }
+}
+
+static void
+test_floating (void)
+{
+ GVariant *value;
+
+ value = g_variant_new_int32 (42);
+ g_assert (g_variant_is_floating (value));
+ g_variant_ref_sink (value);
+ g_assert (!g_variant_is_floating (value));
+ g_variant_unref (value);
+}
+
+static void
+test_bytestring (void)
+{
+ const gchar *test_string = "foo,bar,baz,quux,\xffoooo";
+ GVariant *value;
+ gchar **strv;
+ gchar *str;
+ const gchar *const_str;
+ GVariant *untrusted_empty;
+
+ strv = g_strsplit (test_string, ",", 0);
+
+ value = g_variant_new_bytestring_array ((const gchar **) strv, -1);
+ g_assert (g_variant_is_floating (value));
+ g_strfreev (strv);
+
+ str = g_variant_print (value, FALSE);
+ g_variant_unref (value);
+
+ value = g_variant_parse (NULL, str, NULL, NULL, NULL);
+ g_free (str);
+
+ strv = g_variant_dup_bytestring_array (value, NULL);
+ g_variant_unref (value);
+
+ str = g_strjoinv (",", strv);
+ g_strfreev (strv);
+
+ g_assert_cmpstr (str, ==, test_string);
+ g_free (str);
+
+ strv = g_strsplit (test_string, ",", 0);
+ value = g_variant_new ("(^aay^a&ay^ay^&ay)",
+ strv, strv, strv[0], strv[0]);
+ g_strfreev (strv);
+
+ g_variant_get_child (value, 0, "^a&ay", &strv);
+ str = g_strjoinv (",", strv);
+ g_free (strv);
+ g_assert_cmpstr (str, ==, test_string);
+ g_free (str);
+
+ g_variant_get_child (value, 0, "^aay", &strv);
+ str = g_strjoinv (",", strv);
+ g_strfreev (strv);
+ g_assert_cmpstr (str, ==, test_string);
+ g_free (str);
+
+ g_variant_get_child (value, 1, "^a&ay", &strv);
+ str = g_strjoinv (",", strv);
+ g_free (strv);
+ g_assert_cmpstr (str, ==, test_string);
+ g_free (str);
+
+ g_variant_get_child (value, 1, "^aay", &strv);
+ str = g_strjoinv (",", strv);
+ g_strfreev (strv);
+ g_assert_cmpstr (str, ==, test_string);
+ g_free (str);
+
+ g_variant_get_child (value, 2, "^ay", &str);
+ g_assert_cmpstr (str, ==, "foo");
+ g_free (str);
+
+ g_variant_get_child (value, 2, "^&ay", &str);
+ g_assert_cmpstr (str, ==, "foo");
+
+ g_variant_get_child (value, 3, "^ay", &str);
+ g_assert_cmpstr (str, ==, "foo");
+ g_free (str);
+
+ g_variant_get_child (value, 3, "^&ay", &str);
+ g_assert_cmpstr (str, ==, "foo");
+ g_variant_unref (value);
+
+ untrusted_empty = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), NULL, 0, FALSE, NULL, NULL);
+ value = g_variant_get_normal_form (untrusted_empty);
+ const_str = g_variant_get_bytestring (value);
+ (void) const_str;
+ g_variant_unref (value);
+ g_variant_unref (untrusted_empty);
+}
+
+static void
+test_lookup_value (void)
+{
+ struct {
+ const gchar *dict, *key, *value;
+ } cases[] = {
+ { "@a{ss} {'x': 'y'}", "x", "'y'" },
+ { "@a{ss} {'x': 'y'}", "y" },
+ { "@a{os} {'/x': 'y'}", "/x", "'y'" },
+ { "@a{os} {'/x': 'y'}", "/y" },
+ { "@a{sv} {'x': <'y'>}", "x", "'y'" },
+ { "@a{sv} {'x': <5>}", "x", "5" },
+ { "@a{sv} {'x': <'y'>}", "y" }
+ };
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (cases); i++)
+ {
+ GVariant *dictionary;
+ GVariant *value;
+ gchar *p;
+
+ dictionary = g_variant_parse (NULL, cases[i].dict, NULL, NULL, NULL);
+ value = g_variant_lookup_value (dictionary, cases[i].key, NULL);
+ g_variant_unref (dictionary);
+
+ if (value == NULL && cases[i].value == NULL)
+ continue;
+
+ g_assert (value && cases[i].value);
+ p = g_variant_print (value, FALSE);
+ g_assert_cmpstr (cases[i].value, ==, p);
+ g_variant_unref (value);
+ g_free (p);
+ }
+}
+
+static void
+test_lookup (void)
+{
+ const gchar *str;
+ GVariant *dict;
+ gboolean ok;
+ gint num;
+
+ dict = g_variant_parse (NULL,
+ "{'a': <5>, 'b': <'c'>}",
+ NULL, NULL, NULL);
+
+ ok = g_variant_lookup (dict, "a", "i", &num);
+ g_assert (ok);
+ g_assert_cmpint (num, ==, 5);
+
+ ok = g_variant_lookup (dict, "a", "&s", &str);
+ g_assert (!ok);
+
+ ok = g_variant_lookup (dict, "q", "&s", &str);
+ g_assert (!ok);
+
+ ok = g_variant_lookup (dict, "b", "i", &num);
+ g_assert (!ok);
+
+ ok = g_variant_lookup (dict, "b", "&s", &str);
+ g_assert (ok);
+ g_assert_cmpstr (str, ==, "c");
+
+ ok = g_variant_lookup (dict, "q", "&s", &str);
+ g_assert (!ok);
+
+ g_variant_unref (dict);
+}
+
+static GVariant *
+untrusted (GVariant *a)
+{
+ GVariant *b;
+ const GVariantType *type;
+ GBytes *bytes;
+
+ type = g_variant_get_type (a);
+ bytes = g_variant_get_data_as_bytes (a);
+ b = g_variant_new_from_bytes (type, bytes, FALSE);
+ g_bytes_unref (bytes);
+ g_variant_unref (a);
+
+ return b;
+}
+
+static void
+test_compare (void)
+{
+ GVariant *a;
+ GVariant *b;
+
+ a = untrusted (g_variant_new_byte (5));
+ b = g_variant_new_byte (6);
+ g_assert (g_variant_compare (a, b) < 0);
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_int16 (G_MININT16));
+ b = g_variant_new_int16 (G_MAXINT16);
+ g_assert (g_variant_compare (a, b) < 0);
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_uint16 (0));
+ b = g_variant_new_uint16 (G_MAXUINT16);
+ g_assert (g_variant_compare (a, b) < 0);
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_int32 (G_MININT32));
+ b = g_variant_new_int32 (G_MAXINT32);
+ g_assert (g_variant_compare (a, b) < 0);
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_uint32 (0));
+ b = g_variant_new_uint32 (G_MAXUINT32);
+ g_assert (g_variant_compare (a, b) < 0);
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_int64 (G_MININT64));
+ b = g_variant_new_int64 (G_MAXINT64);
+ g_assert (g_variant_compare (a, b) < 0);
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_uint64 (0));
+ b = g_variant_new_uint64 (G_MAXUINT64);
+ g_assert (g_variant_compare (a, b) < 0);
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_double (G_MINDOUBLE));
+ b = g_variant_new_double (G_MAXDOUBLE);
+ g_assert (g_variant_compare (a, b) < 0);
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_string ("abc"));
+ b = g_variant_new_string ("abd");
+ g_assert (g_variant_compare (a, b) < 0);
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_object_path ("/abc"));
+ b = g_variant_new_object_path ("/abd");
+ g_assert (g_variant_compare (a, b) < 0);
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_signature ("g"));
+ b = g_variant_new_signature ("o");
+ g_assert (g_variant_compare (a, b) < 0);
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_boolean (FALSE));
+ b = g_variant_new_boolean (TRUE);
+ g_assert (g_variant_compare (a, b) < 0);
+ g_variant_unref (a);
+ g_variant_unref (b);
+}
+
+static void
+test_equal (void)
+{
+ GVariant *a;
+ GVariant *b;
+
+ a = untrusted (g_variant_new_byte (5));
+ b = g_variant_get_normal_form (a);
+ g_assert (g_variant_equal (a, b));
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_int16 (G_MININT16));
+ b = g_variant_get_normal_form (a);
+ g_assert (g_variant_equal (a, b));
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_uint16 (0));
+ b = g_variant_get_normal_form (a);
+ g_assert (g_variant_equal (a, b));
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_int32 (G_MININT32));
+ b = g_variant_get_normal_form (a);
+ g_assert (g_variant_equal (a, b));
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_uint32 (0));
+ b = g_variant_get_normal_form (a);
+ g_assert (g_variant_equal (a, b));
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_int64 (G_MININT64));
+ b = g_variant_get_normal_form (a);
+ g_assert (g_variant_equal (a, b));
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_uint64 (0));
+ b = g_variant_get_normal_form (a);
+ g_assert (g_variant_equal (a, b));
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_double (G_MINDOUBLE));
+ b = g_variant_get_normal_form (a);
+ g_assert (g_variant_equal (a, b));
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_string ("abc"));
+ g_assert (g_variant_equal (a, a));
+ b = g_variant_get_normal_form (a);
+ g_assert (g_variant_equal (a, b));
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_object_path ("/abc"));
+ g_assert (g_variant_equal (a, a));
+ b = g_variant_get_normal_form (a);
+ a = untrusted (a);
+ g_assert (g_variant_equal (a, b));
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_signature ("g"));
+ g_assert (g_variant_equal (a, a));
+ b = g_variant_get_normal_form (a);
+ a = untrusted (a);
+ g_assert (g_variant_equal (a, b));
+ g_variant_unref (a);
+ g_variant_unref (b);
+ a = untrusted (g_variant_new_boolean (FALSE));
+ b = g_variant_get_normal_form (a);
+ g_assert (g_variant_equal (a, b));
+ g_variant_unref (a);
+ g_variant_unref (b);
+}
+
+static void
+test_fixed_array (void)
+{
+ GVariant *a;
+ gint32 values[5];
+ const gint32 *elts;
+ gsize n_elts;
+ gint i;
+
+ n_elts = 0;
+ a = g_variant_new_parsed ("[1,2,3,4,5]");
+ elts = g_variant_get_fixed_array (a, &n_elts, sizeof (gint32));
+ g_assert (n_elts == 5);
+ for (i = 0; i < 5; i++)
+ g_assert_cmpint (elts[i], ==, i + 1);
+ g_variant_unref (a);
+
+ n_elts = 0;
+ for (i = 0; i < 5; i++)
+ values[i] = i + 1;
+ a = g_variant_new_fixed_array (G_VARIANT_TYPE_INT32, values,
+ G_N_ELEMENTS (values), sizeof (values[0]));
+ g_assert_cmpstr (g_variant_get_type_string (a), ==, "ai");
+ elts = g_variant_get_fixed_array (a, &n_elts, sizeof (gint32));
+ g_assert (n_elts == 5);
+ for (i = 0; i < 5; i++)
+ g_assert_cmpint (elts[i], ==, i + 1);
+ g_variant_unref (a);
+}
+
+static void
+test_check_format_string (void)
+{
+ GVariant *value;
+
+ value = g_variant_new ("(sas)", "foo", NULL);
+ g_variant_ref_sink (value);
+
+ g_assert (g_variant_check_format_string (value, "(s*)", TRUE));
+ g_assert (g_variant_check_format_string (value, "(s*)", FALSE));
+ g_assert (!g_variant_check_format_string (value, "(u*)", TRUE));
+ g_assert (!g_variant_check_format_string (value, "(u*)", FALSE));
+
+ g_assert (g_variant_check_format_string (value, "(&s*)", FALSE));
+ g_test_expect_message ("GLib", G_LOG_LEVEL_CRITICAL, "*contains a '&' character*");
+ g_assert (!g_variant_check_format_string (value, "(&s*)", TRUE));
+ g_test_assert_expected_messages ();
+
+ g_assert (g_variant_check_format_string (value, "(s^as)", TRUE));
+ g_assert (g_variant_check_format_string (value, "(s^as)", FALSE));
+
+ g_test_expect_message ("GLib", G_LOG_LEVEL_CRITICAL, "*contains a '&' character*");
+ g_assert (!g_variant_check_format_string (value, "(s^a&s)", TRUE));
+ g_test_assert_expected_messages ();
+ g_assert (g_variant_check_format_string (value, "(s^a&s)", FALSE));
+
+ g_variant_unref (value);
+
+ /* Do it again with a type that will let us put a '&' after a '^' */
+ value = g_variant_new ("(say)", "foo", NULL);
+ g_variant_ref_sink (value);
+
+ g_assert (g_variant_check_format_string (value, "(s*)", TRUE));
+ g_assert (g_variant_check_format_string (value, "(s*)", FALSE));
+ g_assert (!g_variant_check_format_string (value, "(u*)", TRUE));
+ g_assert (!g_variant_check_format_string (value, "(u*)", FALSE));
+
+ g_assert (g_variant_check_format_string (value, "(&s*)", FALSE));
+ g_test_expect_message ("GLib", G_LOG_LEVEL_CRITICAL, "*contains a '&' character*");
+ g_assert (!g_variant_check_format_string (value, "(&s*)", TRUE));
+ g_test_assert_expected_messages ();
+
+ g_assert (g_variant_check_format_string (value, "(s^ay)", TRUE));
+ g_assert (g_variant_check_format_string (value, "(s^ay)", FALSE));
+
+ g_test_expect_message ("GLib", G_LOG_LEVEL_CRITICAL, "*contains a '&' character*");
+ g_assert (!g_variant_check_format_string (value, "(s^&ay)", TRUE));
+ g_test_assert_expected_messages ();
+ g_assert (g_variant_check_format_string (value, "(s^&ay)", FALSE));
+
+ g_assert (g_variant_check_format_string (value, "r", FALSE));
+ g_assert (g_variant_check_format_string (value, "(?a?)", FALSE));
+
+ g_variant_unref (value);
+}
+
+static void
+verify_gvariant_checksum (const gchar *sha256,
+ GVariant *v)
+
+{
+ gchar *checksum;
+ checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA256,
+ g_variant_get_data (v),
+ g_variant_get_size (v));
+ g_assert_cmpstr (sha256, ==, checksum);
+ g_free (checksum);
+}
+
+static void
+verify_gvariant_checksum_va (const gchar *sha256,
+ const gchar *fmt,
+ ...)
+{
+ va_list args;
+ GVariant *v;
+
+ va_start (args, fmt);
+
+ v = g_variant_new_va (fmt, NULL, &args);
+ g_variant_ref_sink (v);
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ {
+ GVariant *byteswapped = g_variant_byteswap (v);
+ g_variant_unref (v);
+ v = byteswapped;
+ }
+#endif
+
+ va_end (args);
+
+ verify_gvariant_checksum (sha256, v);
+
+ g_variant_unref (v);
+}
+
+static void
+test_checksum_basic (void)
+{
+ verify_gvariant_checksum_va ("e8a4b2ee7ede79a3afb332b5b6cc3d952a65fd8cffb897f5d18016577c33d7cc",
+ "u", 42);
+ verify_gvariant_checksum_va ("c53e363c33b00cfce298229ee83856b8a98c2e6126cab13f65899f62473b0df5",
+ "s", "moocow");
+ verify_gvariant_checksum_va ("2b4c342f5433ebe591a1da77e013d1b72475562d48578dca8b84bac6651c3cb9",
+ "y", 9);
+ verify_gvariant_checksum_va ("12a3ae445661ce5dee78d0650d33362dec29c4f82af05e7e57fb595bbbacf0ca",
+ "t", G_MAXUINT64);
+ verify_gvariant_checksum_va ("e25a59b24440eb6c833aa79c93b9840e6eab6966add0dacf31df7e9e7000f5b3",
+ "d", 3.14159);
+ verify_gvariant_checksum_va ("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a",
+ "b", TRUE);
+ verify_gvariant_checksum_va ("ca2fd00fa001190744c15c317643ab092e7048ce086a243e2be9437c898de1bb",
+ "q", G_MAXUINT16);
+}
+
+static void
+test_checksum_nested (void)
+{
+ static const char* const strv[] = {"foo", "bar", "baz", NULL};
+
+ verify_gvariant_checksum_va ("31fbc92f08fddaca716188fe4b5d44ae122fc6306fd3c6925af53cfa47ea596d",
+ "(uu)", 41, 43);
+ verify_gvariant_checksum_va ("01759d683cead856d1d386d59af0578841698a424a265345ad5413122f220de8",
+ "(su)", "moocow", 79);
+ verify_gvariant_checksum_va ("52b3ae95f19b3e642ea1d01185aea14a09004c1d1712672644427403a8a0afe6",
+ "(qyst)", G_MAXUINT16, 9, "moocow", G_MAXUINT64);
+ verify_gvariant_checksum_va ("6fc6f4524161c3ae0d316812d7088e3fcd372023edaea2d7821093be40ae1060",
+ "(@ay)", g_variant_new_bytestring ("\xFF\xFF\xFF"));
+ verify_gvariant_checksum_va ("572aca386e1a983dd23bb6eb6e3dfa72eef9ca7c7744581aa800e18d7d9d0b0b",
+ "(^as)", strv);
+ verify_gvariant_checksum_va ("4bddf6174c791bb44fc6a4106573031690064df34b741033a0122ed8dc05bcf3",
+ "(yvu)", 254, g_variant_new ("(^as)", strv), 42);
+}
+
+static void
+test_gbytes (void)
+{
+ GVariant *a;
+ GVariant *tuple;
+ GBytes *bytes;
+ GBytes *bytes2;
+ const guint8 values[5] = { 1, 2, 3, 4, 5 };
+ const guint8 *elts;
+ gsize n_elts;
+ gint i;
+
+ bytes = g_bytes_new (&values, 5);
+ a = g_variant_new_from_bytes (G_VARIANT_TYPE_BYTESTRING, bytes, TRUE);
+ g_bytes_unref (bytes);
+ n_elts = 0;
+ elts = g_variant_get_fixed_array (a, &n_elts, sizeof (guint8));
+ g_assert (n_elts == 5);
+ for (i = 0; i < 5; i++)
+ g_assert_cmpint (elts[i], ==, i + 1);
+
+ bytes2 = g_variant_get_data_as_bytes (a);
+ g_variant_unref (a);
+
+ bytes = g_bytes_new (&values, 5);
+ g_assert (g_bytes_equal (bytes, bytes2));
+ g_bytes_unref (bytes);
+ g_bytes_unref (bytes2);
+
+ tuple = g_variant_new_parsed ("['foo', 'bar']");
+ bytes = g_variant_get_data_as_bytes (tuple); /* force serialisation */
+ a = g_variant_get_child_value (tuple, 1);
+ bytes2 = g_variant_get_data_as_bytes (a);
+ g_assert (!g_bytes_equal (bytes, bytes2));
+
+ g_bytes_unref (bytes);
+ g_bytes_unref (bytes2);
+ g_variant_unref (a);
+ g_variant_unref (tuple);
+}
+
+typedef struct {
+ const GVariantType *type;
+ const gchar *in;
+ const gchar *out;
+} ContextTest;
+
+static void
+test_print_context (void)
+{
+ ContextTest tests[] = {
+ { NULL, "(1, 2, 3, 'abc", " ^^^^" },
+ { NULL, "[1, 2, 3, 'str']", " ^ ^^^^^" },
+ { G_VARIANT_TYPE_UINT16, "{ 'abc':'def' }", " ^^^^^^^^^^^^^^^" },
+ { NULL, "<5", " ^" },
+ { NULL, "'ab\\ux'", " ^^^^^^^" },
+ { NULL, "'ab\\U00efx'", " ^^^^^^^^^^^" }
+ };
+ GVariant *v;
+ gchar *s;
+ gint i;
+ GError *error = NULL;
+
+ for (i = 0; i < G_N_ELEMENTS (tests); i++)
+ {
+ v = g_variant_parse (tests[i].type, tests[i].in, NULL, NULL, &error);
+ g_assert_null (v);
+ s = g_variant_parse_error_print_context (error, tests[i].in);
+ g_assert (strstr (s, tests[i].out) != NULL);
+ g_free (s);
+ g_clear_error (&error);
+ }
+}
+
+static void
+test_error_quark (void)
+{
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ g_assert (g_variant_parser_get_error_quark () == g_variant_parse_error_quark ());
+G_GNUC_END_IGNORE_DEPRECATIONS
+}
+
+static void
+test_stack_builder_init (void)
+{
+ GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_BYTESTRING);
+ GVariant *variant;
+
+ g_variant_builder_add_value (&builder, g_variant_new_byte ('g'));
+ g_variant_builder_add_value (&builder, g_variant_new_byte ('l'));
+ g_variant_builder_add_value (&builder, g_variant_new_byte ('i'));
+ g_variant_builder_add_value (&builder, g_variant_new_byte ('b'));
+ g_variant_builder_add_value (&builder, g_variant_new_byte ('\0'));
+
+ variant = g_variant_ref_sink (g_variant_builder_end (&builder));
+ g_assert_nonnull (variant);
+ g_assert (g_variant_type_equal (g_variant_get_type (variant),
+ G_VARIANT_TYPE_BYTESTRING));
+ g_assert_cmpuint (g_variant_n_children (variant), ==, 5);
+ g_assert_cmpstr (g_variant_get_bytestring (variant), ==, "glib");
+ g_variant_unref (variant);
+}
+
+static GVariant *
+get_asv (void)
+{
+ GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
+
+ g_variant_builder_add (&builder, "{s@v}", "foo", g_variant_new_variant (g_variant_new_string ("FOO")));
+ g_variant_builder_add (&builder, "{s@v}", "bar", g_variant_new_variant (g_variant_new_string ("BAR")));
+
+ return g_variant_ref_sink (g_variant_builder_end (&builder));
+}
+
+static void
+test_stack_dict_init (void)
+{
+ GVariant *asv = get_asv ();
+ GVariantDict dict = G_VARIANT_DICT_INIT (asv);
+ GVariant *variant;
+ GVariantIter iter;
+ gchar *key;
+ GVariant *value;
+
+ g_variant_dict_insert_value (&dict, "baz", g_variant_new_string ("BAZ"));
+ g_variant_dict_insert_value (&dict, "quux", g_variant_new_string ("QUUX"));
+
+ variant = g_variant_ref_sink (g_variant_dict_end (&dict));
+ g_assert_nonnull (variant);
+ g_assert (g_variant_type_equal (g_variant_get_type (variant),
+ G_VARIANT_TYPE_VARDICT));
+ g_assert_cmpuint (g_variant_n_children (variant), ==, 4);
+
+ g_variant_iter_init (&iter, variant);
+ while (g_variant_iter_next (&iter, "{sv}", &key, &value))
+ {
+ gchar *strup = g_ascii_strup (key, -1);
+
+ g_assert_cmpstr (strup, ==, g_variant_get_string (value, NULL));
+ g_free (key);
+ g_free (strup);
+ g_variant_unref (value);
+ }
+
+ g_variant_unref (asv);
+ g_variant_unref (variant);
}
int
g_test_add_func ("/gvariant/serialiser/variant", test_variants);
g_test_add_func ("/gvariant/serialiser/strings", test_strings);
g_test_add_func ("/gvariant/serialiser/byteswap", test_byteswaps);
- g_test_add_func ("/gvariant/containers", test_containers);
for (i = 1; i <= 20; i += 4)
{
g_free (testname);
}
+ g_test_add_func ("/gvariant/string", test_string);
+ g_test_add_func ("/gvariant/utf8", test_utf8);
+ g_test_add_func ("/gvariant/containers", test_containers);
+ g_test_add_func ("/gvariant/format-strings", test_format_strings);
+ g_test_add_func ("/gvariant/invalid-varargs", test_invalid_varargs);
+ g_test_add_func ("/gvariant/varargs", test_varargs);
+ g_test_add_func ("/gvariant/varargs/subprocess/empty-array", test_varargs_empty_array);
+ g_test_add_func ("/gvariant/valist", test_valist);
+ g_test_add_func ("/gvariant/builder-memory", test_builder_memory);
+ g_test_add_func ("/gvariant/hashing", test_hashing);
+ g_test_add_func ("/gvariant/byteswap", test_gv_byteswap);
+ g_test_add_func ("/gvariant/parser", test_parses);
+ g_test_add_func ("/gvariant/parse-failures", test_parse_failures);
+ g_test_add_func ("/gvariant/parse-positional", test_parse_positional);
+ g_test_add_func ("/gvariant/parse/subprocess/bad-format-char", test_parse_bad_format_char);
+ g_test_add_func ("/gvariant/parse/subprocess/bad-format-string", test_parse_bad_format_string);
+ g_test_add_func ("/gvariant/parse/subprocess/bad-args", test_parse_bad_args);
+ g_test_add_func ("/gvariant/floating", test_floating);
+ g_test_add_func ("/gvariant/bytestring", test_bytestring);
+ g_test_add_func ("/gvariant/lookup-value", test_lookup_value);
+ g_test_add_func ("/gvariant/lookup", test_lookup);
+ g_test_add_func ("/gvariant/compare", test_compare);
+ g_test_add_func ("/gvariant/equal", test_equal);
+ g_test_add_func ("/gvariant/fixed-array", test_fixed_array);
+ g_test_add_func ("/gvariant/check-format-string", test_check_format_string);
+
+ g_test_add_func ("/gvariant/checksum-basic", test_checksum_basic);
+ g_test_add_func ("/gvariant/checksum-nested", test_checksum_nested);
+
+ g_test_add_func ("/gvariant/gbytes", test_gbytes);
+ g_test_add_func ("/gvariant/print-context", test_print_context);
+ g_test_add_func ("/gvariant/error-quark", test_error_quark);
+
+ g_test_add_func ("/gvariant/stack-builder-init", test_stack_builder_init);
+ g_test_add_func ("/gvariant/stack-dict-init", test_stack_dict_init);
return g_test_run ();
}