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 routines defined in heap.c.
18 This test program aims to be as comprehensive as possible.
19 With -DNDEBUG, "gcov -b" should report 100% coverage of lines
20 and branches in heap.c routines, except for the is_heap
21 function, which is not called at all with -DNDEBUG. (Without
22 -DNDEBUG, branches caused by failed assertions will also not
23 be taken.) "valgrind --leak-check=yes --show-reachable=yes"
24 should give a clean report, both with and without -DNDEBUG. */
30 #include <libpspp/heap.h>
38 #include <libpspp/compiler.h>
42 /* Currently running test. */
43 static const char *test_name;
45 /* Exit with a failure code.
46 (Place a breakpoint on this function while debugging.) */
53 /* If OK is not true, prints a message about failure on the
54 current source file and the given LINE and terminates. */
56 check_func (bool ok, int line)
60 printf ("Check failed in %s test at %s, line %d\n",
61 test_name, __FILE__, line);
66 /* Verifies that EXPR evaluates to true.
67 If not, prints a message citing the calling line number and
69 #define check(EXPR) check_func ((EXPR), __LINE__)
71 /* Node type and support routines. */
73 /* Test data element. */
76 struct heap_node node; /* Embedded heap element. */
77 int x; /* Primary value. */
82 /* Returns the `struct element' that NODE is embedded within. */
83 static struct element *
84 heap_node_to_element (const struct heap_node *node)
86 return heap_data (node, struct element, node);
89 /* Compares the `x' values in A and B and returns a strcmp-type
90 return value. Verifies that AUX points to aux_data. */
92 compare_elements (const struct heap_node *a_, const struct heap_node *b_,
95 const struct element *a = heap_node_to_element (a_);
96 const struct element *b = heap_node_to_element (b_);
98 check (aux == &aux_data);
99 return a->x < b->x ? -1 : a->x > b->x;
102 /* Returns the smallest of the N integers in ARRAY. */
104 min_int (int *array, size_t n)
110 for (i = 0; i < n; i++)
116 /* Swaps *A and *B. */
118 swap (int *a, int *b)
125 /* Reverses the order of the CNT integers starting at VALUES. */
127 reverse (int *values, size_t cnt)
133 swap (&values[i++], &values[--j]);
136 /* Arranges the CNT elements in VALUES into the lexicographically
137 next greater permutation. Returns true if successful.
138 If VALUES is already the lexicographically greatest
139 permutation of its elements (i.e. ordered from greatest to
140 smallest), arranges them into the lexicographically least
141 permutation (i.e. ordered from smallest to largest) and
144 next_permutation (int *values, size_t cnt)
152 if (values[i] < values[i + 1])
155 for (j = cnt - 1; values[i] >= values[j]; j--)
157 swap (values + i, values + j);
158 reverse (values + (i + 1), cnt - (i + 1));
163 reverse (values, cnt);
171 factorial (unsigned int n)
173 unsigned int value = 1;
179 /* Returns the number of permutations of the CNT values in
180 VALUES. If VALUES contains duplicates, they must be
183 expected_perms (int *values, size_t cnt)
186 unsigned int perm_cnt;
188 perm_cnt = factorial (cnt);
189 for (i = 0; i < cnt; i = j)
191 for (j = i + 1; j < cnt; j++)
192 if (values[i] != values[j])
194 perm_cnt /= factorial (j - i);
199 /* Tests whether PARTS is a K-part integer composition of N.
200 Returns true if so, false otherwise. */
202 is_k_composition (int n, int k, const int parts[])
208 for (i = 0; i < k; i++)
210 if (parts[i] < 1 || parts[i] > n)
217 /* Advances the K-part integer composition of N stored in PARTS
218 to the next lexicographically greater one.
219 Returns true if successful, false if the composition was
220 already the greatest K-part composition of N (in which case
221 PARTS is unaltered). */
223 next_k_composition (int n UNUSED, int k, int parts[])
227 assert (is_k_composition (n, k, parts));
231 for (i = k - 1; i > 0; i--)
242 assert (is_k_composition (n, k, parts));
246 /* Advances *K and PARTS to the next integer composition of N.
247 Compositions are ordered from shortest to longest and in
248 lexicographical order within a given length.
249 Before the first call, initialize *K to 0.
250 After each successful call, *K contains the length of the
251 current composition and the *K elements in PARTS contain its
253 Returns true if successful, false if the set of compositions
254 has been exhausted. */
256 next_composition (int n, int *k, int parts[])
258 if (*k >= 1 && next_k_composition (n, *k, parts))
263 for (i = 0; i < *k; i++)
273 /* Inserts sequences without duplicates into a heap, and then
274 ensures that they appear as the minimum element in the correct
275 order as we delete them. Exhaustively tests every input
276 permutation up to 'max_elems' elements. */
278 test_insert_no_dups_delete_min (void)
280 const int max_elems = 8;
283 for (cnt = 0; cnt <= max_elems; cnt++)
286 struct element *elements;
288 unsigned int permutation_cnt;
291 values = xnmalloc (cnt, sizeof *values);
292 elements = xnmalloc (cnt, sizeof *elements);
293 for (i = 0; i < cnt; i++)
296 h = heap_create (compare_elements, &aux_data);
298 while (permutation_cnt == 0 || next_permutation (values, cnt))
302 for (i = 0; i < cnt; i++)
303 elements[i].x = values[i];
305 check (heap_is_empty (h));
306 for (i = 0; i < cnt; i++)
308 heap_insert (h, &elements[i].node);
309 check (heap_node_to_element (heap_minimum (h))->x
310 == min_int (values, i + 1));
311 check (heap_count (h) == i + 1);
314 for (i = 0; i < cnt; i++)
316 check (heap_node_to_element (heap_minimum (h))->x == i);
317 heap_delete (h, heap_minimum (h));
319 check (heap_is_empty (h));
322 check (permutation_cnt == factorial (cnt));
329 /* Inserts sequences with duplicates into a heap, and then
330 ensures that they appear as the minimum element in the correct
331 order as we delete them. Exhaustively tests every input
332 permutation up to 'max_elems' elements.
334 See Usenet article <87mz4utika.fsf@blp.benpfaff.org> for
335 details of the algorithm used here. */
337 test_insert_with_dups_delete_min (void)
339 const int max_elems = 7;
342 for (cnt = 1; cnt <= max_elems; cnt++)
344 unsigned int composition_cnt;
349 struct element *elements;
352 dups = xnmalloc (cnt, sizeof *dups);
353 values = xnmalloc (cnt, sizeof *values);
354 sorted_values = xnmalloc (cnt, sizeof *sorted_values);
355 elements = xnmalloc (cnt, sizeof *elements);
359 while (next_composition (cnt, &unique_cnt, dups))
363 unsigned int permutation_cnt;
366 for (i = 0; i < unique_cnt; i++)
367 for (j = 0; j < dups[i]; j++)
370 sorted_values[k] = i;
375 h = heap_create (compare_elements, &aux_data);
377 while (permutation_cnt == 0 || next_permutation (values, cnt))
381 for (i = 0; i < cnt; i++)
382 elements[i].x = values[i];
385 check (heap_is_empty (h));
386 for (i = 0; i < cnt; i++)
388 heap_insert (h, &elements[i].node);
391 check (heap_node_to_element (heap_minimum (h))->x == min);
392 check (heap_count (h) == i + 1);
395 for (i = 0; i < cnt; i++)
397 struct element *min = heap_node_to_element (heap_minimum (h));
398 check (min->x == sorted_values[i]);
399 heap_delete (h, heap_minimum (h));
401 check (heap_is_empty (h));
404 check (permutation_cnt == expected_perms (values, cnt));
409 check (composition_cnt == 1 << (cnt - 1));
413 free (sorted_values);
418 /* Inserts a sequence without duplicates into a heap, then
419 deletes them in a different order. */
421 test_insert_no_dups_delete_random (void)
423 const int max_elems = 5;
426 for (cnt = 0; cnt <= max_elems; cnt++)
429 struct element *elements;
430 int *insert, *delete;
431 unsigned int insert_perm_cnt;
434 insert = xnmalloc (cnt, sizeof *insert);
435 delete = xnmalloc (cnt, sizeof *delete);
436 elements = xnmalloc (cnt, sizeof *elements);
437 for (i = 0; i < cnt; i++)
444 h = heap_create (compare_elements, &aux_data);
446 while (insert_perm_cnt == 0 || next_permutation (insert, cnt))
448 unsigned int delete_perm_cnt = 0;
450 while (delete_perm_cnt == 0 || next_permutation (delete, cnt))
455 check (heap_is_empty (h));
457 for (i = 0; i < cnt; i++)
459 heap_insert (h, &elements[insert[i]].node);
462 check (heap_node_to_element (heap_minimum (h))->x == min);
463 check (heap_count (h) == i + 1);
466 for (i = 0; i < cnt; i++)
468 int new_min = min_int (delete + i + 1, cnt - i - 1);
469 heap_delete (h, &elements[delete[i]].node);
470 check (heap_count (h) == cnt - i - 1);
471 if (!heap_is_empty (h))
472 check (heap_node_to_element (heap_minimum (h))->x == new_min);
474 check (heap_is_empty (h));
477 check (delete_perm_cnt == factorial (cnt));
480 check (insert_perm_cnt == factorial (cnt));
488 /* Inserts a set of values into a heap, then changes them to a
489 different random set of values, then removes them in sorted
494 const int max_elems = 8;
497 for (cnt = 0; cnt <= max_elems; cnt++)
500 struct element *elements;
501 int *insert, *delete;
502 unsigned int insert_perm_cnt;
505 insert = xnmalloc (cnt, sizeof *insert);
506 delete = xnmalloc (cnt, sizeof *delete);
507 elements = xnmalloc (cnt, sizeof *elements);
508 for (i = 0; i < cnt; i++)
511 h = heap_create (compare_elements, &aux_data);
513 while (insert_perm_cnt == 0 || next_permutation (insert, cnt))
515 for (i = 0; i < cnt; i++)
516 elements[i].x = insert[i];
518 check (heap_is_empty (h));
519 for (i = 0; i < cnt; i++)
521 int new_min = min_int (insert, i + 1);
522 heap_insert (h, &elements[i].node);
523 check (heap_node_to_element (heap_minimum (h))->x == new_min);
524 check (heap_count (h) == i + 1);
527 for (i = 0; i < cnt; i++)
528 delete[i] = insert[i];
529 for (i = 0; i < cnt; i++)
531 int old_value, old_min, new_min;
532 old_min = min_int (delete, cnt);
533 old_value = delete[i];
534 elements[i].x = delete[i] = rand () % (cnt + 2) - 1;
535 new_min = min_int (delete, cnt);
536 heap_changed (h, &elements[i].node);
537 check (heap_node_to_element (heap_minimum (h))->x
538 == min_int (delete, cnt));
541 for (i = 0; i < cnt; i++)
543 int new_min = min_int (delete + i + 1, cnt - i - 1);
544 heap_delete (h, &elements[i].node);
545 check (heap_count (h) == cnt - i - 1);
546 if (!heap_is_empty (h))
547 check (heap_node_to_element (heap_minimum (h))->x == new_min);
549 check (heap_is_empty (h));
552 check (insert_perm_cnt == factorial (cnt));
560 /* Performs a random sequence of insertions and deletions in a
563 test_random_insert_delete (void)
565 const int max_elems = 64;
566 const int num_actions = 250000;
569 struct element *elements;
574 values = xnmalloc (max_elems, sizeof *values);
575 elements = xnmalloc (max_elems, sizeof *elements);
579 h = heap_create (compare_elements, &aux_data);
580 for (i = 0; i < num_actions; i++)
582 enum { INSERT, DELETE } action;
587 if (insert_chance < 9)
590 else if (cnt == max_elems)
593 if (insert_chance > 0)
597 action = rand () % 10 < insert_chance ? INSERT : DELETE;
599 if (action == INSERT)
604 new_value = rand () % max_elems;
605 values[cnt] = new_value;
606 elements[cnt].x = new_value;
608 heap_insert (h, &elements[cnt].node);
610 old_min = min_int (values, cnt);
614 else if (action == DELETE)
618 int old_min, new_min;
620 old_min = min_int (values, cnt);
622 del_idx = rand () % cnt;
623 del_value = values[del_idx];
624 heap_delete (h, &elements[del_idx].node);
629 values[del_idx] = values[cnt];
630 elements[del_idx] = elements[cnt];
631 heap_moved (h, &elements[del_idx].node);
634 new_min = min_int (values, cnt);
639 check (heap_count (h) == cnt);
640 check (heap_is_empty (h) == (cnt == 0));
642 check (heap_node_to_element (heap_minimum (h))->x
643 == min_int (values, cnt));
652 /* Runs TEST_FUNCTION and prints a message about NAME. */
654 run_test (void (*test_function) (void), const char *name)
665 run_test (test_insert_no_dups_delete_min,
666 "insert (no dups), delete minimum values");
667 run_test (test_insert_with_dups_delete_min,
668 "insert with dups, delete minimum values");
669 run_test (test_insert_no_dups_delete_random,
670 "insert (no dups), delete in random order");
671 run_test (test_inc_dec, "increase and decrease values");
672 run_test (test_random_insert_delete, "random insertions and deletions");