Home | History | Annotate | Line # | Download | only in isc
ht_test.c revision 1.1.1.1
      1 /*	$NetBSD: ht_test.c,v 1.1.1.1 2024/02/21 21:54:54 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