1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2008, 2009, 2010 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 hmapx_* routines defined in
18 hmapx.c. This test program aims to be as comprehensive as
19 possible. "gcov -a -b" should report 100% coverage of lines,
20 blocks and branches in hmapx.c (when compiled with -DNDEBUG).
21 "valgrind --leak-check=yes --show-reachable=yes" should give a
28 #include <libpspp/hmapx.h>
38 #include <libpspp/compiler.h>
40 /* If OK is not true, prints a message about failure on the
41 current source file and the given LINE and terminates. */
43 check_func (bool ok
, int line
)
47 fprintf (stderr
, "%s:%d: check failed\n", __FILE__
, line
);
52 /* Verifies that EXPR evaluates to true.
53 If not, prints a message citing the calling line number and
55 #define check(EXPR) check_func ((EXPR), __LINE__)
57 /* Prints a message about memory exhaustion and exits with a
62 printf ("virtual memory exhausted\n");
66 /* Allocates and returns N bytes of memory. */
83 xmemdup (const void *p
, size_t n
)
85 void *q
= xmalloc (n
);
90 /* Allocates and returns N * M bytes of memory. */
92 xnmalloc (size_t n
, size_t m
)
94 if ((size_t) -1 / m
<= n
)
96 return xmalloc (n
* m
);
99 /* Node type and support routines. */
101 /* Test data element. */
104 int data
; /* Primary value. */
107 /* Compares A and B and returns a strcmp-type return value. */
109 compare_ints (const void *a_
, const void *b_
)
114 return *a
< *b
? -1 : *a
> *b
;
117 /* Swaps *A and *B. */
119 swap (int *a
, int *b
)
126 /* Reverses the order of the N integers starting at VALUES. */
128 reverse (int *values
, size_t n
)
134 swap (&values
[i
++], &values
[--j
]);
137 /* Arranges the N elements in VALUES into the lexicographically
138 next greater permutation. Returns true if successful.
139 If VALUES is already the lexicographically greatest
140 permutation of its elements (i.e. ordered from greatest to
141 smallest), arranges them into the lexicographically least
142 permutation (i.e. ordered from smallest to largest) and
145 next_permutation (int *values
, size_t n
)
153 if (values
[i
] < values
[i
+ 1])
156 for (j
= n
- 1; values
[i
] >= values
[j
]; j
--)
158 swap (values
+ i
, values
+ j
);
159 reverse (values
+ (i
+ 1), n
- (i
+ 1));
172 factorial (unsigned int n
)
174 unsigned int value
= 1;
180 /* Randomly shuffles the N elements in ARRAY, each of which is
181 SIZE bytes in size. */
183 random_shuffle (void *array_
, size_t n
, size_t size
)
185 char *array
= array_
;
186 char *tmp
= xmalloc (size
);
189 for (i
= 0; i
< n
; i
++)
191 size_t j
= rand () % (n
- i
) + i
;
194 memcpy (tmp
, array
+ j
* size
, size
);
195 memcpy (array
+ j
* size
, array
+ i
* size
, size
);
196 memcpy (array
+ i
* size
, tmp
, size
);
203 typedef size_t hash_function (int data
);
206 identity_hash (int data
)
212 constant_hash (int data UNUSED
)
217 static inline uint32_t
218 md4_round (uint32_t a
, uint32_t b
, uint32_t c
, uint32_t d
,
219 uint32_t data
, uint32_t n
)
221 uint32_t x
= a
+ (d
^ (b
& (c
^ d
))) + data
;
222 return (x
<< n
) | (x
>> (32 - n
));
226 random_hash (int data
)
232 a
= md4_round (a
, b
, c
, d
, 0, 3);
233 d
= md4_round (d
, a
, b
, c
, 1, 7);
234 c
= md4_round (c
, d
, a
, b
, 2, 11);
235 b
= md4_round (b
, c
, d
, a
, 3, 19);
236 return a
^ b
^ c
^ d
;
239 static struct hmapx_node
*
240 find_element (struct hmapx
*hmapx
, int data
, hash_function
*hash
)
242 struct hmapx_node
*node
;
244 HMAPX_FOR_EACH_WITH_HASH (e
, node
, hash (data
), hmapx
)
250 /* Checks that HMAPX contains the N ints in DATA, that its
251 structure is correct, and that certain operations on HMAPX
252 produce the expected results. */
254 check_hmapx (struct hmapx
*hmapx
, const int data
[], size_t n
,
260 check (hmapx_is_empty (hmapx
) == (n
== 0));
261 check (hmapx_count (hmapx
) == n
);
262 check (n
<= hmapx_capacity (hmapx
));
264 order
= xmemdup (data
, n
* sizeof *data
);
265 qsort (order
, n
, sizeof *order
, compare_ints
);
267 for (i
= 0; i
< n
; i
= j
)
269 struct hmapx_node
*node
;
273 for (j
= i
+ 1; j
< n
; j
++)
274 if (order
[i
] != order
[j
])
278 HMAPX_FOR_EACH_WITH_HASH (e
, node
, hash (order
[i
]), hmapx
)
279 if (e
->data
== order
[i
])
282 check (count
== j
- i
);
285 check (find_element (hmapx
, -1, hash
) == NULL
);
288 check (hmapx_first (hmapx
) == NULL
);
291 struct hmapx_node
*p
;
295 for (p
= hmapx_first (hmapx
), i
= 0; i
< n
;
296 p
= hmapx_next (hmapx
, p
), i
++)
298 struct element
*e
= hmapx_node_data (p
);
301 check (hmapx_node_hash (p
) == hash (e
->data
));
302 for (j
= 0; j
< left
; j
++)
303 if (order
[j
] == e
->data
)
305 order
[j
] = order
[--left
];
318 /* Inserts the N values from 0 to N - 1 (inclusive) into an
319 HMAPX in the order specified by INSERTIONS, then deletes them in
320 the order specified by DELETIONS, checking the HMAPX's contents
321 for correctness after each operation. Uses HASH as the hash
324 test_insert_delete (const int insertions
[],
325 const int deletions
[],
330 struct element
*elements
;
331 struct hmapx_node
**nodes
;
335 elements
= xnmalloc (n
, sizeof *elements
);
336 nodes
= xnmalloc (n
, sizeof *nodes
);
337 for (i
= 0; i
< n
; i
++)
338 elements
[i
].data
= i
;
341 hmapx_reserve (&hmapx
, reserve
);
342 check_hmapx (&hmapx
, NULL
, 0, hash
);
343 for (i
= 0; i
< n
; i
++)
345 struct hmapx_node
*(*insert
) (struct hmapx
*, void *, size_t hash
);
348 /* Insert the node. Use hmapx_insert_fast if we have not
349 yet exceeded the reserve. */
350 insert
= i
< reserve
? hmapx_insert_fast
: hmapx_insert
;
351 nodes
[insertions
[i
]] = insert (&hmapx
, &elements
[insertions
[i
]],
352 hash (insertions
[i
]));
353 check_hmapx (&hmapx
, insertions
, i
+ 1, hash
);
355 /* A series of insertions should not produce a shrinkable hmapx. */
358 capacity
= hmapx_capacity (&hmapx
);
359 hmapx_shrink (&hmapx
);
360 check (capacity
== hmapx_capacity (&hmapx
));
363 for (i
= 0; i
< n
; i
++)
365 hmapx_delete (&hmapx
, nodes
[deletions
[i
]]);
366 check_hmapx (&hmapx
, deletions
+ i
+ 1, n
- i
- 1, hash
);
368 hmapx_destroy (&hmapx
);
374 /* Inserts values into an HMAPX in each possible order, then
375 removes them in each possible order, up to a specified maximum
376 size, using hash function HASH. */
378 test_insert_any_remove_any (hash_function
*hash
)
380 const int max_elems
= 5;
383 for (n
= 0; n
<= max_elems
; n
++)
385 int *insertions
, *deletions
;
386 unsigned int ins_n_perms
;
389 insertions
= xnmalloc (n
, sizeof *insertions
);
390 deletions
= xnmalloc (n
, sizeof *deletions
);
391 for (i
= 0; i
< n
; i
++)
394 for (ins_n_perms
= 0;
395 ins_n_perms
== 0 || next_permutation (insertions
, n
);
398 unsigned int del_n_perms
;
401 for (i
= 0; i
< n
; i
++)
404 for (del_n_perms
= 0;
405 del_n_perms
== 0 || next_permutation (deletions
, n
);
407 test_insert_delete (insertions
, deletions
, n
, hash
, 1);
409 check (del_n_perms
== factorial (n
));
411 check (ins_n_perms
== factorial (n
));
419 test_insert_any_remove_any_random_hash (void)
421 test_insert_any_remove_any (random_hash
);
425 test_insert_any_remove_any_identity_hash (void)
427 test_insert_any_remove_any (identity_hash
);
431 test_insert_any_remove_any_constant_hash (void)
433 test_insert_any_remove_any (constant_hash
);
436 /* Inserts values into an HMAPX in each possible order, then
437 removes them in the same order, up to a specified maximum
438 size, using hash function HASH. */
440 test_insert_any_remove_same (hash_function
*hash
)
442 const int max_elems
= 7;
445 for (n
= 0; n
<= max_elems
; n
++)
448 unsigned int n_permutations
;
451 values
= xnmalloc (n
, sizeof *values
);
452 for (i
= 0; i
< n
; i
++)
455 for (n_permutations
= 0;
456 n_permutations
== 0 || next_permutation (values
, n
);
458 test_insert_delete (values
, values
, n
, hash
, n
/ 2);
459 check (n_permutations
== factorial (n
));
466 test_insert_any_remove_same_random_hash (void)
468 test_insert_any_remove_same (random_hash
);
472 test_insert_any_remove_same_identity_hash (void)
474 test_insert_any_remove_same (identity_hash
);
478 test_insert_any_remove_same_constant_hash (void)
480 test_insert_any_remove_same (constant_hash
);
483 /* Inserts values into an HMAPX in each possible order, then
484 removes them in reverse order, up to a specified maximum
485 size, using hash function HASH. */
487 test_insert_any_remove_reverse (hash_function
*hash
)
489 const int max_elems
= 7;
492 for (n
= 0; n
<= max_elems
; n
++)
494 int *insertions
, *deletions
;
495 unsigned int n_permutations
;
498 insertions
= xnmalloc (n
, sizeof *insertions
);
499 deletions
= xnmalloc (n
, sizeof *deletions
);
500 for (i
= 0; i
< n
; i
++)
503 for (n_permutations
= 0;
504 n_permutations
== 0 || next_permutation (insertions
, n
);
507 memcpy (deletions
, insertions
, sizeof *insertions
* n
);
508 reverse (deletions
, n
);
510 test_insert_delete (insertions
, deletions
, n
, hash
, n
);
512 check (n_permutations
== factorial (n
));
520 test_insert_any_remove_reverse_random_hash (void)
522 test_insert_any_remove_reverse (random_hash
);
526 test_insert_any_remove_reverse_identity_hash (void)
528 test_insert_any_remove_reverse (identity_hash
);
532 test_insert_any_remove_reverse_constant_hash (void)
534 test_insert_any_remove_reverse (constant_hash
);
537 /* Inserts and removes up to MAX_ELEMS values in an hmapx, in
538 random order, using hash function HASH. */
540 test_random_sequence (int max_elems
, hash_function
*hash
)
542 const int max_trials
= 8;
545 for (n
= 0; n
<= max_elems
; n
+= 2)
547 int *insertions
, *deletions
;
551 insertions
= xnmalloc (n
, sizeof *insertions
);
552 deletions
= xnmalloc (n
, sizeof *deletions
);
553 for (i
= 0; i
< n
; i
++)
555 for (i
= 0; i
< n
; i
++)
558 for (trial
= 0; trial
< max_trials
; trial
++)
560 random_shuffle (insertions
, n
, sizeof *insertions
);
561 random_shuffle (deletions
, n
, sizeof *deletions
);
563 test_insert_delete (insertions
, deletions
, n
, hash
, 0);
572 test_random_sequence_random_hash (void)
574 test_random_sequence (64, random_hash
);
578 test_random_sequence_identity_hash (void)
580 test_random_sequence (64, identity_hash
);
584 test_random_sequence_constant_hash (void)
586 test_random_sequence (32, constant_hash
);
589 /* Inserts MAX_ELEMS elements into an HMAPX in ascending order,
590 then delete in ascending order and shrink the hmapx at each
591 step, using hash function HASH. */
593 test_insert_ordered (int max_elems
, hash_function
*hash
)
595 struct element
*elements
;
596 struct hmapx_node
**nodes
;
602 elements
= xnmalloc (max_elems
, sizeof *elements
);
603 nodes
= xnmalloc (max_elems
, sizeof *nodes
);
604 values
= xnmalloc (max_elems
, sizeof *values
);
605 for (i
= 0; i
< max_elems
; i
++)
607 values
[i
] = elements
[i
].data
= i
;
608 nodes
[i
] = hmapx_insert (&hmapx
, &elements
[i
], hash (elements
[i
].data
));
609 check_hmapx (&hmapx
, values
, i
+ 1, hash
);
611 if (hash
== identity_hash
)
613 /* Check that every every hash bucket has (almost) the
614 same number of nodes in it. */
619 for (j
= 0; j
<= hmapx
.hmap
.mask
; j
++)
622 struct hmap_node
*node
;
624 for (node
= hmapx
.hmap
.buckets
[j
]; node
!= NULL
;
632 check (max
- min
<= 1);
635 for (i
= 0; i
< max_elems
; i
++)
637 hmapx_delete (&hmapx
, nodes
[i
]);
638 hmapx_shrink (&hmapx
);
639 check_hmapx (&hmapx
, values
+ i
+ 1, max_elems
- i
- 1, hash
);
641 hmapx_destroy (&hmapx
);
648 test_insert_ordered_random_hash (void)
650 test_insert_ordered (1024, random_hash
);
654 test_insert_ordered_identity_hash (void)
656 test_insert_ordered (1024, identity_hash
);
660 test_insert_ordered_constant_hash (void)
662 test_insert_ordered (128, constant_hash
);
665 /* Inserts up to MAX_ELEMS elements into an HMAPX, then moves the
666 nodes around in memory, using hash function HASH. */
668 test_moved (int max_elems
, hash_function
*hash
)
670 struct element
*e
[2];
673 struct hmapx_node
**nodes
;
678 e
[0] = xnmalloc (max_elems
, sizeof *e
[0]);
679 e
[1] = xnmalloc (max_elems
, sizeof *e
[1]);
680 values
= xnmalloc (max_elems
, sizeof *values
);
681 nodes
= xnmalloc (max_elems
, sizeof *nodes
);
683 for (i
= 0; i
< max_elems
; i
++)
685 values
[i
] = e
[cur
][i
].data
= i
;
686 nodes
[i
] = hmapx_insert (&hmapx
, &e
[cur
][i
], hash (e
[cur
][i
].data
));
687 check_hmapx (&hmapx
, values
, i
+ 1, hash
);
689 for (j
= 0; j
<= i
; j
++)
691 e
[!cur
][j
] = e
[cur
][j
];
692 hmapx_move (nodes
[j
], &e
[cur
][j
]);
693 check_hmapx (&hmapx
, values
, i
+ 1, hash
);
697 hmapx_destroy (&hmapx
);
705 test_moved_random_hash (void)
707 test_moved (128, random_hash
);
711 test_moved_identity_hash (void)
713 test_moved (128, identity_hash
);
717 test_moved_constant_hash (void)
719 test_moved (32, constant_hash
);
722 /* Inserts values into an HMAPX, then changes their values, using
723 hash function HASH. */
725 test_changed (hash_function
*hash
)
727 const int max_elems
= 6;
730 for (n
= 0; n
<= max_elems
; n
++)
732 int *values
, *changed_values
;
733 struct hmapx_node
**nodes
;
734 struct element
*elements
;
735 unsigned int n_permutations
;
738 values
= xnmalloc (n
, sizeof *values
);
739 changed_values
= xnmalloc (n
, sizeof *changed_values
);
740 elements
= xnmalloc (n
, sizeof *elements
);
741 nodes
= xnmalloc (n
, sizeof *nodes
);
742 for (i
= 0; i
< n
; i
++)
745 for (n_permutations
= 0;
746 n_permutations
== 0 || next_permutation (values
, n
);
749 for (i
= 0; i
< n
; i
++)
752 for (j
= 0; j
<= n
; j
++)
758 /* Add to HMAPX in order. */
759 for (k
= 0; k
< n
; k
++)
762 elements
[n
].data
= n
;
763 nodes
[n
] = hmapx_insert (&hmapx
, &elements
[n
],
764 hash (elements
[n
].data
));
766 check_hmapx (&hmapx
, values
, n
, hash
);
768 /* Change value i to j. */
769 elements
[i
].data
= j
;
770 hmapx_changed (&hmapx
, nodes
[i
],
771 hash (elements
[i
].data
));
772 for (k
= 0; k
< n
; k
++)
773 changed_values
[k
] = k
;
774 changed_values
[i
] = j
;
775 check_hmapx (&hmapx
, changed_values
, n
, hash
);
777 hmapx_destroy (&hmapx
);
781 check (n_permutations
== factorial (n
));
784 free (changed_values
);
791 test_changed_random_hash (void)
793 test_changed (random_hash
);
797 test_changed_identity_hash (void)
799 test_changed (identity_hash
);
803 test_changed_constant_hash (void)
805 test_changed (constant_hash
);
808 /* Inserts values into an HMAPX, then changes and moves their
809 values, using hash function HASH. */
811 test_change (hash_function
*hash
)
813 const int max_elems
= 6;
816 for (n
= 0; n
<= max_elems
; n
++)
818 int *values
, *changed_values
;
819 struct hmapx_node
**nodes
;
820 struct element
*elements
;
821 struct element replacement
;
822 unsigned int n_permutations
;
825 values
= xnmalloc (n
, sizeof *values
);
826 changed_values
= xnmalloc (n
, sizeof *changed_values
);
827 elements
= xnmalloc (n
, sizeof *elements
);
828 nodes
= xnmalloc (n
, sizeof *nodes
);
829 for (i
= 0; i
< n
; i
++)
832 for (n_permutations
= 0;
833 n_permutations
== 0 || next_permutation (values
, n
);
836 for (i
= 0; i
< n
; i
++)
839 for (j
= 0; j
<= n
; j
++)
845 /* Add to HMAPX in order. */
846 for (k
= 0; k
< n
; k
++)
849 elements
[n
].data
= n
;
850 nodes
[n
] = hmapx_insert (&hmapx
, &elements
[n
],
851 hash (elements
[n
].data
));
853 check_hmapx (&hmapx
, values
, n
, hash
);
855 /* Change value i to j. */
856 replacement
.data
= j
;
857 hmapx_change (&hmapx
, nodes
[i
], &replacement
, hash (j
));
858 for (k
= 0; k
< n
; k
++)
859 changed_values
[k
] = k
;
860 changed_values
[i
] = j
;
861 check_hmapx (&hmapx
, changed_values
, n
, hash
);
863 hmapx_destroy (&hmapx
);
867 check (n_permutations
== factorial (n
));
870 free (changed_values
);
877 test_change_random_hash (void)
879 test_change (random_hash
);
883 test_change_identity_hash (void)
885 test_change (identity_hash
);
889 test_change_constant_hash (void)
891 test_change (constant_hash
);
895 test_swap (int max_elems
, hash_function
*hash
)
897 struct element
*elements
;
900 struct hmapx
*working
, *empty
;
907 elements
= xnmalloc (max_elems
, sizeof *elements
);
908 values
= xnmalloc (max_elems
, sizeof *values
);
909 for (i
= 0; i
< max_elems
; i
++)
912 values
[i
] = elements
[i
].data
= i
;
913 hmapx_insert (working
, &elements
[i
], hash (elements
[i
].data
));
914 check_hmapx (working
, values
, i
+ 1, hash
);
915 check_hmapx (empty
, NULL
, 0, hash
);
928 test_swap_random_hash (void)
930 test_swap (128, random_hash
);
933 /* Inserts elements into an HMAPX in ascending order, then clears the hash
934 table using hmapx_clear(). */
938 const int max_elems
= 128;
939 struct element
*elements
;
940 struct hmapx_node
**nodes
;
945 elements
= xnmalloc (max_elems
, sizeof *elements
);
946 nodes
= xnmalloc (max_elems
, sizeof *nodes
);
947 values
= xnmalloc (max_elems
, sizeof *values
);
950 for (n
= 0; n
<= max_elems
; n
++)
954 for (i
= 0; i
< n
; i
++)
956 values
[i
] = elements
[i
].data
= i
;
957 nodes
[i
] = hmapx_insert (&hmapx
, &elements
[i
],
958 random_hash (elements
[i
].data
));
959 check_hmapx (&hmapx
, values
, i
+ 1, random_hash
);
961 hmapx_clear (&hmapx
);
962 check_hmapx (&hmapx
, NULL
, 0, random_hash
);
964 hmapx_destroy (&hmapx
);
972 test_destroy_null (void)
974 hmapx_destroy (NULL
);
977 /* Test shrinking an empty hash table. */
979 test_shrink_empty (void)
984 hmapx_reserve (&hmapx
, 123);
985 hmapx_shrink (&hmapx
);
986 hmapx_destroy (&hmapx
);
994 const char *description
;
995 void (*function
) (void);
998 static const struct test tests
[] =
1001 "insert-any-remove-any-random-hash",
1002 "insert any order, delete any order (random hash)",
1003 test_insert_any_remove_any_random_hash
1006 "insert-any-remove-any-identity-hash",
1007 "insert any order, delete any order (identity hash)",
1008 test_insert_any_remove_any_identity_hash
1011 "insert-any-remove-any-constant-hash",
1012 "insert any order, delete any order (constant hash)",
1013 test_insert_any_remove_any_constant_hash
1016 "insert-any-remove-same-random-hash",
1017 "insert any order, delete same order (random hash)",
1018 test_insert_any_remove_same_random_hash
1021 "insert-any-remove-same-identity-hash",
1022 "insert any order, delete same order (identity hash)",
1023 test_insert_any_remove_same_identity_hash
1026 "insert-any-remove-same-constant-hash",
1027 "insert any order, delete same order (constant hash)",
1028 test_insert_any_remove_same_constant_hash
1031 "insert-any-remove-reverse-random-hash",
1032 "insert any order, delete reverse order (random hash)",
1033 test_insert_any_remove_reverse_random_hash
1036 "insert-any-remove-reverse-identity-hash",
1037 "insert any order, delete reverse order (identity hash)",
1038 test_insert_any_remove_reverse_identity_hash
1041 "insert-any-remove-reverse-constant-hash",
1042 "insert any order, delete reverse order (constant hash)",
1043 test_insert_any_remove_reverse_constant_hash
1046 "random-sequence-random-hash",
1047 "insert and delete in random sequence (random hash)",
1048 test_random_sequence_random_hash
1051 "random-sequence-identity-hash",
1052 "insert and delete in random sequence (identity hash)",
1053 test_random_sequence_identity_hash
1056 "random-sequence-constant-hash",
1057 "insert and delete in random sequence (constant hash)",
1058 test_random_sequence_constant_hash
1061 "insert-ordered-random-hash",
1062 "insert in ascending order (random hash)",
1063 test_insert_ordered_random_hash
1066 "insert-ordered-identity-hash",
1067 "insert in ascending order (identity hash)",
1068 test_insert_ordered_identity_hash
1071 "insert-ordered-constant-hash",
1072 "insert in ascending order (constant hash)",
1073 test_insert_ordered_constant_hash
1076 "moved-random-hash",
1077 "move elements around in memory (random hash)",
1078 test_moved_random_hash
1081 "moved-identity-hash",
1082 "move elements around in memory (identity hash)",
1083 test_moved_identity_hash
1086 "moved-constant-hash",
1087 "move elements around in memory (constant hash)",
1088 test_moved_constant_hash
1091 "changed-random-hash",
1092 "change key data in nodes (random hash)",
1093 test_changed_random_hash
1096 "changed-identity-hash",
1097 "change key data in nodes (identity hash)",
1098 test_changed_identity_hash
1101 "changed-constant-hash",
1102 "change key data in nodes (constant hash)",
1103 test_changed_constant_hash
1106 "change-random-hash",
1107 "change and move key data in nodes (random hash)",
1108 test_change_random_hash
1111 "change-identity-hash",
1112 "change and move key data in nodes (identity hash)",
1113 test_change_identity_hash
1116 "change-constant-hash",
1117 "change and move key data in nodes (constant hash)",
1118 test_change_constant_hash
1122 "test swapping tables",
1123 test_swap_random_hash
1127 "test clearing hash table",
1132 "test destroying null table",
1137 "test shrinking an empty table",
1142 enum { N_TESTS
= sizeof tests
/ sizeof *tests
};
1145 main (int argc
, char *argv
[])
1151 fprintf (stderr
, "exactly one argument required; use --help for help\n");
1152 return EXIT_FAILURE
;
1154 else if (!strcmp (argv
[1], "--help"))
1156 printf ("%s: test hash map of pointers\n"
1157 "usage: %s TEST-NAME\n"
1158 "where TEST-NAME is one of the following:\n",
1160 for (i
= 0; i
< N_TESTS
; i
++)
1161 printf (" %s\n %s\n", tests
[i
].name
, tests
[i
].description
);
1166 for (i
= 0; i
< N_TESTS
; i
++)
1167 if (!strcmp (argv
[1], tests
[i
].name
))
1169 tests
[i
].function ();
1173 fprintf (stderr
, "unknown test %s; use --help for help\n", argv
[1]);
1174 return EXIT_FAILURE
;