Simplify subprocesses in tests
[platform/upstream/glib.git] / glib / tests / hash.c
index efc23ef..be7fe69 100644 (file)
 #  include <config.h>
 #endif
 
-#if STDC_HEADERS
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#endif
 
 #include <glib.h>
 
@@ -243,7 +241,6 @@ not_even_foreach (gpointer key,
   g_assert (i != 3);
 }
 
-
 static gboolean
 remove_even_foreach (gpointer key,
                      gpointer value,
@@ -385,6 +382,35 @@ direct_hash_test (void)
 }
 
 static void
+int_hash_test (void)
+{
+  gint       i, rc;
+  GHashTable     *h;
+  gint     values[20];
+  gint key;
+
+  h = g_hash_table_new (g_int_hash, g_int_equal);
+  g_assert (h != NULL);
+  for (i = 0; i < 20; i++)
+    {
+      values[i] = i + 42;
+      g_hash_table_insert (h, &values[i], GINT_TO_POINTER (i + 42));
+    }
+
+  g_assert (g_hash_table_size (h) == 20);
+
+  for (i = 0; i < 20; i++)
+    {
+      key = i + 42;
+      rc = GPOINTER_TO_INT (g_hash_table_lookup (h, &key));
+
+      g_assert_cmpint (rc, ==, i + 42);
+    }
+
+  g_hash_table_destroy (h);
+}
+
+static void
 int64_hash_test (void)
 {
   gint       i, rc;
@@ -510,15 +536,25 @@ set_hash_test (void)
   for (i = 2; i < 5000; i += 7)
     {
       char *s = g_strdup_printf ("%d", i);
-      g_hash_table_insert (hash_table, s, s);
+      g_assert (g_hash_table_add (hash_table, s));
     }
 
+  g_assert (!g_hash_table_add (hash_table, g_strdup_printf ("%d", 2)));
+
   i = 0;
   g_hash_table_foreach (hash_table, set_check, &i);
   g_assert_cmpint (i, ==, g_hash_table_size (hash_table));
 
+  g_assert (g_hash_table_contains (hash_table, "2"));
+  g_assert (g_hash_table_contains (hash_table, "9"));
+  g_assert (!g_hash_table_contains (hash_table, "a"));
+
   /* this will cause the hash table to loose set nature */
-  g_hash_table_insert (hash_table, g_strdup ("a"), "b");
+  g_assert (g_hash_table_insert (hash_table, g_strdup ("a"), "b"));
+  g_assert (!g_hash_table_insert (hash_table, g_strdup ("a"), "b"));
+
+  g_assert (g_hash_table_replace (hash_table, g_strdup ("c"), "d"));
+  g_assert (!g_hash_table_replace (hash_table, g_strdup ("c"), "d"));
 
   g_assert_cmpstr (g_hash_table_lookup (hash_table, "2"), ==, "2");
   g_assert_cmpstr (g_hash_table_lookup (hash_table, "a"), ==, "b");
@@ -861,6 +897,33 @@ set_ref_hash_test (void)
 
 GHashTable *h;
 
+typedef struct {
+    gchar *string;
+    gboolean freed;
+} FakeFreeData;
+
+GPtrArray *fake_free_data;
+
+static void
+fake_free (gpointer dead)
+{
+  guint i;
+
+  for (i = 0; i < fake_free_data->len; i++)
+    {
+      FakeFreeData *ffd = g_ptr_array_index (fake_free_data, i);
+
+      if (ffd->string == (gchar *) dead)
+        {
+          g_assert (!ffd->freed);
+          ffd->freed = TRUE;
+          return;
+        }
+    }
+
+  g_assert_not_reached ();
+}
+
 static void
 value_destroy_insert (gpointer value)
 {
@@ -870,18 +933,60 @@ value_destroy_insert (gpointer value)
 static void
 test_destroy_modify (void)
 {
+  FakeFreeData *ffd;
+  guint i;
+
   g_test_bug ("650459");
 
-  h = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, value_destroy_insert);
+  fake_free_data = g_ptr_array_new ();
+
+  h = g_hash_table_new_full (g_str_hash, g_str_equal, fake_free, value_destroy_insert);
+
+  ffd = g_new0 (FakeFreeData, 1);
+  ffd->string = g_strdup ("a");
+  g_ptr_array_add (fake_free_data, ffd);
+  g_hash_table_insert (h, ffd->string, "b");
+
+  ffd = g_new0 (FakeFreeData, 1);
+  ffd->string = g_strdup ("c");
+  g_ptr_array_add (fake_free_data, ffd);
+  g_hash_table_insert (h, ffd->string, "d");
 
-  g_hash_table_insert (h, g_strdup ("a"), g_strdup ("b"));
-  g_hash_table_insert (h, g_strdup ("c"), g_strdup ("d"));
-  g_hash_table_insert (h, g_strdup ("e"), g_strdup ("f"));
-  g_hash_table_insert (h, g_strdup ("g"), g_strdup ("h"));
-  g_hash_table_insert (h, g_strdup ("h"), g_strdup ("k"));
-  g_hash_table_insert (h, g_strdup ("a"), g_strdup ("c"));
+  ffd = g_new0 (FakeFreeData, 1);
+  ffd->string = g_strdup ("e");
+  g_ptr_array_add (fake_free_data, ffd);
+  g_hash_table_insert (h, ffd->string, "f");
+
+  ffd = g_new0 (FakeFreeData, 1);
+  ffd->string = g_strdup ("g");
+  g_ptr_array_add (fake_free_data, ffd);
+  g_hash_table_insert (h, ffd->string, "h");
+
+  ffd = g_new0 (FakeFreeData, 1);
+  ffd->string = g_strdup ("h");
+  g_ptr_array_add (fake_free_data, ffd);
+  g_hash_table_insert (h, ffd->string, "k");
+
+  ffd = g_new0 (FakeFreeData, 1);
+  ffd->string = g_strdup ("a");
+  g_ptr_array_add (fake_free_data, ffd);
+  g_hash_table_insert (h, ffd->string, "c");
 
   g_hash_table_remove (h, "c");
+
+  /* that removed everything... */
+  for (i = 0; i < fake_free_data->len; i++)
+    {
+      FakeFreeData *ffd = g_ptr_array_index (fake_free_data, i);
+
+      g_assert (ffd->freed);
+      g_free (ffd->string);
+      g_free (ffd);
+    }
+
+  g_ptr_array_unref (fake_free_data);
+
+  /* ... so this is a no-op */
   g_hash_table_remove (h, "e");
 
   g_hash_table_unref (h);
@@ -966,6 +1071,53 @@ test_foreach (void)
   g_hash_table_unref (hash);
 }
 
+static gboolean
+foreach_steal_func (gpointer key, gpointer value, gpointer data)
+{
+  GHashTable *hash2 = data;
+
+  if (strstr ("ace", (gchar*)key))
+    {
+      g_hash_table_insert (hash2, key, value);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+
+static void
+test_foreach_steal (void)
+{
+  GHashTable *hash;
+  GHashTable *hash2;
+
+  hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+  hash2 = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+  g_hash_table_insert (hash, g_strdup ("a"), g_strdup ("A"));
+  g_hash_table_insert (hash, g_strdup ("b"), g_strdup ("B"));
+  g_hash_table_insert (hash, g_strdup ("c"), g_strdup ("C"));
+  g_hash_table_insert (hash, g_strdup ("d"), g_strdup ("D"));
+  g_hash_table_insert (hash, g_strdup ("e"), g_strdup ("E"));
+  g_hash_table_insert (hash, g_strdup ("f"), g_strdup ("F"));
+
+  g_hash_table_foreach_steal (hash, foreach_steal_func, hash2);
+
+  g_assert_cmpint (g_hash_table_size (hash), ==, 3);
+  g_assert_cmpint (g_hash_table_size (hash2), ==, 3);
+
+  g_assert_cmpstr (g_hash_table_lookup (hash2, "a"), ==, "A");
+  g_assert_cmpstr (g_hash_table_lookup (hash, "b"), ==, "B");
+  g_assert_cmpstr (g_hash_table_lookup (hash2, "c"), ==, "C");
+  g_assert_cmpstr (g_hash_table_lookup (hash, "d"), ==, "D");
+  g_assert_cmpstr (g_hash_table_lookup (hash2, "e"), ==, "E");
+  g_assert_cmpstr (g_hash_table_lookup (hash, "f"), ==, "F");
+
+  g_hash_table_unref (hash);
+  g_hash_table_unref (hash2);
+}
+
 struct _GHashTable
 {
   gint             size;
@@ -1144,6 +1296,82 @@ test_iter_replace (void)
   g_hash_table_unref (h);
 }
 
+static void
+replace_first_character (gchar *string)
+{
+  string[0] = 'b';
+}
+
+static void
+test_set_insert_corruption (void)
+{
+  GHashTable *hash_table =
+    g_hash_table_new_full (g_str_hash, g_str_equal,
+        (GDestroyNotify) replace_first_character, NULL);
+  GHashTableIter iter;
+  gchar a[] = "foo";
+  gchar b[] = "foo";
+  gpointer key, value;
+
+  g_test_bug ("692815");
+
+  g_hash_table_insert (hash_table, a, a);
+  g_assert (g_hash_table_contains (hash_table, "foo"));
+
+  g_hash_table_insert (hash_table, b, b);
+
+  g_assert_cmpuint (g_hash_table_size (hash_table), ==, 1);
+  g_hash_table_iter_init (&iter, hash_table);
+  if (!g_hash_table_iter_next (&iter, &key, &value))
+    g_assert_not_reached();
+
+  /* per the documentation to g_hash_table_insert(), 'b' has now been freed,
+   * and the sole key in 'hash_table' should be 'a'.
+   */
+  g_assert (key != b);
+  g_assert (key == a);
+
+  g_assert_cmpstr (b, ==, "boo");
+
+  /* g_hash_table_insert() also says that the value should now be 'b',
+   * which is probably not what the caller intended but is precisely what they
+   * asked for.
+   */
+  g_assert (value == b);
+
+  /* even though the hash has now been de-set-ified: */
+  g_assert (g_hash_table_contains (hash_table, "foo"));
+
+  g_hash_table_unref (hash_table);
+}
+
+static void
+test_set_to_strv (void)
+{
+  GHashTable *set;
+  gchar **strv;
+  guint n;
+
+  set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+  g_hash_table_add (set, g_strdup ("xyz"));
+  g_hash_table_add (set, g_strdup ("xyz"));
+  g_hash_table_add (set, g_strdup ("abc"));
+  strv = (gchar **) g_hash_table_get_keys_as_array (set, &n);
+  g_hash_table_steal_all (set);
+  g_hash_table_unref (set);
+  g_assert_cmpint (n, ==, 2);
+  n = g_strv_length (strv);
+  g_assert_cmpint (n, ==, 2);
+  if (g_str_equal (strv[0], "abc"))
+    g_assert_cmpstr (strv[1], ==, "xyz");
+  else
+    {
+    g_assert_cmpstr (strv[0], ==, "xyz");
+    g_assert_cmpstr (strv[1], ==, "abc");
+    }
+  g_strfreev (strv);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -1155,6 +1383,7 @@ main (int argc, char *argv[])
   g_test_add_data_func ("/hash/one", GINT_TO_POINTER (TRUE), second_hash_test);
   g_test_add_data_func ("/hash/honeyman", GINT_TO_POINTER (FALSE), second_hash_test);
   g_test_add_func ("/hash/direct", direct_hash_test);
+  g_test_add_func ("/hash/int", int_hash_test);
   g_test_add_func ("/hash/int64", int64_hash_test);
   g_test_add_func ("/hash/double", double_hash_test);
   g_test_add_func ("/hash/string", string_hash_test);
@@ -1164,12 +1393,15 @@ main (int argc, char *argv[])
   g_test_add_func ("/hash/remove-all", test_remove_all);
   g_test_add_func ("/hash/find", test_find);
   g_test_add_func ("/hash/foreach", test_foreach);
+  g_test_add_func ("/hash/foreach-steal", test_foreach_steal);
 
   /* tests for individual bugs */
   g_test_add_func ("/hash/lookup-null-key", test_lookup_null_key);
   g_test_add_func ("/hash/destroy-modify", test_destroy_modify);
   g_test_add_func ("/hash/consistency", test_internal_consistency);
   g_test_add_func ("/hash/iter-replace", test_iter_replace);
+  g_test_add_func ("/hash/set-insert-corruption", test_set_insert_corruption);
+  g_test_add_func ("/hash/set-to-strv", test_set_to_strv);
 
   return g_test_run ();