2 * Copyright (C) 2010-2013 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "test_suite.h"
18 #include <collections/hashtable.h>
19 #include <utils/chunk.h>
21 /*******************************************************************************
22 * string hash table functions
25 static u_int
hash(char *key
)
27 return chunk_hash(chunk_from_str(key
));
30 static bool equals(char *key1
, char *key2
)
32 return streq(key1
, key2
);
35 /*******************************************************************************
39 static hashtable_t
*ht
;
43 ht
= hashtable_create((hashtable_hash_t
)hash
,
44 (hashtable_equals_t
)equals
, 0);
45 ck_assert_int_eq(ht
->get_count(ht
), 0);
49 START_TEARDOWN(teardown_ht
)
55 /*******************************************************************************
59 START_TEST(test_put_get
)
61 char *k1
= "key1", *k2
= "key2", *k3
= "key3";
62 char *v1
= "val1", *v2
= "val2", *v3
= "val3", *value
;
64 value
= ht
->put(ht
, k1
, v1
);
65 ck_assert_int_eq(ht
->get_count(ht
), 1);
66 ck_assert(streq(ht
->get(ht
, k1
), v1
));
67 ck_assert(ht
->get(ht
, k2
) == NULL
);
68 ck_assert(ht
->get(ht
, k3
) == NULL
);
69 ck_assert(value
== NULL
);
73 ck_assert_int_eq(ht
->get_count(ht
), 3);
74 ck_assert(streq(ht
->get(ht
, k1
), v1
));
75 ck_assert(streq(ht
->get(ht
, k2
), v2
));
76 ck_assert(streq(ht
->get(ht
, k3
), v3
));
78 value
= ht
->put(ht
, k2
, v1
);
79 ck_assert_int_eq(ht
->get_count(ht
), 3);
80 ck_assert(streq(value
, v2
));
81 ck_assert(streq(ht
->get(ht
, k2
), v1
));
85 /*******************************************************************************
89 static u_int
hash_match(char *key
)
91 return chunk_hash(chunk_create(key
, 4));
94 static bool equal_match(char *key1
, char *key2
)
96 if (!strneq(key1
, key2
, 4))
100 /* look for an item with a key < than what we look for */
101 return strcmp(key1
, key2
) >= 0;
104 START_TEST(test_get_match
)
106 char *k1
= "key1_a", *k2
= "key2", *k3
= "key1_b", *k4
= "key1_c";
107 char *v1
= "val1", *v2
= "val2", *v3
= "val3", *value
;
109 ht
= hashtable_create((hashtable_hash_t
)hash_match
,
110 (hashtable_equals_t
)equals
, 0);
114 value
= ht
->put(ht
, k3
, v3
);
115 ck_assert_int_eq(ht
->get_count(ht
), 3);
116 ck_assert(streq(ht
->get(ht
, k1
), v1
));
117 ck_assert(streq(ht
->get(ht
, k2
), v2
));
118 ck_assert(streq(ht
->get(ht
, k3
), v3
));
119 ck_assert(value
== NULL
);
121 value
= ht
->get_match(ht
, k1
, (hashtable_equals_t
)equal_match
);
122 ck_assert(value
!= NULL
);
123 ck_assert(streq(value
, v1
));
124 value
= ht
->get_match(ht
, k2
, (hashtable_equals_t
)equal_match
);
125 ck_assert(value
!= NULL
);
126 ck_assert(streq(value
, v2
));
127 value
= ht
->get_match(ht
, k3
, (hashtable_equals_t
)equal_match
);
128 ck_assert(value
!= NULL
);
129 ck_assert(streq(value
, v1
));
130 value
= ht
->get_match(ht
, k4
, (hashtable_equals_t
)equal_match
);
131 ck_assert(value
!= NULL
);
132 ck_assert(streq(value
, v1
));
138 /*******************************************************************************
142 static void do_remove(char *k1
, char *k2
, char *k3
)
144 char *v1
= "val1", *v2
= "val2", *v3
= "val3", *value
;
150 value
= ht
->remove(ht
, k2
);
151 ck_assert_int_eq(ht
->get_count(ht
), 2);
152 ck_assert(streq(ht
->get(ht
, k1
), v1
));
153 ck_assert(streq(ht
->get(ht
, k3
), v3
));
154 ck_assert(streq(value
, v2
));
155 ck_assert(ht
->get(ht
, k2
) == NULL
);
157 value
= ht
->remove(ht
, k2
);
158 ck_assert_int_eq(ht
->get_count(ht
), 2);
159 ck_assert(value
== NULL
);
161 value
= ht
->remove(ht
, k1
);
162 value
= ht
->remove(ht
, k3
);
163 ck_assert_int_eq(ht
->get_count(ht
), 0);
164 ck_assert(ht
->get(ht
, k1
) == NULL
);
165 ck_assert(ht
->get(ht
, k2
) == NULL
);
166 ck_assert(ht
->get(ht
, k3
) == NULL
);
169 START_TEST(test_remove
)
171 char *k1
= "key1", *k2
= "key2", *k3
= "key3";
173 do_remove(k1
, k2
, k3
);
177 START_TEST(test_remove_one_bucket
)
179 char *k1
= "key1_a", *k2
= "key1_b", *k3
= "key1_c";
182 /* set a capacity to avoid rehashing, which would change the items' order */
183 ht
= hashtable_create((hashtable_hash_t
)hash_match
,
184 (hashtable_equals_t
)equals
, 8);
186 do_remove(k1
, k2
, k3
);
190 /*******************************************************************************
194 START_TEST(test_enumerator
)
196 char *k1
= "key1", *k2
= "key2", *k3
= "key3", *key
;
197 char *v1
= "val1", *v2
= "val2", *v3
= "val3", *value
;
198 enumerator_t
*enumerator
;
206 enumerator
= ht
->create_enumerator(ht
);
207 while (enumerator
->enumerate(enumerator
, &key
, &value
))
209 ck_assert(streq(key
, k1
) || streq(key
, k2
) || streq(key
, k3
));
210 ck_assert(streq(value
, v1
) || streq(value
, v2
) || streq(value
, v3
));
211 ck_assert(!streq(key
, k1
) || streq(value
, v1
));
212 ck_assert(!streq(key
, k2
) || streq(value
, v2
));
213 ck_assert(!streq(key
, k3
) || streq(value
, v3
));
216 enumerator
->destroy(enumerator
);
217 ck_assert_int_eq(count
, 3);
220 enumerator
= ht
->create_enumerator(ht
);
221 while (enumerator
->enumerate(enumerator
, NULL
, NULL
))
225 enumerator
->destroy(enumerator
);
226 ck_assert_int_eq(count
, 3);
228 value
= ht
->remove(ht
, k1
);
229 value
= ht
->remove(ht
, k2
);
230 value
= ht
->remove(ht
, k3
);
233 enumerator
= ht
->create_enumerator(ht
);
234 while (enumerator
->enumerate(enumerator
, &key
, &value
))
238 enumerator
->destroy(enumerator
);
239 ck_assert_int_eq(count
, 0);
243 /*******************************************************************************
247 static void do_remove_at(char *k1
, char *k2
, char *k3
)
249 char *v1
= "val1", *v2
= "val2", *v3
= "val3", *value
, *key
;
250 enumerator_t
*enumerator
;
256 enumerator
= ht
->create_enumerator(ht
);
257 ht
->remove_at(ht
, enumerator
);
258 while (enumerator
->enumerate(enumerator
, &key
, &value
))
262 ht
->remove_at(ht
, enumerator
);
265 enumerator
->destroy(enumerator
);
267 ck_assert_int_eq(ht
->get_count(ht
), 2);
268 ck_assert(ht
->get(ht
, k1
) != NULL
);
269 ck_assert(ht
->get(ht
, k3
) != NULL
);
270 ck_assert(ht
->get(ht
, k2
) == NULL
);
274 ck_assert_int_eq(ht
->get_count(ht
), 3);
275 ck_assert(ht
->get(ht
, k1
) != NULL
);
276 ck_assert(ht
->get(ht
, k2
) != NULL
);
277 ck_assert(ht
->get(ht
, k3
) != NULL
);
279 enumerator
= ht
->create_enumerator(ht
);
280 while (enumerator
->enumerate(enumerator
, &key
, &value
))
282 ht
->remove_at(ht
, enumerator
);
284 enumerator
->destroy(enumerator
);
286 ck_assert_int_eq(ht
->get_count(ht
), 0);
287 ck_assert(ht
->get(ht
, k1
) == NULL
);
288 ck_assert(ht
->get(ht
, k2
) == NULL
);
289 ck_assert(ht
->get(ht
, k3
) == NULL
);
292 START_TEST(test_remove_at
)
294 char *k1
= "key1", *k2
= "key2", *k3
= "key3";
296 do_remove_at(k1
, k2
, k3
);
300 START_TEST(test_remove_at_one_bucket
)
302 char *k1
= "key1_a", *k2
= "key1_b", *k3
= "key1_c";
305 /* set a capacity to avoid rehashing, which would change the items' order */
306 ht
= hashtable_create((hashtable_hash_t
)hash_match
,
307 (hashtable_equals_t
)equals
, 8);
308 do_remove_at(k1
, k2
, k3
);
312 Suite
*hashtable_suite_create()
317 s
= suite_create("hashtable");
319 tc
= tcase_create("put/get");
320 tcase_add_checked_fixture(tc
, setup_ht
, teardown_ht
);
321 tcase_add_test(tc
, test_put_get
);
322 suite_add_tcase(s
, tc
);
324 tc
= tcase_create("get_match");
325 tcase_add_test(tc
, test_get_match
);
326 suite_add_tcase(s
, tc
);
328 tc
= tcase_create("remove");
329 tcase_add_checked_fixture(tc
, setup_ht
, teardown_ht
);
330 tcase_add_test(tc
, test_remove
);
331 tcase_add_test(tc
, test_remove_one_bucket
);
332 suite_add_tcase(s
, tc
);
334 tc
= tcase_create("enumerator");
335 tcase_add_checked_fixture(tc
, setup_ht
, teardown_ht
);
336 tcase_add_test(tc
, test_enumerator
);
337 suite_add_tcase(s
, tc
);
339 tc
= tcase_create("remove_at");
340 tcase_add_checked_fixture(tc
, setup_ht
, teardown_ht
);
341 tcase_add_test(tc
, test_remove_at
);
342 tcase_add_test(tc
, test_remove_at_one_bucket
);
343 suite_add_tcase(s
, tc
);