1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009 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 /* Currently running test. */
44 static const char *test_name;
46 /* Exit with a failure code.
47 (Place a breakpoint on this function while debugging.) */
54 /* If OK is not true, prints a message about failure on the
55 current source file and the given LINE and terminates. */
57 check_func (bool ok, int line)
61 printf ("Check failed in %s test at %s, line %d\n",
62 test_name, __FILE__, line);
67 /* Verifies that EXPR evaluates to true.
68 If not, prints a message citing the calling line number and
70 #define check(EXPR) check_func ((EXPR), __LINE__)
72 /* A contiguous region. */
75 unsigned long int start; /* Start of region. */
76 unsigned long int end; /* One past the end. */
79 /* Number of bits in an unsigned int. */
80 #define UINT_BIT (CHAR_BIT * sizeof (unsigned int))
82 /* Returns the number of contiguous 1-bits in X starting from bit
84 This implementation is designed to be obviously correct, not
87 count_one_bits (unsigned long int x)
98 /* Searches the bits in PATTERN from right to left starting from
99 bit OFFSET for one or more 1-bits. If any are found, sets
100 *START to the bit index of the first and *WIDTH to the number
101 of contiguous 1-bits and returns true. Otherwise, returns
103 This implementation is designed to be obviously correct, not
106 next_region (unsigned int pattern, unsigned int offset,
107 unsigned long int *start, unsigned long int *width)
111 assert (offset <= UINT_BIT);
112 for (i = offset; i < UINT_BIT; i++)
113 if (pattern & (1u << i))
116 *width = count_one_bits (pattern >> i);
122 /* Searches the bits in PATTERN from left to right starting from
123 just beyond bit OFFSET for one or more 1-bits. If any are
124 found, sets *START to the bit index of the first and *WIDTH to
125 the number of contiguous 1-bits and returns true. Otherwise,
127 This implementation is designed to be obviously correct, not
130 prev_region (unsigned int pattern, unsigned int offset,
131 unsigned long int *start, unsigned long int *width)
135 assert (offset <= UINT_BIT);
136 for (i = offset; i-- > 0; )
137 if (pattern & (1u << i))
141 while (i-- > 0 && pattern & (1u << i))
151 /* Searches the bits in PATTERN from right to left starting from
152 bit OFFSET. Returns the bit index of the first 1-bit found,
153 or ULONG_MAX if none is found. */
154 static unsigned long int
155 next_1bit (unsigned int pattern, unsigned int offset)
157 for (; offset < UINT_BIT; offset++)
158 if (pattern & (1u << offset))
163 /* Prints the regions in RS to stdout. */
165 print_regions (const struct range_set *rs)
167 const struct range_set_node *node;
170 for (node = range_set_first (rs); node != NULL;
171 node = range_set_next (rs, node))
172 printf (" (%lu,%lu)",
173 range_set_node_get_start (node), range_set_node_get_end (node));
177 /* Checks that the regions in RS match the bits in PATTERN. */
179 check_pattern (const struct range_set *rs, unsigned int pattern)
181 const struct range_set_node *node;
182 unsigned long int start, width;
183 unsigned long int s1, s2;
186 for (node = rand () % 2 ? range_set_first (rs) : range_set_next (rs, NULL),
188 next_region (pattern, start + width, &start, &width);
189 node = range_set_next (rs, node))
191 check (node != NULL);
192 check (range_set_node_get_start (node) == start);
193 check (range_set_node_get_end (node) == start + width);
194 check (range_set_node_get_width (node) == width);
196 check (node == NULL);
198 for (node = rand () % 2 ? range_set_last (rs) : range_set_prev (rs, NULL),
200 prev_region (pattern, start, &start, &width);
201 node = range_set_prev (rs, node))
203 check (node != NULL);
204 check (range_set_node_get_start (node) == start);
205 check (range_set_node_get_end (node) == start + width);
206 check (range_set_node_get_width (node) == width);
208 check (node == NULL);
210 /* Scan from all possible positions, resetting the cache each
211 time, to ensure that we get the correct answers without
213 for (start = 0; start <= 32; start++)
215 struct range_set *nonconst_rs = (struct range_set *) rs;
216 nonconst_rs->cache_end = 0;
217 s1 = range_set_scan (rs, start);
218 s2 = next_1bit (pattern, start);
222 /* Scan in forward order to exercise expected cache behavior. */
223 for (s1 = range_set_scan (rs, 0), s2 = next_1bit (pattern, 0); ;
224 s1 = range_set_scan (rs, s1 + 1), s2 = next_1bit (pattern, s2 + 1))
231 /* Scan in random order to frustrate cache. */
232 for (i = 0; i < 32; i++)
234 start = rand () % 32;
235 s1 = range_set_scan (rs, start);
236 s2 = next_1bit (pattern, start);
240 /* Test range_set_scan() with negative cache. */
241 check (!range_set_contains (rs, 999));
242 check (range_set_scan (rs, 1111) == ULONG_MAX);
244 for (i = 0; i < UINT_BIT; i++)
245 check (range_set_contains (rs, i) == ((pattern & (1u << i)) != 0));
246 check (!range_set_contains (rs,
247 UINT_BIT + rand () % (ULONG_MAX - UINT_BIT)));
249 check (range_set_is_empty (rs) == (pattern == 0));
252 /* Creates and returns a range set that contains regions for the
253 bits set in PATTERN. */
254 static struct range_set *
255 make_pattern (unsigned int pattern)
257 unsigned long int start = 0;
258 unsigned long int width = 0;
259 struct range_set *rs = range_set_create_pool (NULL);
260 while (next_region (pattern, start + width, &start, &width))
261 range_set_insert (rs, start, width);
262 check_pattern (rs, pattern);
266 /* Returns an unsigned int with bits OFS...OFS+CNT (exclusive)
267 set to 1, other bits set to 0. */
269 bit_range (unsigned int ofs, unsigned int cnt)
271 assert (ofs < UINT_BIT);
272 assert (cnt <= UINT_BIT);
273 assert (ofs + cnt <= UINT_BIT);
275 return cnt < UINT_BIT ? ((1u << cnt) - 1) << ofs : UINT_MAX;
278 /* Tests inserting all possible patterns into all possible range
279 sets (up to a small maximum number of bits). */
283 const int positions = 9;
284 unsigned int init_pat;
287 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
288 for (i = 0; i < positions + 1; i++)
289 for (j = i; j <= positions + 1; j++)
291 struct range_set *rs, *rs2;
292 unsigned int final_pat;
294 rs = make_pattern (init_pat);
295 range_set_insert (rs, i, j - i);
296 final_pat = init_pat | bit_range (i, j - i);
297 check_pattern (rs, final_pat);
298 rs2 = range_set_clone (rs, NULL);
299 check_pattern (rs2, final_pat);
300 range_set_destroy (rs);
301 range_set_destroy (rs2);
305 /* Tests deleting all possible patterns from all possible range
306 sets (up to a small maximum number of bits). */
310 const int positions = 9;
311 unsigned int init_pat;
314 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
315 for (i = 0; i < positions + 1; i++)
316 for (j = i; j <= positions + 1; j++)
318 struct range_set *rs;
319 unsigned int final_pat;
321 rs = make_pattern (init_pat);
322 range_set_delete (rs, i, j - i);
323 final_pat = init_pat & ~bit_range (i, j - i);
324 check_pattern (rs, final_pat);
325 range_set_destroy (rs);
329 /* Tests all possible allocation in all possible range sets (up
330 to a small maximum number of bits). */
334 const int positions = 9;
335 unsigned int init_pat;
338 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
339 for (request = 1; request <= positions + 1; request++)
341 struct range_set *rs;
342 unsigned long int start, width, expect_start, expect_width;
343 bool success, expect_success;
344 unsigned int final_pat;
347 /* Figure out expected results. */
348 expect_success = false;
349 expect_start = expect_width = 0;
350 final_pat = init_pat;
351 for (i = 0; i < positions; i++)
352 if (init_pat & (1u << i))
354 expect_success = true;
356 expect_width = count_one_bits (init_pat >> i);
357 if (expect_width > request)
358 expect_width = request;
359 final_pat &= ~bit_range (expect_start, expect_width);
364 rs = make_pattern (init_pat);
365 success = range_set_allocate (rs, request, &start, &width);
366 check_pattern (rs, final_pat);
367 range_set_destroy (rs);
370 check (success == expect_success);
373 check (start == expect_start);
374 check (width == expect_width);
379 /* Tests all possible full allocations in all possible range sets
380 (up to a small maximum number of bits). */
382 test_allocate_fully (void)
384 const int positions = 9;
385 unsigned int init_pat;
388 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
389 for (request = 1; request <= positions + 1; request++)
391 struct range_set *rs;
392 unsigned long int start, expect_start;
393 bool success, expect_success;
394 unsigned int final_pat;
397 /* Figure out expected results. */
398 expect_success = false;
400 final_pat = init_pat;
401 for (i = 0; i < positions - request + 1; i++)
405 final_pat = init_pat;
406 for (j = i; j < i + request; j++)
408 if (!(init_pat & (1u << j)))
410 final_pat &= ~(1u << j);
413 expect_success = true;
417 final_pat = init_pat;
421 rs = make_pattern (init_pat);
422 success = range_set_allocate_fully (rs, request, &start);
423 check_pattern (rs, final_pat);
424 range_set_destroy (rs);
427 check (success == expect_success);
429 check (start == expect_start);
433 /* Tests freeing a range set through a pool. */
438 struct range_set *rs;
440 /* Destroy the range set, then the pool.
441 Makes sure that this doesn't cause a double-free. */
442 pool = pool_create ();
443 rs = range_set_create_pool (pool);
444 range_set_insert (rs, 1, 10);
445 range_set_destroy (rs);
448 /* Just destroy the pool.
449 Makes sure that this doesn't cause a leak. */
450 pool = pool_create ();
451 rs = range_set_create_pool (pool);
452 range_set_insert (rs, 1, 10);
456 /* Tests range_set_destroy(NULL). */
458 test_destroy_null (void)
460 range_set_destroy (NULL);
465 /* Runs TEST_FUNCTION and prints a message about NAME. */
467 run_test (void (*test_function) (void), const char *name)
478 run_test (test_insert, "insert");
479 run_test (test_delete, "delete");
480 run_test (test_allocate, "allocate");
481 run_test (test_allocate_fully, "allocate_fully");
482 run_test (test_pool, "pool");
483 run_test (test_destroy_null, "destroy null");