xref: /netbsd-src/external/mpl/bind/dist/tests/isc/ht_test.c (revision 4439cfd0acf9c7dc90625e5cd83b2317a9ab8967)
1 /*	$NetBSD: ht_test.c,v 1.2 2024/02/21 22:52:50 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 #include <inttypes.h>
17 #include <sched.h> /* IWYU pragma: keep */
18 #include <setjmp.h>
19 #include <stdarg.h>
20 #include <stddef.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #define UNIT_TESTING
26 #include <cmocka.h>
27 
28 #include <isc/hash.h>
29 #include <isc/ht.h>
30 #include <isc/mem.h>
31 #include <isc/print.h>
32 #include <isc/string.h>
33 #include <isc/util.h>
34 
35 #include <tests/isc.h>
36 
37 /* INCLUDE LAST */
38 
39 #define mctx __mctx
40 #include "ht.c"
41 #undef mctx
42 
43 static void
44 test_ht_full(int bits, uintptr_t count) {
45 	isc_ht_t *ht = NULL;
46 	isc_result_t result;
47 	uintptr_t i;
48 
49 	isc_ht_init(&ht, mctx, bits, ISC_HT_CASE_SENSITIVE);
50 	assert_non_null(ht);
51 
52 	for (i = 1; i < count; i++) {
53 		/*
54 		 * Note: snprintf() is followed with strlcat()
55 		 * to ensure we are always filling the 16 byte key.
56 		 */
57 		unsigned char key[16];
58 		snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
59 		strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
60 		result = isc_ht_add(ht, key, 16, (void *)i);
61 		assert_int_equal(result, ISC_R_SUCCESS);
62 	}
63 
64 	for (i = 1; i < count; i++) {
65 		unsigned char key[16];
66 		void *f = NULL;
67 		snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
68 		strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
69 		result = isc_ht_find(ht, key, 16, &f);
70 		assert_int_equal(result, ISC_R_SUCCESS);
71 		assert_ptr_equal((void *)i, (void *)f);
72 	}
73 
74 	for (i = 1; i < count; i++) {
75 		unsigned char key[16];
76 		snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
77 		strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
78 		result = isc_ht_add(ht, key, 16, (void *)i);
79 		assert_int_equal(result, ISC_R_EXISTS);
80 	}
81 
82 	for (i = 1; i < count; i++) {
83 		char key[64];
84 		/*
85 		 * Note: the key size is now strlen(key) which is bigger
86 		 * then the keys added above.
87 		 */
88 		snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
89 		strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
90 		result = isc_ht_add(ht, (const unsigned char *)key, strlen(key),
91 				    (void *)i);
92 		assert_int_equal(result, ISC_R_SUCCESS);
93 	}
94 
95 	for (i = 1; i < count; i++) {
96 		unsigned char key[16];
97 		void *f = NULL;
98 		/*
99 		 * Note: case of KEY is now in capitals,
100 		 */
101 		snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
102 		strlcat((char *)key, " KEY of a raw hashtable!!", sizeof(key));
103 		result = isc_ht_find(ht, key, 16, &f);
104 		assert_int_equal(result, ISC_R_NOTFOUND);
105 		assert_null(f);
106 	}
107 
108 	for (i = 1; i < count; i++) {
109 		char key[64];
110 		void *f = NULL;
111 		snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
112 		strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
113 		result = isc_ht_find(ht, (const unsigned char *)key,
114 				     strlen(key), &f);
115 		assert_int_equal(result, ISC_R_SUCCESS);
116 		assert_ptr_equal(f, (void *)i);
117 	}
118 
119 	for (i = 1; i < count; i++) {
120 		unsigned char key[16];
121 		void *f = NULL;
122 		snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
123 		strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
124 		result = isc_ht_delete(ht, key, 16);
125 		assert_int_equal(result, ISC_R_SUCCESS);
126 		result = isc_ht_find(ht, key, 16, &f);
127 		assert_int_equal(result, ISC_R_NOTFOUND);
128 		assert_null(f);
129 	}
130 
131 	for (i = 1; i < count; i++) {
132 		unsigned char key[16];
133 		/*
134 		 * Note: upper case KEY.
135 		 */
136 		snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
137 		strlcat((char *)key, " KEY of a raw hashtable!!", sizeof(key));
138 		result = isc_ht_add(ht, key, 16, (void *)i);
139 		assert_int_equal(result, ISC_R_SUCCESS);
140 	}
141 
142 	for (i = 1; i < count; i++) {
143 		char key[64];
144 		void *f = NULL;
145 		snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
146 		strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
147 		result = isc_ht_delete(ht, (const unsigned char *)key,
148 				       strlen(key));
149 		assert_int_equal(result, ISC_R_SUCCESS);
150 		result = isc_ht_find(ht, (const unsigned char *)key,
151 				     strlen(key), &f);
152 		assert_int_equal(result, ISC_R_NOTFOUND);
153 		assert_null(f);
154 	}
155 
156 	for (i = 1; i < count; i++) {
157 		unsigned char key[16];
158 		void *f = NULL;
159 		/*
160 		 * Note: case of KEY is now in capitals,
161 		 */
162 		snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
163 		strlcat((char *)key, " KEY of a raw hashtable!!", sizeof(key));
164 		result = isc_ht_find(ht, key, 16, &f);
165 		assert_int_equal(result, ISC_R_SUCCESS);
166 		assert_ptr_equal((void *)i, (void *)f);
167 	}
168 
169 	for (i = 1; i < count; i++) {
170 		unsigned char key[16];
171 		void *f = NULL;
172 		snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
173 		strlcat((char *)key, " key of a raw hashtable!!", sizeof(key));
174 		result = isc_ht_find(ht, key, 16, &f);
175 		assert_int_equal(result, ISC_R_NOTFOUND);
176 		assert_null(f);
177 	}
178 
179 	isc_ht_destroy(&ht);
180 	assert_null(ht);
181 }
182 
183 static void
184 test_ht_iterator(void) {
185 	isc_ht_t *ht = NULL;
186 	isc_result_t result;
187 	isc_ht_iter_t *iter = NULL;
188 	uintptr_t i;
189 	uintptr_t count = 10000;
190 	uint32_t walked;
191 	unsigned char key[16];
192 	size_t tksize;
193 
194 	isc_ht_init(&ht, mctx, 16, ISC_HT_CASE_SENSITIVE);
195 	assert_non_null(ht);
196 	for (i = 1; i <= count; i++) {
197 		/*
198 		 * Note that the string we're snprintfing is always > 16 bytes
199 		 * so we are always filling the key.
200 		 */
201 		snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
202 		strlcat((char *)key, "key of a raw hashtable!!", sizeof(key));
203 		result = isc_ht_add(ht, key, 16, (void *)i);
204 		assert_int_equal(result, ISC_R_SUCCESS);
205 	}
206 
207 	walked = 0;
208 	isc_ht_iter_create(ht, &iter);
209 
210 	for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;
211 	     result = isc_ht_iter_next(iter))
212 	{
213 		unsigned char *tkey = NULL;
214 		void *v = NULL;
215 
216 		isc_ht_iter_current(iter, &v);
217 		isc_ht_iter_currentkey(iter, &tkey, &tksize);
218 		assert_int_equal(tksize, 16);
219 		i = (uintptr_t)v;
220 		snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
221 		strlcat((char *)key, "key of a raw hashtable!!", sizeof(key));
222 		assert_memory_equal(key, tkey, 16);
223 		walked++;
224 	}
225 	assert_int_equal(walked, count);
226 	assert_int_equal(result, ISC_R_NOMORE);
227 
228 	/* erase odd */
229 	walked = 0;
230 	result = isc_ht_iter_first(iter);
231 	while (result == ISC_R_SUCCESS) {
232 		unsigned char *tkey = NULL;
233 		void *v = NULL;
234 
235 		isc_ht_iter_current(iter, &v);
236 		isc_ht_iter_currentkey(iter, &tkey, &tksize);
237 		assert_int_equal(tksize, 16);
238 		i = (uintptr_t)v;
239 		snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
240 		strlcat((char *)key, "key of a raw hashtable!!", sizeof(key));
241 		assert_memory_equal(key, tkey, 16);
242 		if ((uintptr_t)v % 2 == 0) {
243 			result = isc_ht_iter_delcurrent_next(iter);
244 		} else {
245 			result = isc_ht_iter_next(iter);
246 		}
247 		walked++;
248 	}
249 	assert_int_equal(result, ISC_R_NOMORE);
250 	assert_int_equal(walked, count);
251 
252 	/* erase even */
253 	walked = 0;
254 	result = isc_ht_iter_first(iter);
255 	while (result == ISC_R_SUCCESS) {
256 		unsigned char *tkey = NULL;
257 		void *v = NULL;
258 
259 		isc_ht_iter_current(iter, &v);
260 		isc_ht_iter_currentkey(iter, &tkey, &tksize);
261 		assert_int_equal(tksize, 16);
262 		i = (uintptr_t)v;
263 		snprintf((char *)key, sizeof(key), "%u", (unsigned int)i);
264 		strlcat((char *)key, "key of a raw hashtable!!", sizeof(key));
265 		assert_memory_equal(key, tkey, 16);
266 		if ((uintptr_t)v % 2 == 1) {
267 			result = isc_ht_iter_delcurrent_next(iter);
268 		} else {
269 			result = isc_ht_iter_next(iter);
270 		}
271 		walked++;
272 	}
273 	assert_int_equal(result, ISC_R_NOMORE);
274 	assert_int_equal(walked, count / 2);
275 
276 	walked = 0;
277 	for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;
278 	     result = isc_ht_iter_next(iter))
279 	{
280 		walked++;
281 	}
282 
283 	assert_int_equal(result, ISC_R_NOMORE);
284 	assert_int_equal(walked, 0);
285 
286 	isc_ht_iter_destroy(&iter);
287 	assert_null(iter);
288 
289 	isc_ht_destroy(&ht);
290 	assert_null(ht);
291 }
292 
293 /* 20 bit, 200K elements test */
294 ISC_RUN_TEST_IMPL(isc_ht_20) {
295 	UNUSED(state);
296 	test_ht_full(20, 200000);
297 }
298 
299 /* 8 bit, 20000 elements crowded test */
300 ISC_RUN_TEST_IMPL(isc_ht_8) {
301 	UNUSED(state);
302 	test_ht_full(8, 20000);
303 }
304 
305 ISC_RUN_TEST_IMPL(isc_ht_1) {
306 	UNUSED(state);
307 	test_ht_full(1, 100);
308 }
309 
310 /* test hashtable iterator */
311 
312 ISC_RUN_TEST_IMPL(isc_ht_iterator) {
313 	UNUSED(state);
314 	test_ht_iterator();
315 }
316 
317 ISC_RUN_TEST_IMPL(isc_ht_case) {
318 	isc_ht_t *ht = NULL;
319 	void *f = NULL;
320 	isc_result_t result = ISC_R_UNSET;
321 
322 	unsigned char lower[16] = { "test case" };
323 	unsigned char same[16] = { "test case" };
324 	unsigned char upper[16] = { "TEST CASE" };
325 	unsigned char mixed[16] = { "tEsT CaSe" };
326 
327 	isc_ht_init(&ht, mctx, 8, ISC_HT_CASE_SENSITIVE);
328 	assert_non_null(ht);
329 
330 	result = isc_ht_add(ht, lower, 16, (void *)lower);
331 	assert_int_equal(result, ISC_R_SUCCESS);
332 
333 	result = isc_ht_add(ht, same, 16, (void *)same);
334 	assert_int_equal(result, ISC_R_EXISTS);
335 
336 	result = isc_ht_add(ht, upper, 16, (void *)upper);
337 	assert_int_equal(result, ISC_R_SUCCESS);
338 
339 	result = isc_ht_find(ht, mixed, 16, &f);
340 	assert_int_equal(result, ISC_R_NOTFOUND);
341 	assert_null(f);
342 
343 	isc_ht_destroy(&ht);
344 	assert_null(ht);
345 
346 	isc_ht_init(&ht, mctx, 8, ISC_HT_CASE_INSENSITIVE);
347 	assert_non_null(ht);
348 
349 	result = isc_ht_add(ht, lower, 16, (void *)lower);
350 	assert_int_equal(result, ISC_R_SUCCESS);
351 
352 	result = isc_ht_add(ht, same, 16, (void *)same);
353 	assert_int_equal(result, ISC_R_EXISTS);
354 
355 	result = isc_ht_add(ht, upper, 16, (void *)upper);
356 	assert_int_equal(result, ISC_R_EXISTS);
357 
358 	result = isc_ht_find(ht, mixed, 16, &f);
359 	assert_int_equal(result, ISC_R_SUCCESS);
360 	assert_ptr_equal(f, &lower);
361 
362 	isc_ht_destroy(&ht);
363 	assert_null(ht);
364 }
365 
366 ISC_TEST_LIST_START
367 ISC_TEST_ENTRY(isc_ht_case)
368 ISC_TEST_ENTRY(isc_ht_20)
369 ISC_TEST_ENTRY(isc_ht_8)
370 ISC_TEST_ENTRY(isc_ht_1)
371 ISC_TEST_ENTRY(isc_ht_iterator)
372 ISC_TEST_LIST_END
373 
374 ISC_TEST_MAIN
375