hmap: New function hmap_clear().
[pspp] / tests / libpspp / hmap-test.c
index 7ad86292fa4a12ae4e20342a8567ff3b53f02b85..bbe341388a3ce530b26957afd8e89a3df586d6c1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    "valgrind --leak-check=yes --show-reachable=yes" should give a
    clean report. */
 
+/* GCC 4.3 miscompiles some of the tests below, so we do not run
+   these tests on GCC 4.3.  This is a bug in GCC 4.3 triggered by
+   the test program, not a bug in the library under test.  GCC
+   4.2 or earlier and GCC 4.4 or later do not have this bug.
+
+   Here is a minimal test program that demonstrates the same or a
+   similar bug in GCC 4.3:
+
+   #include <stdio.h>
+   #include <stdlib.h>
+
+   struct node
+     {
+       struct node *next;
+       unsigned int data1;
+       int data2;
+     };
+   struct list
+     {
+       struct node *head;
+       int dummy;
+     };
+
+   static void *
+   xmalloc (int n)
+   {
+     return malloc (n);
+   }
+
+   static void
+   check_list (struct list *list)
+   {
+     int i __attribute__((unused));
+     struct node *e;
+     for (e = list->head; e != NULL; e = e->next)
+       if (e->data1 != e->data2)
+         abort ();
+   }
+
+   int
+   main (void)
+   {
+   #define MAX_ELEMS 2
+     struct node *elements = xmalloc (MAX_ELEMS * sizeof *elements);
+     int *values = xmalloc (MAX_ELEMS * sizeof *values);
+     struct list list;
+     int i;
+
+     list.head = NULL;
+     for (i = 0; i < MAX_ELEMS; i++)
+       {
+         values[i] = elements[i].data2 = i;
+         elements[i].data1 = elements[i].data2;
+         elements[i].next = list.head;
+         list.head = &elements[i];
+       }
+     check_list (&list);
+     return 0;
+   }
+*/
+
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
@@ -76,6 +137,10 @@ xalloc_die (void)
   exit (EXIT_FAILURE);
 }
 
+static void *xmalloc (size_t n) MALLOC_LIKE;
+static void *xnmalloc (size_t n, size_t m) MALLOC_LIKE;
+static void *xmemdup (const void *p, size_t n) MALLOC_LIKE;
+
 /* Allocates and returns N bytes of memory. */
 static void *
 xmalloc (size_t n)
@@ -277,6 +342,7 @@ check_hmap (struct hmap *hmap, const int data[], size_t cnt,
   size_t i, j;
   int *order;
 
+  check (hmap_is_empty (hmap) == (cnt == 0));
   check (hmap_count (hmap) == cnt);
   check (cnt <= hmap_capacity (hmap));
 
@@ -313,7 +379,6 @@ check_hmap (struct hmap *hmap, const int data[], size_t cnt,
       for (p = hmap_first (hmap), i = 0; i < cnt; p = hmap_next (hmap, p), i++)
         {
           struct element *e = hmap_node_to_element (p);
-          size_t j;
 
           check (hmap_node_hash (&e->node) == hash (e->data));
           for (j = 0; j < left; j++)
@@ -601,6 +666,10 @@ test_insert_ordered (int max_elems, hash_function *hash)
   struct hmap hmap;
   int i;
 
+#if __GNUC__ == 4 && __GNUC_MINOR__ == 3
+  return;
+#endif  /* GCC 4.3 */
+
   hmap_init (&hmap);
   elements = xnmalloc (max_elems, sizeof *elements);
   values = xnmalloc (max_elems, sizeof *values);
@@ -673,6 +742,10 @@ test_moved (int max_elems, hash_function *hash)
   struct hmap hmap;
   int i, j;
 
+#if __GNUC__ == 4 && __GNUC_MINOR__ == 3
+  return;
+#endif  /* GCC 4.3 */
+
   hmap_init (&hmap);
   e[0] = xnmalloc (max_elems, sizeof *e[0]);
   e[1] = xnmalloc (max_elems, sizeof *e[1]);
@@ -808,6 +881,10 @@ test_swap (int max_elems, hash_function *hash)
   struct hmap *working, *empty;
   int i;
 
+#if __GNUC__ == 4 && __GNUC_MINOR__ == 3
+  return;
+#endif  /* GCC 4.3 */
+
   hmap_init (&a);
   hmap_init (&b);
   working = &a;
@@ -838,6 +915,45 @@ test_swap_random_hash (void)
   test_swap (128, random_hash);
 }
 
+/* Inserts elements into an hmap in ascending order, then clears the hash table
+   using hmap_clear(). */
+static void
+test_clear (void)
+{
+  const int max_elems = 128;
+  struct element *elements;
+  int *values;
+  struct hmap hmap;
+  int cnt;
+
+#if __GNUC__ == 4 && __GNUC_MINOR__ == 3
+  return;
+#endif  /* GCC 4.3 */
+
+  elements = xnmalloc (max_elems, sizeof *elements);
+  values = xnmalloc (max_elems, sizeof *values);
+
+  for (cnt = 0; cnt <= max_elems; cnt++)
+    {
+      int i;
+
+      hmap_init (&hmap);
+      for (i = 0; i < cnt; i++)
+        {
+          values[i] = elements[i].data = i;
+          hmap_insert (&hmap, &elements[i].node,
+                       random_hash (elements[i].data));
+          check_hmap (&hmap, values, i + 1, random_hash);
+        }
+      hmap_clear (&hmap);
+      check_hmap (&hmap, NULL, 0, random_hash);
+      hmap_destroy (&hmap);
+    }
+
+  free (elements);
+  free (values);
+}
+
 static void
 test_destroy_null (void) 
 {
@@ -922,10 +1038,19 @@ main (void)
 
   run_test (test_swap_random_hash, "test swapping tables");
 
+  run_test (test_clear, "test clearing hash table");
+
   run_test (test_destroy_null, "test destroying null table");
   run_test (test_shrink_empty, "test shrinking an empty table");
 
   putchar ('\n');
 
+#if __GNUC__ == 4 && __GNUC_MINOR__ == 3
+  /* We skipped some of the tests, so return a value that
+     Automake will interpret as "skipped", instead of one that
+     means success. */
+  return 77;
+#else
   return 0;
+#endif
 }