GNU libavl 2.0.1
Author: Ben Pfaff

4.14.7 Main Program |

Everything comes together in the main program. The test itself (default or overflow) is selected with enum test:

    138. <Test declarations 121> +=
    /* Test to perform. */
    enum test
      {
        TST_CORRECTNESS,		/* Default tests. */
        TST_OVERFLOW,		/* Stack overflow test. */
        TST_NULL                    /* No test, just overhead. */
      };

The program's entire behavior is controlled by struct test_options, defined as follows:

    139. <Test declarations 121> +=
    /* Program options. */
    struct test_options
      {
        enum test test;                     /* Test to perform. */
        enum insert_order insert_order;     /* Insertion order. */
        enum delete_order delete_order;     /* Deletion order. */

        enum mt_policy alloc_policy;        /* Allocation policy. */
        int alloc_arg[2];                   /* Policy arguments. */
        int alloc_incr; /* Amount to increment alloc_arg each iteration. */

        int node_cnt;                       /* Number of nodes in tree. */
        int iter_cnt;                       /* Number of runs. */

        int seed_given;                     /* Seed provided on command line? */
        unsigned seed;                      /* Random number seed. */

        int verbosity;                      /* Verbosity level, 0=default. */
        int nonstop;                        /* Don't stop after one error? */
      };

The main() function for the test program is perhaps a bit long, but simple. It begins by parsing the command line and allocating memory, then repeats a loop once for each repetition of the test. Within the loop, an insertion and a deletion order are selected, the memory tracker is set up, and test function (either test() or test_overflow()) is called.

    140. <Test main program 140> =
    int
    main (int argc, char *argv[])
    {
      struct test_options opts;	/* Command-line options. */
      int *insert, *delete;		/* Insertion and deletion orders. */
      int success;                  /* Everything okay so far? */

      /* Initialize pgm_name, using argv[0] if sensible. */
      pgm_name = argv[0] != NULL && argv[0][0] != '\0' ? argv[0] : "bst-test";

      /* Parse command line into options. */
      parse_command_line (argv, &opts);

      if (opts.verbosity >= 0)
        fputs ("bst-test for GNU libavl 2.0.1; use --help to get help.\n", stdout);

      if (!opts.seed_given)
        opts.seed = time_seed () % 32768u;

      insert = xmalloc (sizeof *insert * opts.node_cnt);
      delete = xmalloc (sizeof *delete * opts.node_cnt);

      /* Run the tests. */
      success = 1;
      while (opts.iter_cnt--)
        {
          struct mt_allocator *alloc;

          if (opts.verbosity >= 0)
            {
              printf ("Testing seed=%u", opts.seed);
              if (opts.alloc_incr)
                printf (", alloc arg=%d", opts.alloc_arg[0]);
              printf ("...\n");
              fflush (stdout);
            }

          /* Generate insertion and deletion order.
             Seed them separately to ensure deletion order is
             independent of insertion order. */
          srand (opts.seed);
          gen_insertions (opts.node_cnt, opts.insert_order, insert);

          srand (++opts.seed);
          gen_deletions (opts.node_cnt, opts.delete_order, insert, delete);

          if (opts.verbosity >= 1)
            {
              int i;

              printf ("  Insertion order:");
              for (i = 0; i < opts.node_cnt; i++)
                printf (" %d", insert[i]);
              printf (".\n");

              if (opts.test == TST_CORRECTNESS)
                {
                  printf ("Deletion order:");
                  for (i = 0; i < opts.node_cnt; i++)
                    printf (" %d", delete[i]);
                  printf (".\n");
                }
            }

          alloc = mt_create (opts.alloc_policy, opts.alloc_arg, opts.verbosity);

          {
            int okay;
            struct libavl_allocator *a = mt_allocator (alloc);

            switch (opts.test)
              {
              case TST_CORRECTNESS:
                okay = test_correctness (a, insert, delete, opts.node_cnt,
                                         opts.verbosity);
                break;

              case TST_OVERFLOW:
                okay = test_overflow (a, insert, opts.node_cnt, opts.verbosity);
                break;

              case TST_NULL:
                okay = 1;
                break;

              default:
                assert (0);
              }

            if (okay)
              {
                if (opts.verbosity >= 1)
                  printf ("  No errors.\n");
              }
            else
              {
                success = 0;
                printf ("  Error!\n");
              }
          }

          mt_destroy (alloc);
          opts.alloc_arg[0] += opts.alloc_incr;

          if (!success && !opts.nonstop)
            break;
        }

      free (delete);
      free (insert);

      return success ? EXIT_SUCCESS : EXIT_FAILURE;
    }

This code is included in 97.

The main program initializes our single global variable, pgm_name, which receives the name of the program at start of execution:

    141. <Test declarations 121> +=
    /* Program name. */
    char *pgm_name;

4.14.6 Utility Functions | 4.14 Testing | 4.15 Additional Exercises