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 routines defined in
20 range-set.c. This test program aims to be as comprehensive as
21 possible. With -DNDEBUG, "gcov -b" should report 100%
22 coverage of lines and branches in range-set.c routines.
23 (Without -DNDEBUG, branches caused by failed assertions will
24 not be taken.) "valgrind --leak-check=yes
25 --show-reachable=yes" should give a clean report, both with
26 and without -DNDEBUG. */
32 #include <libpspp/range-set.h>
40 #include <libpspp/compiler.h>
41 #include <libpspp/pool.h>
45 /* Currently running test. */
46 static const char *test_name;
48 /* Exit with a failure code.
49 (Place a breakpoint on this function while debugging.) */
56 /* If OK is not true, prints a message about failure on the
57 current source file and the given LINE and terminates. */
59 check_func (bool ok, int line)
63 printf ("Check failed in %s test at %s, line %d\n",
64 test_name, __FILE__, line);
69 /* Verifies that EXPR evaluates to true.
70 If not, prints a message citing the calling line number and
72 #define check(EXPR) check_func ((EXPR), __LINE__)
74 /* A contiguous region. */
77 unsigned long int start; /* Start of region. */
78 unsigned long int end; /* One past the end. */
81 /* Number of bits in an unsigned int. */
82 #define UINT_BIT (CHAR_BIT * sizeof (unsigned int))
84 /* Returns the number of contiguous 1-bits in X starting from bit
86 This implementation is designed to be obviously correct, not
89 count_one_bits (unsigned long int x)
100 /* Searches the bits in PATTERN from right to left starting from
101 bit OFFSET for one or more 1-bits. If any are found, sets
102 *START to the bit index of the first and *WIDTH to the number
103 of contiguous 1-bits and returns true. Otherwise, returns
105 This implementation is designed to be obviously correct, not
108 next_region (unsigned int pattern, unsigned int offset,
109 unsigned long int *start, unsigned long int *width)
113 assert (offset <= UINT_BIT);
114 for (i = offset; i < UINT_BIT; i++)
115 if (pattern & (1u << i))
118 *width = count_one_bits (pattern >> i);
124 /* Prints the regions in RS to stdout. */
126 print_regions (const struct range_set *rs)
128 const struct range_set_node *node;
131 for (node = range_set_first (rs); node != NULL;
132 node = range_set_next (rs, node))
133 printf (" (%lu,%lu)",
134 range_set_node_get_start (node), range_set_node_get_end (node));
138 /* Checks that the regions in RS match the bits in PATTERN. */
140 check_pattern (const struct range_set *rs, unsigned int pattern)
142 const struct range_set_node *node;
143 unsigned long int start, width;
146 for (node = rand () % 2 ? range_set_first (rs) : range_set_next (rs, NULL),
148 next_region (pattern, start + width, &start, &width);
149 node = range_set_next (rs, node))
151 check (node != NULL);
152 check (range_set_node_get_start (node) == start);
153 check (range_set_node_get_end (node) == start + width);
154 check (range_set_node_get_width (node) == width);
156 check (node == NULL);
158 for (i = 0; i < UINT_BIT; i++)
159 check (range_set_contains (rs, i) == ((pattern & (1u << i)) != 0));
160 check (!range_set_contains (rs,
161 UINT_BIT + rand () % (ULONG_MAX - UINT_BIT)));
163 check (range_set_is_empty (rs) == (pattern == 0));
166 /* Creates and returns a range set that contains regions for the
167 bits set in PATTERN. */
168 static struct range_set *
169 make_pattern (unsigned int pattern)
171 unsigned long int start = 0;
172 unsigned long int width = 0;
173 struct range_set *rs = range_set_create_pool (NULL);
174 while (next_region (pattern, start + width, &start, &width))
175 range_set_insert (rs, start, width);
176 check_pattern (rs, pattern);
180 /* Returns an unsigned int with bits OFS...OFS+CNT (exclusive)
181 set to 1, other bits set to 0. */
183 bit_range (unsigned int ofs, unsigned int cnt)
185 assert (ofs < UINT_BIT);
186 assert (cnt <= UINT_BIT);
187 assert (ofs + cnt <= UINT_BIT);
189 return cnt < UINT_BIT ? ((1u << cnt) - 1) << ofs : UINT_MAX;
192 /* Tests inserting all possible patterns into all possible range
193 sets (up to a small maximum number of bits). */
197 const int positions = 9;
198 unsigned int init_pat;
201 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
202 for (i = 0; i < positions + 1; i++)
203 for (j = i; j <= positions + 1; j++)
205 struct range_set *rs, *rs2;
206 unsigned int final_pat;
208 rs = make_pattern (init_pat);
209 range_set_insert (rs, i, j - i);
210 final_pat = init_pat | bit_range (i, j - i);
211 check_pattern (rs, final_pat);
212 rs2 = range_set_clone (rs, NULL);
213 check_pattern (rs2, final_pat);
214 range_set_destroy (rs);
215 range_set_destroy (rs2);
219 /* Tests deleting all possible patterns from all possible range
220 sets (up to a small maximum number of bits). */
224 const int positions = 9;
225 unsigned int init_pat;
228 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
229 for (i = 0; i < positions + 1; i++)
230 for (j = i; j <= positions + 1; j++)
232 struct range_set *rs;
233 unsigned int final_pat;
235 rs = make_pattern (init_pat);
236 range_set_delete (rs, i, j - i);
237 final_pat = init_pat & ~bit_range (i, j - i);
238 check_pattern (rs, final_pat);
239 range_set_destroy (rs);
243 /* Tests all possible allocation in all possible range sets (up
244 to a small maximum number of bits). */
248 const int positions = 9;
249 unsigned int init_pat;
252 for (init_pat = 0; init_pat < (1u << positions); init_pat++)
253 for (request = 1; request <= positions + 1; request++)
255 struct range_set *rs;
256 unsigned long int start, width, expect_start, expect_width;
257 bool success, expect_success;
258 unsigned int final_pat;
261 /* Figure out expected results. */
262 expect_success = false;
263 expect_start = expect_width = 0;
264 final_pat = init_pat;
265 for (i = 0; i < positions; i++)
266 if (init_pat & (1u << i))
268 expect_success = true;
270 expect_width = count_one_bits (init_pat >> i);
271 if (expect_width > request)
272 expect_width = request;
273 final_pat &= ~bit_range (expect_start, expect_width);
278 rs = make_pattern (init_pat);
279 success = range_set_allocate (rs, request, &start, &width);
280 check_pattern (rs, final_pat);
281 range_set_destroy (rs);
284 check (success == expect_success);
287 check (start == expect_start);
288 check (width == expect_width);
293 /* Tests freeing a range set through a pool. */
298 struct range_set *rs;
300 /* Destroy the range set, then the pool.
301 Makes sure that this doesn't cause a double-free. */
302 pool = pool_create ();
303 rs = range_set_create_pool (pool);
304 range_set_insert (rs, 1, 10);
305 range_set_destroy (rs);
308 /* Just destroy the pool.
309 Makes sure that this doesn't cause a leak. */
310 pool = pool_create ();
311 rs = range_set_create_pool (pool);
312 range_set_insert (rs, 1, 10);
318 /* Runs TEST_FUNCTION and prints a message about NAME. */
320 run_test (void (*test_function) (void), const char *name)
331 run_test (test_insert, "insert");
332 run_test (test_delete, "delete");
333 run_test (test_allocate, "allocate");
334 run_test (test_pool, "pool");