Add list of unimplemented features.
[pspp] / tests / libpspp / abt-test.c
index ce857b050dd1cdbd4147cbf6e623f309ac0bc297..177e8f9108c3027b9085445642ac3c0843518f63 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, 2011 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 abt_* routines defined in
    abt.c.  This test program aims to be as comprehensive as
 
 /* This is a test program for the abt_* routines defined in
    abt.c.  This test program aims to be as comprehensive as
@@ -28,7 +26,6 @@
 
 #include <libpspp/abt.h>
 
 
 #include <libpspp/abt.h>
 
-#include <assert.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdio.h>
 
 #include <libpspp/compiler.h>
 \f
 
 #include <libpspp/compiler.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 ();
     }
 }
@@ -77,9 +70,9 @@ xalloc_die (void)
 
 /* Allocates and returns N bytes of memory. */
 static void *
 
 /* Allocates and returns N bytes of memory. */
 static void *
-xmalloc (size_t n) 
+xmalloc (size_t n)
 {
 {
-  if (n != 0) 
+  if (n != 0)
     {
       void *p = malloc (n);
       if (p == NULL)
     {
       void *p = malloc (n);
       if (p == NULL)
@@ -92,7 +85,7 @@ xmalloc (size_t n)
 }
 
 static void *
 }
 
 static void *
-xmemdup (const void *p, size_t n) 
+xmemdup (const void *p, size_t n)
 {
   void *q = xmalloc (n);
   memcpy (q, p, n);
 {
   void *q = xmalloc (n);
   memcpy (q, p, n);
@@ -101,7 +94,7 @@ xmemdup (const void *p, size_t n)
 
 /* Allocates and returns N * M bytes of memory. */
 static void *
 
 /* Allocates and returns N * M bytes of memory. */
 static void *
-xnmalloc (size_t n, size_t m) 
+xnmalloc (size_t n, size_t m)
 {
   if ((size_t) -1 / m <= n)
     xalloc_die ();
 {
   if ((size_t) -1 / m <= n)
     xalloc_die ();
@@ -125,14 +118,14 @@ static int aux_data;
 static struct element *
 abt_node_to_element (const struct abt_node *node)
 {
 static struct element *
 abt_node_to_element (const struct abt_node *node)
 {
-  return abt_data (node, struct element, node);
+  return ABT_DATA (node, struct element, node);
 }
 
 /* Compares the `x' values in A and B and returns a strcmp-type
    return value.  Verifies that AUX points to aux_data. */
 static int
 compare_elements (const struct abt_node *a_, const struct abt_node *b_,
 }
 
 /* Compares the `x' values in A and B and returns a strcmp-type
    return value.  Verifies that AUX points to aux_data. */
 static int
 compare_elements (const struct abt_node *a_, const struct abt_node *b_,
-                  const void *aux) 
+                  const void *aux)
 {
   const struct element *a = abt_node_to_element (a_);
   const struct element *b = abt_node_to_element (b_);
 {
   const struct element *a = abt_node_to_element (a_);
   const struct element *b = abt_node_to_element (b_);
@@ -144,25 +137,22 @@ compare_elements (const struct abt_node *a_, const struct abt_node *b_,
 /* Recalculates the count for NODE's subtree by adding up the
    counts for its LEFT and RIGHT child subtrees. */
 static void
 /* Recalculates the count for NODE's subtree by adding up the
    counts for its LEFT and RIGHT child subtrees. */
 static void
-reaugment_elements (struct abt_node *node_,
-                    const struct abt_node *left,
-                    const struct abt_node *right,
-                    const void *aux) 
+reaugment_elements (struct abt_node *node_, const void *aux)
 {
   struct element *node = abt_node_to_element (node_);
 
   check (aux == &aux_data);
 
   node->count = 1;
 {
   struct element *node = abt_node_to_element (node_);
 
   check (aux == &aux_data);
 
   node->count = 1;
-  if (left != NULL)
-    node->count += abt_node_to_element (left)->count;
-  if (right != NULL)
-    node->count += abt_node_to_element (right)->count;
+  if (node->node.down[0] != NULL)
+    node->count += abt_node_to_element (node->node.down[0])->count;
+  if (node->node.down[1] != NULL)
+    node->count += abt_node_to_element (node->node.down[1])->count;
 }
 
 /* Compares A and B and returns a strcmp-type return value. */
 static int
 }
 
 /* Compares A and B and returns a strcmp-type return value. */
 static int
-compare_ints_noaux (const void *a_, const void *b_) 
+compare_ints_noaux (const void *a_, const void *b_)
 {
   const int *a = a_;
   const int *b = b_;
 {
   const int *a = a_;
   const int *b = b_;
@@ -172,25 +162,25 @@ compare_ints_noaux (const void *a_, const void *b_)
 
 /* 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
@@ -198,34 +188,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)
@@ -233,19 +223,19 @@ factorial (unsigned int n)
   return value;
 }
 
   return value;
 }
 
-/* Randomly shuffles the CNT elements in ARRAY, each of which is
+/* Randomly shuffles the N elements in ARRAY, each of which is
    SIZE bytes in size. */
 static void
    SIZE bytes in size. */
 static void
-random_shuffle (void *array_, size_t cnt, size_t size)
+random_shuffle (void *array_, size_t n, size_t size)
 {
   char *array = array_;
   char *tmp = xmalloc (size);
   size_t i;
 
 {
   char *array = array_;
   char *tmp = xmalloc (size);
   size_t i;
 
-  for (i = 0; i < cnt; i++) 
+  for (i = 0; i < n; i++)
     {
     {
-      size_t j = rand () % (cnt - i) + i;
-      if (i != j) 
+      size_t j = rand () % (n - i) + i;
+      if (i != j)
         {
           memcpy (tmp, array + j * size, size);
           memcpy (array + j * size, array + i * size, size);
         {
           memcpy (tmp, array + j * size, size);
           memcpy (array + j * size, array + i * size, size);
@@ -259,16 +249,16 @@ random_shuffle (void *array_, size_t cnt, size_t size)
 /* Finds and returns the element in ABT that is in the given
    0-based POSITION in in-order. */
 static struct element *
 /* Finds and returns the element in ABT that is in the given
    0-based POSITION in in-order. */
 static struct element *
-find_by_position (struct abt *abt, int position) 
+find_by_position (struct abt *abt, int position)
 {
   struct abt_node *p;
 {
   struct abt_node *p;
-  for (p = abt->root; p != NULL; ) 
+  for (p = abt->root; p != NULL;)
     {
       int p_pos = p->down[0] ? abt_node_to_element (p->down[0])->count : 0;
       if (position == p_pos)
         return abt_node_to_element (p);
       else if (position < p_pos)
     {
       int p_pos = p->down[0] ? abt_node_to_element (p->down[0])->count : 0;
       if (position == p_pos)
         return abt_node_to_element (p);
       else if (position < p_pos)
-        p = p->down[0]; 
+        p = p->down[0];
       else
         {
           p = p->down[1];
       else
         {
           p = p->down[1];
@@ -281,11 +271,11 @@ find_by_position (struct abt *abt, int position)
 /* Checks that all the augmentations are correct in the subtree
    rooted at P.  Returns the number of nodes in the subtree. */
 static int
 /* Checks that all the augmentations are correct in the subtree
    rooted at P.  Returns the number of nodes in the subtree. */
 static int
-check_augmentations (struct abt_node *p_) 
+check_augmentations (struct abt_node *p_)
 {
   if (p_ == NULL)
     return 0;
 {
   if (p_ == NULL)
     return 0;
-  else 
+  else
     {
       struct element *p = abt_node_to_element (p_);
       int left_count = check_augmentations (p->node.down[0]);
     {
       struct element *p = abt_node_to_element (p_);
       int left_count = check_augmentations (p->node.down[0]);
@@ -298,9 +288,9 @@ check_augmentations (struct abt_node *p_)
 
 /* Check that the levels are correct in the subtree rooted at P. */
 static void
 
 /* Check that the levels are correct in the subtree rooted at P. */
 static void
-check_levels (struct abt_node *p) 
+check_levels (struct abt_node *p)
 {
 {
-  if (p != NULL) 
+  if (p != NULL)
     {
       int i, j;
 
     {
       int i, j;
 
@@ -308,11 +298,11 @@ check_levels (struct abt_node *p)
       check_levels (p->down[1]);
 
       check (p->level >= 1);
       check_levels (p->down[1]);
 
       check (p->level >= 1);
-      if (p->level > 1) 
+      if (p->level > 1)
         {
           struct abt_node *q = p->down[1];
           check (q != NULL);
         {
           struct abt_node *q = p->down[1];
           check (q != NULL);
-          check (q->level == p->level || q->level == p->level - 1); 
+          check (q->level == p->level || q->level == p->level - 1);
         }
 
       for (i = 0; i < 2; i++)
         }
 
       for (i = 0; i < 2; i++)
@@ -323,25 +313,25 @@ check_levels (struct abt_node *p)
     }
 }
 
     }
 }
 
-/* Checks that ABT contains the CNT ints in DATA, that its
+/* Checks that ABT contains the N ints in DATA, that its
    structure is correct, and that certain operations on ABT
    produce the expected results. */
 static void
    structure is correct, and that certain operations on ABT
    produce the expected results. */
 static void
-check_abt (struct abt *abt, const int data[], size_t cnt) 
+check_abt (struct abt *abt, const int data[], size_t n)
 {
   struct element e;
   size_t i;
   int *order;
 
 {
   struct element e;
   size_t i;
   int *order;
 
-  order = xmemdup (data, cnt * sizeof *data);
-  qsort (order, cnt, sizeof *order, compare_ints_noaux);
+  order = xmemdup (data, n * sizeof *data);
+  qsort (order, n, sizeof *order, compare_ints_noaux);
 
 
-  if (abt->compare != NULL) 
+  if (abt->compare != NULL)
     {
     {
-      for (i = 0; i < cnt; i++)
+      for (i = 0; i < n; i++)
         {
           struct abt_node *p;
         {
           struct abt_node *p;
-      
+
           e.data = data[i];
           if (rand () % 2)
             p = abt_find (abt, &e.node);
           e.data = data[i];
           if (rand () % 2)
             p = abt_find (abt, &e.node);
@@ -358,34 +348,35 @@ check_abt (struct abt *abt, const int data[], size_t cnt)
 
   check_levels (abt->root);
   check_augmentations (abt->root);
 
   check_levels (abt->root);
   check_augmentations (abt->root);
-  for (i = 0; i < cnt; i++)
+  for (i = 0; i < n; i++)
     check (find_by_position (abt, i)->data == order[i]);
 
     check (find_by_position (abt, i)->data == order[i]);
 
-  if (cnt == 0) 
+  if (n == 0)
     {
       check (abt_first (abt) == NULL);
       check (abt_last (abt) == NULL);
       check (abt_next (abt, NULL) == NULL);
       check (abt_prev (abt, NULL) == NULL);
     }
     {
       check (abt_first (abt) == NULL);
       check (abt_last (abt) == NULL);
       check (abt_next (abt, NULL) == NULL);
       check (abt_prev (abt, NULL) == NULL);
     }
-  else 
+  else
     {
       struct abt_node *p;
     {
       struct abt_node *p;
-  
-      for (p = abt_first (abt), i = 0; i < cnt; p = abt_next (abt, p), i++)
+
+      for (p = abt_first (abt), i = 0; i < n; p = abt_next (abt, p), i++)
         check (abt_node_to_element (p)->data == order[i]);
       check (p == NULL);
 
         check (abt_node_to_element (p)->data == order[i]);
       check (p == NULL);
 
-      for (p = abt_last (abt), i = 0; i < cnt; p = abt_prev (abt, p), i++)
-        check (abt_node_to_element (p)->data == order[cnt - i - 1]);
+      for (p = abt_last (abt), i = 0; i < n; p = abt_prev (abt, p), i++)
+        check (abt_node_to_element (p)->data == order[n - i - 1]);
       check (p == NULL);
     }
       check (p == NULL);
     }
+  check (abt_is_empty (abt) == (n == 0));
 
   free (order);
 }
 
 /* Ways that nodes can be inserted. */
 
   free (order);
 }
 
 /* Ways that nodes can be inserted. */
-enum insertion_method 
+enum insertion_method
   {
     INSERT,             /* With abt_insert. */
     INSERT_AFTER,       /* With abt_insert_after. */
   {
     INSERT,             /* With abt_insert. */
     INSERT_AFTER,       /* With abt_insert_after. */
@@ -395,39 +386,39 @@ enum insertion_method
 /* Inserts INSERT into ABT with the given METHOD. */
 static void
 insert_node (struct abt *abt, struct element *insert,
 /* Inserts INSERT into ABT with the given METHOD. */
 static void
 insert_node (struct abt *abt, struct element *insert,
-             enum insertion_method method) 
+             enum insertion_method method)
 {
 {
-  if (method == INSERT) 
+  if (method == INSERT)
     check (abt_insert (abt, &insert->node) == NULL);
     check (abt_insert (abt, &insert->node) == NULL);
-  else 
+  else
     {
       struct abt_node *p = abt->root;
       int dir = 0;
       if (p != NULL)
     {
       struct abt_node *p = abt->root;
       int dir = 0;
       if (p != NULL)
-        for (;;) 
+        for (;;)
           {
             dir = insert->data > abt_node_to_element (p)->data;
             if (p->down[dir] == NULL)
               break;
             p = p->down[dir];
           }
           {
             dir = insert->data > abt_node_to_element (p)->data;
             if (p->down[dir] == NULL)
               break;
             p = p->down[dir];
           }
-      if (method == INSERT_AFTER) 
+      if (method == INSERT_AFTER)
         {
           if (p != NULL && (dir != 1 || p->down[1] != NULL))
             p = abt_prev (abt, p);
         {
           if (p != NULL && (dir != 1 || p->down[1] != NULL))
             p = abt_prev (abt, p);
-          abt_insert_after (abt, p, &insert->node); 
+          abt_insert_after (abt, p, &insert->node);
         }
       else
         {
           if (p != NULL && (dir != 0 || p->down[0] != NULL))
             p = abt_next (abt, p);
         }
       else
         {
           if (p != NULL && (dir != 0 || p->down[0] != NULL))
             p = abt_next (abt, p);
-          abt_insert_before (abt, p, &insert->node); 
+          abt_insert_before (abt, p, &insert->node);
         }
     }
 }
 
 
         }
     }
 }
 
 
-/* Inserts the CNT values from 0 to CNT - 1 (inclusive) into an
+/* Inserts the N values from 0 to N - 1 (inclusive) into an
    ABT in the order specified by INSERTIONS using the given
    METHOD, then deletes them in the order specified by DELETIONS,
    checking the ABT's contents for correctness after each
    ABT in the order specified by INSERTIONS using the given
    METHOD, then deletes them in the order specified by DELETIONS,
    checking the ABT's contents for correctness after each
@@ -436,85 +427,85 @@ static void
 do_test_insert_delete (enum insertion_method method,
                        const int insertions[],
                        const int deletions[],
 do_test_insert_delete (enum insertion_method method,
                        const int insertions[],
                        const int deletions[],
-                       size_t cnt) 
+                       size_t n)
 {
   struct element *elements;
   struct abt abt;
   size_t i;
 {
   struct element *elements;
   struct abt abt;
   size_t i;
-  
-  elements = xnmalloc (cnt, sizeof *elements);
-  for (i = 0; i < cnt; i++)
+
+  elements = xnmalloc (n, sizeof *elements);
+  for (i = 0; i < n; i++)
     elements[i].data = i;
 
   abt_init (&abt, method == INSERT ? compare_elements : NULL,
             reaugment_elements, &aux_data);
   check_abt (&abt, NULL, 0);
     elements[i].data = i;
 
   abt_init (&abt, method == INSERT ? compare_elements : NULL,
             reaugment_elements, &aux_data);
   check_abt (&abt, NULL, 0);
-  for (i = 0; i < cnt; i++)
+  for (i = 0; i < n; i++)
     {
       insert_node (&abt, &elements[insertions[i]], method);
       check_abt (&abt, insertions, i + 1);
     }
     {
       insert_node (&abt, &elements[insertions[i]], method);
       check_abt (&abt, insertions, i + 1);
     }
-  for (i = 0; i < cnt; i++)
+  for (i = 0; i < n; i++)
     {
       abt_delete (&abt, &elements[deletions[i]].node);
     {
       abt_delete (&abt, &elements[deletions[i]].node);
-      check_abt (&abt, deletions + i + 1, cnt - i - 1);
+      check_abt (&abt, deletions + i + 1, n - i - 1);
     }
 
   free (elements);
 }
 
     }
 
   free (elements);
 }
 
-/* Inserts the CNT values from 0 to CNT - 1 (inclusive) into an
+/* Inserts the N values from 0 to N - 1 (inclusive) into an
    ABT in the order specified by INSERTIONS, then deletes them in
    the order specified by DELETIONS, checking the ABT's contents
    for correctness after each operation. */
 static void
 test_insert_delete (const int insertions[],
                     const int deletions[],
    ABT in the order specified by INSERTIONS, then deletes them in
    the order specified by DELETIONS, checking the ABT's contents
    for correctness after each operation. */
 static void
 test_insert_delete (const int insertions[],
                     const int deletions[],
-                    size_t cnt) 
+                    size_t n)
 {
 {
-  do_test_insert_delete (INSERT, insertions, deletions, cnt);
-  do_test_insert_delete (INSERT_AFTER, insertions, deletions, cnt);
-  do_test_insert_delete (INSERT_BEFORE, insertions, deletions, cnt);
+  do_test_insert_delete (INSERT, insertions, deletions, n);
+  do_test_insert_delete (INSERT_AFTER, insertions, deletions, n);
+  do_test_insert_delete (INSERT_BEFORE, insertions, deletions, n);
 }
 \f
 /* Inserts values into an ABT in each possible order, then
    removes them in each possible order, up to a specified maximum
    size. */
 static void
 }
 \f
 /* Inserts values into an ABT in each possible order, then
    removes them in each possible order, up to a specified maximum
    size. */
 static void
-test_insert_any_remove_any (void) 
+test_insert_any_remove_any (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++)
     {
       int *insertions, *deletions;
     {
       int *insertions, *deletions;
-      unsigned int ins_perm_cnt;
+      unsigned int ins_n_perms;
       int i;
 
       int i;
 
-      insertions = xnmalloc (cnt, sizeof *insertions);
-      deletions = xnmalloc (cnt, sizeof *deletions);
-      for (i = 0; i < cnt; i++) 
+      insertions = xnmalloc (n, sizeof *insertions);
+      deletions = xnmalloc (n, sizeof *deletions);
+      for (i = 0; i < n; i++)
         insertions[i] = i;
 
         insertions[i] = i;
 
-      for (ins_perm_cnt = 0;
-           ins_perm_cnt == 0 || next_permutation (insertions, cnt);
-           ins_perm_cnt++) 
+      for (ins_n_perms = 0;
+           ins_n_perms == 0 || next_permutation (insertions, n);
+           ins_n_perms++)
         {
         {
-          unsigned int del_perm_cnt;
+          unsigned int del_n_perms;
           int i;
 
           int i;
 
-          for (i = 0; i < cnt; i++) 
+          for (i = 0; i < n; i++)
             deletions[i] = i;
 
             deletions[i] = i;
 
-          for (del_perm_cnt = 0;
-               del_perm_cnt == 0 || next_permutation (deletions, cnt);
-               del_perm_cnt++) 
-            test_insert_delete (insertions, deletions, cnt);
+          for (del_n_perms = 0;
+               del_n_perms == 0 || next_permutation (deletions, n);
+               del_n_perms++)
+            test_insert_delete (insertions, deletions, n);
 
 
-          check (del_perm_cnt == factorial (cnt));
+          check (del_n_perms == factorial (n));
         }
         }
-      check (ins_perm_cnt == factorial (cnt));
+      check (ins_n_perms == factorial (n));
 
       free (insertions);
       free (deletions);
 
       free (insertions);
       free (deletions);
@@ -525,26 +516,26 @@ test_insert_any_remove_any (void)
    removes them in the same order, up to a specified maximum
    size. */
 static void
    removes them in the same order, up to a specified maximum
    size. */
 static void
-test_insert_any_remove_same (void) 
+test_insert_any_remove_same (void)
 {
   const int max_elems = 7;
 {
   const int max_elems = 7;
-  int cnt;
+  int n;
 
 
-  for (cnt = 0; cnt <= max_elems; cnt++) 
+  for (n = 0; n <= max_elems; n++)
     {
       int *values;
     {
       int *values;
-      unsigned int permutation_cnt;
+      unsigned int n_permutations;
       int i;
 
       int i;
 
-      values = xnmalloc (cnt, sizeof *values);
-      for (i = 0; i < cnt; i++) 
+      values = xnmalloc (n, sizeof *values);
+      for (i = 0; i < n; i++)
         values[i] = i;
 
         values[i] = i;
 
-      for (permutation_cnt = 0;
-           permutation_cnt == 0 || next_permutation (values, cnt);
-           permutation_cnt++)
-        test_insert_delete (values, values, cnt);
-      check (permutation_cnt == factorial (cnt));
+      for (n_permutations = 0;
+           n_permutations == 0 || next_permutation (values, n);
+           n_permutations++)
+        test_insert_delete (values, values, n);
+      check (n_permutations == factorial (n));
 
       free (values);
     }
 
       free (values);
     }
@@ -554,32 +545,32 @@ test_insert_any_remove_same (void)
    removes them in reverse order, up to a specified maximum
    size. */
 static void
    removes them in reverse order, up to a specified maximum
    size. */
 static void
-test_insert_any_remove_reverse (void) 
+test_insert_any_remove_reverse (void)
 {
   const int max_elems = 7;
 {
   const int max_elems = 7;
-  int cnt;
+  int n;
 
 
-  for (cnt = 0; cnt <= max_elems; cnt++) 
+  for (n = 0; n <= max_elems; n++)
     {
       int *insertions, *deletions;
     {
       int *insertions, *deletions;
-      unsigned int permutation_cnt;
+      unsigned int n_permutations;
       int i;
 
       int i;
 
-      insertions = xnmalloc (cnt, sizeof *insertions);
-      deletions = xnmalloc (cnt, sizeof *deletions);
-      for (i = 0; i < cnt; i++) 
+      insertions = xnmalloc (n, sizeof *insertions);
+      deletions = xnmalloc (n, sizeof *deletions);
+      for (i = 0; i < n; i++)
         insertions[i] = i;
 
         insertions[i] = i;
 
-      for (permutation_cnt = 0;
-           permutation_cnt == 0 || next_permutation (insertions, cnt);
-           permutation_cnt++) 
+      for (n_permutations = 0;
+           n_permutations == 0 || next_permutation (insertions, n);
+           n_permutations++)
         {
         {
-          memcpy (deletions, insertions, sizeof *insertions * cnt);
-          reverse (deletions, cnt);
-          
-          test_insert_delete (insertions, deletions, cnt); 
+          memcpy (deletions, insertions, sizeof *insertions * n);
+          reverse (deletions, n);
+
+          test_insert_delete (insertions, deletions, n);
         }
         }
-      check (permutation_cnt == factorial (cnt));
+      check (n_permutations == factorial (n));
 
       free (insertions);
       free (deletions);
 
       free (insertions);
       free (deletions);
@@ -588,31 +579,31 @@ test_insert_any_remove_reverse (void)
 
 /* Inserts and removes values in an ABT in random orders. */
 static void
 
 /* Inserts and removes values in an ABT in random orders. */
 static void
-test_random_sequence (void) 
+test_random_sequence (void)
 {
   const int max_elems = 128;
   const int max_trials = 8;
 {
   const int max_elems = 128;
   const int max_trials = 8;
-  int cnt;
+  int n;
 
 
-  for (cnt = 0; cnt <= max_elems; cnt += 2) 
+  for (n = 0; n <= max_elems; n += 2)
     {
       int *insertions, *deletions;
       int trial;
       int i;
 
     {
       int *insertions, *deletions;
       int trial;
       int i;
 
-      insertions = xnmalloc (cnt, sizeof *insertions);
-      deletions = xnmalloc (cnt, sizeof *deletions);
-      for (i = 0; i < cnt; i++) 
+      insertions = xnmalloc (n, sizeof *insertions);
+      deletions = xnmalloc (n, sizeof *deletions);
+      for (i = 0; i < n; i++)
         insertions[i] = i;
         insertions[i] = i;
-      for (i = 0; i < cnt; i++) 
+      for (i = 0; i < n; i++)
         deletions[i] = i;
 
         deletions[i] = i;
 
-      for (trial = 0; trial < max_trials; trial++) 
+      for (trial = 0; trial < max_trials; trial++)
         {
         {
-          random_shuffle (insertions, cnt, sizeof *insertions);
-          random_shuffle (deletions, cnt, sizeof *deletions);
-      
-          test_insert_delete (insertions, deletions, cnt); 
+          random_shuffle (insertions, n, sizeof *insertions);
+          random_shuffle (deletions, n, sizeof *deletions);
+
+          test_insert_delete (insertions, deletions, n);
         }
 
       free (insertions);
         }
 
       free (insertions);
@@ -622,7 +613,7 @@ test_random_sequence (void)
 
 /* Inserts elements into an ABT in ascending order. */
 static void
 
 /* Inserts elements into an ABT in ascending order. */
 static void
-test_insert_ordered (void) 
+test_insert_ordered (void)
 {
   const int max_elems = 1024;
   struct element *elements;
 {
   const int max_elems = 1024;
   struct element *elements;
@@ -633,7 +624,7 @@ test_insert_ordered (void)
   abt_init (&abt, compare_elements, reaugment_elements, &aux_data);
   elements = xnmalloc (max_elems, sizeof *elements);
   values = xnmalloc (max_elems, sizeof *values);
   abt_init (&abt, compare_elements, reaugment_elements, &aux_data);
   elements = xnmalloc (max_elems, sizeof *elements);
   values = xnmalloc (max_elems, sizeof *values);
-  for (i = 0; i < max_elems; i++) 
+  for (i = 0; i < max_elems; i++)
     {
       values[i] = elements[i].data = i;
       check (abt_insert (&abt, &elements[i].node) == NULL);
     {
       values[i] = elements[i].data = i;
       check (abt_insert (&abt, &elements[i].node) == NULL);
@@ -646,7 +637,7 @@ test_insert_ordered (void)
 /* Inserts elements into an ABT, then moves the nodes around in
    memory. */
 static void
 /* Inserts elements into an ABT, then moves the nodes around in
    memory. */
 static void
-test_moved (void) 
+test_moved (void)
 {
   const int max_elems = 128;
   struct element *e[2];
 {
   const int max_elems = 128;
   struct element *e[2];
@@ -660,13 +651,13 @@ test_moved (void)
   e[1] = xnmalloc (max_elems, sizeof *e[1]);
   values = xnmalloc (max_elems, sizeof *values);
   cur = 0;
   e[1] = xnmalloc (max_elems, sizeof *e[1]);
   values = xnmalloc (max_elems, sizeof *values);
   cur = 0;
-  for (i = 0; i < max_elems; i++) 
+  for (i = 0; i < max_elems; i++)
     {
       values[i] = e[cur][i].data = i;
       check (abt_insert (&abt, &e[cur][i].node) == NULL);
       check_abt (&abt, values, i + 1);
 
     {
       values[i] = e[cur][i].data = i;
       check (abt_insert (&abt, &e[cur][i].node) == NULL);
       check_abt (&abt, values, i + 1);
 
-      for (j = 0; j <= i; j++) 
+      for (j = 0; j <= i; j++)
         {
           e[!cur][j] = e[cur][j];
           abt_moved (&abt, &e[!cur][j].node);
         {
           e[!cur][j] = e[cur][j];
           abt_moved (&abt, &e[!cur][j].node);
@@ -684,29 +675,29 @@ static void
 test_changed (void)
 {
   const int max_elems = 6;
 test_changed (void)
 {
   const int max_elems = 6;
-  int cnt;
+  int n;
 
 
-  for (cnt = 0; cnt <= max_elems; cnt++) 
+  for (n = 0; n <= max_elems; n++)
     {
       int *values, *changed_values;
       struct element *elements;
     {
       int *values, *changed_values;
       struct element *elements;
-      unsigned int permutation_cnt;
+      unsigned int n_permutations;
       int i;
 
       int i;
 
-      values = xnmalloc (cnt, sizeof *values);
-      changed_values = xnmalloc (cnt, sizeof *changed_values);
-      elements = xnmalloc (cnt, sizeof *elements);
-      for (i = 0; i < cnt; i++) 
+      values = xnmalloc (n, sizeof *values);
+      changed_values = xnmalloc (n, sizeof *changed_values);
+      elements = xnmalloc (n, sizeof *elements);
+      for (i = 0; i < n; i++)
         values[i] = i;
 
         values[i] = i;
 
-      for (permutation_cnt = 0;
-           permutation_cnt == 0 || next_permutation (values, cnt);
-           permutation_cnt++) 
+      for (n_permutations = 0;
+           n_permutations == 0 || next_permutation (values, n);
+           n_permutations++)
         {
         {
-          for (i = 0; i < cnt; i++) 
+          for (i = 0; i < n; i++)
             {
               int j, k;
             {
               int j, k;
-              for (j = 0; j <= cnt; j++) 
+              for (j = 0; j <= n; j++)
                 {
                   struct abt abt;
                   struct abt_node *changed_retval;
                 {
                   struct abt abt;
                   struct abt_node *changed_retval;
@@ -715,37 +706,37 @@ test_changed (void)
                             &aux_data);
 
                   /* Add to ABT in order. */
                             &aux_data);
 
                   /* Add to ABT in order. */
-                  for (k = 0; k < cnt; k++) 
+                  for (k = 0; k < n; k++)
                     {
                       int n = values[k];
                       elements[n].data = n;
                     {
                       int n = values[k];
                       elements[n].data = n;
-                      check (abt_insert (&abt, &elements[n].node) == NULL); 
+                      check (abt_insert (&abt, &elements[n].node) == NULL);
                     }
                     }
-                  check_abt (&abt, values, cnt);
+                  check_abt (&abt, values, n);
 
                   /* Change value i to j. */
                   elements[i].data = j;
 
                   /* Change value i to j. */
                   elements[i].data = j;
-                  for (k = 0; k < cnt; k++)
+                  for (k = 0; k < n; k++)
                     changed_values[k] = k;
                   changed_retval = abt_changed (&abt, &elements[i].node);
                     changed_values[k] = k;
                   changed_retval = abt_changed (&abt, &elements[i].node);
-                  if (i != j && j < cnt)
+                  if (i != j && j < n)
                     {
                       /* Will cause duplicate. */
                       check (changed_retval == &elements[j].node);
                     {
                       /* Will cause duplicate. */
                       check (changed_retval == &elements[j].node);
-                      changed_values[i] = changed_values[cnt - 1];
-                      check_abt (&abt, changed_values, cnt - 1);
+                      changed_values[i] = changed_values[n - 1];
+                      check_abt (&abt, changed_values, n - 1);
                     }
                   else
                     {
                       /* Succeeds. */
                       check (changed_retval == NULL);
                       changed_values[i] = j;
                     }
                   else
                     {
                       /* Succeeds. */
                       check (changed_retval == NULL);
                       changed_values[i] = j;
-                      check_abt (&abt, changed_values, cnt);
+                      check_abt (&abt, changed_values, n);
                     }
                 }
                     }
                 }
-            } 
+            }
         }
         }
-      check (permutation_cnt == factorial (cnt));
+      check (n_permutations == factorial (n));
 
       free (values);
       free (changed_values);
 
       free (values);
       free (changed_values);
@@ -755,32 +746,84 @@ test_changed (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-any-remove-any",
+      "insert any order, delete any order",
+      test_insert_any_remove_any
+    },
+    {
+      "insert-any-remove-same",
+      "insert any order, delete same order",
+      test_insert_any_remove_same
+    },
+    {
+      "insert-any-remove-reverse",
+      "insert any order, delete reverse order",
+      test_insert_any_remove_reverse
+    },
+    {
+      "random-sequence",
+      "insert and delete in random sequence",
+      test_random_sequence
+    },
+    {
+      "insert-ordered",
+      "insert in ascending order",
+      test_insert_ordered
+    },
+    {
+      "moved",
+      "move elements around in memory",
+      test_moved
+    },
+    {
+      "changed",
+      "change key data in nodes",
+      test_changed
+    }
+  };
+
+enum { N_TESTS = sizeof tests / sizeof *tests };
 
 int
 
 int
-main (void) 
+main (int argc, char *argv[])
 {
 {
-  run_test (test_insert_any_remove_any,
-            "insert any order, delete any order");
-  run_test (test_insert_any_remove_same,
-            "insert any order, delete same order");
-  run_test (test_insert_any_remove_reverse,
-            "insert any order, delete reverse order");
-  run_test (test_random_sequence,
-            "insert and delete in random sequence");
-  run_test (test_insert_ordered,
-            "insert in ascending order");
-  run_test (test_moved, "move elements around in memory");
-  run_test (test_changed, "change key data in nodes");
-  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 augmented binary tree\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;
+    }
 }
 }