Sat, 30 Dec 2023 18:48:25 +0100
migrate map tests - relates to #342
tests/Makefile | file | annotate | diff | comparison | revisions | |
tests/test_hash_map.c | file | annotate | diff | comparison | revisions | |
tests/test_map.cpp | file | annotate | diff | comparison | revisions | |
tests/test_map_generics.c | file | annotate | diff | comparison | revisions | |
tests/test_map_generics.h | file | annotate | diff | comparison | revisions | |
tests/test_mempool.c | file | annotate | diff | comparison | revisions | |
tests/ucxtest.c | file | annotate | diff | comparison | revisions |
1.1 --- a/tests/Makefile Sat Dec 30 15:21:16 2023 +0100 1.2 +++ b/tests/Makefile Sat Dec 30 18:48:25 2023 +0100 1.3 @@ -28,7 +28,7 @@ 1.4 TEST_DIR=$(build_dir)/tests 1.5 1.6 SRC = util_allocator.c test_utils.c test_hash_key.c test_allocator.c \ 1.7 - test_string.c test_printf.c test_mempool.c ucxtest.c 1.8 + test_string.c test_printf.c test_mempool.c test_hash_map.c ucxtest.c 1.9 1.10 OBJ_EXT=.o 1.11 OBJ=$(SRC:%.c=$(TEST_DIR)/%$(OBJ_EXT)) 1.12 @@ -57,11 +57,11 @@ 1.13 @echo "Compiling $<" 1.14 $(CC) -o $@ $(CFLAGS) -c $< 1.15 1.16 -$(TEST_DIR)/test_map_generics$(OBJ_EXT): test_map_generics.c \ 1.17 - test_map_generics.h ../src/cx/map.h ../src/cx/common.h \ 1.18 - ../src/cx/collection.h ../src/cx/allocator.h ../src/cx/iterator.h \ 1.19 - ../src/cx/string.h ../src/cx/hash_key.h ../src/cx/hash_map.h \ 1.20 - ../src/cx/map.h 1.21 +$(TEST_DIR)/test_hash_map$(OBJ_EXT): test_hash_map.c ../src/cx/test.h \ 1.22 + util_allocator.h ../src/cx/allocator.h ../src/cx/common.h \ 1.23 + ../src/cx/hash_map.h ../src/cx/map.h ../src/cx/collection.h \ 1.24 + ../src/cx/allocator.h ../src/cx/iterator.h ../src/cx/string.h \ 1.25 + ../src/cx/hash_key.h 1.26 @echo "Compiling $<" 1.27 $(CC) -o $@ $(CFLAGS) -c $< 1.28
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/tests/test_hash_map.c Sat Dec 30 18:48:25 2023 +0100 2.3 @@ -0,0 +1,669 @@ 2.4 +/* 2.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 2.6 + * 2.7 + * Copyright 2023 Mike Becker, Olaf Wintermann All rights reserved. 2.8 + * 2.9 + * Redistribution and use in source and binary forms, with or without 2.10 + * modification, are permitted provided that the following conditions are met: 2.11 + * 2.12 + * 1. Redistributions of source code must retain the above copyright 2.13 + * notice, this list of conditions and the following disclaimer. 2.14 + * 2.15 + * 2. Redistributions in binary form must reproduce the above copyright 2.16 + * notice, this list of conditions and the following disclaimer in the 2.17 + * documentation and/or other materials provided with the distribution. 2.18 + * 2.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2.29 + * POSSIBILITY OF SUCH DAMAGE. 2.30 + */ 2.31 + 2.32 +#include "cx/test.h" 2.33 +#include "util_allocator.h" 2.34 + 2.35 +#include "cx/hash_map.h" 2.36 + 2.37 +CX_TEST(test_hash_map_create) { 2.38 + CxTestingAllocator talloc; 2.39 + cx_testing_allocator_init(&talloc); 2.40 + CxAllocator *allocator = &talloc.base; 2.41 + CX_TEST_DO { 2.42 + CxMap *map = cxHashMapCreate(allocator, 1, 0); 2.43 + struct cx_hash_map_s *hmap = (struct cx_hash_map_s *) map; 2.44 + CX_TEST_ASSERT(hmap->bucket_count > 0); 2.45 + for(size_t i = 0 ; i < hmap->bucket_count ; i++) { 2.46 + CX_TEST_ASSERT(hmap->buckets[i] == NULL); 2.47 + } 2.48 + CX_TEST_ASSERT(map->item_size == 1); 2.49 + CX_TEST_ASSERT(map->size == 0); 2.50 + CX_TEST_ASSERT(map->allocator == allocator); 2.51 + CX_TEST_ASSERT(!map->store_pointer); 2.52 + CX_TEST_ASSERT(map->cmpfunc == NULL); 2.53 + CX_TEST_ASSERT(map->simple_destructor == NULL); 2.54 + CX_TEST_ASSERT(map->advanced_destructor == NULL); 2.55 + CX_TEST_ASSERT(map->destructor_data == NULL); 2.56 + cxMapStorePointers(map); 2.57 + CX_TEST_ASSERT(map->store_pointer); 2.58 + CX_TEST_ASSERT(map->item_size == sizeof(void *)); 2.59 + cxMapStoreObjects(map); 2.60 + CX_TEST_ASSERT(!map->store_pointer); 2.61 + 2.62 + cxMapDestroy(map); 2.63 + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); 2.64 + } 2.65 + cx_testing_allocator_destroy(&talloc); 2.66 +} 2.67 + 2.68 +CX_TEST(test_hash_map_create_store_pointers) { 2.69 + CxTestingAllocator talloc; 2.70 + cx_testing_allocator_init(&talloc); 2.71 + CxAllocator *allocator = &talloc.base; 2.72 + CX_TEST_DO { 2.73 + CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 0); 2.74 + struct cx_hash_map_s *hmap = (struct cx_hash_map_s *) map; 2.75 + CX_TEST_ASSERT(hmap->bucket_count > 0); 2.76 + for (size_t i = 0; i < hmap->bucket_count; i++) { 2.77 + CX_TEST_ASSERT(hmap->buckets[i] == NULL); 2.78 + } 2.79 + CX_TEST_ASSERT(map->size == 0); 2.80 + CX_TEST_ASSERT(map->allocator == allocator); 2.81 + CX_TEST_ASSERT(map->store_pointer); 2.82 + CX_TEST_ASSERT(map->item_size == sizeof(void *)); 2.83 + 2.84 + cxMapDestroy(map); 2.85 + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); 2.86 + } 2.87 + cx_testing_allocator_destroy(&talloc); 2.88 +} 2.89 + 2.90 +CX_TEST(test_hash_map_rehash) { 2.91 + CxTestingAllocator talloc; 2.92 + cx_testing_allocator_init(&talloc); 2.93 + CxAllocator *allocator = &talloc.base; 2.94 + CX_TEST_DO { 2.95 + CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 7); 2.96 + 2.97 + cxMapPut(map, "key 1", (void *) "val 1"); 2.98 + cxMapPut(map, "key 2", (void *) "val 2"); 2.99 + cxMapPut(map, "key 3", (void *) "val 3"); 2.100 + cxMapPut(map, "foo 4", (void *) "val 4"); 2.101 + cxMapPut(map, "key 5", (void *) "val 5"); 2.102 + cxMapPut(map, "key 6", (void *) "val 6"); 2.103 + cxMapPut(map, "bar 7", (void *) "val 7"); 2.104 + cxMapPut(map, "key 8", (void *) "val 8"); 2.105 + cxMapPut(map, "key 9", (void *) "val 9"); 2.106 + cxMapPut(map, "key 10", (void *) "val 10"); 2.107 + 2.108 + CX_TEST_ASSERT(((struct cx_hash_map_s *)map)->bucket_count == 7); 2.109 + int result = cxMapRehash(map); 2.110 + CX_TEST_ASSERT(result == 0); 2.111 + CX_TEST_ASSERT(((struct cx_hash_map_s *)map)->bucket_count == 25); 2.112 + CX_TEST_ASSERT(map->size == 10); 2.113 + 2.114 + CX_TEST_ASSERT(0 == strcmp(cxMapGet(map, "key 1"), "val 1")); 2.115 + CX_TEST_ASSERT(0 == strcmp(cxMapGet(map, "key 2"), "val 2")); 2.116 + CX_TEST_ASSERT(0 == strcmp(cxMapGet(map, "key 3"), "val 3")); 2.117 + CX_TEST_ASSERT(0 == strcmp(cxMapGet(map, "foo 4"), "val 4")); 2.118 + CX_TEST_ASSERT(0 == strcmp(cxMapGet(map, "key 5"), "val 5")); 2.119 + CX_TEST_ASSERT(0 == strcmp(cxMapGet(map, "key 6"), "val 6")); 2.120 + CX_TEST_ASSERT(0 == strcmp(cxMapGet(map, "bar 7"), "val 7")); 2.121 + CX_TEST_ASSERT(0 == strcmp(cxMapGet(map, "key 8"), "val 8")); 2.122 + CX_TEST_ASSERT(0 == strcmp(cxMapGet(map, "key 9"), "val 9")); 2.123 + CX_TEST_ASSERT(0 == strcmp(cxMapGet(map, "key 10"), "val 10")); 2.124 + 2.125 + cxMapDestroy(map); 2.126 + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); 2.127 + } 2.128 + cx_testing_allocator_destroy(&talloc); 2.129 +} 2.130 + 2.131 +CX_TEST(test_hash_map_rehash_not_required) { 2.132 + CxTestingAllocator talloc; 2.133 + cx_testing_allocator_init(&talloc); 2.134 + CxAllocator *allocator = &talloc.base; 2.135 + CX_TEST_DO { 2.136 + CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 8); 2.137 + 2.138 + cxMapPut(map, "key 1", (void *) "val 1"); 2.139 + cxMapPut(map, "key 2", (void *) "val 2"); 2.140 + cxMapPut(map, "key 3", (void *) "val 3"); 2.141 + cxMapPut(map, "key 4", (void *) "val 4"); 2.142 + cxMapPut(map, "key 5", (void *) "val 5"); 2.143 + cxMapPut(map, "key 6", (void *) "val 6"); 2.144 + 2.145 + // 6/8 does not exceed 0.75, therefore the function should not rehash 2.146 + int result = cxMapRehash(map); 2.147 + CX_TEST_ASSERT(result == 0); 2.148 + CX_TEST_ASSERT(((struct cx_hash_map_s *)map)->bucket_count == 8); 2.149 + 2.150 + cxMapDestroy(map); 2.151 + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); 2.152 + } 2.153 + cx_testing_allocator_destroy(&talloc); 2.154 +} 2.155 + 2.156 +CX_TEST(test_hash_map_clear) { 2.157 + CxTestingAllocator talloc; 2.158 + cx_testing_allocator_init(&talloc); 2.159 + CxAllocator *allocator = &talloc.base; 2.160 + CX_TEST_DO { 2.161 + CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 0); 2.162 + 2.163 + cxMapPut(map, "key 1", (void *) "val 1"); 2.164 + cxMapPut(map, "key 2", (void *) "val 2"); 2.165 + cxMapPut(map, "key 3", (void *) "val 3"); 2.166 + 2.167 + CX_TEST_ASSERT(map->size == 3); 2.168 + 2.169 + cxMapClear(map); 2.170 + 2.171 + CX_TEST_ASSERT(map->size == 0); 2.172 + CX_TEST_ASSERT(cxMapGet(map, "key 1") == NULL); 2.173 + CX_TEST_ASSERT(cxMapGet(map, "key 2") == NULL); 2.174 + CX_TEST_ASSERT(cxMapGet(map, "key 3") == NULL); 2.175 + 2.176 + cxMapDestroy(map); 2.177 + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); 2.178 + } 2.179 + cx_testing_allocator_destroy(&talloc); 2.180 +} 2.181 + 2.182 +CX_TEST(test_hash_map_store_ucx_strings) { 2.183 + CxTestingAllocator talloc; 2.184 + cx_testing_allocator_init(&talloc); 2.185 + CxAllocator *allocator = &talloc.base; 2.186 + CX_TEST_DO { 2.187 + // create the map 2.188 + CxMap *map = cxHashMapCreate(allocator, sizeof(cxstring), 8); 2.189 + 2.190 + // define some strings 2.191 + cxstring s1 = CX_STR("this"); 2.192 + cxstring s2 = CX_STR("is"); 2.193 + cxstring s3 = CX_STR("a"); 2.194 + cxstring s4 = CX_STR("test"); 2.195 + cxstring s5 = CX_STR("setup"); 2.196 + 2.197 + // put them into the map 2.198 + cxMapPut(map, "s1", &s1); 2.199 + cxMapPut(map, "s2", &s2); 2.200 + cxMapPut(map, "s3", &s3); 2.201 + cxMapPut(map, "s4", &s4); 2.202 + 2.203 + // overwrite a value 2.204 + cxMapPut(map, "s1", &s5); 2.205 + 2.206 + // look up a string 2.207 + cxstring * s3p = cxMapGet(map, "s3"); 2.208 + CX_TEST_ASSERT(s3p->length == s3.length); 2.209 + CX_TEST_ASSERT(s3p->ptr == s3.ptr); 2.210 + CX_TEST_ASSERT(s3p != &s3); 2.211 + 2.212 + // remove a string 2.213 + cxMapRemove(map, "s2"); 2.214 + CX_TEST_ASSERT(map->size == 3); 2.215 + 2.216 + // iterate 2.217 + bool s3found = false, s4found = false, s5found = false; 2.218 + CxIterator iter = cxMapIteratorValues(map); 2.219 + cx_foreach(cxstring*, s, iter) { 2.220 + s3found |= s3.ptr == s->ptr; 2.221 + s4found |= s4.ptr == s->ptr; 2.222 + s5found |= s5.ptr == s->ptr; 2.223 + } 2.224 + CX_TEST_ASSERT(s3found && s4found && s5found); 2.225 + 2.226 + cxMapDestroy(map); 2.227 + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); 2.228 + } 2.229 + cx_testing_allocator_destroy(&talloc); 2.230 +} 2.231 + 2.232 +CX_TEST(test_hash_map_remove_via_iterator) { 2.233 + CxTestingAllocator talloc; 2.234 + cx_testing_allocator_init(&talloc); 2.235 + CxAllocator *allocator = &talloc.base; 2.236 + CX_TEST_DO { 2.237 + CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 4); 2.238 + 2.239 + cxMapPut(map, "key 1", (void *) "val 1"); 2.240 + cxMapPut(map, "key 2", (void *) "val 2"); 2.241 + cxMapPut(map, "key 3", (void *) "val 3"); 2.242 + cxMapPut(map, "key 4", (void *) "val 4"); 2.243 + cxMapPut(map, "key 5", (void *) "val 5"); 2.244 + cxMapPut(map, "key 6", (void *) "val 6"); 2.245 + 2.246 + CxMutIterator iter = cxMapMutIterator(map); 2.247 + cx_foreach(CxMapEntry*, entry, iter) { 2.248 + if (((char const *)entry->key->data)[4] % 2 == 1) cxIteratorFlagRemoval(iter); 2.249 + } 2.250 + CX_TEST_ASSERT(map->size == 3); 2.251 + CX_TEST_ASSERT(iter.index == map->size); 2.252 + 2.253 + CX_TEST_ASSERT(cxMapGet(map, "key 1") == NULL); 2.254 + CX_TEST_ASSERT(cxMapGet(map, "key 2") != NULL); 2.255 + CX_TEST_ASSERT(cxMapGet(map, "key 3") == NULL); 2.256 + CX_TEST_ASSERT(cxMapGet(map, "key 4") != NULL); 2.257 + CX_TEST_ASSERT(cxMapGet(map, "key 5") == NULL); 2.258 + CX_TEST_ASSERT(cxMapGet(map, "key 6") != NULL); 2.259 + 2.260 + cxMapDestroy(map); 2.261 + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); 2.262 + } 2.263 + cx_testing_allocator_destroy(&talloc); 2.264 +} 2.265 + 2.266 +static void test_simple_destructor(void *data) { 2.267 + strcpy(data, "OK"); 2.268 +} 2.269 + 2.270 +static void test_advanced_destructor( 2.271 + __attribute__((__unused__)) void *unused, 2.272 + void *data 2.273 +) { 2.274 + strcpy(data, "OK"); 2.275 +} 2.276 + 2.277 +static CX_TEST_SUBROUTINE(verify_any_destructor, CxMap *map) { 2.278 + CxHashKey k1 = cx_hash_key_str("key 1"); 2.279 + CxHashKey k2 = cx_hash_key_str("key 2"); 2.280 + CxHashKey k3 = cx_hash_key_str("key 3"); 2.281 + CxHashKey k4 = cx_hash_key_str("key 4"); 2.282 + CxHashKey k5 = cx_hash_key_str("key 5"); 2.283 + 2.284 + char v1[] = "val 1"; 2.285 + char v2[] = "val 2"; 2.286 + char v3[] = "val 3"; 2.287 + char v4[] = "val 4"; 2.288 + char v5[] = "val 5"; 2.289 + 2.290 + cxMapPut(map, k1, v1); 2.291 + cxMapPut(map, k2, v2); 2.292 + cxMapPut(map, k3, v3); 2.293 + cxMapPut(map, k4, v4); 2.294 + 2.295 + cxMapRemove(map, k2); 2.296 + char *r = cxMapRemoveAndGet(map, k3); 2.297 + cxMapDetach(map, k1); 2.298 + 2.299 + CX_TEST_ASSERT(0 == strcmp(v1, "val 1")); 2.300 + CX_TEST_ASSERT(0 == strcmp(v2, "OK")); 2.301 + CX_TEST_ASSERT(0 == strcmp(v3, "val 3")); 2.302 + CX_TEST_ASSERT(0 == strcmp(v4, "val 4")); 2.303 + CX_TEST_ASSERT(0 == strcmp(v5, "val 5")); 2.304 + CX_TEST_ASSERT(r == v3); 2.305 + 2.306 + cxMapClear(map); 2.307 + 2.308 + CX_TEST_ASSERT(0 == strcmp(v1, "val 1")); 2.309 + CX_TEST_ASSERT(0 == strcmp(v2, "OK")); 2.310 + CX_TEST_ASSERT(0 == strcmp(v3, "val 3")); 2.311 + CX_TEST_ASSERT(0 == strcmp(v4, "OK")); 2.312 + CX_TEST_ASSERT(0 == strcmp(v5, "val 5")); 2.313 + 2.314 + cxMapPut(map, k1, (void *) v1); 2.315 + cxMapPut(map, k3, (void *) v3); 2.316 + cxMapPut(map, k5, (void *) v5); 2.317 + 2.318 + { 2.319 + CxMutIterator iter = cxMapMutIteratorKeys(map); 2.320 + cx_foreach(CxHashKey*, key, iter) { 2.321 + if (((char*)key->data)[4] == '1') cxIteratorFlagRemoval(iter); 2.322 + } 2.323 + } 2.324 + { 2.325 + CxMutIterator iter = cxMapMutIteratorValues(map); 2.326 + cx_foreach(char*, v, iter) { 2.327 + if (v[4] == '5') cxIteratorFlagRemoval(iter); 2.328 + } 2.329 + } 2.330 + 2.331 + CX_TEST_ASSERT(0 == strcmp(v1, "OK")); 2.332 + CX_TEST_ASSERT(0 == strcmp(v2, "OK")); 2.333 + CX_TEST_ASSERT(0 == strcmp(v3, "val 3")); 2.334 + CX_TEST_ASSERT(0 == strcmp(v4, "OK")); 2.335 + CX_TEST_ASSERT(0 == strcmp(v5, "OK")); 2.336 + 2.337 + v1[0] = v2[0] = v4[0] = v5[0] = 'c'; 2.338 + 2.339 + cxMapDestroy(map); 2.340 + 2.341 + CX_TEST_ASSERT(0 == strcmp(v1, "cK")); 2.342 + CX_TEST_ASSERT(0 == strcmp(v2, "cK")); 2.343 + CX_TEST_ASSERT(0 == strcmp(v3, "OK")); 2.344 + CX_TEST_ASSERT(0 == strcmp(v4, "cK")); 2.345 + CX_TEST_ASSERT(0 == strcmp(v5, "cK")); 2.346 +} 2.347 + 2.348 +CX_TEST(test_hash_map_simple_destructor) { 2.349 + CxTestingAllocator talloc; 2.350 + cx_testing_allocator_init(&talloc); 2.351 + CxAllocator *allocator = &talloc.base; 2.352 + CX_TEST_DO { 2.353 + CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 0); 2.354 + map->simple_destructor = test_simple_destructor; 2.355 + CX_TEST_CALL_SUBROUTINE(verify_any_destructor, map); 2.356 + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); 2.357 + } 2.358 + cx_testing_allocator_destroy(&talloc); 2.359 +} 2.360 + 2.361 +CX_TEST(test_hash_map_advanced_destructor) { 2.362 + CxTestingAllocator talloc; 2.363 + cx_testing_allocator_init(&talloc); 2.364 + CxAllocator *allocator = &talloc.base; 2.365 + CX_TEST_DO { 2.366 + CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 0); 2.367 + map->advanced_destructor = test_advanced_destructor; 2.368 + CX_TEST_CALL_SUBROUTINE(verify_any_destructor, map); 2.369 + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); 2.370 + } 2.371 + cx_testing_allocator_destroy(&talloc); 2.372 +} 2.373 + 2.374 +CX_TEST(test_empty_map_size) { 2.375 + CX_TEST_DO { 2.376 + CX_TEST_ASSERT(cxEmptyMap->size == 0); 2.377 + } 2.378 +} 2.379 + 2.380 +CX_TEST(test_empty_map_iterator) { 2.381 + CxMap *map = cxEmptyMap; 2.382 + 2.383 + CxIterator it1 = cxMapIterator(map); 2.384 + CxIterator it2 = cxMapIteratorValues(map); 2.385 + CxIterator it3 = cxMapIteratorKeys(map); 2.386 + CxMutIterator it4 = cxMapMutIterator(map); 2.387 + CxMutIterator it5 = cxMapMutIteratorValues(map); 2.388 + CxMutIterator it6 = cxMapMutIteratorKeys(map); 2.389 + 2.390 + CX_TEST_DO { 2.391 + CX_TEST_ASSERT(!cxIteratorValid(it1)); 2.392 + CX_TEST_ASSERT(!cxIteratorValid(it2)); 2.393 + CX_TEST_ASSERT(!cxIteratorValid(it3)); 2.394 + CX_TEST_ASSERT(!cxIteratorValid(it4)); 2.395 + CX_TEST_ASSERT(!cxIteratorValid(it5)); 2.396 + CX_TEST_ASSERT(!cxIteratorValid(it6)); 2.397 + 2.398 + int c = 0; 2.399 + cx_foreach(void*, data, it1) c++; 2.400 + cx_foreach(void*, data, it2) c++; 2.401 + cx_foreach(void*, data, it3) c++; 2.402 + cx_foreach(void*, data, it4) c++; 2.403 + cx_foreach(void*, data, it5) c++; 2.404 + cx_foreach(void*, data, it6) c++; 2.405 + CX_TEST_ASSERT(c == 0); 2.406 + } 2.407 +} 2.408 + 2.409 +CX_TEST(test_empty_map_no_ops) { 2.410 + CX_TEST_DO { 2.411 + // assertion not possible 2.412 + // test that no segfault happens and valgrind is happy 2.413 + cxMapClear(cxEmptyMap); 2.414 + cxMapDestroy(cxEmptyMap); 2.415 + CX_TEST_ASSERT(true); 2.416 + } 2.417 +} 2.418 + 2.419 +CX_TEST(test_empty_map_get) { 2.420 + CX_TEST_DO { 2.421 + CxHashKey key = cx_hash_key_str("test"); 2.422 + CX_TEST_ASSERT(cxMapGet(cxEmptyMap, key) == NULL); 2.423 + } 2.424 +} 2.425 + 2.426 +CX_TEST(test_hash_map_generics) { 2.427 + CxTestingAllocator talloc; 2.428 + cx_testing_allocator_init(&talloc); 2.429 + CxAllocator *allocator = &talloc.base; 2.430 + CX_TEST_DO { 2.431 + CxMap *map = cxHashMapCreate(allocator, sizeof(cxstring), 0); 2.432 + cxMapPut(map, "test", "test"); 2.433 + cxMapPut(map, cx_mutstr("foo"), "bar"); 2.434 + cxMapPut(map, cx_str("hallo"), "welt"); 2.435 + 2.436 + CX_TEST_ASSERT(map->size == 3); 2.437 + CX_TEST_ASSERT(0 == strcmp(cxMapGet(map, "test"), "test")); 2.438 + CX_TEST_ASSERT(0 == strcmp(cxMapGet(map, "foo"), "bar")); 2.439 + CX_TEST_ASSERT(0 == strcmp(cxMapGet(map, "hallo"), "welt")); 2.440 + 2.441 + // note: we don't have a destructor here, so remove and detach are the same 2.442 + cxMapRemove(map, cx_str("test")); 2.443 + char const *hallo = "hallo"; 2.444 + cxMapDetach(map, hallo); 2.445 + cxMapPut(map, cx_hash_key_str("key"), "value"); 2.446 + 2.447 + CX_TEST_ASSERT(map->size == 2); 2.448 + CX_TEST_ASSERT(0 == strcmp(cxMapGet(map, "key"), "value")); 2.449 + CX_TEST_ASSERT(0 == strcmp(cxMapGet(map, "foo"), "bar")); 2.450 + 2.451 + void *r; 2.452 + r = cxMapRemoveAndGet(map, "key"); 2.453 + r = cxMapRemoveAndGet(map, cx_str("foo")); 2.454 + if (r != NULL) map->size = 47; 2.455 + 2.456 + CX_TEST_ASSERT(map->size == 0); 2.457 + 2.458 + cxMapDestroy(map); 2.459 + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); 2.460 + } 2.461 + cx_testing_allocator_destroy(&talloc); 2.462 +} 2.463 + 2.464 +struct test_map_kv { 2.465 + char const *key; 2.466 + char const *value; 2.467 +}; 2.468 + 2.469 +static struct test_map_kv const test_map_operations[] = { 2.470 + {"key 1", "test"}, 2.471 + {"key 2", "blub"}, 2.472 + {"key 3", "hallo"}, 2.473 + {"key 2", "foobar"}, 2.474 + {"key 4", "value 4"}, 2.475 + {"key 5", "value 5"}, 2.476 + {"key 6", "value 6"}, 2.477 + {"key 4", NULL}, 2.478 + {"key 7", "value 7"}, 2.479 + {"key 8", "value 8"}, 2.480 + {"does not exist", NULL}, 2.481 + {"key 9", "value 9"}, 2.482 + {"key 6", "other value"}, 2.483 + {"key 7", "something else"}, 2.484 + {"key 8", NULL}, 2.485 + {"key 2", NULL}, 2.486 + {"key 8", "new value"}, 2.487 +}; 2.488 +static size_t const test_map_operations_len = 2.489 + sizeof(test_map_operations) / sizeof(struct test_map_kv); 2.490 +static struct test_map_kv test_map_reference[] = { 2.491 + {"key 1", NULL}, 2.492 + {"key 2", NULL}, 2.493 + {"key 3", NULL}, 2.494 + {"key 4", NULL}, 2.495 + {"key 5", NULL}, 2.496 + {"key 6", NULL}, 2.497 + {"key 7", NULL}, 2.498 + {"key 8", NULL}, 2.499 + {"key 9", NULL}, 2.500 +}; 2.501 +static size_t const test_map_reference_len = 2.502 + sizeof(test_map_reference) / sizeof(struct test_map_kv); 2.503 + 2.504 +static void test_map_reference_put(char const *key, char const* value) { 2.505 + for (size_t i = 0 ; i < test_map_reference_len ; i++) { 2.506 + if (0 == strcmp(key, test_map_reference[i].key)) { 2.507 + test_map_reference[i].value = value; 2.508 + return; 2.509 + } 2.510 + } 2.511 +} 2.512 + 2.513 +static char const *test_map_reference_get(char const *key) { 2.514 + for (size_t i = 0 ; i < test_map_reference_len ; i++) { 2.515 + if (0 == strcmp(key, test_map_reference[i].key)) { 2.516 + return test_map_reference[i].value; 2.517 + } 2.518 + } 2.519 + return NULL; 2.520 +} 2.521 + 2.522 +static char const *test_map_reference_remove(char const *key) { 2.523 + for (size_t i = 0 ; i < test_map_reference_len ; i++) { 2.524 + if (0 == strcmp(key, test_map_reference[i].key)) { 2.525 + char const *ret = test_map_reference[i].value; 2.526 + test_map_reference[i].value = NULL; 2.527 + return ret; 2.528 + } 2.529 + } 2.530 + return NULL; 2.531 +} 2.532 + 2.533 +static size_t test_map_reference_size(void) { 2.534 + size_t size = 0; 2.535 + for (size_t i = 0; i < test_map_reference_len; i++) { 2.536 + if (test_map_reference[i].value != NULL) { 2.537 + size++; 2.538 + } 2.539 + } 2.540 + return size; 2.541 +} 2.542 + 2.543 +static CX_TEST_SUBROUTINE(verify_map_contents, CxMap *map) { 2.544 + // verify that the reference map has same size (i.e. no other keys are mapped) 2.545 + CX_TEST_ASSERT(map->size == test_map_reference_size()); 2.546 + 2.547 + // verify key iterator 2.548 + { 2.549 + // collect the keys from the map iterator 2.550 + CxIterator keyiter = cxMapIteratorKeys(map); 2.551 + CxHashKey *keys = calloc(map->size, sizeof(CxHashKey)); 2.552 + cx_foreach(CxHashKey*, elem, keyiter) { 2.553 + keys[keyiter.index] = *elem; 2.554 + } 2.555 + CX_TEST_ASSERT(keyiter.index == map->size); 2.556 + // verify that all keys are mapped to values in reference map 2.557 + for (size_t i = 0 ; i < map->size ; i++) { 2.558 + cxmutstr ksz = cx_strdup(cx_strn(keys[i].data, keys[i].len)); 2.559 + CX_TEST_ASSERT(test_map_reference_get(ksz.ptr) != NULL); 2.560 + cx_strfree(&ksz); 2.561 + } 2.562 + free(keys); 2.563 + } 2.564 + 2.565 + // verify value iterator 2.566 + { 2.567 + // by using that the values in our test data are unique strings 2.568 + // we can re-use a similar approach as above 2.569 + CxIterator valiter = cxMapIteratorValues(map); 2.570 + char const** values = calloc(map->size, sizeof(char const*)); 2.571 + cx_foreach(char const*, elem, valiter) { 2.572 + values[valiter.index] = elem; 2.573 + } 2.574 + CX_TEST_ASSERT(valiter.index == map->size); 2.575 + // verify that all values are present in the reference map 2.576 + for (size_t i = 0 ; i < map->size ; i++) { 2.577 + bool found = false; 2.578 + for (size_t j = 0; j < test_map_reference_len ; j++) { 2.579 + if (test_map_reference[j].value == values[i]) { 2.580 + found = true; 2.581 + break; 2.582 + } 2.583 + } 2.584 + CX_TEST_ASSERTM(found, "A value was not found in the reference map"); 2.585 + } 2.586 + free(values); 2.587 + } 2.588 + 2.589 + // verify pair iterator 2.590 + { 2.591 + CxIterator pairiter = cxMapIterator(map); 2.592 + struct test_map_kv *pairs = calloc(map->size, sizeof(struct test_map_kv)); 2.593 + cx_foreach(CxMapEntry*, entry, pairiter) { 2.594 + CxHashKey const *key = entry->key; 2.595 + pairs[pairiter.index].key = cx_strdup(cx_strn(key->data, key->len)).ptr; 2.596 + pairs[pairiter.index].value = entry->value; 2.597 + } 2.598 + CX_TEST_ASSERT(pairiter.index == map->size); 2.599 + // verify that all pairs are present in the reference map 2.600 + for (size_t i = 0 ; i < map->size ; i++) { 2.601 + CX_TEST_ASSERT(test_map_reference_get(pairs[i].key) == pairs[i].value); 2.602 + // this was strdup'ed 2.603 + free((void*)pairs[i].key); 2.604 + } 2.605 + free(pairs); 2.606 + } 2.607 +} 2.608 + 2.609 +CX_TEST(test_hash_map_basic_operations) { 2.610 + CxTestingAllocator talloc; 2.611 + cx_testing_allocator_init(&talloc); 2.612 + CxAllocator *allocator = &talloc.base; 2.613 + CX_TEST_DO { 2.614 + // create the map 2.615 + CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 8); 2.616 + 2.617 + // clear the reference map 2.618 + for (size_t i = 0 ; i < test_map_reference_len ; i++) { 2.619 + test_map_reference[i].value = NULL; 2.620 + } 2.621 + 2.622 + // verify iterators for empty map 2.623 + CX_TEST_CALL_SUBROUTINE(verify_map_contents, map); 2.624 + 2.625 + // execute operations and verify results 2.626 + for (size_t i = 0 ; i < test_map_operations_len ; i++) { 2.627 + struct test_map_kv kv = test_map_operations[i]; 2.628 + CxHashKey key = cx_hash_key_str(kv.key); 2.629 + key.hash = 0; // force the hash map to compute the hash 2.630 + if (kv.value != NULL) { 2.631 + // execute a put operation and verify that the exact value can be read back 2.632 + test_map_reference_put(kv.key, kv.value); 2.633 + int result = cxMapPut(map, key, (void *) kv.value); 2.634 + CX_TEST_ASSERT(result == 0); 2.635 + void *added = cxMapGet(map, key); 2.636 + CX_TEST_ASSERT(0 == memcmp(kv.value, added, strlen(kv.value))); 2.637 + } else { 2.638 + // execute a remove and verify that the removed element was returned (or NULL) 2.639 + char const *found = test_map_reference_remove(kv.key); 2.640 + void *removed = cxMapRemoveAndGet(map, key); 2.641 + CX_TEST_ASSERT(found == removed); 2.642 + } 2.643 + // compare the current map state with the reference map 2.644 + CX_TEST_CALL_SUBROUTINE(verify_map_contents, map); 2.645 + } 2.646 + 2.647 + // destroy the map and verify the memory (de)allocations 2.648 + cxMapDestroy(map); 2.649 + CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); 2.650 + } 2.651 + cx_testing_allocator_destroy(&talloc); 2.652 +} 2.653 + 2.654 +CxTestSuite *cx_test_suite_hash_map(void) { 2.655 + CxTestSuite *suite = cx_test_suite_new("map"); 2.656 + 2.657 + cx_test_register(suite, test_hash_map_create); 2.658 + cx_test_register(suite, test_hash_map_create_store_pointers); 2.659 + cx_test_register(suite, test_hash_map_basic_operations); 2.660 + cx_test_register(suite, test_hash_map_rehash); 2.661 + cx_test_register(suite, test_hash_map_rehash_not_required); 2.662 + cx_test_register(suite, test_hash_map_clear); 2.663 + cx_test_register(suite, test_hash_map_store_ucx_strings); 2.664 + cx_test_register(suite, test_hash_map_remove_via_iterator); 2.665 + cx_test_register(suite, test_empty_map_no_ops); 2.666 + cx_test_register(suite, test_empty_map_size); 2.667 + cx_test_register(suite, test_empty_map_get); 2.668 + cx_test_register(suite, test_empty_map_iterator); 2.669 + cx_test_register(suite, test_hash_map_generics); 2.670 + 2.671 + return suite; 2.672 +}
3.1 --- a/tests/test_map.cpp Sat Dec 30 15:21:16 2023 +0100 3.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 3.3 @@ -1,521 +0,0 @@ 3.4 -/* 3.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3.6 - * 3.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 3.8 - * 3.9 - * Redistribution and use in source and binary forms, with or without 3.10 - * modification, are permitted provided that the following conditions are met: 3.11 - * 3.12 - * 1. Redistributions of source code must retain the above copyright 3.13 - * notice, this list of conditions and the following disclaimer. 3.14 - * 3.15 - * 2. Redistributions in binary form must reproduce the above copyright 3.16 - * notice, this list of conditions and the following disclaimer in the 3.17 - * documentation and/or other materials provided with the distribution. 3.18 - * 3.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 3.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 3.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3.29 - * POSSIBILITY OF SUCH DAMAGE. 3.30 - */ 3.31 - 3.32 -#include "cx/hash_map.h" 3.33 -#include "cx/utils.h" 3.34 -#include "cx/string.h" 3.35 -#include "util_allocator.h" 3.36 -#include "test_map_generics.h" 3.37 - 3.38 -#include <gtest/gtest.h> 3.39 -#include <unordered_map> 3.40 -#include <unordered_set> 3.41 - 3.42 -struct map_operation { 3.43 - enum { 3.44 - put, rm 3.45 - } op; 3.46 - char const *key; 3.47 - char const *value; 3.48 -}; 3.49 - 3.50 -auto generate_map_operations() -> std::vector<map_operation> { 3.51 - return { 3.52 - {map_operation::put, "key 1", "test"}, 3.53 - {map_operation::put, "key 2", "blub"}, 3.54 - {map_operation::put, "key 3", "hallo"}, 3.55 - {map_operation::put, "key 2", "foobar"}, 3.56 - {map_operation::put, "key 4", "value 4"}, 3.57 - {map_operation::put, "key 5", "value 5"}, 3.58 - {map_operation::put, "key 6", "value 6"}, 3.59 - {map_operation::rm, "key 4", nullptr}, 3.60 - {map_operation::put, "key 7", "value 7"}, 3.61 - {map_operation::put, "key 8", "value 8"}, 3.62 - {map_operation::rm, "does not exist", nullptr}, 3.63 - {map_operation::put, "key 9", "value 9"}, 3.64 - {map_operation::put, "key 6", "other value"}, 3.65 - {map_operation::put, "key 7", "something else"}, 3.66 - {map_operation::rm, "key 8", nullptr}, 3.67 - {map_operation::rm, "key 2", nullptr}, 3.68 - {map_operation::put, "key 8", "new value"}, 3.69 - }; 3.70 -} 3.71 - 3.72 -static void verify_map_contents( 3.73 - CxMap *map, 3.74 - std::unordered_map<std::string, std::string> const &refmap 3.75 -) { 3.76 - // verify key iterator 3.77 - { 3.78 - auto keyiter = cxMapIteratorKeys(map); 3.79 - std::unordered_set<std::string> keys; 3.80 - cx_foreach(CxHashKey*, elem, keyiter) { 3.81 - keys.insert(std::string(reinterpret_cast<char const *>(elem->data), elem->len)); 3.82 - } 3.83 - EXPECT_EQ(keyiter.index, map->size); 3.84 - ASSERT_EQ(keys.size(), map->size); 3.85 - for (auto &&k: keys) { 3.86 - EXPECT_NE(refmap.find(k), refmap.end()); 3.87 - } 3.88 - } 3.89 - 3.90 - // verify value iterator 3.91 - { 3.92 - auto valiter = cxMapIteratorValues(map); 3.93 - std::unordered_set<std::string> values; // we use that the values in our test data are unique strings 3.94 - cx_foreach(char const*, elem, valiter) { 3.95 - values.insert(std::string(elem)); 3.96 - } 3.97 - EXPECT_EQ(valiter.index, map->size); 3.98 - ASSERT_EQ(values.size(), map->size); 3.99 - for (auto &&v: values) { 3.100 - EXPECT_NE(std::find_if(refmap.begin(), refmap.end(), 3.101 - [v](auto const &e) { return e.second == v; }), refmap.end()); 3.102 - } 3.103 - } 3.104 - 3.105 - // verify pair iterator 3.106 - { 3.107 - auto pairiter = cxMapIterator(map); 3.108 - std::unordered_map<std::string, std::string> pairs; 3.109 - cx_foreach(CxMapEntry*, entry, pairiter) { 3.110 - pairs[std::string(reinterpret_cast<char const *>(entry->key->data), entry->key->len)] = std::string( 3.111 - (char *) entry->value); 3.112 - } 3.113 - EXPECT_EQ(pairiter.index, map->size); 3.114 - ASSERT_EQ(pairs.size(), refmap.size()); 3.115 - for (auto &&p: pairs) { 3.116 - ASSERT_EQ(p.second, refmap.at(p.first)); 3.117 - } 3.118 - } 3.119 -} 3.120 - 3.121 -TEST(CxHashMap, Create) { 3.122 - CxTestingAllocator allocator; 3.123 - auto map = cxHashMapCreate(&allocator, 1, 0); 3.124 - auto hmap = reinterpret_cast<struct cx_hash_map_s *>(map); 3.125 - EXPECT_GT(hmap->bucket_count, 0); 3.126 - cx_for_n(i, hmap->bucket_count) { 3.127 - EXPECT_EQ(hmap->buckets[i], nullptr); 3.128 - } 3.129 - EXPECT_EQ(map->item_size, 1); 3.130 - EXPECT_EQ(map->size, 0); 3.131 - EXPECT_EQ(map->allocator, &allocator); 3.132 - EXPECT_FALSE(map->store_pointer); 3.133 - EXPECT_EQ(map->cmpfunc, nullptr); 3.134 - EXPECT_EQ(map->simple_destructor, nullptr); 3.135 - EXPECT_EQ(map->advanced_destructor, nullptr); 3.136 - EXPECT_EQ(map->destructor_data, nullptr); 3.137 - cxMapStorePointers(map); 3.138 - EXPECT_TRUE(map->store_pointer); 3.139 - EXPECT_EQ(map->item_size, sizeof(void *)); 3.140 - cxMapStoreObjects(map); 3.141 - EXPECT_FALSE(map->store_pointer); 3.142 - 3.143 - cxMapDestroy(map); 3.144 - EXPECT_TRUE(allocator.verify()); 3.145 -} 3.146 - 3.147 -TEST(CxHashMap, CreateForStoringPointers) { 3.148 - CxTestingAllocator allocator; 3.149 - auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 0); 3.150 - auto hmap = reinterpret_cast<struct cx_hash_map_s *>(map); 3.151 - EXPECT_GT(hmap->bucket_count, 0); 3.152 - cx_for_n(i, hmap->bucket_count) { 3.153 - EXPECT_EQ(hmap->buckets[i], nullptr); 3.154 - } 3.155 - EXPECT_EQ(map->size, 0); 3.156 - EXPECT_EQ(map->allocator, &allocator); 3.157 - EXPECT_TRUE(map->store_pointer); 3.158 - EXPECT_EQ(map->item_size, sizeof(void *)); 3.159 - 3.160 - cxMapDestroy(map); 3.161 - EXPECT_TRUE(allocator.verify()); 3.162 -} 3.163 - 3.164 -TEST(CxHashMap, BasicOperations) { 3.165 - // create the map 3.166 - CxTestingAllocator allocator; 3.167 - auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 8); 3.168 - 3.169 - // create a reference map 3.170 - std::unordered_map<std::string, std::string> refmap; 3.171 - 3.172 - // generate operations 3.173 - auto ops = generate_map_operations(); 3.174 - 3.175 - // verify iterators for empty map 3.176 - verify_map_contents(map, refmap); 3.177 - 3.178 - // execute operations and verify results 3.179 - for (auto &&op: ops) { 3.180 - CxHashKey key = cx_hash_key_str(op.key); 3.181 - key.hash = 0; // force the hash map to compute the hash 3.182 - if (op.op == map_operation::put) { 3.183 - // execute a put operation and verify that the exact value can be read back 3.184 - refmap[std::string(op.key)] = std::string(op.value); 3.185 - int result = cxMapPut(map, key, (void *) op.value); 3.186 - EXPECT_EQ(result, 0); 3.187 - auto added = cxMapGet(map, key); 3.188 - EXPECT_EQ(memcmp(op.value, added, strlen(op.value)), 0); 3.189 - } else { 3.190 - // execute a remove and verify that the removed element was returned (or nullptr) 3.191 - auto found = refmap.find(op.key); 3.192 - auto removed = cxMapRemoveAndGet(map, key); 3.193 - if (found == refmap.end()) { 3.194 - EXPECT_EQ(removed, nullptr); 3.195 - } else { 3.196 - EXPECT_EQ(std::string((char *) removed), found->second); 3.197 - refmap.erase(found); 3.198 - } 3.199 - } 3.200 - // compare the current map state with the reference map 3.201 - verify_map_contents(map, refmap); 3.202 - } 3.203 - 3.204 - // destroy the map and verify the memory (de)allocations 3.205 - cxMapDestroy(map); 3.206 - EXPECT_TRUE(allocator.verify()); 3.207 -} 3.208 - 3.209 -TEST(CxHashMap, RemoveViaIterator) { 3.210 - CxTestingAllocator allocator; 3.211 - auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 4); 3.212 - 3.213 - cxMapPut(map, "key 1", (void *) "val 1"); 3.214 - cxMapPut(map, "key 2", (void *) "val 2"); 3.215 - cxMapPut(map, "key 3", (void *) "val 3"); 3.216 - cxMapPut(map, "key 4", (void *) "val 4"); 3.217 - cxMapPut(map, "key 5", (void *) "val 5"); 3.218 - cxMapPut(map, "key 6", (void *) "val 6"); 3.219 - 3.220 - auto iter = cxMapMutIterator(map); 3.221 - cx_foreach(CxMapEntry*, entry, iter) { 3.222 - if (reinterpret_cast<char const *>(entry->key->data)[4] % 2 == 1) cxIteratorFlagRemoval(iter); 3.223 - } 3.224 - EXPECT_EQ(map->size, 3); 3.225 - EXPECT_EQ(iter.index, map->size); 3.226 - 3.227 - EXPECT_EQ(cxMapGet(map, "key 1"), nullptr); 3.228 - EXPECT_NE(cxMapGet(map, "key 2"), nullptr); 3.229 - EXPECT_EQ(cxMapGet(map, "key 3"), nullptr); 3.230 - EXPECT_NE(cxMapGet(map, "key 4"), nullptr); 3.231 - EXPECT_EQ(cxMapGet(map, "key 5"), nullptr); 3.232 - EXPECT_NE(cxMapGet(map, "key 6"), nullptr); 3.233 - 3.234 - cxMapDestroy(map); 3.235 - EXPECT_TRUE(allocator.verify()); 3.236 -} 3.237 - 3.238 -TEST(CxHashMap, RehashNotRequired) { 3.239 - CxTestingAllocator allocator; 3.240 - auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 8); 3.241 - 3.242 - cxMapPut(map, "key 1", (void *) "val 1"); 3.243 - cxMapPut(map, "key 2", (void *) "val 2"); 3.244 - cxMapPut(map, "key 3", (void *) "val 3"); 3.245 - cxMapPut(map, "key 4", (void *) "val 4"); 3.246 - cxMapPut(map, "key 5", (void *) "val 5"); 3.247 - cxMapPut(map, "key 6", (void *) "val 6"); 3.248 - 3.249 - // 6/8 does not exceed 0.75, therefore the function should not rehash 3.250 - int result = cxMapRehash(map); 3.251 - EXPECT_EQ(result, 0); 3.252 - EXPECT_EQ(reinterpret_cast<struct cx_hash_map_s *>(map)->bucket_count, 8); 3.253 - 3.254 - cxMapDestroy(map); 3.255 - EXPECT_TRUE(allocator.verify()); 3.256 -} 3.257 - 3.258 -TEST(CxHashMap, Rehash) { 3.259 - CxTestingAllocator allocator; 3.260 - auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 7); 3.261 - 3.262 - cxMapPut(map, "key 1", (void *) "val 1"); 3.263 - cxMapPut(map, "key 2", (void *) "val 2"); 3.264 - cxMapPut(map, "key 3", (void *) "val 3"); 3.265 - cxMapPut(map, "foo 4", (void *) "val 4"); 3.266 - cxMapPut(map, "key 5", (void *) "val 5"); 3.267 - cxMapPut(map, "key 6", (void *) "val 6"); 3.268 - cxMapPut(map, "bar 7", (void *) "val 7"); 3.269 - cxMapPut(map, "key 8", (void *) "val 8"); 3.270 - cxMapPut(map, "key 9", (void *) "val 9"); 3.271 - cxMapPut(map, "key 10", (void *) "val 10"); 3.272 - 3.273 - int result = cxMapRehash(map); 3.274 - EXPECT_EQ(result, 0); 3.275 - EXPECT_EQ(reinterpret_cast<struct cx_hash_map_s *>(map)->bucket_count, 25); 3.276 - EXPECT_EQ(map->size, 10); 3.277 - 3.278 - EXPECT_STREQ((char *) cxMapGet(map, "key 1"), "val 1"); 3.279 - EXPECT_STREQ((char *) cxMapGet(map, "key 2"), "val 2"); 3.280 - EXPECT_STREQ((char *) cxMapGet(map, "key 3"), "val 3"); 3.281 - EXPECT_STREQ((char *) cxMapGet(map, "foo 4"), "val 4"); 3.282 - EXPECT_STREQ((char *) cxMapGet(map, "key 5"), "val 5"); 3.283 - EXPECT_STREQ((char *) cxMapGet(map, "key 6"), "val 6"); 3.284 - EXPECT_STREQ((char *) cxMapGet(map, "bar 7"), "val 7"); 3.285 - EXPECT_STREQ((char *) cxMapGet(map, "key 8"), "val 8"); 3.286 - EXPECT_STREQ((char *) cxMapGet(map, "key 9"), "val 9"); 3.287 - EXPECT_STREQ((char *) cxMapGet(map, "key 10"), "val 10"); 3.288 - 3.289 - cxMapDestroy(map); 3.290 - EXPECT_TRUE(allocator.verify()); 3.291 -} 3.292 - 3.293 -TEST(CxHashMap, Clear) { 3.294 - CxTestingAllocator allocator; 3.295 - auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 0); 3.296 - 3.297 - cxMapPut(map, "key 1", (void *) "val 1"); 3.298 - cxMapPut(map, "key 2", (void *) "val 2"); 3.299 - cxMapPut(map, "key 3", (void *) "val 3"); 3.300 - 3.301 - EXPECT_EQ(map->size, 3); 3.302 - 3.303 - cxMapClear(map); 3.304 - 3.305 - EXPECT_EQ(map->size, 0); 3.306 - EXPECT_EQ(cxMapGet(map, "key 1"), nullptr); 3.307 - EXPECT_EQ(cxMapGet(map, "key 2"), nullptr); 3.308 - EXPECT_EQ(cxMapGet(map, "key 3"), nullptr); 3.309 - 3.310 - cxMapDestroy(map); 3.311 - EXPECT_TRUE(allocator.verify()); 3.312 -} 3.313 - 3.314 -TEST(CxHashMap, StoreUcxStrings) { 3.315 - // create the map 3.316 - CxTestingAllocator allocator; 3.317 - auto map = cxHashMapCreate(&allocator, sizeof(cxstring), 8); 3.318 - 3.319 - // define some strings 3.320 - auto s1 = CX_STR("this"); 3.321 - auto s2 = CX_STR("is"); 3.322 - auto s3 = CX_STR("a"); 3.323 - auto s4 = CX_STR("test"); 3.324 - auto s5 = CX_STR("setup"); 3.325 - 3.326 - // put them into the map 3.327 - cxMapPut(map, "s1", &s1); 3.328 - cxMapPut(map, "s2", &s2); 3.329 - cxMapPut(map, "s3", &s3); 3.330 - cxMapPut(map, "s4", &s4); 3.331 - 3.332 - // overwrite a value 3.333 - cxMapPut(map, "s1", &s5); 3.334 - 3.335 - // look up a string 3.336 - auto s3p = reinterpret_cast<cxstring *>(cxMapGet(map, "s3")); 3.337 - EXPECT_EQ(s3p->length, s3.length); 3.338 - EXPECT_EQ(s3p->ptr, s3.ptr); 3.339 - EXPECT_NE(s3p, &s3); 3.340 - 3.341 - // remove a string 3.342 - cxMapRemove(map, "s2"); 3.343 - 3.344 - // iterate 3.345 - auto ref = std::vector{s5.ptr, s3.ptr, s4.ptr}; 3.346 - auto iter = cxMapIteratorValues(map); 3.347 - cx_foreach(cxstring*, s, iter) { 3.348 - auto found = std::find(ref.begin(), ref.end(), s->ptr); 3.349 - ASSERT_NE(found, ref.end()); 3.350 - ref.erase(found); 3.351 - } 3.352 - EXPECT_EQ(ref.size(), 0); 3.353 - 3.354 - cxMapDestroy(map); 3.355 - EXPECT_TRUE(allocator.verify()); 3.356 -} 3.357 - 3.358 -static void test_simple_destructor(void *data) { 3.359 - strcpy((char *) data, "OK"); 3.360 -} 3.361 - 3.362 -static void test_advanced_destructor( 3.363 - [[maybe_unused]] void *unused, 3.364 - void *data 3.365 -) { 3.366 - strcpy((char *) data, "OK"); 3.367 -} 3.368 - 3.369 -static void verify_any_destructor(CxMap *map) { 3.370 - auto k1 = cx_hash_key_str("key 1"); 3.371 - auto k2 = cx_hash_key_str("key 2"); 3.372 - auto k3 = cx_hash_key_str("key 3"); 3.373 - auto k4 = cx_hash_key_str("key 4"); 3.374 - auto k5 = cx_hash_key_str("key 5"); 3.375 - 3.376 - char v1[] = "val 1"; 3.377 - char v2[] = "val 2"; 3.378 - char v3[] = "val 3"; 3.379 - char v4[] = "val 4"; 3.380 - char v5[] = "val 5"; 3.381 - 3.382 - cxMapPut(map, k1, (void *) v1); 3.383 - cxMapPut(map, k2, (void *) v2); 3.384 - cxMapPut(map, k3, (void *) v3); 3.385 - cxMapPut(map, k4, (void *) v4); 3.386 - 3.387 - cxMapRemove(map, k2); 3.388 - auto r = cxMapRemoveAndGet(map, k3); 3.389 - cxMapDetach(map, k1); 3.390 - 3.391 - EXPECT_STREQ(v1, "val 1"); 3.392 - EXPECT_STREQ(v2, "OK"); 3.393 - EXPECT_STREQ(v3, "val 3"); 3.394 - EXPECT_STREQ(v4, "val 4"); 3.395 - EXPECT_STREQ(v5, "val 5"); 3.396 - EXPECT_EQ(r, v3); 3.397 - 3.398 - cxMapClear(map); 3.399 - 3.400 - EXPECT_STREQ(v1, "val 1"); 3.401 - EXPECT_STREQ(v2, "OK"); 3.402 - EXPECT_STREQ(v3, "val 3"); 3.403 - EXPECT_STREQ(v4, "OK"); 3.404 - EXPECT_STREQ(v5, "val 5"); 3.405 - 3.406 - cxMapPut(map, k1, (void *) v1); 3.407 - cxMapPut(map, k3, (void *) v3); 3.408 - cxMapPut(map, k5, (void *) v5); 3.409 - 3.410 - { 3.411 - auto iter = cxMapMutIteratorKeys(map); 3.412 - cx_foreach(CxHashKey*, key, iter) { 3.413 - if (reinterpret_cast<char const *>(key->data)[4] == '1') cxIteratorFlagRemoval(iter); 3.414 - } 3.415 - } 3.416 - { 3.417 - auto iter = cxMapMutIteratorValues(map); 3.418 - cx_foreach(char*, v, iter) { 3.419 - if (v[4] == '5') cxIteratorFlagRemoval(iter); 3.420 - } 3.421 - } 3.422 - 3.423 - EXPECT_STREQ(v1, "OK"); 3.424 - EXPECT_STREQ(v2, "OK"); 3.425 - EXPECT_STREQ(v3, "val 3"); 3.426 - EXPECT_STREQ(v4, "OK"); 3.427 - EXPECT_STREQ(v5, "OK"); 3.428 - 3.429 - v1[0] = v2[0] = v4[0] = v5[0] = 'c'; 3.430 - 3.431 - cxMapDestroy(map); 3.432 - 3.433 - EXPECT_STREQ(v1, "cK"); 3.434 - EXPECT_STREQ(v2, "cK"); 3.435 - EXPECT_STREQ(v3, "OK"); 3.436 - EXPECT_STREQ(v4, "cK"); 3.437 - EXPECT_STREQ(v5, "cK"); 3.438 -} 3.439 - 3.440 -TEST(CxHashMap, SimpleDestructor) { 3.441 - CxTestingAllocator allocator; 3.442 - auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 0); 3.443 - map->simple_destructor = test_simple_destructor; 3.444 - verify_any_destructor(map); 3.445 - EXPECT_TRUE(allocator.verify()); 3.446 -} 3.447 - 3.448 -TEST(CxHashMap, AdvancedDestructor) { 3.449 - CxTestingAllocator allocator; 3.450 - auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 0); 3.451 - map->advanced_destructor = test_advanced_destructor; 3.452 - verify_any_destructor(map); 3.453 - EXPECT_TRUE(allocator.verify()); 3.454 -} 3.455 - 3.456 -TEST(CxHashMap, Generics) { 3.457 - CxTestingAllocator allocator; 3.458 - auto map = test_map_generics_step_1(&allocator); 3.459 - 3.460 - EXPECT_EQ(map->size, 3); 3.461 - EXPECT_STREQ((char *) cxMapGet(map, "test"), "test"); 3.462 - EXPECT_STREQ((char *) cxMapGet(map, "foo"), "bar"); 3.463 - EXPECT_STREQ((char *) cxMapGet(map, "hallo"), "welt"); 3.464 - 3.465 - test_map_generics_step_2(map); 3.466 - 3.467 - EXPECT_EQ(map->size, 2); 3.468 - EXPECT_STREQ((char *) cxMapGet(map, "key"), "value"); 3.469 - EXPECT_STREQ((char *) cxMapGet(map, "foo"), "bar"); 3.470 - 3.471 - test_map_generics_step_3(map); 3.472 - 3.473 - EXPECT_EQ(map->size, 0); 3.474 - 3.475 - cxMapDestroy(map); 3.476 - EXPECT_TRUE(allocator.verify()); 3.477 -} 3.478 - 3.479 -TEST(EmptyMap, Size) { 3.480 - auto map = cxEmptyMap; 3.481 - 3.482 - EXPECT_EQ(map->size, 0); 3.483 -} 3.484 - 3.485 -TEST(EmptyMap, Iterator) { 3.486 - auto map = cxEmptyMap; 3.487 - 3.488 - auto it1 = cxMapIterator(map); 3.489 - auto it2 = cxMapIteratorValues(map); 3.490 - auto it3 = cxMapIteratorKeys(map); 3.491 - auto it4 = cxMapMutIterator(map); 3.492 - auto it5 = cxMapMutIteratorValues(map); 3.493 - auto it6 = cxMapMutIteratorKeys(map); 3.494 - 3.495 - EXPECT_FALSE(cxIteratorValid(it1)); 3.496 - EXPECT_FALSE(cxIteratorValid(it2)); 3.497 - EXPECT_FALSE(cxIteratorValid(it3)); 3.498 - EXPECT_FALSE(cxIteratorValid(it4)); 3.499 - EXPECT_FALSE(cxIteratorValid(it5)); 3.500 - EXPECT_FALSE(cxIteratorValid(it6)); 3.501 - 3.502 - int c = 0; 3.503 - cx_foreach(void*, data, it1) c++; 3.504 - cx_foreach(void*, data, it2) c++; 3.505 - cx_foreach(void*, data, it3) c++; 3.506 - cx_foreach(void*, data, it4) c++; 3.507 - cx_foreach(void*, data, it5) c++; 3.508 - cx_foreach(void*, data, it6) c++; 3.509 - EXPECT_EQ(c, 0); 3.510 -} 3.511 - 3.512 -TEST(EmptyMap, NoOps) { 3.513 - auto map = cxEmptyMap; 3.514 - 3.515 - ASSERT_NO_FATAL_FAILURE(cxMapClear(map)); 3.516 - ASSERT_NO_FATAL_FAILURE(cxMapDestroy(map)); 3.517 -} 3.518 - 3.519 -TEST(EmptyMap, Get) { 3.520 - auto map = cxEmptyMap; 3.521 - 3.522 - CxHashKey key = cx_hash_key_str("test"); 3.523 - EXPECT_EQ(cxMapGet(map, key), nullptr); 3.524 -}
4.1 --- a/tests/test_map_generics.c Sat Dec 30 15:21:16 2023 +0100 4.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 4.3 @@ -1,55 +0,0 @@ 4.4 -/* 4.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 4.6 - * 4.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 4.8 - * 4.9 - * Redistribution and use in source and binary forms, with or without 4.10 - * modification, are permitted provided that the following conditions are met: 4.11 - * 4.12 - * 1. Redistributions of source code must retain the above copyright 4.13 - * notice, this list of conditions and the following disclaimer. 4.14 - * 4.15 - * 2. Redistributions in binary form must reproduce the above copyright 4.16 - * notice, this list of conditions and the following disclaimer in the 4.17 - * documentation and/or other materials provided with the distribution. 4.18 - * 4.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 4.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 4.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 4.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 4.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 4.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 4.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 4.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4.29 - * POSSIBILITY OF SUCH DAMAGE. 4.30 - */ 4.31 - 4.32 -#include "test_map_generics.h" 4.33 -#include "cx/hash_map.h" 4.34 - 4.35 -CxMap *test_map_generics_step_1(CxAllocator const * allocator) { 4.36 - CxMap *map = cxHashMapCreate(allocator, sizeof(cxstring), 0); 4.37 - 4.38 - cxMapPut(map, "test", "test"); 4.39 - cxMapPut(map, cx_mutstr("foo"), "bar"); 4.40 - cxMapPut(map, cx_str("hallo"), "welt"); 4.41 - 4.42 - return map; 4.43 -} 4.44 - 4.45 -void test_map_generics_step_2(CxMap *map) { 4.46 - // note: we don't have a destructor here, so remove and detach are the same 4.47 - cxMapRemove(map, cx_str("test")); 4.48 - char const* hallo = "hallo"; 4.49 - cxMapDetach(map, hallo); 4.50 - cxMapPut(map, cx_hash_key_str("key"), "value"); 4.51 -} 4.52 - 4.53 -void test_map_generics_step_3(CxMap *map) { 4.54 - void *r; 4.55 - r = cxMapRemoveAndGet(map, "key"); 4.56 - r = cxMapRemoveAndGet(map, cx_str("foo")); 4.57 - if (r != NULL) map->size = 47; 4.58 -}
5.1 --- a/tests/test_map_generics.h Sat Dec 30 15:21:16 2023 +0100 5.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 5.3 @@ -1,48 +0,0 @@ 5.4 -/* 5.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 5.6 - * 5.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 5.8 - * 5.9 - * Redistribution and use in source and binary forms, with or without 5.10 - * modification, are permitted provided that the following conditions are met: 5.11 - * 5.12 - * 1. Redistributions of source code must retain the above copyright 5.13 - * notice, this list of conditions and the following disclaimer. 5.14 - * 5.15 - * 2. Redistributions in binary form must reproduce the above copyright 5.16 - * notice, this list of conditions and the following disclaimer in the 5.17 - * documentation and/or other materials provided with the distribution. 5.18 - * 5.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 5.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 5.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 5.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 5.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 5.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 5.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 5.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 5.29 - * POSSIBILITY OF SUCH DAMAGE. 5.30 - */ 5.31 - 5.32 -#ifndef UCX_TEST_MAP_GENERICS_H 5.33 -#define UCX_TEST_MAP_GENERICS_H 5.34 - 5.35 -#include "cx/map.h" 5.36 - 5.37 -#ifdef __cplusplus 5.38 -extern "C" { 5.39 -#endif 5.40 - 5.41 -CxMap *test_map_generics_step_1(CxAllocator const *); 5.42 - 5.43 -void test_map_generics_step_2(CxMap *); 5.44 - 5.45 -void test_map_generics_step_3(CxMap *); 5.46 - 5.47 -#ifdef __cplusplus 5.48 -} // extern "C" 5.49 -#endif 5.50 - 5.51 -#endif //UCX_TEST_MAP_GENERICS_H
6.1 --- a/tests/test_mempool.c Sat Dec 30 15:21:16 2023 +0100 6.2 +++ b/tests/test_mempool.c Sat Dec 30 18:48:25 2023 +0100 6.3 @@ -97,7 +97,7 @@ 6.4 while (rdata == data) { 6.5 n <<= 1; 6.6 // eventually the memory should be moved elsewhere 6.7 - CX_TEST_ASSERTM(n < 65536, "Reallocation attempt failed - test not executable."); 6.8 + CX_TEST_ASSERTM(n < 65536, "Reallocation attempt failed - test not executable"); 6.9 rdata = cxRealloc(pool->allocator, data, n * sizeof(intptr_t)); 6.10 } 6.11
7.1 --- a/tests/ucxtest.c Sat Dec 30 15:21:16 2023 +0100 7.2 +++ b/tests/ucxtest.c Sat Dec 30 18:48:25 2023 +0100 7.3 @@ -35,6 +35,7 @@ 7.4 CxTestSuite *cx_test_suite_string(void); 7.5 CxTestSuite *cx_test_suite_printf(void); 7.6 CxTestSuite *cx_test_suite_mempool(void); 7.7 +CxTestSuite *cx_test_suite_hash_map(void); 7.8 7.9 #define run_tests(suite) cx_test_run_stdout(suite); success += (suite)->success; failure += (suite)->failure 7.10 #define execute_test_suites(...) unsigned success = 0, failure = 0; CxTestSuite* test_suites[] = {__VA_ARGS__}; \ 7.11 @@ -51,7 +52,8 @@ 7.12 cx_test_suite_allocator(), 7.13 cx_test_suite_string(), 7.14 cx_test_suite_printf(), 7.15 - cx_test_suite_mempool() 7.16 + cx_test_suite_mempool(), 7.17 + cx_test_suite_hash_map() 7.18 ); 7.19 printf("=== OVERALL RESULT ===\n"); 7.20 printf(" Total: %u\n Success: %u\n Failure: %u\n",