1 /* PSPP - computes sample statistics.
2 Copyright (C) 2007 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 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, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 /* This is a test program for the bt_* routines defined in bt.c.
20 This test program aims to be as comprehensive as possible.
21 "gcov -b" should report 100% coverage of lines and branches in
22 bt.c. "valgrind --leak-check=yes --show-reachable=yes" should
23 give a clean report. */
29 #include <libpspp/bt.h>
39 #include <libpspp/compiler.h>
41 /* Currently running test. */
42 static const char *test_name;
44 /* Exit with a failure code.
45 (Place a breakpoint on this function while debugging.) */
52 /* If OK is not true, prints a message about failure on the
53 current source file and the given LINE and terminates. */
55 check_func (bool ok, int line)
59 printf ("Check failed in %s test at %s, line %d\n",
60 test_name, __FILE__, line);
65 /* Verifies that EXPR evaluates to true.
66 If not, prints a message citing the calling line number and
68 #define check(EXPR) check_func ((EXPR), __LINE__)
70 /* Prints a message about memory exhaustion and exits with a
75 printf ("virtual memory exhausted\n");
79 /* Allocates and returns N bytes of memory. */
96 xmemdup (const void *p, size_t n)
98 void *q = xmalloc (n);
103 /* Allocates and returns N * M bytes of memory. */
105 xnmalloc (size_t n, size_t m)
107 if ((size_t) -1 / m <= n)
109 return xmalloc (n * m);
112 /* Node type and support routines. */
114 /* Test data element. */
117 struct bt_node node; /* Embedded binary tree element. */
118 int data; /* Primary value. */
123 /* Returns the `struct element' that NODE is embedded within. */
124 static struct element *
125 bt_node_to_element (const struct bt_node *node)
127 return bt_data (node, struct element, node);
130 /* Compares the `x' values in A and B and returns a strcmp-type
131 return value. Verifies that AUX points to aux_data. */
133 compare_elements (const struct bt_node *a_, const struct bt_node *b_,
136 const struct element *a = bt_node_to_element (a_);
137 const struct element *b = bt_node_to_element (b_);
139 check (aux == &aux_data);
140 return a->data < b->data ? -1 : a->data > b->data;
143 /* Compares A and B and returns a strcmp-type return value. */
145 compare_ints_noaux (const void *a_, const void *b_)
150 return *a < *b ? -1 : *a > *b;
153 /* Swaps *A and *B. */
155 swap (int *a, int *b)
162 /* Reverses the order of the CNT integers starting at VALUES. */
164 reverse (int *values, size_t cnt)
170 swap (&values[i++], &values[--j]);
173 /* Arranges the CNT elements in VALUES into the lexicographically
174 next greater permutation. Returns true if successful.
175 If VALUES is already the lexicographically greatest
176 permutation of its elements (i.e. ordered from greatest to
177 smallest), arranges them into the lexicographically least
178 permutation (i.e. ordered from smallest to largest) and
181 next_permutation (int *values, size_t cnt)
189 if (values[i] < values[i + 1])
192 for (j = cnt - 1; values[i] >= values[j]; j--)
194 swap (values + i, values + j);
195 reverse (values + (i + 1), cnt - (i + 1));
200 reverse (values, cnt);
208 factorial (unsigned int n)
210 unsigned int value = 1;
216 /* Randomly shuffles the CNT elements in ARRAY, each of which is
217 SIZE bytes in size. */
219 random_shuffle (void *array_, size_t cnt, size_t size)
221 char *array = array_;
222 char *tmp = xmalloc (size);
225 for (i = 0; i < cnt; i++)
227 size_t j = rand () % (cnt - i) + i;
230 memcpy (tmp, array + j * size, size);
231 memcpy (array + j * size, array + i * size, size);
232 memcpy (array + i * size, tmp, size);
239 /* Calculates floor(log(n)/log(sqrt(2))). */
241 calculate_h_alpha (size_t n)
243 size_t thresholds[] =
245 0, 2, 2, 3, 4, 6, 8, 12, 16, 23, 32, 46, 64, 91, 128, 182, 256, 363,
246 512, 725, 1024, 1449, 2048, 2897, 4096, 5793, 8192, 11586, 16384,
247 23171, 32768, 46341, 65536, 92682, 131072, 185364, 262144, 370728,
248 524288, 741456, 1048576, 1482911, 2097152, 2965821, 4194304, 5931642,
249 8388608, 11863284, 16777216, 23726567, 33554432, 47453133, 67108864,
250 94906266, 134217728, 189812532, 268435456, 379625063, 536870912,
251 759250125, 1073741824, 1518500250, 2147483648, 3037000500,
253 size_t threshold_cnt = sizeof thresholds / sizeof *thresholds;
256 for (i = 0; i < threshold_cnt; i++)
257 if (thresholds[i] > n)
262 /* Returns the height of the tree rooted at NODE. */
264 get_height (struct bt_node *node)
270 int left = get_height (node->down[0]);
271 int right = get_height (node->down[1]);
272 return 1 + (left > right ? left : right);
276 /* Checks that BT is loosely alpha-height balanced, that is, that
277 its height is no more than h_alpha(count) + 1, where
278 h_alpha(n) = floor(log(n)/log(1/alpha)). */
280 check_balance (struct bt *bt)
282 /* In the notation of the Galperin and Rivest paper (and of
283 CLR), the height of a tree is the number of edges in the
284 longest path from the root to a leaf, so we have to subtract
285 1 from our measured height. */
286 int height = get_height (bt->root) - 1;
287 int max_height = calculate_h_alpha (bt_count (bt)) + 1;
288 check (height <= max_height);
291 /* Checks that BT contains the CNT ints in DATA, that its
292 structure is correct, and that certain operations on BT
293 produce the expected results. */
295 check_bt (struct bt *bt, const int data[], size_t cnt)
301 order = xmemdup (data, cnt * sizeof *data);
302 qsort (order, cnt, sizeof *order, compare_ints_noaux);
304 for (i = 0; i < cnt; i++)
310 p = bt_find (bt, &e.node);
312 p = bt_insert (bt, &e.node);
314 check (p != &e.node);
315 check (bt_node_to_element (p)->data == data[i]);
319 check (bt_find (bt, &e.node) == NULL);
325 check (bt_first (bt) == NULL);
326 check (bt_last (bt) == NULL);
327 check (bt_next (bt, NULL) == NULL);
328 check (bt_prev (bt, NULL) == NULL);
334 for (p = bt_first (bt), i = 0; i < cnt; p = bt_next (bt, p), i++)
335 check (bt_node_to_element (p)->data == order[i]);
338 for (p = bt_last (bt), i = 0; i < cnt; p = bt_prev (bt, p), i++)
339 check (bt_node_to_element (p)->data == order[cnt - i - 1]);
346 /* Inserts the CNT values from 0 to CNT - 1 (inclusive) into an
347 BT in the order specified by INSERTIONS, then deletes them in
348 the order specified by DELETIONS, checking the BT's contents
349 for correctness after each operation. */
351 test_insert_delete (const int insertions[],
352 const int deletions[],
355 struct element *elements;
359 elements = xnmalloc (cnt, sizeof *elements);
360 for (i = 0; i < cnt; i++)
361 elements[i].data = i;
363 bt_init (&bt, compare_elements, &aux_data);
364 check_bt (&bt, NULL, 0);
365 for (i = 0; i < cnt; i++)
367 check (bt_insert (&bt, &elements[insertions[i]].node) == NULL);
368 check_bt (&bt, insertions, i + 1);
370 for (i = 0; i < cnt; i++)
372 bt_delete (&bt, &elements[deletions[i]].node);
373 check_bt (&bt, deletions + i + 1, cnt - i - 1);
379 /* Inserts values into an BT in each possible order, then
380 removes them in each possible order, up to a specified maximum
383 test_insert_any_remove_any (void)
385 const int max_elems = 5;
388 for (cnt = 0; cnt <= max_elems; cnt++)
390 int *insertions, *deletions;
391 unsigned int ins_perm_cnt;
394 insertions = xnmalloc (cnt, sizeof *insertions);
395 deletions = xnmalloc (cnt, sizeof *deletions);
396 for (i = 0; i < cnt; i++)
399 for (ins_perm_cnt = 0;
400 ins_perm_cnt == 0 || next_permutation (insertions, cnt);
403 unsigned int del_perm_cnt;
406 for (i = 0; i < cnt; i++)
409 for (del_perm_cnt = 0;
410 del_perm_cnt == 0 || next_permutation (deletions, cnt);
412 test_insert_delete (insertions, deletions, cnt);
414 check (del_perm_cnt == factorial (cnt));
416 check (ins_perm_cnt == factorial (cnt));
423 /* Inserts values into an BT in each possible order, then
424 removes them in the same order, up to a specified maximum
427 test_insert_any_remove_same (void)
429 const int max_elems = 7;
432 for (cnt = 0; cnt <= max_elems; cnt++)
435 unsigned int permutation_cnt;
438 values = xnmalloc (cnt, sizeof *values);
439 for (i = 0; i < cnt; i++)
442 for (permutation_cnt = 0;
443 permutation_cnt == 0 || next_permutation (values, cnt);
445 test_insert_delete (values, values, cnt);
446 check (permutation_cnt == factorial (cnt));
452 /* Inserts values into an BT in each possible order, then
453 removes them in reverse order, up to a specified maximum
456 test_insert_any_remove_reverse (void)
458 const int max_elems = 7;
461 for (cnt = 0; cnt <= max_elems; cnt++)
463 int *insertions, *deletions;
464 unsigned int permutation_cnt;
467 insertions = xnmalloc (cnt, sizeof *insertions);
468 deletions = xnmalloc (cnt, sizeof *deletions);
469 for (i = 0; i < cnt; i++)
472 for (permutation_cnt = 0;
473 permutation_cnt == 0 || next_permutation (insertions, cnt);
476 memcpy (deletions, insertions, sizeof *insertions * cnt);
477 reverse (deletions, cnt);
479 test_insert_delete (insertions, deletions, cnt);
481 check (permutation_cnt == factorial (cnt));
488 /* Inserts and removes values in an BT in random orders. */
490 test_random_sequence (void)
492 const int max_elems = 128;
493 const int max_trials = 8;
496 for (cnt = 0; cnt <= max_elems; cnt += 2)
498 int *insertions, *deletions;
502 insertions = xnmalloc (cnt, sizeof *insertions);
503 deletions = xnmalloc (cnt, sizeof *deletions);
504 for (i = 0; i < cnt; i++)
506 for (i = 0; i < cnt; i++)
509 for (trial = 0; trial < max_trials; trial++)
511 random_shuffle (insertions, cnt, sizeof *insertions);
512 random_shuffle (deletions, cnt, sizeof *deletions);
514 test_insert_delete (insertions, deletions, cnt);
522 /* Inserts elements into an BT in ascending order. */
524 test_insert_ordered (void)
526 const int max_elems = 1024;
527 struct element *elements;
532 bt_init (&bt, compare_elements, &aux_data);
533 elements = xnmalloc (max_elems, sizeof *elements);
534 values = xnmalloc (max_elems, sizeof *values);
535 for (i = 0; i < max_elems; i++)
537 values[i] = elements[i].data = i;
538 check (bt_insert (&bt, &elements[i].node) == NULL);
539 check_bt (&bt, values, i + 1);
545 /* Tests bt_find_ge and bt_find_le. */
547 test_find_ge_le (void)
549 const int max_elems = 10;
550 struct element *elements;
552 unsigned int inc_pat;
554 elements = xnmalloc (max_elems, sizeof *elements);
555 values = xnmalloc (max_elems, sizeof *values);
556 for (inc_pat = 0; inc_pat < (1u << max_elems); inc_pat++)
562 /* Insert the values in the pattern into BT. */
563 bt_init (&bt, compare_elements, &aux_data);
564 for (i = 0; i < max_elems; i++)
565 if (inc_pat & (1u << i))
567 values[elem_cnt] = elements[elem_cnt].data = i;
568 check (bt_insert (&bt, &elements[elem_cnt].node) == NULL);
571 check_bt (&bt, values, elem_cnt);
573 /* Try find_ge and find_le for each possible element value. */
574 for (i = -1; i <= max_elems; i++)
577 struct bt_node *ge, *le;
581 for (j = 0; j < elem_cnt; j++)
583 if (ge == NULL && values[j] >= i)
584 ge = &elements[j].node;
586 le = &elements[j].node;
590 check (bt_find_ge (&bt, &tmp.node) == ge);
591 check (bt_find_le (&bt, &tmp.node) == le);
598 /* Inserts elements into an BT, then moves the nodes around in
603 const int max_elems = 128;
604 struct element *e[2];
610 bt_init (&bt, compare_elements, &aux_data);
611 e[0] = xnmalloc (max_elems, sizeof *e[0]);
612 e[1] = xnmalloc (max_elems, sizeof *e[1]);
613 values = xnmalloc (max_elems, sizeof *values);
615 for (i = 0; i < max_elems; i++)
617 values[i] = e[cur][i].data = i;
618 check (bt_insert (&bt, &e[cur][i].node) == NULL);
619 check_bt (&bt, values, i + 1);
621 for (j = 0; j <= i; j++)
623 e[!cur][j] = e[cur][j];
624 bt_moved (&bt, &e[!cur][j].node);
625 check_bt (&bt, values, i + 1);
634 /* Inserts values into an BT, then changes their values. */
638 const int max_elems = 6;
641 for (cnt = 0; cnt <= max_elems; cnt++)
643 int *values, *changed_values;
644 struct element *elements;
645 unsigned int permutation_cnt;
648 values = xnmalloc (cnt, sizeof *values);
649 changed_values = xnmalloc (cnt, sizeof *changed_values);
650 elements = xnmalloc (cnt, sizeof *elements);
651 for (i = 0; i < cnt; i++)
654 for (permutation_cnt = 0;
655 permutation_cnt == 0 || next_permutation (values, cnt);
658 for (i = 0; i < cnt; i++)
661 for (j = 0; j <= cnt; j++)
664 struct bt_node *changed_retval;
666 bt_init (&bt, compare_elements, &aux_data);
668 /* Add to BT in order. */
669 for (k = 0; k < cnt; k++)
672 elements[n].data = n;
673 check (bt_insert (&bt, &elements[n].node) == NULL);
675 check_bt (&bt, values, cnt);
677 /* Change value i to j. */
678 elements[i].data = j;
679 for (k = 0; k < cnt; k++)
680 changed_values[k] = k;
681 changed_retval = bt_changed (&bt, &elements[i].node);
682 if (i != j && j < cnt)
684 /* Will cause duplicate. */
685 check (changed_retval == &elements[j].node);
686 changed_values[i] = changed_values[cnt - 1];
687 check_bt (&bt, changed_values, cnt - 1);
692 check (changed_retval == NULL);
693 changed_values[i] = j;
694 check_bt (&bt, changed_values, cnt);
699 check (permutation_cnt == factorial (cnt));
702 free (changed_values);
709 /* Runs TEST_FUNCTION and prints a message about NAME. */
711 run_test (void (*test_function) (void), const char *name)
722 run_test (test_insert_any_remove_any,
723 "insert any order, delete any order");
724 run_test (test_insert_any_remove_same,
725 "insert any order, delete same order");
726 run_test (test_insert_any_remove_reverse,
727 "insert any order, delete reverse order");
728 run_test (test_random_sequence,
729 "insert and delete in random sequence");
730 run_test (test_insert_ordered,
731 "insert in ascending order");
732 run_test (test_find_ge_le, "find_ge and find_le");
733 run_test (test_moved, "move elements around in memory");
734 run_test (test_changed, "change key data in nodes");