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
18 range-map.c. This test program aims to be as comprehensive as
19 possible. With -DNDEBUG, "gcov -b" should report 100%
20 coverage of lines and branches in range-map.c routines.
21 (Without -DNDEBUG, branches caused by failed assertions will
22 not be taken.) "valgrind --leak-check=yes
23 --show-reachable=yes" should give a clean report, both with
24 and without -DNDEBUG. */
30 #include <libpspp/range-map.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 /* Swaps *A and *B. */
80 /* Reverses the order of the CNT integers starting at VALUES. */
82 reverse (int *values, size_t cnt)
88 swap (&values[i++], &values[--j]);
91 /* Arranges the CNT blocks in VALUES into the lexicographically
92 next greater permutation. Returns true if successful.
93 If VALUES is already the lexicographically greatest
94 permutation of its blocks (i.e. ordered from greatest to
95 smallest), arranges them into the lexicographically least
96 permutation (i.e. ordered from smallest to largest) and
99 next_permutation (int *values, size_t cnt)
107 if (values[i] < values[i + 1])
110 for (j = cnt - 1; values[i] >= values[j]; j--)
112 swap (values + i, values + j);
113 reverse (values + (i + 1), cnt - (i + 1));
118 reverse (values, cnt);
126 factorial (unsigned int n)
128 unsigned int value = 1;
129 /* Disallow N values that overflow on 32-bit machines. */
136 /* Tests whether PARTS is a K-part integer composition of N.
137 Returns true if so, false otherwise. */
139 is_k_composition (int n, int k, const int parts[])
145 for (i = 0; i < k; i++)
147 if (parts[i] < 1 || parts[i] > n)
154 /* Advances the K-part integer composition of N stored in PARTS
155 to the next lexicographically greater one.
156 Returns true if successful, false if the composition was
157 already the greatest K-part composition of N (in which case
158 PARTS is unaltered). */
160 next_k_composition (int n UNUSED, int k, int parts[])
164 assert (is_k_composition (n, k, parts));
168 for (i = k - 1; i > 0; i--)
179 assert (is_k_composition (n, k, parts));
183 /* Sets the K integers in PARTS to the lexicographically first
184 K-part composition of N. */
186 first_k_composition (int n, int k, int parts[])
192 for (i = 0; i < k; i++)
194 parts[k - 1] += n - k;
197 /* Advances *K and PARTS to the next integer composition of N.
198 Compositions are ordered from shortest to longest and in
199 lexicographical order within a given length.
200 Before the first call, initialize *K to 0.
201 After each successful call, *K contains the length of the
202 current composition and the *K blocks in PARTS contain its
204 Returns true if successful, false if the set of compositions
205 has been exhausted. */
207 next_composition (int n, int *k, int parts[])
209 if (*k >= 1 && next_k_composition (n, *k, parts))
213 first_k_composition (n, ++*k, parts);
220 /* Test data element. */
223 struct range_map_node node; /* Embedded tower block. */
224 int x; /* Primary value. */
227 static struct element *
228 range_map_node_to_element (struct range_map_node *node)
230 return range_map_data (node, struct element, node);
233 /* Element we expect to find. */
234 struct expected_element
236 int x; /* Primary value. */
237 unsigned long int start; /* Start of region. */
238 unsigned long int end; /* End of region. */
241 /* Compares expected_element A and B and returns a strcmp()-type
244 compare_expected_element (const void *a_, const void *b_)
246 const struct expected_element *a = (const struct expected_element *) a_;
247 const struct expected_element *b = (const struct expected_element *) b_;
248 return a->start < b->start ? -1 : a->start > b->start;
251 /* Checks that RM contains the ELEM_CNT elements described by
254 check_range_map (struct range_map *rm,
255 struct expected_element elements[], size_t elem_cnt)
257 struct expected_element *sorted;
258 struct range_map_node *node;
261 sorted = xnmalloc (elem_cnt, sizeof *sorted);
262 memcpy (sorted, elements, elem_cnt * sizeof *elements);
263 qsort (sorted, elem_cnt, sizeof *sorted, compare_expected_element);
265 check (range_map_is_empty (rm) == (elem_cnt == 0));
267 for (i = 0; i < elem_cnt; i++)
269 struct expected_element *e = &sorted[i];
270 unsigned long int position;
272 /* Check that range_map_lookup finds all the positions
273 within the element. */
274 for (position = e->start; position < e->end; position++)
276 struct range_map_node *found = range_map_lookup (rm, position);
277 check (found != NULL);
278 check (range_map_node_to_element (found)->x == e->x);
279 check (range_map_node_get_start (found) == e->start);
280 check (range_map_node_get_end (found) == e->end);
281 check (range_map_node_get_width (found) == e->end - e->start);
284 /* If there shouldn't be any elements in the positions just
285 before or after the element, verify that
286 range_map_lookup doesn't find any there. */
287 if (e->start > 0 && (i == 0 || e[-1].end < e->start))
288 check (range_map_lookup (rm, e->start - 1) == NULL);
289 if (i == elem_cnt - 1 || e->end < e[1].start)
290 check (range_map_lookup (rm, e->end) == NULL);
293 for (node = (rand () % 2 ? range_map_first (rm) : range_map_next (rm, NULL)),
296 node = range_map_next (rm, node), i++)
298 struct expected_element *e = &sorted[i];
299 check (range_map_node_to_element (node)->x == e->x);
301 check (i == elem_cnt);
306 /* Tests inserting all possible sets of ranges into a range map
307 in all possible orders, up to a specified maximum overall
312 const int max_range = 7;
315 for (cnt = 1; cnt <= max_range; cnt++)
317 unsigned int composition_cnt;
318 struct expected_element *expected;
322 struct element *elements;
324 expected = xnmalloc (cnt, sizeof *expected);
325 widths = xnmalloc (cnt, sizeof *widths);
326 order = xnmalloc (cnt, sizeof *order);
327 elements = xnmalloc (cnt, sizeof *elements);
331 while (next_composition (cnt, &elem_cnt, widths))
334 unsigned int permutation_cnt;
336 for (i = 0; i < elem_cnt; i++)
340 while (permutation_cnt == 0 || next_permutation (order, elem_cnt))
344 /* Inserts the elem_cnt elements with the given
345 widths[] into T in the order given by order[]. */
346 range_map_init (&rm);
347 for (i = 0; i < elem_cnt; i++)
349 unsigned long int start, end;
353 elements[idx].x = idx;
355 /* Find start and end of element. */
357 for (j = 0; j < idx; j++)
359 end = start + widths[j];
362 range_map_insert (&rm, start, end - start,
363 &elements[idx].node);
365 /* Check map contents. */
367 expected[i].start = start;
368 expected[i].end = end;
369 check_range_map (&rm, expected, i + 1);
373 check (permutation_cnt == factorial (elem_cnt));
377 check (composition_cnt == 1 << (cnt - 1));
386 /* Tests deleting ranges from a range map in all possible orders,
387 up to a specified maximum overall range. */
389 test_delete (int gap)
391 const int max_range = 7;
394 for (cnt = 1; cnt <= max_range; cnt++)
396 unsigned int composition_cnt;
397 struct expected_element *expected;
401 struct element *elements;
403 expected = xnmalloc (cnt, sizeof *expected);
404 widths = xnmalloc (cnt, sizeof *widths);
405 order = xnmalloc (cnt, sizeof *order);
406 elements = xnmalloc (cnt, sizeof *elements);
410 while (next_composition (cnt, &elem_cnt, widths))
413 unsigned int permutation_cnt;
415 for (i = 0; i < elem_cnt; i++)
419 while (permutation_cnt == 0 || next_permutation (order, elem_cnt))
422 unsigned long int start;
424 /* Insert all the elements. */
425 range_map_init (&rm);
427 for (i = 0; i < elem_cnt; i++)
429 int width = widths[i] > gap ? widths[i] - gap : widths[i];
430 unsigned long int end = start + width;
433 range_map_insert (&rm, start, end - start,
438 assert (j < elem_cnt);
442 expected[j].start = start;
443 expected[j].end = end;
450 check_range_map (&rm, expected, elem_cnt);
452 /* Delete the elements in the specified order. */
453 for (i = 0; i < elem_cnt; i++)
455 range_map_delete (&rm, &elements[order[i]].node);
456 check_range_map (&rm, expected + i + 1, elem_cnt - i - 1);
461 check (permutation_cnt == factorial (elem_cnt));
465 check (composition_cnt == 1 << (cnt - 1));
474 /* Tests deleting ranges from a range map filled with contiguous
475 ranges in all possible orders, up to a specified maximum
478 test_delete_contiguous (void)
483 /* Tests deleting ranges from a range map filled with ranges
484 sometimes separated by gaps in all possible orders, up to a
485 specified maximum overall range. */
487 test_delete_gaps (void)
494 /* Runs TEST_FUNCTION and prints a message about NAME. */
496 run_test (void (*test_function) (void), const char *name)
507 run_test (test_insert, "insert");
508 run_test (test_delete_contiguous, "delete from contiguous ranges");
509 run_test (test_delete_gaps, "delete from ranges separated by gaps");