docs
[pspp] / tests / libpspp / heap-test.c
index 642ce7e05a0c3a5c904945ccc161d41e12679142..3e941a22d81165bbf6003d1fe69b526a8b86ac4c 100644 (file)
@@ -1,20 +1,18 @@
-/* PSPP - computes sample statistics.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2007, 2010, 2012 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 the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
+   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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
 
 
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA. */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 /* This is a test program for the routines defined in heap.c.
    This test program aims to be as comprehensive as possible.
 
 /* This is a test program for the routines defined in heap.c.
    This test program aims to be as comprehensive as possible.
 
 #include "xalloc.h"
 \f
 
 #include "xalloc.h"
 \f
-/* Currently running test. */
-static const char *test_name;
-
 /* Exit with a failure code.
    (Place a breakpoint on this function while debugging.) */
 static void
 /* Exit with a failure code.
    (Place a breakpoint on this function while debugging.) */
 static void
-check_die (void) 
+check_die (void)
 {
 {
-  exit (EXIT_FAILURE);   
+  exit (EXIT_FAILURE);
 }
 
 /* If OK is not true, prints a message about failure on the
    current source file and the given LINE and terminates. */
 static void
 }
 
 /* If OK is not true, prints a message about failure on the
    current source file and the given LINE and terminates. */
 static void
-check_func (bool ok, int line) 
+check_func (bool ok, int line)
 {
 {
-  if (!ok) 
+  if (!ok)
     {
     {
-      printf ("Check failed in %s test at %s, line %d\n",
-              test_name, __FILE__, line);
+      fprintf (stderr, "%s:%d: check failed\n", __FILE__, line);
       check_die ();
     }
 }
       check_die ();
     }
 }
@@ -79,7 +73,7 @@ struct element
     int x;                      /* Primary value. */
   };
 
     int x;                      /* Primary value. */
   };
 
-int aux_data;
+static int aux_data;
 
 /* Returns the `struct element' that NODE is embedded within. */
 static struct element *
 
 /* Returns the `struct element' that NODE is embedded within. */
 static struct element *
