1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2010 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* This is a test program for the abt_* routines defined in
18 abt.c. This test program aims to be as comprehensive as
19 possible. "gcov -b" should report 100% coverage of lines and
20 branches in the abt_* routines. "valgrind --leak-check=yes
21 --show-reachable=yes" should give a clean report. */
27 #include <libpspp/abt.h>
36 #include <libpspp/compiler.h>
38 /* Exit with a failure code.
39 (Place a breakpoint on this function while debugging.) */
46 /* If OK is not true, prints a message about failure on the
47 current source file and the given LINE and terminates. */
49 check_func (bool ok, int line)
53 fprintf (stderr, "%s:%d: check failed\n", __FILE__, line);
58 /* Verifies that EXPR evaluates to true.
59 If not, prints a message citing the calling line number and
61 #define check(EXPR) check_func ((EXPR), __LINE__)
63 /* Prints a message about memory exhaustion and exits with a
68 printf ("virtual memory exhausted\n");
72 /* Allocates and returns N bytes of memory. */
89 xmemdup (const void *p, size_t n)
91 void *q = xmalloc (n);
96 /* Allocates and returns N * M bytes of memory. */
98 xnmalloc (size_t n, size_t m)
100 if ((size_t) -1 / m <= n)
102 return xmalloc (n * m);
105 /* Node type and support routines. */
107 /* Test data element. */
110 struct abt_node node; /* Embedded binary tree element. */
111 int data; /* Primary value. */
112 int count; /* Number of nodes in subtree,
113 including this node. */
118 /* Returns the `struct element' that NODE is embedded within. */
119 static struct element *
120 abt_node_to_element (const struct abt_node *node)
122 return abt_data (node, struct element, node);
125 /* Compares the `x' values in A and B and returns a strcmp-type
126 return value. Verifies that AUX points to aux_data. */
128 compare_elements (const struct abt_node *a_, const struct abt_node *b_,
131 const struct element *a = abt_node_to_element (a_);
132 const struct element *b = abt_node_to_element (b_);
134 check (aux == &aux_data);
135 return a->data < b->data ? -1 : a->data > b->data;
138 /* Recalculates the count for NODE's subtree by adding up the
139 counts for its LEFT and RIGHT child subtrees. */
141 reaugment_elements (struct abt_node *node_,
142 const struct abt_node *left,
143 const struct abt_node *right,
146 struct element *node = abt_node_to_element (node_);
148 check (aux == &aux_data);
152 node->count += abt_node_to_element (left)->count;
154 node->count += abt_node_to_element (right)->count;
157 /* Compares A and B and returns a strcmp-type return value. */
159 compare_ints_noaux (const void *a_, const void *b_)
164 return *a < *b ? -1 : *a > *b;
167 /* Swaps *A and *B. */
169 swap (int *a, int *b)
176 /* Reverses the order of the CNT integers starting at VALUES. */
178 reverse (int *values, size_t cnt)
184 swap (&values[i++], &values[--j]);
187 /* Arranges the CNT elements in VALUES into the lexicographically
188 next greater permutation. Returns true if successful.
189 If VALUES is already the lexicographically greatest
190 permutation of its elements (i.e. ordered from greatest to
191 smallest), arranges them into the lexicographically least
192 permutation (i.e. ordered from smallest to largest) and
195 next_permutation (int *values, size_t cnt)
203 if (values[i] < values[i + 1])
206 for (j = cnt - 1; values[i] >= values[j]; j--)
208 swap (values + i, values + j);
209 reverse (values + (i + 1), cnt - (i + 1));
214 reverse (values, cnt);
222 factorial (unsigned int n)
224 unsigned int value = 1;
230 /* Randomly shuffles the CNT elements in ARRAY, each of which is
231 SIZE bytes in size. */
233 random_shuffle (void *array_, size_t cnt, size_t size)
235 char *array = array_;
236 char *tmp = xmalloc (size);
239 for (i = 0; i < cnt; i++)
241 size_t j = rand () % (cnt - i) + i;
244 memcpy (tmp, array + j * size, size);
245 memcpy (array + j * size, array + i * size, size);
246 memcpy (array + i * size, tmp, size);
253 /* Finds and returns the element in ABT that is in the given
254 0-based POSITION in in-order. */
255 static struct element *
256 find_by_position (struct abt *abt, int position)
259 for (p = abt->root; p != NULL; )
261 int p_pos = p->down[0] ? abt_node_to_element (p->down[0])->count : 0;
262 if (position == p_pos)
263 return abt_node_to_element (p);
264 else if (position < p_pos)
269 position -= p_pos + 1;
275 /* Checks that all the augmentations are correct in the subtree
276 rooted at P. Returns the number of nodes in the subtree. */
278 check_augmentations (struct abt_node *p_)
284 struct element *p = abt_node_to_element (p_);
285 int left_count = check_augmentations (p->node.down[0]);
286 int right_count = check_augmentations (p->node.down[1]);
287 int total = left_count + right_count + 1;
288 check (p->count == total);
293 /* Check that the levels are correct in the subtree rooted at P. */
295 check_levels (struct abt_node *p)
301 check_levels (p->down[0]);
302 check_levels (p->down[1]);
304 check (p->level >= 1);
307 struct abt_node *q = p->down[1];
309 check (q->level == p->level || q->level == p->level - 1);
312 for (i = 0; i < 2; i++)
313 if (p->down[i] != NULL)
314 for (j = 0; j < 2; j++)
315 if (p->down[i]->down[j] != NULL)
316 check (p->down[i]->down[j]->level < p->level);
320 /* Checks that ABT contains the CNT ints in DATA, that its
321 structure is correct, and that certain operations on ABT
322 produce the expected results. */
324 check_abt (struct abt *abt, const int data[], size_t cnt)
330 order = xmemdup (data, cnt * sizeof *data);
331 qsort (order, cnt, sizeof *order, compare_ints_noaux);
333 if (abt->compare != NULL)
335 for (i = 0; i < cnt; i++)
341 p = abt_find (abt, &e.node);
343 p = abt_insert (abt, &e.node);
345 check (p != &e.node);
346 check (abt_node_to_element (p)->data == data[i]);
350 check (abt_find (abt, &e.node) == NULL);
353 check_levels (abt->root);
354 check_augmentations (abt->root);
355 for (i = 0; i < cnt; i++)
356 check (find_by_position (abt, i)->data == order[i]);
360 check (abt_first (abt) == NULL);
361 check (abt_last (abt) == NULL);
362 check (abt_next (abt, NULL) == NULL);
363 check (abt_prev (abt, NULL) == NULL);
369 for (p = abt_first (abt), i = 0; i < cnt; p = abt_next (abt, p), i++)
370 check (abt_node_to_element (p)->data == order[i]);
373 for (p = abt_last (abt), i = 0; i < cnt; p = abt_prev (abt, p), i++)
374 check (abt_node_to_element (p)->data == order[cnt - i - 1]);
381 /* Ways that nodes can be inserted. */
382 enum insertion_method
384 INSERT, /* With abt_insert. */
385 INSERT_AFTER, /* With abt_insert_after. */
386 INSERT_BEFORE /* With abt_insert_before. */
389 /* Inserts INSERT into ABT with the given METHOD. */
391 insert_node (struct abt *abt, struct element *insert,
392 enum insertion_method method)
394 if (method == INSERT)
395 check (abt_insert (abt, &insert->node) == NULL);
398 struct abt_node *p = abt->root;
403 dir = insert->data > abt_node_to_element (p)->data;
404 if (p->down[dir] == NULL)
408 if (method == INSERT_AFTER)
410 if (p != NULL && (dir != 1 || p->down[1] != NULL))
411 p = abt_prev (abt, p);
412 abt_insert_after (abt, p, &insert->node);
416 if (p != NULL && (dir != 0 || p->down[0] != NULL))
417 p = abt_next (abt, p);
418 abt_insert_before (abt, p, &insert->node);
424 /* Inserts the CNT values from 0 to CNT - 1 (inclusive) into an
425 ABT in the order specified by INSERTIONS using the given
426 METHOD, then deletes them in the order specified by DELETIONS,
427 checking the ABT's contents for correctness after each
430 do_test_insert_delete (enum insertion_method method,
431 const int insertions[],
432 const int deletions[],
435 struct element *elements;
439 elements = xnmalloc (cnt, sizeof *elements);
440 for (i = 0; i < cnt; i++)
441 elements[i].data = i;
443 abt_init (&abt, method == INSERT ? compare_elements : NULL,
444 reaugment_elements, &aux_data);
445 check_abt (&abt, NULL, 0);
446 for (i = 0; i < cnt; i++)
448 insert_node (&abt, &elements[insertions[i]], method);
449 check_abt (&abt, insertions, i + 1);
451 for (i = 0; i < cnt; i++)
453 abt_delete (&abt, &elements[deletions[i]].node);
454 check_abt (&abt, deletions + i + 1, cnt - i - 1);
460 /* Inserts the CNT values from 0 to CNT - 1 (inclusive) into an
461 ABT in the order specified by INSERTIONS, then deletes them in
462 the order specified by DELETIONS, checking the ABT's contents
463 for correctness after each operation. */
465 test_insert_delete (const int insertions[],
466 const int deletions[],
469 do_test_insert_delete (INSERT, insertions, deletions, cnt);
470 do_test_insert_delete (INSERT_AFTER, insertions, deletions, cnt);
471 do_test_insert_delete (INSERT_BEFORE, insertions, deletions, cnt);
474 /* Inserts values into an ABT in each possible order, then
475 removes them in each possible order, up to a specified maximum
478 test_insert_any_remove_any (void)
480 const int max_elems = 5;
483 for (cnt = 0; cnt <= max_elems; cnt++)
485 int *insertions, *deletions;
486 unsigned int ins_perm_cnt;
489 insertions = xnmalloc (cnt, sizeof *insertions);
490 deletions = xnmalloc (cnt, sizeof *deletions);
491 for (i = 0; i < cnt; i++)
494 for (ins_perm_cnt = 0;
495 ins_perm_cnt == 0 || next_permutation (insertions, cnt);
498 unsigned int del_perm_cnt;
501 for (i = 0; i < cnt; i++)
504 for (del_perm_cnt = 0;
505 del_perm_cnt == 0 || next_permutation (deletions, cnt);
507 test_insert_delete (insertions, deletions, cnt);
509 check (del_perm_cnt == factorial (cnt));
511 check (ins_perm_cnt == factorial (cnt));
518 /* Inserts values into an ABT in each possible order, then
519 removes them in the same order, up to a specified maximum
522 test_insert_any_remove_same (void)
524 const int max_elems = 7;
527 for (cnt = 0; cnt <= max_elems; cnt++)
530 unsigned int permutation_cnt;
533 values = xnmalloc (cnt, sizeof *values);
534 for (i = 0; i < cnt; i++)
537 for (permutation_cnt = 0;
538 permutation_cnt == 0 || next_permutation (values, cnt);
540 test_insert_delete (values, values, cnt);
541 check (permutation_cnt == factorial (cnt));
547 /* Inserts values into an ABT in each possible order, then
548 removes them in reverse order, up to a specified maximum
551 test_insert_any_remove_reverse (void)
553 const int max_elems = 7;
556 for (cnt = 0; cnt <= max_elems; cnt++)
558 int *insertions, *deletions;
559 unsigned int permutation_cnt;
562 insertions = xnmalloc (cnt, sizeof *insertions);
563 deletions = xnmalloc (cnt, sizeof *deletions);
564 for (i = 0; i < cnt; i++)
567 for (permutation_cnt = 0;
568 permutation_cnt == 0 || next_permutation (insertions, cnt);
571 memcpy (deletions, insertions, sizeof *insertions * cnt);
572 reverse (deletions, cnt);
574 test_insert_delete (insertions, deletions, cnt);
576 check (permutation_cnt == factorial (cnt));
583 /* Inserts and removes values in an ABT in random orders. */
585 test_random_sequence (void)
587 const int max_elems = 128;
588 const int max_trials = 8;
591 for (cnt = 0; cnt <= max_elems; cnt += 2)
593 int *insertions, *deletions;
597 insertions = xnmalloc (cnt, sizeof *insertions);
598 deletions = xnmalloc (cnt, sizeof *deletions);
599 for (i = 0; i < cnt; i++)
601 for (i = 0; i < cnt; i++)
604 for (trial = 0; trial < max_trials; trial++)
606 random_shuffle (insertions, cnt, sizeof *insertions);
607 random_shuffle (deletions, cnt, sizeof *deletions);
609 test_insert_delete (insertions, deletions, cnt);
617 /* Inserts elements into an ABT in ascending order. */
619 test_insert_ordered (void)
621 const int max_elems = 1024;
622 struct element *elements;
627 abt_init (&abt, compare_elements, reaugment_elements, &aux_data);
628 elements = xnmalloc (max_elems, sizeof *elements);
629 values = xnmalloc (max_elems, sizeof *values);
630 for (i = 0; i < max_elems; i++)
632 values[i] = elements[i].data = i;
633 check (abt_insert (&abt, &elements[i].node) == NULL);
634 check_abt (&abt, values, i + 1);
640 /* Inserts elements into an ABT, then moves the nodes around in
645 const int max_elems = 128;
646 struct element *e[2];
652 abt_init (&abt, compare_elements, reaugment_elements, &aux_data);
653 e[0] = xnmalloc (max_elems, sizeof *e[0]);
654 e[1] = xnmalloc (max_elems, sizeof *e[1]);
655 values = xnmalloc (max_elems, sizeof *values);
657 for (i = 0; i < max_elems; i++)
659 values[i] = e[cur][i].data = i;
660 check (abt_insert (&abt, &e[cur][i].node) == NULL);
661 check_abt (&abt, values, i + 1);
663 for (j = 0; j <= i; j++)
665 e[!cur][j] = e[cur][j];
666 abt_moved (&abt, &e[!cur][j].node);
667 check_abt (&abt, values, i + 1);
676 /* Inserts values into an ABT, then changes their values. */
680 const int max_elems = 6;
683 for (cnt = 0; cnt <= max_elems; cnt++)
685 int *values, *changed_values;
686 struct element *elements;
687 unsigned int permutation_cnt;
690 values = xnmalloc (cnt, sizeof *values);
691 changed_values = xnmalloc (cnt, sizeof *changed_values);
692 elements = xnmalloc (cnt, sizeof *elements);
693 for (i = 0; i < cnt; i++)
696 for (permutation_cnt = 0;
697 permutation_cnt == 0 || next_permutation (values, cnt);
700 for (i = 0; i < cnt; i++)
703 for (j = 0; j <= cnt; j++)
706 struct abt_node *changed_retval;
708 abt_init (&abt, compare_elements, reaugment_elements,
711 /* Add to ABT in order. */
712 for (k = 0; k < cnt; k++)
715 elements[n].data = n;
716 check (abt_insert (&abt, &elements[n].node) == NULL);
718 check_abt (&abt, values, cnt);
720 /* Change value i to j. */
721 elements[i].data = j;
722 for (k = 0; k < cnt; k++)
723 changed_values[k] = k;
724 changed_retval = abt_changed (&abt, &elements[i].node);
725 if (i != j && j < cnt)
727 /* Will cause duplicate. */
728 check (changed_retval == &elements[j].node);
729 changed_values[i] = changed_values[cnt - 1];
730 check_abt (&abt, changed_values, cnt - 1);
735 check (changed_retval == NULL);
736 changed_values[i] = j;
737 check_abt (&abt, changed_values, cnt);
742 check (permutation_cnt == factorial (cnt));
745 free (changed_values);
755 const char *description;
756 void (*function) (void);
759 static const struct test tests[] =
762 "insert-any-remove-any",
763 "insert any order, delete any order",
764 test_insert_any_remove_any
767 "insert-any-remove-same",
768 "insert any order, delete same order",
769 test_insert_any_remove_same
772 "insert-any-remove-reverse",
773 "insert any order, delete reverse order",
774 test_insert_any_remove_reverse
778 "insert and delete in random sequence",
783 "insert in ascending order",
788 "move elements around in memory",
793 "change key data in nodes",
798 enum { N_TESTS = sizeof tests / sizeof *tests };
801 main (int argc, char *argv[])
807 fprintf (stderr, "exactly one argument required; use --help for help\n");
810 else if (!strcmp (argv[1], "--help"))
812 printf ("%s: test augmented binary tree\n"
813 "usage: %s TEST-NAME\n"
814 "where TEST-NAME is one of the following:\n",
816 for (i = 0; i < N_TESTS; i++)
817 printf (" %s\n %s\n", tests[i].name, tests[i].description);
822 for (i = 0; i < N_TESTS; i++)
823 if (!strcmp (argv[1], tests[i].name))
825 tests[i].function ();
829 fprintf (stderr, "unknown test %s; use --help for help\n", argv[1]);