1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007 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 /* Currently running test. */
39 static const char *test_name;
41 /* Exit with a failure code.
42 (Place a breakpoint on this function while debugging.) */
49 /* If OK is not true, prints a message about failure on the
50 current source file and the given LINE and terminates. */
52 check_func (bool ok, int line)
56 printf ("Check failed in %s test at %s, line %d\n",
57 test_name, __FILE__, line);
62 /* Verifies that EXPR evaluates to true.
63 If not, prints a message citing the calling line number and
65 #define check(EXPR) check_func ((EXPR), __LINE__)
67 /* Prints a message about memory exhaustion and exits with a
72 printf ("virtual memory exhausted\n");
76 /* Allocates and returns N bytes of memory. */
93 xmemdup (const void *p, size_t n)
95 void *q = xmalloc (n);
100 /* Allocates and returns N * M bytes of memory. */
102 xnmalloc (size_t n, size_t m)
104 if ((size_t) -1 / m <= n)
106 return xmalloc (n * m);
109 /* Node type and support routines. */
111 /* Test data element. */
114 struct abt_node node; /* Embedded binary tree element. */
115 int data; /* Primary value. */
116 int count; /* Number of nodes in subtree,
117 including this node. */
122 /* Returns the `struct element' that NODE is embedded within. */
123 static struct element *
124 abt_node_to_element (const struct abt_node *node)
126 return abt_data (node, struct element, node);
129 /* Compares the `x' values in A and B and returns a strcmp-type
130 return value. Verifies that AUX points to aux_data. */
132 compare_elements (const struct abt_node *a_, const struct abt_node *b_,
135 const struct element *a = abt_node_to_element (a_);
136 const struct element *b = abt_node_to_element (b_);
138 check (aux == &aux_data);
139 return a->data < b->data ? -1 : a->data > b->data;
142 /* Recalculates the count for NODE's subtree by adding up the
143 counts for its LEFT and RIGHT child subtrees. */
145 reaugment_elements (struct abt_node *node_,
146 const struct abt_node *left,
147 const struct abt_node *right,
150 struct element *node = abt_node_to_element (node_);
152 check (aux == &aux_data);
156 node->count += abt_node_to_element (left)->count;
158 node->count += abt_node_to_element (right)->count;
161 /* Compares A and B and returns a strcmp-type return value. */
163 compare_ints_noaux (const void *a_, const void *b_)
168 return *a < *b ? -1 : *a > *b;
171 /* Swaps *A and *B. */
173 swap (int *a, int *b)
180 /* Reverses the order of the CNT integers starting at VALUES. */
182 reverse (int *values, size_t cnt)
188 swap (&values[i++], &values[--j]);
191 /* Arranges the CNT elements in VALUES into the lexicographically
192 next greater permutation. Returns true if successful.
193 If VALUES is already the lexicographically greatest
194 permutation of its elements (i.e. ordered from greatest to
195 smallest), arranges them into the lexicographically least
196 permutation (i.e. ordered from smallest to largest) and
199 next_permutation (int *values, size_t cnt)
207 if (values[i] < values[i + 1])
210 for (j = cnt - 1; values[i] >= values[j]; j--)
212 swap (values + i, values + j);
213 reverse (values + (i + 1), cnt - (i + 1));
218 reverse (values, cnt);
226 factorial (unsigned int n)
228 unsigned int value = 1;
234 /* Randomly shuffles the CNT elements in ARRAY, each of which is
235 SIZE bytes in size. */
237 random_shuffle (void *array_, size_t cnt, size_t size)
239 char *array = array_;
240 char *tmp = xmalloc (size);
243 for (i = 0; i < cnt; i++)
245 size_t j = rand () % (cnt - i) + i;
248 memcpy (tmp, array + j * size, size);
249 memcpy (array + j * size, array + i * size, size);
250 memcpy (array + i * size, tmp, size);
257 /* Finds and returns the element in ABT that is in the given
258 0-based POSITION in in-order. */
259 static struct element *
260 find_by_position (struct abt *abt, int position)
263 for (p = abt->root; p != NULL; )
265 int p_pos = p->down[0] ? abt_node_to_element (p->down[0])->count : 0;
266 if (position == p_pos)
267 return abt_node_to_element (p);
268 else if (position < p_pos)
273 position -= p_pos + 1;
279 /* Checks that all the augmentations are correct in the subtree
280 rooted at P. Returns the number of nodes in the subtree. */
282 check_augmentations (struct abt_node *p_)
288 struct element *p = abt_node_to_element (p_);
289 int left_count = check_augmentations (p->node.down[0]);
290 int right_count = check_augmentations (p->node.down[1]);
291 int total = left_count + right_count + 1;
292 check (p->count == total);
297 /* Check that the levels are correct in the subtree rooted at P. */
299 check_levels (struct abt_node *p)
305 check_levels (p->down[0]);
306 check_levels (p->down[1]);
308 check (p->level >= 1);
311 struct abt_node *q = p->down[1];
313 check (q->level == p->level || q->level == p->level - 1);
316 for (i = 0; i < 2; i++)
317 if (p->down[i] != NULL)
318 for (j = 0; j < 2; j++)
319 if (p->down[i]->down[j] != NULL)
320 check (p->down[i]->down[j]->level < p->level);
324 /* Checks that ABT contains the CNT ints in DATA, that its
325 structure is correct, and that certain operations on ABT
326 produce the expected results. */
328 check_abt (struct abt *abt, const int data[], size_t cnt)
334 order = xmemdup (data, cnt * sizeof *data);
335 qsort (order, cnt, sizeof *order, compare_ints_noaux);
337 if (abt->compare != NULL)
339 for (i = 0; i < cnt; i++)
345 p = abt_find (abt, &e.node);
347 p = abt_insert (abt, &e.node);
349 check (p != &e.node);
350 check (abt_node_to_element (p)->data == data[i]);
354 check (abt_find (abt, &e.node) == NULL);
357 check_levels (abt->root);
358 check_augmentations (abt->root);
359 for (i = 0; i < cnt; i++)
360 check (find_by_position (abt, i)->data == order[i]);
364 check (abt_first (abt) == NULL);
365 check (abt_last (abt) == NULL);
366 check (abt_next (abt, NULL) == NULL);
367 check (abt_prev (abt, NULL) == NULL);
373 for (p = abt_first (abt), i = 0; i < cnt; p = abt_next (abt, p), i++)
374 check (abt_node_to_element (p)->data == order[i]);
377 for (p = abt_last (abt), i = 0; i < cnt; p = abt_prev (abt, p), i++)
378 check (abt_node_to_element (p)->data == order[cnt - i - 1]);
385 /* Ways that nodes can be inserted. */
386 enum insertion_method
388 INSERT, /* With abt_insert. */
389 INSERT_AFTER, /* With abt_insert_after. */
390 INSERT_BEFORE /* With abt_insert_before. */
393 /* Inserts INSERT into ABT with the given METHOD. */
395 insert_node (struct abt *abt, struct element *insert,
396 enum insertion_method method)
398 if (method == INSERT)
399 check (abt_insert (abt, &insert->node) == NULL);
402 struct abt_node *p = abt->root;
407 dir = insert->data > abt_node_to_element (p)->data;
408 if (p->down[dir] == NULL)
412 if (method == INSERT_AFTER)
414 if (p != NULL && (dir != 1 || p->down[1] != NULL))
415 p = abt_prev (abt, p);
416 abt_insert_after (abt, p, &insert->node);
420 if (p != NULL && (dir != 0 || p->down[0] != NULL))
421 p = abt_next (abt, p);
422 abt_insert_before (abt, p, &insert->node);
428 /* Inserts the CNT values from 0 to CNT - 1 (inclusive) into an
429 ABT in the order specified by INSERTIONS using the given
430 METHOD, then deletes them in the order specified by DELETIONS,
431 checking the ABT's contents for correctness after each
434 do_test_insert_delete (enum insertion_method method,
435 const int insertions[],
436 const int deletions[],
439 struct element *elements;
443 elements = xnmalloc (cnt, sizeof *elements);
444 for (i = 0; i < cnt; i++)
445 elements[i].data = i;
447 abt_init (&abt, method == INSERT ? compare_elements : NULL,
448 reaugment_elements, &aux_data);
449 check_abt (&abt, NULL, 0);
450 for (i = 0; i < cnt; i++)
452 insert_node (&abt, &elements[insertions[i]], method);
453 check_abt (&abt, insertions, i + 1);
455 for (i = 0; i < cnt; i++)
457 abt_delete (&abt, &elements[deletions[i]].node);
458 check_abt (&abt, deletions + i + 1, cnt - i - 1);
464 /* Inserts the CNT values from 0 to CNT - 1 (inclusive) into an
465 ABT in the order specified by INSERTIONS, then deletes them in
466 the order specified by DELETIONS, checking the ABT's contents
467 for correctness after each operation. */
469 test_insert_delete (const int insertions[],
470 const int deletions[],
473 do_test_insert_delete (INSERT, insertions, deletions, cnt);
474 do_test_insert_delete (INSERT_AFTER, insertions, deletions, cnt);
475 do_test_insert_delete (INSERT_BEFORE, insertions, deletions, cnt);
478 /* Inserts values into an ABT in each possible order, then
479 removes them in each possible order, up to a specified maximum
482 test_insert_any_remove_any (void)
484 const int max_elems = 5;
487 for (cnt = 0; cnt <= max_elems; cnt++)
489 int *insertions, *deletions;
490 unsigned int ins_perm_cnt;
493 insertions = xnmalloc (cnt, sizeof *insertions);
494 deletions = xnmalloc (cnt, sizeof *deletions);
495 for (i = 0; i < cnt; i++)
498 for (ins_perm_cnt = 0;
499 ins_perm_cnt == 0 || next_permutation (insertions, cnt);
502 unsigned int del_perm_cnt;
505 for (i = 0; i < cnt; i++)
508 for (del_perm_cnt = 0;
509 del_perm_cnt == 0 || next_permutation (deletions, cnt);
511 test_insert_delete (insertions, deletions, cnt);
513 check (del_perm_cnt == factorial (cnt));
515 check (ins_perm_cnt == factorial (cnt));
522 /* Inserts values into an ABT in each possible order, then
523 removes them in the same order, up to a specified maximum
526 test_insert_any_remove_same (void)
528 const int max_elems = 7;
531 for (cnt = 0; cnt <= max_elems; cnt++)
534 unsigned int permutation_cnt;
537 values = xnmalloc (cnt, sizeof *values);
538 for (i = 0; i < cnt; i++)
541 for (permutation_cnt = 0;
542 permutation_cnt == 0 || next_permutation (values, cnt);
544 test_insert_delete (values, values, cnt);
545 check (permutation_cnt == factorial (cnt));
551 /* Inserts values into an ABT in each possible order, then
552 removes them in reverse order, up to a specified maximum
555 test_insert_any_remove_reverse (void)
557 const int max_elems = 7;
560 for (cnt = 0; cnt <= max_elems; cnt++)
562 int *insertions, *deletions;
563 unsigned int permutation_cnt;
566 insertions = xnmalloc (cnt, sizeof *insertions);
567 deletions = xnmalloc (cnt, sizeof *deletions);
568 for (i = 0; i < cnt; i++)
571 for (permutation_cnt = 0;
572 permutation_cnt == 0 || next_permutation (insertions, cnt);
575 memcpy (deletions, insertions, sizeof *insertions * cnt);
576 reverse (deletions, cnt);
578 test_insert_delete (insertions, deletions, cnt);
580 check (permutation_cnt == factorial (cnt));
587 /* Inserts and removes values in an ABT in random orders. */
589 test_random_sequence (void)
591 const int max_elems = 128;
592 const int max_trials = 8;
595 for (cnt = 0; cnt <= max_elems; cnt += 2)
597 int *insertions, *deletions;
601 insertions = xnmalloc (cnt, sizeof *insertions);
602 deletions = xnmalloc (cnt, sizeof *deletions);
603 for (i = 0; i < cnt; i++)
605 for (i = 0; i < cnt; i++)
608 for (trial = 0; trial < max_trials; trial++)
610 random_shuffle (insertions, cnt, sizeof *insertions);
611 random_shuffle (deletions, cnt, sizeof *deletions);
613 test_insert_delete (insertions, deletions, cnt);
621 /* Inserts elements into an ABT in ascending order. */
623 test_insert_ordered (void)
625 const int max_elems = 1024;
626 struct element *elements;
631 abt_init (&abt, compare_elements, reaugment_elements, &aux_data);
632 elements = xnmalloc (max_elems, sizeof *elements);
633 values = xnmalloc (max_elems, sizeof *values);
634 for (i = 0; i < max_elems; i++)
636 values[i] = elements[i].data = i;
637 check (abt_insert (&abt, &elements[i].node) == NULL);
638 check_abt (&abt, values, i + 1);
644 /* Inserts elements into an ABT, then moves the nodes around in
649 const int max_elems = 128;
650 struct element *e[2];
656 abt_init (&abt, compare_elements, reaugment_elements, &aux_data);
657 e[0] = xnmalloc (max_elems, sizeof *e[0]);
658 e[1] = xnmalloc (max_elems, sizeof *e[1]);
659 values = xnmalloc (max_elems, sizeof *values);
661 for (i = 0; i < max_elems; i++)
663 values[i] = e[cur][i].data = i;
664 check (abt_insert (&abt, &e[cur][i].node) == NULL);
665 check_abt (&abt, values, i + 1);
667 for (j = 0; j <= i; j++)
669 e[!cur][j] = e[cur][j];
670 abt_moved (&abt, &e[!cur][j].node);
671 check_abt (&abt, values, i + 1);
680 /* Inserts values into an ABT, then changes their values. */
684 const int max_elems = 6;
687 for (cnt = 0; cnt <= max_elems; cnt++)
689 int *values, *changed_values;
690 struct element *elements;
691 unsigned int permutation_cnt;
694 values = xnmalloc (cnt, sizeof *values);
695 changed_values = xnmalloc (cnt, sizeof *changed_values);
696 elements = xnmalloc (cnt, sizeof *elements);
697 for (i = 0; i < cnt; i++)
700 for (permutation_cnt = 0;
701 permutation_cnt == 0 || next_permutation (values, cnt);
704 for (i = 0; i < cnt; i++)
707 for (j = 0; j <= cnt; j++)
710 struct abt_node *changed_retval;
712 abt_init (&abt, compare_elements, reaugment_elements,
715 /* Add to ABT in order. */
716 for (k = 0; k < cnt; k++)
719 elements[n].data = n;
720 check (abt_insert (&abt, &elements[n].node) == NULL);
722 check_abt (&abt, values, cnt);
724 /* Change value i to j. */
725 elements[i].data = j;
726 for (k = 0; k < cnt; k++)
727 changed_values[k] = k;
728 changed_retval = abt_changed (&abt, &elements[i].node);
729 if (i != j && j < cnt)
731 /* Will cause duplicate. */
732 check (changed_retval == &elements[j].node);
733 changed_values[i] = changed_values[cnt - 1];
734 check_abt (&abt, changed_values, cnt - 1);
739 check (changed_retval == NULL);
740 changed_values[i] = j;
741 check_abt (&abt, changed_values, cnt);
746 check (permutation_cnt == factorial (cnt));
749 free (changed_values);
756 /* Runs TEST_FUNCTION and prints a message about NAME. */
758 run_test (void (*test_function) (void), const char *name)
769 run_test (test_insert_any_remove_any,
770 "insert any order, delete any order");
771 run_test (test_insert_any_remove_same,
772 "insert any order, delete same order");
773 run_test (test_insert_any_remove_reverse,
774 "insert any order, delete reverse order");
775 run_test (test_random_sequence,
776 "insert and delete in random sequence");
777 run_test (test_insert_ordered,
778 "insert in ascending order");
779 run_test (test_moved, "move elements around in memory");
780 run_test (test_changed, "change key data in nodes");