1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009, 2010, 2011, 2012 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-set.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-set.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-set.h>
38 #include <libpspp/compiler.h>
39 #include <libpspp/pool.h>
43 /* Exit with a failure code.
44 (Place a breakpoint on this function while debugging.) */
51 /* If OK is not true, prints a message about failure on the
52 current source file and the given LINE and terminates. */
54 check_func (bool ok, int line)
58 fprintf (stderr, "%s:%d: check failed\n", __FILE__, line);
63 /* Verifies that EXPR evaluates to true.
64 If not, prints a message citing the calling line number and
66 #define check(EXPR) check_func ((EXPR), __LINE__)
68 /* A contiguous region. */
71 unsigned long int start; /* Start of region. */
72 unsigned long int end; /* One past the end. */
75 /* Number of bits in an unsigned int. */
76 #define UINT_BIT (CHAR_BIT * sizeof (unsigned int))
78 /* Returns the number of contiguous 1-bits in X starting from bit
80 This implementation is designed to be obviously correct, not
83 count_one_bits (unsigned long int x)
94 /* Searches the bits in PATTERN from right to left starting from
95 bit OFFSET for one or more 1-bits. If any are found, sets
96 *START to the bit index of the first and *WIDTH to the number
97 of contiguous 1-bits and returns true. Otherwise, returns
99 This implementation is designed to be obviously correct, not
102 next_region (unsigned int pattern, unsigned int offset,
103 unsigned long int *start, unsigned long int *width)
107 assert (offset <= UINT_BIT);
108 for (i = offset; i < UINT_BIT; i++)
109 if (pattern & (1u << i))
112 *width = count_one_bits (pattern >> i);
118 /* Searches the bits in PATTERN from left to right starting from
119 just beyond bit OFFSET for one or more 1-bits. If any are
120 found, sets *START to the bit index of the first and *WIDTH to
121 the number of contiguous 1-bits and returns true. Otherwise,
123 This implementation is designed to be obviously correct, not
126 prev_region (unsigned int pattern, unsigned int offset,
127 unsigned long int *start, unsigned long int *width)
131 assert (offset <= UINT_BIT);
132 for (i = offset; i-- > 0; )
133 if (pattern & (1u << i))
137 while (i-- > 0 && pattern & (1u << i))
147 /* Searches the bits in PATTERN from right to left starting from
148 bit OFFSET. Returns the bit index of the first 1-bit found,
149 or ULONG_MAX if none is found. */
150 static unsigned long int
151 next_1bit (unsigned int pattern, unsigned int offset)
153 for (; offset < UINT_BIT; offset++)
154 if (pattern & (1u << offset))
159 /* Prints the regions in RS to stdout. */
161 print_regions (const struct range_set *rs)
163 const struct range_set_node *node;
166 RANGE_SET_FOR_EACH (node, rs)
167 printf (" (%lu,%lu)",
168 range_set_node_get_start (node), range_set_node_get_end (node));
172 /* Checks that the regions in RS match the bits in PATTERN. */
174 check_pattern (const struct range_set *rs, unsigned int pattern)
176 const struct range_set_node *node;
177 unsigned long int start, width;
178 unsigned long int s1, s2;
181 for (node = rand () % 2 ? range_set_first (rs) : range_set_next (rs, NULL),
183 next_region (pattern, start + width, &start, &width);
184 node = range_set_next (rs, node))
186 check (node != NULL);
187 check (range_set_node_get_start (node) == start);
188 check (range_set_node_get_end (node) == start + width);
189 check (range_set_node_get_width (node) == width);
191 check (node == NULL);
193 for (node = rand () % 2 ? range_set_last (rs) : range_set_prev (rs, NULL),
195 prev_region (pattern, start, &start, &width);
196 node = range_set_prev (rs, node))
198 check (node != NULL);
199 check (range_set_node_get_start (node) == start);
200 check (range_set_node_get_end (node) == start + width);
201 check (range_set_node_get_width (node) == width);
203 check (node == NULL);
205 /* Scan from all possible positions, resetting the cache each
206 time, to ensure that we get the correct answers without
208 for (start = 0; start <= 32; start++)
210 struct range_set *nonconst_rs = CONST_CAST (struct range_set *, rs);
211 nonconst_rs->cache_end = 0;
212 s1 = range_set_scan (rs, start);
213 s2 = next_1bit (pattern, start);
217 /* Scan in forward order to exercise expected cache behavior. */
218 for (s1 = range_set_scan (rs, 0), s2 = next_1bit (pattern, 0); ;
219 s1 = range_set_scan (rs, s1 + 1), s2 = next_1bit (pattern, s2 + 1))
226 /* Scan in random order to frustrate cache. */
227 for (i = 0; i < 32; i++)
229 start = rand () % 32;
230 s1 = range_set_scan (rs, start);
231 s2 = next_1bit (pattern, start);
235 /* Test range_set_scan() with negative cache. */
236 check (!range_set_contains (rs, 999));
237 check (range_set_scan (rs, 1111) == ULONG_MAX);
239 for (i = 0; i < UINT_BIT; i++)
240 check (range_set_contains (rs, i) == ((pattern & (1u << i)) != 0));
241 check (!range_set_contains (rs,
242 UINT_BIT + rand () % (ULONG_MAX - UINT_BIT)));
244 check (range_set_is_empty (rs) == (pattern == 0));
247 /* Creates and returns a range set that contains regions for the
248 bits set in PATTERN. */
249 static struct range_set *
250 make_pattern (unsigned int pattern)
252 unsigned long int start = 0;
253 unsigned long int width = 0;
254 struct range_set *rs = range_set_create_pool (NULL);
255 while (next_region (pattern, start + width, &start, &width))
256 range_set_set1 (rs, start, width);
257 check_pattern (rs, pattern);
261 /* Returns an unsigned int with bits OFS...OFS+CNT (exclusive)
262 set to 1, other bits set to 0. */
264 bit_range (unsigned int ofs, unsigned int cnt)
266 assert (ofs < UINT_BIT);
267 assert (cnt <= UINT_BIT);
268 assert (ofs + cnt <= UINT_BIT);
270 return cnt < UINT_BIT ? ((1u << cnt) - 1) << ofs : UINT_MAX;
273 /* Tests inserting all possible patterns into all possible range
274 sets (up to a small maximum number of bits). */
278 const int positions = 9;
279 unsigned int init_pat;
282 #if __GNUC__ == 4 && __GNUC_MINOR__ == 2 && __llvm__
283 /* This test seems to trigger a bug in llvm-gcc 4.2 on Mac OS X 10.8.0.
284 Exit code 77 tells the Autotest framework that the test was skipped. */
288 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
289 for (i = 0; i < positions + 1; i++)
290 for (j = i; j <= positions + 1; j++)
292 struct range_set *rs, *rs2;
293 unsigned int final_pat;
295 rs = make_pattern (init_pat);
296 range_set_set1 (rs, i, j - i);
297 final_pat = init_pat | bit_range (i, j - i);
298 check_pattern (rs, final_pat);
299 rs2 = range_set_clone (rs, NULL);
300 check_pattern (rs2, final_pat);
301 range_set_destroy (rs);
302 range_set_destroy (rs2);
306 /* Tests deleting all possible patterns from all possible range
307 sets (up to a small maximum number of bits). */
311 const int positions = 9;
312 unsigned int init_pat;
315 #if __GNUC__ == 4 && __GNUC_MINOR__ == 2 && __llvm__
316 /* This test seems to trigger a bug in llvm-gcc 4.2 on Mac OS X 10.8.0.
317 Exit code 77 tells the Autotest framework that the test was skipped. */
321 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
322 for (i = 0; i < positions + 1; i++)
323 for (j = i; j <= positions + 1; j++)
325 struct range_set *rs;
326 unsigned int final_pat;
328 rs = make_pattern (init_pat);
329 range_set_set0 (rs, i, j - i);
330 final_pat = init_pat & ~bit_range (i, j - i);
331 check_pattern (rs, final_pat);
332 range_set_destroy (rs);
336 /* Tests all possible allocation in all possible range sets (up
337 to a small maximum number of bits). */
341 const int positions = 9;
342 unsigned int init_pat;
345 #if __GNUC__ == 4 && __GNUC_MINOR__ == 2 && __llvm__
346 /* This test seems to trigger a bug in llvm-gcc 4.2 on Mac OS X 10.8.0.
347 Exit code 77 tells the Autotest framework that the test was skipped. */
351 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
352 for (request = 1; request <= positions + 1; request++)
354 struct range_set *rs;
355 unsigned long int start, width, expect_start, expect_width;
356 bool success, expect_success;
357 unsigned int final_pat;
360 /* Figure out expected results. */
361 expect_success = false;
362 expect_start = expect_width = 0;
363 final_pat = init_pat;
364 for (i = 0; i < positions; i++)
365 if (init_pat & (1u << i))
367 expect_success = true;
369 expect_width = count_one_bits (init_pat >> i);
370 if (expect_width > request)
371 expect_width = request;
372 final_pat &= ~bit_range (expect_start, expect_width);
377 rs = make_pattern (init_pat);
378 success = range_set_allocate (rs, request, &start, &width);
379 check_pattern (rs, final_pat);
380 range_set_destroy (rs);
383 check (success == expect_success);
386 check (start == expect_start);
387 check (width == expect_width);
392 /* Tests all possible full allocations in all possible range sets
393 (up to a small maximum number of bits). */
395 test_allocate_fully (void)
397 const int positions = 9;
398 unsigned int init_pat;
401 #if __GNUC__ == 4 && __GNUC_MINOR__ == 2 && __llvm__
402 /* This test seems to trigger a bug in llvm-gcc 4.2 on Mac OS X 10.8.0.
403 Exit code 77 tells the Autotest framework that the test was skipped. */
407 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
408 for (request = 1; request <= positions + 1; request++)
410 struct range_set *rs;
411 unsigned long int start, expect_start;
412 bool success, expect_success;
413 unsigned int final_pat;
416 /* Figure out expected results. */
417 expect_success = false;
419 final_pat = init_pat;
420 for (i = 0; i < positions - request + 1; i++)
424 final_pat = init_pat;
425 for (j = i; j < i + request; j++)
427 if (!(init_pat & (1u << j)))
429 final_pat &= ~(1u << j);
432 expect_success = true;
436 final_pat = init_pat;
440 rs = make_pattern (init_pat);
441 success = range_set_allocate_fully (rs, request, &start);
442 check_pattern (rs, final_pat);
443 range_set_destroy (rs);
446 check (success == expect_success);
448 check (start == expect_start);
452 /* Tests freeing a range set through a pool. */
457 struct range_set *rs;
459 /* Destroy the range set, then the pool.
460 Makes sure that this doesn't cause a double-free. */
461 pool = pool_create ();
462 rs = range_set_create_pool (pool);
463 range_set_set1 (rs, 1, 10);
464 range_set_destroy (rs);
467 /* Just destroy the pool.
468 Makes sure that this doesn't cause a leak. */
469 pool = pool_create ();
470 rs = range_set_create_pool (pool);
471 range_set_set1 (rs, 1, 10);
475 /* Tests range_set_destroy(NULL). */
477 test_destroy_null (void)
479 range_set_destroy (NULL);
487 const char *description;
488 void (*function) (void);
491 static const struct test tests[] =
525 enum { N_TESTS = sizeof tests / sizeof *tests };
528 main (int argc, char *argv[])
534 fprintf (stderr, "exactly one argument required; use --help for help\n");
537 else if (!strcmp (argv[1], "--help"))
539 printf ("%s: test range set library\n"
540 "usage: %s TEST-NAME\n"
541 "where TEST-NAME is one of the following:\n",
543 for (i = 0; i < N_TESTS; i++)
544 printf (" %s\n %s\n", tests[i].name, tests[i].description);
549 for (i = 0; i < N_TESTS; i++)
550 if (!strcmp (argv[1], tests[i].name))
552 tests[i].function ();
556 fprintf (stderr, "unknown test %s; use --help for help\n", argv[1]);