tests/test_hash_map.c

changeset 1467
bb6f04c35310
parent 1466
a58c65d31342
--- a/tests/test_hash_map.c	Sun Nov 02 18:04:35 2025 +0100
+++ b/tests/test_hash_map.c	Mon Nov 03 19:55:04 2025 +0100
@@ -836,7 +836,6 @@
     }
     CX_TEST_DO {
         int c = 4;
-        test_hash_map_clone_func_max_clones = 100; // no limit
         CX_TEST_ASSERT(0 == cxMapDifference(dst, s1, s2, test_hash_map_clone_func, allocator, &c));
         CX_TEST_ASSERT(cxMapSize(dst) == 2);
         CX_TEST_ASSERT(*((int*)cxMapGet(dst, "k1")) == 5);
@@ -852,6 +851,218 @@
     cx_testing_allocator_destroy(&talloc);
 }
 
+CX_TEST(test_hash_map_intersection) {
+    CxMap *dst = cxHashMapCreateSimple(sizeof(int));
+
+    CxMap *s1 = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    CxMap *s2 = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    const char *s1_keys[] = {"k1", "k2", "k3", "k4"};
+    int s1_values[] = {1, 3, 4, 6};
+    const char *s2_keys[] = {"k4", "k5", "k2", "k6"};
+    int s2_values[] = {5, 9, 15, 23};
+    for (unsigned int i = 0 ; i < 4 ; i++) {
+        cxMapPut(s1, s1_keys[i], &s1_values[i]);
+        cxMapPut(s2, s2_keys[i], &s2_values[i]);
+    }
+    CX_TEST_DO {
+        int c = 4;
+        CX_TEST_ASSERT(0 == cxMapIntersection(dst, s1, s2, test_hash_map_clone_func, NULL, &c));
+        CX_TEST_ASSERT(cxMapSize(dst) == 2);
+        CX_TEST_ASSERT(*((int*)cxMapGet(dst, "k2")) == 7);
+        CX_TEST_ASSERT(*((int*)cxMapGet(dst, "k4")) == 10);
+    }
+    cxMapFree(dst);
+    cxMapFree(s1);
+    cxMapFree(s2);
+}
+
+CX_TEST(test_hash_map_intersection_alloc_fail) {
+    CxMap *dst = cxHashMapCreateSimple(sizeof(int));
+
+    CxMap *s1 = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    CxMap *s2 = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    const char *s1_keys[] = {"k1", "k2", "k3", "k4"};
+    int s1_values[] = {1, 3, 4, 6};
+    const char *s2_keys[] = {"k4", "k5", "k2", "k6"};
+    int s2_values[] = {5, 9, 15, 23};
+    for (unsigned int i = 0 ; i < 4 ; i++) {
+        cxMapPut(s1, s1_keys[i], &s1_values[i]);
+        cxMapPut(s2, s2_keys[i], &s2_values[i]);
+    }
+    CX_TEST_DO {
+        int c = 4;
+        test_hash_map_clone_func_max_enabled = true;
+        test_hash_map_clone_func_max_clones = 1;
+        CX_TEST_ASSERT(0 != cxMapIntersection(dst, s1, s2, test_hash_map_clone_func, NULL, &c));
+        test_hash_map_clone_func_max_enabled = false;
+        CX_TEST_ASSERT(cxMapSize(dst) == 1);
+        // the concrete element which is affected might change when the hash function changes
+        CX_TEST_ASSERT(*((int*)cxMapGet(dst, "k2")) == 7);
+        CX_TEST_ASSERT(cxMapGet(dst, "k4") == NULL);
+    }
+    cxMapFree(dst);
+    cxMapFree(s1);
+    cxMapFree(s2);
+}
+
+CX_TEST(test_hash_map_list_intersection) {
+    CxMap *dst = cxHashMapCreateSimple(sizeof(int));
+    CxMap *src = cxHashMapCreateSimple(sizeof(int));
+    CxList *keys = cxArrayListCreate(NULL, cx_hash_key_cmp, sizeof(CxHashKey), 4);
+
+    const char *src_keys[] = {"k1", "k2", "k3", "k4"};
+    int src_values[] = {1, 3, 4, 6};
+    for (unsigned int i = 0 ; i < 4 ; i++) {
+        cxMapPut(src, src_keys[i], &src_values[i]);
+    }
+    const char *k[] = {"k4", "k5", "k2", "k6"};
+    for (unsigned int i = 0 ; i < 4 ; i++) {
+        CxHashKey key = CX_HASH_KEY(k[i]);
+        cxListAdd(keys, &key);
+    }
+    CX_TEST_DO {
+        int c = 4;
+        CX_TEST_ASSERT(0 == cxMapListIntersection(dst, src, keys, test_hash_map_clone_func, NULL, &c));
+        CX_TEST_ASSERT(cxMapSize(dst) == 2);
+        CX_TEST_ASSERT(*((int*)cxMapGet(dst, "k2")) == 7);
+        CX_TEST_ASSERT(*((int*)cxMapGet(dst, "k4")) == 10);
+    }
+    cxMapFree(dst);
+    cxMapFree(src);
+    cxListFree(keys);
+}
+
+CX_TEST(test_hash_map_list_intersection_alloc_fail) {
+    CxMap *dst = cxHashMapCreateSimple(sizeof(int));
+    CxMap *src = cxHashMapCreateSimple(sizeof(int));
+    CxList *keys = cxArrayListCreate(NULL, cx_hash_key_cmp, sizeof(CxHashKey), 4);
+
+    const char *src_keys[] = {"k1", "k2", "k3", "k4"};
+    int src_values[] = {1, 3, 4, 6};
+    for (unsigned int i = 0 ; i < 4 ; i++) {
+        cxMapPut(src, src_keys[i], &src_values[i]);
+    }
+    const char *k[] = {"k4", "k5", "k2", "k6"};
+    for (unsigned int i = 0 ; i < 4 ; i++) {
+        CxHashKey key = CX_HASH_KEY(k[i]);
+        cxListAdd(keys, &key);
+    }
+    CX_TEST_DO {
+        int c = 4;
+        test_hash_map_clone_func_max_enabled = true;
+        test_hash_map_clone_func_max_clones = 1;
+        CX_TEST_ASSERT(0 != cxMapListIntersection(dst, src, keys, test_hash_map_clone_func, NULL, &c));
+        test_hash_map_clone_func_max_enabled = false;
+        CX_TEST_ASSERT(cxMapSize(dst) == 1);
+        // the concrete element which is affected might change when the hash function changes
+        CX_TEST_ASSERT(*((int*)cxMapGet(dst, "k2")) == 7);
+        CX_TEST_ASSERT(cxMapGet(dst, "k4") == NULL);
+    }
+    cxMapFree(dst);
+    cxMapFree(src);
+    cxListFree(keys);
+}
+
+CX_TEST(test_hash_map_intersection_non_empty_target) {
+    CxMap *dst = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    cxDefineAdvancedDestructor(dst, cxFree, (void*) cxDefaultAllocator);
+
+    CxMap *s1 = cxHashMapCreateSimple(sizeof(int));
+    CxMap *s2 = cxHashMapCreateSimple(sizeof(int));
+    const char *s1_keys[] = {"k1", "k2", "k3", "k4"};
+    int s1_values[] = {1, 3, 4, 6};
+    const char *s2_keys[] = {"k4", "k5", "k2", "k6"};
+    int s2_values[] = {5, 9, 15, 23};
+    for (unsigned int i = 0 ; i < 4 ; i++) {
+        cxMapPut(s1, s1_keys[i], &s1_values[i]);
+        cxMapPut(s2, s2_keys[i], &s2_values[i]);
+    }
+
+    // add k7 to dst which is not in src, and also not in the difference
+    int *k7 = cxMallocDefault(sizeof(int));
+    *k7 = 1337;
+    cxMapPut(dst, "k7", k7);
+
+    CX_TEST_DO {
+        int c = 4;
+        CX_TEST_ASSERT(0 == cxMapIntersection(dst, s1, s2, test_hash_map_clone_func, NULL, &c));
+        CX_TEST_ASSERT(cxMapSize(dst) == 3);
+        CX_TEST_ASSERT(*((int*)cxMapGet(dst, "k2")) == 7);
+        CX_TEST_ASSERT(*((int*)cxMapGet(dst, "k4")) == 10);
+        CX_TEST_ASSERT(*(int*)cxMapGet(dst, "k7") == 1337);
+    }
+    cxMapFree(dst);
+    cxMapFree(s1);
+    cxMapFree(s2);
+}
+
+CX_TEST(test_hash_map_list_intersection_non_empty_target) {
+    CxMap *dst = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    cxDefineAdvancedDestructor(dst, cxFree, (void*) cxDefaultAllocator);
+    CxMap *src = cxHashMapCreateSimple(sizeof(int));
+    CxList *keys = cxArrayListCreate(NULL, cx_hash_key_cmp, sizeof(CxHashKey), 4);
+
+    const char *src_keys[] = {"k1", "k2", "k3", "k4"};
+    int src_values[] = {1, 3, 4, 6};
+    for (unsigned int i = 0 ; i < 4 ; i++) {
+        cxMapPut(src, src_keys[i], &src_values[i]);
+    }
+    const char *k[] = {"k4", "k5", "k2", "k6"};
+    for (unsigned int i = 0 ; i < 4 ; i++) {
+        CxHashKey key = CX_HASH_KEY(k[i]);
+        cxListAdd(keys, &key);
+    }
+
+    // add k7 to dst which is not in src, and also not in the difference
+    int *k7 = cxMallocDefault(sizeof(int));
+    *k7 = 1337;
+    cxMapPut(dst, "k7", k7);
+
+    CX_TEST_DO {
+        int c = 4;
+        CX_TEST_ASSERT(0 == cxMapListIntersection(dst, src, keys, test_hash_map_clone_func, NULL, &c));
+        CX_TEST_ASSERT(cxMapSize(dst) == 3);
+        CX_TEST_ASSERT(*((int*)cxMapGet(dst, "k2")) == 7);
+        CX_TEST_ASSERT(*((int*)cxMapGet(dst, "k4")) == 10);
+        CX_TEST_ASSERT(*(int*)cxMapGet(dst, "k7") == 1337);
+    }
+
+    cxMapFree(dst);
+    cxMapFree(src);
+    cxListFree(keys);
+}
+
+CX_TEST(test_hash_map_intersection_ptr) {
+    CxTestingAllocator talloc;
+    cx_testing_allocator_init(&talloc);
+    CxAllocator *allocator = &talloc.base;
+    CxMap *dst = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    cxDefineAdvancedDestructor(dst, cxFree, allocator);
+
+    CxMap *s1 = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    CxMap *s2 = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    const char *s1_keys[] = {"k1", "k2", "k3", "k4"};
+    int s1_values[] = {1, 3, 4, 6};
+    const char *s2_keys[] = {"k4", "k5", "k2", "k6"};
+    int s2_values[] = {5, 9, 15, 23};
+    for (unsigned int i = 0 ; i < 4 ; i++) {
+        cxMapPut(s1, s1_keys[i], &s1_values[i]);
+        cxMapPut(s2, s2_keys[i], &s2_values[i]);
+    }
+    CX_TEST_DO {
+        int c = 4;
+        CX_TEST_ASSERT(0 == cxMapIntersection(dst, s1, s2, test_hash_map_clone_func, allocator, &c));
+        CX_TEST_ASSERT(cxMapSize(dst) == 2);
+        CX_TEST_ASSERT(*((int*)cxMapGet(dst, "k2")) == 7);
+        CX_TEST_ASSERT(*((int*)cxMapGet(dst, "k4")) == 10);
+        CX_TEST_ASSERT(cx_testing_allocator_used(&talloc));
+    }
+    cxMapFree(dst);
+    cxMapFree(s1);
+    cxMapFree(s2);
+    cx_testing_allocator_destroy(&talloc);
+}
+
 CX_TEST(test_empty_map_size) {
     CX_TEST_DO {
         CX_TEST_ASSERT(cxEmptyMap->collection.size == 0);
@@ -1207,6 +1418,13 @@
     cx_test_register(suite, test_hash_map_list_difference_alloc_fail);
     cx_test_register(suite, test_hash_map_difference_non_empty_target);
     cx_test_register(suite, test_hash_map_list_difference_non_empty_target);
+    cx_test_register(suite, test_hash_map_intersection);
+    cx_test_register(suite, test_hash_map_intersection_ptr);
+    cx_test_register(suite, test_hash_map_list_intersection);
+    cx_test_register(suite, test_hash_map_intersection_alloc_fail);
+    cx_test_register(suite, test_hash_map_list_intersection_alloc_fail);
+    cx_test_register(suite, test_hash_map_intersection_non_empty_target);
+    cx_test_register(suite, test_hash_map_list_intersection_non_empty_target);
     cx_test_register(suite, test_empty_map_no_ops);
     cx_test_register(suite, test_empty_map_size);
     cx_test_register(suite, test_empty_map_get);

mercurial