+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 GByteArray *
+flatten_vectors (GVariantVectors *v)
+{
+ GByteArray *result;
+ guint i;
+
+ result = g_byte_array_new ();
+
+ for (i = 0; i < v->vectors->len; i++)
+ {
+ GVariantVector vec = g_array_index (v->vectors, GVariantVector, i);
+
+ if (vec.gbytes)
+ g_byte_array_append (result, vec.data.pointer, vec.size);
+ else
+ g_byte_array_append (result, v->extra_bytes->data + vec.data.offset, vec.size);
+ }
+
+ return result;
+}
+
+static void
+test_vector_serialiser (void)
+{
+ GVariantVectors vectors;
+ GByteArray *flattened;
+ GVariant *value;
+ guint i;
+
+ for (i = 0; i < 100; i++)
+ {
+ value = create_random_gvariant (4);
+
+ GLIB_PRIVATE_CALL(g_variant_to_vectors) (value, &vectors);
+ flattened = flatten_vectors (&vectors);
+ g_byte_array_free (vectors.extra_bytes, TRUE);
+ g_byte_array_free (vectors.offsets, TRUE);
+ g_array_free (vectors.vectors, TRUE);
+
+#if 0
+ if (flattened->len != g_variant_get_size (value) ||
+ memcmp (flattened->data, g_variant_get_data (value), flattened->len) != 0)
+ {
+ g_file_set_contents ("flattened", flattened->data, flattened->len, NULL);
+ g_file_set_contents ("serialised", g_variant_get_data (value), g_variant_get_size (value), NULL);
+ g_print ("type is %s\n", g_variant_get_type_string (value));
+ g_assert_not_reached ();
+ }
+#endif
+
+ g_assert_cmpint (flattened->len, ==, g_variant_get_size (value));
+ g_assert (memcmp (flattened->data, g_variant_get_data (value), flattened->len) == 0);
+
+ g_byte_array_free (flattened, TRUE);
+ g_variant_unref (value);
+ }
+}
+