[glib/GVariantType] GVariantType test: add subtype checking



commit 9dd33c1c3f03456871b7efa9758eeefe2af90364
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Jan 22 20:10:18 2010 -0500

    GVariantType test: add subtype checking

 glib/tests/gvarianttype.c |  201 +++++++++++++++++++++++++++++++++++++--------
 1 files changed, 167 insertions(+), 34 deletions(-)
---
diff --git a/glib/tests/gvarianttype.c b/glib/tests/gvarianttype.c
index 3a49f81..c354e74 100644
--- a/glib/tests/gvarianttype.c
+++ b/glib/tests/gvarianttype.c
@@ -26,6 +26,9 @@ 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
@@ -110,39 +113,7 @@ append_type_string (GString *string,
           break;
 
         case 2:
-          {
-            GVariantType *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);
-          }
+          result = append_tuple_type_string (string, description, depth);
 
           g_assert (g_variant_type_is_tuple (result));
           break;
@@ -195,6 +166,46 @@ append_type_string (GString *string,
     }
 }
 
+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)
@@ -447,12 +458,118 @@ describe_type (const GVariantType *type)
   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));
+
+      /* but it should not be a supertype unless it is 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 < 10000; i++)
+  for (i = 0; i < 2000; i++)
     {
       GString *type_string, *description;
       GVariantType *type, *other_type;
@@ -477,6 +594,22 @@ test_gvarianttype (void)
       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



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]