@@ -92,7 +86,7 @@ heap_node_to_element (const struct heap_node *node)
    return value.  Verifies that AUX points to aux_data. */
 static int
 compare_elements (const struct heap_node *a_, const struct heap_node *b_,
    return value.  Verifies that AUX points to aux_data. */
 static int
 compare_elements (const struct heap_node *a_, const struct heap_node *b_,
-                  const void *aux) 
+                  const void *aux)
 {
   const struct element *a = heap_node_to_element (a_);
   const struct element *b = heap_node_to_element (b_);
 {
   const struct element *a = heap_node_to_element (a_);
   const struct element *b = heap_node_to_element (b_);
@@ -103,7 +97,7 @@ compare_elements (const struct heap_node *a_, const struct heap_node *b_,
 
 /* Returns the smallest of the N integers in ARRAY. */
 static int
 
 /* Returns the smallest of the N integers in ARRAY. */
 static int
-min_int (int *array, size_t n) 
+min_int (int *array, size_t n)
 {
   int min;
   size_t i;
 {
   int min;
   size_t i;
@@ -117,25 +111,25 @@ min_int (int *array, size_t n)
 
 /* Swaps *A and *B. */
 static void
 
 /* Swaps *A and *B. */
 static void
-swap (int *a, int *b) 
+swap (int *a, int *b)
 {
   int t = *a;
   *a = *b;
   *b = t;
 }
 
 {
   int t = *a;
   *a = *b;
   *b = t;
 }
 
-/* Reverses the order of the CNT integers starting at VALUES. */
+/* Reverses the order of the N integers starting at VALUES. */
 static void
 static void
-reverse (int *values, size_t cnt)
+reverse (int *values, size_t n)
 {
   size_t i = 0;
 {
   size_t i = 0;
-  size_t j = cnt;
+  size_t j = n;
 
   while (j > i)
     swap (&values[i++], &values[--j]);
 }
 
 
   while (j > i)
     swap (&values[i++], &values[--j]);
 }
 
-/* Arranges the CNT elements in VALUES into the lexicographically
+/* Arranges the N elements in VALUES into the lexicographically
    next greater permutation.  Returns true if successful.
    If VALUES is already the lexicographically greatest
    permutation of its elements (i.e. ordered from greatest to
    next greater permutation.  Returns true if successful.
    If VALUES is already the lexicographically greatest
    permutation of its elements (i.e. ordered from greatest to
@@ -143,34 +137,34 @@ reverse (int *values, size_t cnt)
    permutation (i.e. ordered from smallest to largest) and
    returns false. */
 static bool
    permutation (i.e. ordered from smallest to largest) and
    returns false. */
 static bool
-next_permutation (int *values, size_t cnt)
+next_permutation (int *values, size_t n)
 {
 {
-  if (cnt > 0)
+  if (n > 0)
     {
     {
-      size_t i = cnt - 1;
-      while (i != 0) 
+      size_t i = n - 1;
+      while (i != 0)
         {
           i--;
           if (values[i] < values[i + 1])
             {
               size_t j;
         {
           i--;
           if (values[i] < values[i + 1])
             {
               size_t j;
-              for (j = cnt - 1; values[i] >= values[j]; j--)
+              for (j = n - 1; values[i] >= values[j]; j--)
                 continue;
               swap (values + i, values + j);
                 continue;
               swap (values + i, values + j);
-              reverse (values + (i + 1), cnt - (i + 1));
+              reverse (values + (i + 1), n - (i + 1));
               return true;
               return true;
-            } 
+            }
         }
         }
-      
-      reverse (values, cnt);
+
+      reverse (values, n);
     }
     }
-  
+
   return false;
 }
 
 /* Returns N!. */
 static unsigned int
   return false;
 }
 
 /* Returns N!. */
 static unsigned int
-factorial (unsigned int n) 
+factorial (unsigned int n)
 {
   unsigned int value = 1;
   while (n > 1)
 {
   unsigned int value = 1;
   while (n > 1)
@@ -178,30 +172,30 @@ factorial (unsigned int n)
   return value;
 }
 
   return value;
 }
 
-/* Returns the number of permutations of the CNT values in
+/* Returns the number of permutations of the N values in
    VALUES.  If VALUES contains duplicates, they must be
    adjacent. */
 static unsigned int
    VALUES.  If VALUES contains duplicates, they must be
    adjacent. */
 static unsigned int
-expected_perms (int *values, size_t cnt) 
+expected_perms (int *values, size_t n)
 {
   size_t i, j;
 {
   size_t i, j;
-  unsigned int perm_cnt;
-  
-  perm_cnt = factorial (cnt);
-  for (i = 0; i < cnt; i = j) 
+  unsigned int n_perms;
+
+  n_perms = factorial (n);
+  for (i = 0; i < n; i = j)
     {
     {
-      for (j = i + 1; j < cnt; j++)
+      for (j = i + 1; j < n; j++)
         if (values[i] != values[j])
           break;
         if (values[i] != values[j])
           break;
-      perm_cnt /= factorial (j - i);
+      n_perms /= factorial (j - i);
     }
     }
-  return perm_cnt;
+  return n_perms;
 }
 
 /* Tests whether PARTS is a K-part integer composition of N.
    Returns true if so, false otherwise. */
 static bool UNUSED
 }
 
 /* Tests whether PARTS is a K-part integer composition of N.
    Returns true if so, false otherwise. */
 static bool UNUSED
-is_k_composition (int n, int k, const int parts[]) 
+is_k_composition (int n, int k, const int parts[])
 {
   int sum;
   int i;
 {
   int sum;
   int i;
@@ -222,7 +216,7 @@ is_k_composition (int n, int k, const int parts[])
    already the greatest K-part composition of N (in which case
    PARTS is unaltered). */
 static bool
    already the greatest K-part composition of N (in which case
    PARTS is unaltered). */
 static bool
-next_k_composition (int n UNUSED, int k, int parts[]) 
+next_k_composition (int n UNUSED, int k, int parts[])
 {
   int x, i;
 
 {
   int x, i;
 
@@ -255,7 +249,7 @@ next_k_composition (int n UNUSED, int k, int parts[])
    Returns true if successful, false if the set of compositions
    has been exhausted. */
 static bool
    Returns true if successful, false if the set of compositions
    has been exhausted. */
 static bool
-next_composition (int n, int *k, int parts[]) 
+next_composition (int n, int *k, int parts[])
 {
   if (*k >= 1 && next_k_composition (n, *k, parts))
     return true;
 {
   if (*k >= 1 && next_k_composition (n, *k, parts))
     return true;
@@ -277,35 +271,35 @@ next_composition (int n, int *k, int parts[])
    order as we delete them.  Exhaustively tests every input
    permutation up to 'max_elems' elements. */
 static void
    order as we delete them.  Exhaustively tests every input
    permutation up to 'max_elems' elements. */
 static void
-test_insert_no_dups_delete_min (void) 
+test_insert_no_dups_delete_min (void)
 {
   const int max_elems = 8;
 {
   const int max_elems = 8;
-  int cnt;
+  int n;
 
 
-  for (cnt = 0; cnt <= max_elems; cnt++) 
+  for (n = 0; n <= max_elems; n++)
     {
       struct heap *h;
       struct element *elements;
       int *values;
     {
       struct heap *h;
       struct element *elements;
       int *values;
-      unsigned int permutation_cnt;
+      unsigned int n_permutations;
       int i;
 
       int i;
 
-      values = xnmalloc (cnt, sizeof *values);
-      elements = xnmalloc (cnt, sizeof *elements);
-      for (i = 0; i < cnt; i++) 
+      values = xnmalloc (n, sizeof *values);
+      elements = xnmalloc (n, sizeof *elements);
+      for (i = 0; i < n; i++)
         values[i] = i;
 
       h = heap_create (compare_elements, &aux_data);
         values[i] = i;
 
       h = heap_create (compare_elements, &aux_data);
-      permutation_cnt = 0;
-      while (permutation_cnt == 0 || next_permutation (values, cnt)) 
+      n_permutations = 0;
+      while (n_permutations == 0 || next_permutation (values, n))
         {
           int i;
 
         {
           int i;
 
-          for (i = 0; i < cnt; i++) 
+          for (i = 0; i < n; i++)
             elements[i].x = values[i];
 
           check (heap_is_empty (h));
             elements[i].x = values[i];
 
           check (heap_is_empty (h));
-          for (i = 0; i < cnt; i++) 
+          for (i = 0; i < n; i++)
             {
               heap_insert (h, &elements[i].node);
               check (heap_node_to_element (heap_minimum (h))->x
             {
               heap_insert (h, &elements[i].node);
               check (heap_node_to_element (heap_minimum (h))->x
@@ -313,15 +307,15 @@ test_insert_no_dups_delete_min (void)
               check (heap_count (h) == i + 1);
             }
 
               check (heap_count (h) == i + 1);
             }
 
-          for (i = 0; i < cnt; i++)
+          for (i = 0; i < n; i++)
             {
               check (heap_node_to_element (heap_minimum (h))->x == i);
               heap_delete (h, heap_minimum (h));
             }
           check (heap_is_empty (h));
             {
               check (heap_node_to_element (heap_minimum (h))->x == i);
               heap_delete (h, heap_minimum (h));
             }
           check (heap_is_empty (h));
-          permutation_cnt++;
+          n_permutations++;
         }
         }
-      check (permutation_cnt == factorial (cnt));
+      check (n_permutations == factorial (n));
       heap_destroy (h);
       free (values);
       free (elements);
       heap_destroy (h);
       free (values);
       free (elements);
@@ -336,56 +330,54 @@ test_insert_no_dups_delete_min (void)
    See Usenet article <87mz4utika.fsf@blp.benpfaff.org> for
    details of the algorithm used here. */
 static void
    See Usenet article <87mz4utika.fsf@blp.benpfaff.org> for
    details of the algorithm used here. */
 static void
-test_insert_with_dups_delete_min (void) 
+test_insert_with_dups_delete_min (void)
 {
   const int max_elems = 7;
 {
   const int max_elems = 7;
-  int cnt;
-
-  for (cnt = 1; cnt <= max_elems; cnt++) 
+  for (int n_elems = 1; n_elems <= max_elems; n_elems++)
     {
     {
-      unsigned int composition_cnt;
+      unsigned int n_compositions;
       int *dups;
       int *dups;
-      int unique_cnt;
+      int n_uniques;
       int *values;
       int *sorted_values;
       struct element *elements;
       int n = 0;
       int *values;
       int *sorted_values;
       struct element *elements;
       int n = 0;
-      
-      dups = xnmalloc (cnt, sizeof *dups);
-      values = xnmalloc (cnt, sizeof *values);
-      sorted_values = xnmalloc (cnt, sizeof *sorted_values);
-      elements = xnmalloc (cnt, sizeof *elements);
-
-      unique_cnt = 0;
-      composition_cnt = 0;
-      while (next_composition (cnt, &unique_cnt, dups)) 
+
+      dups = xnmalloc (n_elems, sizeof *dups);
+      values = xnmalloc (n_elems, sizeof *values);
+      sorted_values = xnmalloc (n_elems, sizeof *sorted_values);
+      elements = xnmalloc (n_elems, sizeof *elements);
+
+      n_uniques = 0;
+      n_compositions = 0;
+      while (next_composition (n_elems, &n_uniques, dups))
         {
           struct heap *h;
           int i, j, k;
         {
           struct heap *h;
           int i, j, k;
-          unsigned int permutation_cnt;
+          unsigned int n_permutations;
 
           k = 0;
 
           k = 0;
-          for (i = 0; i < unique_cnt; i++) 
+          for (i = 0; i < n_uniques; i++)
             for (j = 0; j < dups[i]; j++)
               {
                 values[k] = i;
                 sorted_values[k] = i;
                 k++;
               }
             for (j = 0; j < dups[i]; j++)
               {
                 values[k] = i;
                 sorted_values[k] = i;
                 k++;
               }
-          check (k == cnt);
+          check (k == n_elems);
 
           h = heap_create (compare_elements, &aux_data);
 
           h = heap_create (compare_elements, &aux_data);
-          permutation_cnt = 0;
-          while (permutation_cnt == 0 || next_permutation (values, cnt)) 
+          n_permutations = 0;
+          while (n_permutations == 0 || next_permutation (values, n_elems))
             {
               int min = INT_MAX;
 
             {
               int min = INT_MAX;
 
-              for (i = 0; i < cnt; i++)
+              for (i = 0; i < n_elems; i++)
                 elements[i].x = values[i];
               n++;
 
               check (heap_is_empty (h));
                 elements[i].x = values[i];
               n++;
 
               check (heap_is_empty (h));
-              for (i = 0; i < cnt; i++) 
+              for (i = 0; i < n_elems; i++)
                 {
                   heap_insert (h, &elements[i].node);
                   if (values[i] < min)
                 {
                   heap_insert (h, &elements[i].node);
                   if (values[i] < min)
@@ -394,21 +386,21 @@ test_insert_with_dups_delete_min (void)
                   check (heap_count (h) == i + 1);
                 }
 
                   check (heap_count (h) == i + 1);
                 }
 
-              for (i = 0; i < cnt; i++)
+              for (i = 0; i < n_elems; i++)
                 {
                   struct element *min = heap_node_to_element (heap_minimum (h));
                   check (min->x == sorted_values[i]);
                   heap_delete (h, heap_minimum (h));
                 }
               check (heap_is_empty (h));
                 {
                   struct element *min = heap_node_to_element (heap_minimum (h));
                   check (min->x == sorted_values[i]);
                   heap_delete (h, heap_minimum (h));
                 }
               check (heap_is_empty (h));
-              permutation_cnt++;
+              n_permutations++;
             }
             }
-          check (permutation_cnt == expected_perms (values, cnt));
+          check (n_permutations == expected_perms (values, n_elems));
           heap_destroy (h);
           heap_destroy (h);
-          
-          composition_cnt++;
+
+          n_compositions++;
         }
         }
-      check (composition_cnt == 1 << (cnt - 1));
+      check (n_compositions == 1 << (n_elems - 1));
 
       free (dups);
       free (values);
 
       free (dups);
       free (values);
@@ -420,23 +412,23 @@ test_insert_with_dups_delete_min (void)
 /* Inserts a sequence without duplicates into a heap, then
    deletes them in a different order. */
 static void
 /* Inserts a sequence without duplicates into a heap, then
    deletes them in a different order. */
 static void
-test_insert_no_dups_delete_random (void) 
+test_insert_no_dups_delete_random (void)
 {
   const int max_elems = 5;
 {
   const int max_elems = 5;
-  int cnt;
+  int n;
 
 
-  for (cnt = 0; cnt <= max_elems; cnt++) 
+  for (n = 0; n <= max_elems; n++)
     {
       struct heap *h;
       struct element *elements;
       int *insert, *delete;
     {
       struct heap *h;
       struct element *elements;
       int *insert, *delete;
-      unsigned int insert_perm_cnt;
+      unsigned int insert_n_perms;
       int i;
 
       int i;
 
-      insert = xnmalloc (cnt, sizeof *insert);
-      delete = xnmalloc (cnt, sizeof *delete);
-      elements = xnmalloc (cnt, sizeof *elements);
-      for (i = 0; i < cnt; i++) 
+      insert = xnmalloc (n, sizeof *insert);
+      delete = xnmalloc (n, sizeof *delete);
+      elements = xnmalloc (n, sizeof *elements);
+      for (i = 0; i < n; i++)
         {
           insert[i] = i;
           delete[i] = i;
         {
           insert[i] = i;
           delete[i] = i;
@@ -444,19 +436,19 @@ test_insert_no_dups_delete_random (void)
         }
 
       h = heap_create (compare_elements, &aux_data);
         }
 
       h = heap_create (compare_elements, &aux_data);
-      insert_perm_cnt = 0;
-      while (insert_perm_cnt == 0 || next_permutation (insert, cnt)) 
+      insert_n_perms = 0;
+      while (insert_n_perms == 0 || next_permutation (insert, n))
         {
         {
-          unsigned int delete_perm_cnt = 0;
+          unsigned int delete_n_perms = 0;
 
 
-          while (delete_perm_cnt == 0 || next_permutation (delete, cnt)) 
+          while (delete_n_perms == 0 || next_permutation (delete, n))
             {
               int min;
               int i;
 
               check (heap_is_empty (h));
               min = INT_MAX;
             {
               int min;
               int i;
 
               check (heap_is_empty (h));
               min = INT_MAX;
-              for (i = 0; i < cnt; i++) 
+              for (i = 0; i < n; i++)
                 {
                   heap_insert (h, &elements[insert[i]].node);
                   if (insert[i] < min)
                 {
                   heap_insert (h, &elements[insert[i]].node);
                   if (insert[i] < min)
@@ -465,21 +457,21 @@ test_insert_no_dups_delete_random (void)
                   check (heap_count (h) == i + 1);
                 }
 
                   check (heap_count (h) == i + 1);
                 }
 
-              for (i = 0; i < cnt; i++)
+              for (i = 0; i < n; i++)
                 {
                 {
-                  int new_min = min_int (delete + i + 1, cnt - i - 1);
+                  int new_min = min_int (delete + i + 1, n - i - 1);
                   heap_delete (h, &elements[delete[i]].node);
                   heap_delete (h, &elements[delete[i]].node);
-                  check (heap_count (h) == cnt - i - 1);
+                  check (heap_count (h) == n - i - 1);
                   if (!heap_is_empty (h))
                     check (heap_node_to_element (heap_minimum (h))->x == new_min);
                 }
               check (heap_is_empty (h));
                   if (!heap_is_empty (h))
                     check (heap_node_to_element (heap_minimum (h))->x == new_min);
                 }
               check (heap_is_empty (h));
-              delete_perm_cnt++;
+              delete_n_perms++;
             }
             }
-          check (delete_perm_cnt == factorial (cnt));
-          insert_perm_cnt++; 
+          check (delete_n_perms == factorial (n));
+          insert_n_perms++;
         }
         }
-      check (insert_perm_cnt == factorial (cnt));
+      check (insert_n_perms == factorial (n));
       heap_destroy (h);
       free (insert);
       free (delete);
       heap_destroy (h);
       free (insert);
       free (delete);
@@ -487,38 +479,38 @@ test_insert_no_dups_delete_random (void)
     }
 }
 
     }
 }
 
-/* Inserts a set of values into a heap, then changes them to a 
+/* Inserts a set of values into a heap, then changes them to a
    different random set of values, then removes them in sorted
    order. */
 static void
    different random set of values, then removes them in sorted
    order. */
 static void
-test_inc_dec (void) 
+test_inc_dec (void)
 {
   const int max_elems = 8;
 {
   const int max_elems = 8;
-  int cnt;
+  int n;
 
 
-  for (cnt = 0; cnt <= max_elems; cnt++) 
+  for (n = 0; n <= max_elems; n++)
     {
       struct heap *h;
       struct element *elements;
       int *insert, *delete;
     {
       struct heap *h;
       struct element *elements;
       int *insert, *delete;
-      unsigned int insert_perm_cnt;
+      unsigned int insert_n_perms;
       int i;
 
       int i;
 
-      insert = xnmalloc (cnt, sizeof *insert);
-      delete = xnmalloc (cnt, sizeof *delete);
-      elements = xnmalloc (cnt, sizeof *elements);
-      for (i = 0; i < cnt; i++) 
+      insert = xnmalloc (n, sizeof *insert);
+      delete = xnmalloc (n, sizeof *delete);
+      elements = xnmalloc (n, sizeof *elements);
+      for (i = 0; i < n; i++)
         insert[i] = i;
 
       h = heap_create (compare_elements, &aux_data);
         insert[i] = i;
 
       h = heap_create (compare_elements, &aux_data);
-      insert_perm_cnt = 0;
-      while (insert_perm_cnt == 0 || next_permutation (insert, cnt)) 
+      insert_n_perms = 0;
+      while (insert_n_perms == 0 || next_permutation (insert, n))
         {
         {
-          for (i = 0; i < cnt; i++) 
+          for (i = 0; i < n; i++)
             elements[i].x = insert[i];
 
           check (heap_is_empty (h));
             elements[i].x = insert[i];
 
           check (heap_is_empty (h));
-          for (i = 0; i < cnt; i++) 
+          for (i = 0; i < n; i++)
             {
               int new_min = min_int (insert, i + 1);
               heap_insert (h, &elements[i].node);
             {
               int new_min = min_int (insert, i + 1);
               heap_insert (h, &elements[i].node);
@@ -526,32 +518,28 @@ test_inc_dec (void)
               check (heap_count (h) == i + 1);
             }
 
               check (heap_count (h) == i + 1);
             }
 
-          for (i = 0; i < cnt; i++)
+          for (i = 0; i < n; i++)
             delete[i] = insert[i];
             delete[i] = insert[i];
-          for (i = 0; i < cnt; i++) 
+          for (i = 0; i < n; i++)
             {
             {
-              int old_value, old_min, new_min;
-              old_min = min_int (delete, cnt);
-              old_value = delete[i];
-              elements[i].x = delete[i] = rand () % (cnt + 2) - 1;
-              new_min = min_int (delete, cnt);
+              elements[i].x = delete[i] = rand () % (n + 2) - 1;
               heap_changed (h, &elements[i].node);
               check (heap_node_to_element (heap_minimum (h))->x
               heap_changed (h, &elements[i].node);
               check (heap_node_to_element (heap_minimum (h))->x
-                     == min_int (delete, cnt));
+                     == min_int (delete, n));
             }
 
             }
 
-          for (i = 0; i < cnt; i++)
+          for (i = 0; i < n; i++)
             {
             {
-              int new_min = min_int (delete + i + 1, cnt - i - 1);
+              int new_min = min_int (delete + i + 1, n - i - 1);
               heap_delete (h, &elements[i].node);
               heap_delete (h, &elements[i].node);
-              check (heap_count (h) == cnt - i - 1);
+              check (heap_count (h) == n - i - 1);
               if (!heap_is_empty (h))
                 check (heap_node_to_element (heap_minimum (h))->x == new_min);
             }
           check (heap_is_empty (h));
               if (!heap_is_empty (h))
                 check (heap_node_to_element (heap_minimum (h))->x == new_min);
             }
           check (heap_is_empty (h));
-          insert_perm_cnt++; 
+          insert_n_perms++;
         }
         }
-      check (insert_perm_cnt == factorial (cnt));
+      check (insert_n_perms == factorial (n));
       heap_destroy (h);
       free (insert);
       free (delete);
       heap_destroy (h);
       free (insert);
       free (delete);
@@ -562,87 +550,77 @@ test_inc_dec (void)
 /* Performs a random sequence of insertions and deletions in a
    heap. */
 static void
 /* Performs a random sequence of insertions and deletions in a
    heap. */
 static void
-test_random_insert_delete (void) 
+test_random_insert_delete (void)
 {
   const int max_elems = 64;
   const int num_actions = 250000;
   struct heap *h;
   int *values;
   struct element *elements;
 {
   const int max_elems = 64;
   const int num_actions = 250000;
   struct heap *h;
   int *values;
   struct element *elements;
-  int cnt;
+  int n;
   int insert_chance;
   int i;
 
   values = xnmalloc (max_elems, sizeof *values);
   elements = xnmalloc (max_elems, sizeof *elements);
   int insert_chance;
   int i;
 
   values = xnmalloc (max_elems, sizeof *values);
   elements = xnmalloc (max_elems, sizeof *elements);
-  cnt = 0;
+  n = 0;
   insert_chance = 5;
 
   h = heap_create (compare_elements, &aux_data);
   insert_chance = 5;
 
   h = heap_create (compare_elements, &aux_data);
-  for (i = 0; i < num_actions; i++) 
+  for (i = 0; i < num_actions; i++)
     {
       enum { INSERT, DELETE } action;
 
     {
       enum { INSERT, DELETE } action;
 
-      if (cnt == 0) 
+      if (n == 0)
         {
           action = INSERT;
           if (insert_chance < 9)
         {
           action = INSERT;
           if (insert_chance < 9)
-            insert_chance++; 
+            insert_chance++;
         }
         }
-      else if (cnt == max_elems) 
+      else if (n == max_elems)
         {
           action = DELETE;
           if (insert_chance > 0)
         {
           action = DELETE;
           if (insert_chance > 0)
-            insert_chance--; 
+            insert_chance--;
         }
       else
         action = rand () % 10 < insert_chance ? INSERT : DELETE;
 
         }
       else
         action = rand () % 10 < insert_chance ? INSERT : DELETE;
 
-      if (action == INSERT) 
+      if (action == INSERT)
         {
           int new_value;
         {
           int new_value;
-          int old_min;
 
           new_value = rand () % max_elems;
 
           new_value = rand () % max_elems;
-          values[cnt] = new_value;
-          elements[cnt].x = new_value;
+          values[n] = new_value;
+          elements[n].x = new_value;
 
 
-          heap_insert (h, &elements[cnt].node);
+          heap_insert (h, &elements[n].node);
 
 
-          old_min = min_int (values, cnt);
-
-          cnt++;
+          n++;
         }
       else if (action == DELETE)
         {
           int del_idx;
         }
       else if (action == DELETE)
         {
           int del_idx;
-          int del_value;
-          int old_min, new_min;
-
-          old_min = min_int (values, cnt);
 
 
-          del_idx = rand () % cnt;
-          del_value = values[del_idx];
+          del_idx = rand () % n;
           heap_delete (h, &elements[del_idx].node);
 
           heap_delete (h, &elements[del_idx].node);
 
-          cnt--;
-          if (del_idx != cnt) 
+          n--;
+          if (del_idx != n)
             {
             {
-              values[del_idx] = values[cnt];
-              elements[del_idx] = elements[cnt];
+              values[del_idx] = values[n];
+              elements[del_idx] = elements[n];
               heap_moved (h, &elements[del_idx].node);
             }
               heap_moved (h, &elements[del_idx].node);
             }
-
-          new_min = min_int (values, cnt);
         }
       else
         abort ();
 
         }
       else
         abort ();
 
-      check (heap_count (h) == cnt);
-      check (heap_is_empty (h) == (cnt == 0));
-      if (cnt > 0)
+      check (heap_count (h) == n);
+      check (heap_is_empty (h) == (n == 0));
+      if (n > 0)
         check (heap_node_to_element (heap_minimum (h))->x
         check (heap_node_to_element (heap_minimum (h))->x
-               == min_int (values, cnt));
+               == min_int (values, n));
     }
   heap_destroy (h);
   free (elements);
     }
   heap_destroy (h);
   free (elements);
@@ -651,28 +629,74 @@ test_random_insert_delete (void)
 \f
 /* Main program. */
 
 \f
 /* Main program. */
 
-/* Runs TEST_FUNCTION and prints a message about NAME. */
-static void
-run_test (void (*test_function) (void), const char *name) 
-{
-  test_name = name;
-  putchar ('.');
-  fflush (stdout);
-  test_function ();
-}
+struct test
+  {
+    const char *name;
+    const char *description;
+    void (*function) (void);
+  };
+
+static const struct test tests[] =
+  {
+    {
+      "insert-no-dups-delete-min",
+      "insert (no dups), delete minimum values",
+      test_insert_no_dups_delete_min
+    },
+    {
+      "insert-with-dups-delete-min",
+      "insert with dups, delete minimum values",
+      test_insert_with_dups_delete_min
+    },
+    {
+      "insert-no-dups-delete-random",
+      "insert (no dups), delete in random order",
+      test_insert_no_dups_delete_random
+    },
+    {
+      "inc-dec",
+      "increase and decrease values",
+      test_inc_dec
+    },
+    {
+      "random-insert-delete",
+      "random insertions and deletions",
+      test_random_insert_delete
+    }
+  };
+
+enum { N_TESTS = sizeof tests / sizeof *tests };
 
 int
 
 int
-main (void) 
+main (int argc, char *argv[])
 {
 {
-  run_test (test_insert_no_dups_delete_min,
-            "insert (no dups), delete minimum values");
-  run_test (test_insert_with_dups_delete_min,
-            "insert with dups, delete minimum values");
-  run_test (test_insert_no_dups_delete_random,
-            "insert (no dups), delete in random order");
-  run_test (test_inc_dec, "increase and decrease values");
-  run_test (test_random_insert_delete, "random insertions and deletions");
-  putchar ('\n');
-
-  return 0;
+  int i;
+
+  if (argc != 2)
+    {
+      fprintf (stderr, "exactly one argument required; use --help for help\n");
+      return EXIT_FAILURE;
+    }
+  else if (!strcmp (argv[1], "--help"))
+    {
+      printf ("%s: test heap library\n"
+              "usage: %s TEST-NAME\n"
+              "where TEST-NAME is one of the following:\n",
+              argv[0], argv[0]);
+      for (i = 0; i < N_TESTS; i++)
+        printf ("  %s\n    %s\n", tests[i].name, tests[i].description);
+      return 0;
+    }
+  else
+    {
+      for (i = 0; i < N_TESTS; i++)
+        if (!strcmp (argv[1], tests[i].name))
+          {
+            tests[i].function ();
+            return 0;
+          }
+
+      fprintf (stderr, "unknown test %s; use --help for help\n", argv[1]);
+      return EXIT_FAILURE;
+    }
 }
 }