#include "c_HashST.h" #include "c_Test.h" #include #include // ========================================== // 1. 测试框架配套:虚操作函数模拟实现 // ========================================== // --- Key 虚操作实现:以动态独立分配内存、长度未知的“深层堆字符串指针 (char**)”作为键 --- static uint32_t test_key_string_hash(const void* data, void* arg) { (void)arg; const char* str = *(const char* const*)data; uint32_t hash = 0; while (*str) { hash = 31 * hash + (unsigned char)(*str); str++; } return hash; } static void* test_key_string_cp(const void* data, void* arg) { (void)arg; const char* original = *(const char* const*)data; char* clone = (char*)malloc(strlen(original) + 1); if (clone) strcpy(clone, original); char** storage = (char**)malloc(sizeof(char*)); if (storage) *storage = clone; return (void*)storage; } static void test_key_string_free(void* data, void* arg) { (void)arg; if (data) { char** storage = (char**)data; free(*storage); free(storage); } } static bool test_key_string_eq(const void* data1, const void* data2, void* arg) { (void)arg; const char* s1 = *(const char* const*)data1; const char* s2 = *(const char* const*)data2; return strcmp(s1, s2) == 0; } // --- Value 虚操作实现:以动态独立分配内存的“结构体对象指针 (Task_t**)”作为值 --- typedef struct { int id; int payload; } TestTask_t; static void* test_val_task_cp(const void* data, void* arg) { (void)arg; const TestTask_t* original = *(const TestTask_t* const*)data; TestTask_t* clone = (TestTask_t*)malloc(sizeof(TestTask_t)); if (clone) { clone->id = original->id; clone->payload = original->payload; } TestTask_t** storage = (TestTask_t**)malloc(sizeof(TestTask_t*)); if (storage) *storage = clone; return (void*)storage; } static void test_val_task_free(void* data, void* arg) { (void)arg; if (data) { TestTask_t** storage = (TestTask_t**)data; free(*storage); free(storage); } } static bool test_val_task_eq(const void* data1, const void* data2, void* arg) { (void)arg; const TestTask_t* t1 = *(const TestTask_t* const*)data1; const TestTask_t* t2 = *(const TestTask_t* const*)data2; return (t1->id == t2->id && t1->payload == t2->payload); } // ========================================== // 2. 自动化单元测试集 // ========================================== TEST_CASE(test_c_HashST_Base_CRUD_Flow) { c_HashST_t map; // 1. 初始化多态虚操作集(Key 采用堆字符串,Value 采用堆任务结构体) c_HashKeyOps_t key_ops = { test_key_string_hash, test_key_string_cp, test_key_string_free, test_key_string_eq, NULL }; c_HashValOps_t val_ops = { test_val_task_cp, test_val_task_free, test_val_task_eq, NULL }; // 2. 初始化初始容量为 4 的哈希符号表 c_err_t err = c_HashST_Init(&map, 4, key_ops, val_ops, &c_DefaultAllocator); ASSERT_INT_EQ(C_ERR_OK, err); // 声明待插入的临时浅数据线 const char* k1 = "Task_Alpha"; TestTask_t t1_raw = { 101, 555 }; const TestTask_t* v1 = &t1_raw; const char* k2 = "Task_Beta"; TestTask_t t2_raw = { 102, 666 }; const TestTask_t* v2 = &t2_raw; const char* k3 = "Task_Gamma"; TestTask_t t3_raw = { 103, 777 }; const TestTask_t* v3 = &t3_raw; // 3. Put 添加行为断言 ASSERT_INT_EQ(C_ERR_OK, c_HashST_Put(&map, &k1, &v1)); ASSERT_INT_EQ(C_ERR_OK, c_HashST_Put(&map, &k2, &v2)); ASSERT_INT_EQ(C_ERR_OK, c_HashST_Put(&map, &k3, &v3)); ASSERT_INT_EQ(3, (int)map.size); // 4. Contains 包含性状态断言(使用物理地址不同的副本 Key 进行全等检索) const char* search_k1 = "Task_Alpha"; const char* search_fake = "Task_Unknown"; ASSERT_TRUE(c_HashST_Contains(&map, &search_k1)); ASSERT_TRUE(!c_HashST_Contains(&map, &search_fake)); // 5. Get 数据读取与物理结构体字段穿透比对 void* get_res_ptr = c_HashST_Get(&map, &search_k1); ASSERT_TRUE(get_res_ptr != NULL); // 穿透二级指针,精确检验深拷贝出来的值的成员变量 TestTask_t* matched_task = *(TestTask_t**)get_res_ptr; ASSERT_INT_EQ(101, matched_task->id); ASSERT_INT_EQ(555, matched_task->payload); // 6. Put 相同键下的覆写更新(Overwrite)语义核验 TestTask_t t1_update_raw = { 101, 9999 }; const TestTask_t* v1_update = &t1_update_raw; ASSERT_INT_EQ(C_ERR_OK, c_HashST_Put(&map, &k1, &v1_update)); ASSERT_INT_EQ(3, (int)map.size); // 覆写后,全局哈希大小必须守恒 get_res_ptr = c_HashST_Get(&map, &search_k1); ASSERT_TRUE(get_res_ptr != NULL); ASSERT_INT_EQ(9999, (*(TestTask_t**)get_res_ptr)->payload); // 配额必须已被更新覆盖 // 7. Remove 单路摘除断言 ASSERT_INT_EQ(C_ERR_OK, c_HashST_Remove(&map, &search_k1)); ASSERT_INT_EQ(2, (int)map.size); // 递减正确 ASSERT_TRUE(c_HashST_Get(&map, &search_k1) == NULL); // 再拿应该彻底变空 // 8. 全清理注销销毁线,多态自由解构,阻断任何残留 c_HashST_Destroy(&map); } TEST_CASE(test_c_HashST_Resize_And_Collision) { c_HashST_t map; c_HashKeyOps_t key_ops = { test_key_string_hash, test_key_string_cp, test_key_string_free, test_key_string_eq, NULL }; c_HashValOps_t val_ops = { test_val_task_cp, test_val_task_free, test_val_task_eq, NULL }; // 1. 初始化一个极小容量的哈希表(故意设为 1,强迫后面插入的所有节点落入同一个桶中,构成 100% 碰撞拉链链条) c_err_t err = c_HashST_Init(&map, 1, key_ops, val_ops, &c_DefaultAllocator); ASSERT_INT_EQ(C_ERR_OK, err); const char* k1 = "Key_Coll_1"; TestTask_t t1 = { 1, 10 }; const TestTask_t* v1 = &t1; const char* k2 = "Key_Coll_2"; TestTask_t t2 = { 2, 20 }; const TestTask_t* v2 = &t2; const char* k3 = "Key_Coll_3"; TestTask_t t3 = { 3, 30 }; const TestTask_t* v3 = &t3; ASSERT_INT_EQ(C_ERR_OK, c_HashST_Put(&map, &k1, &v1)); ASSERT_INT_EQ(C_ERR_OK, c_HashST_Put(&map, &k2, &v2)); ASSERT_INT_EQ(C_ERR_OK, c_HashST_Put(&map, &k3, &v3)); // 2. NumCol 碰撞指标验证:在容量为 1 且塞入 3 个数据时,产生的物理碰撞线数必然为 2 次 ASSERT_INT_EQ(2, (int)c_HashST_NumCol(&map)); // 3. 核心压测:触发大跨度扩容变轨(容量从 1 直接倍增重塑至 16) // 扩容后,原先挤在 0 号桶拉链中的 3 个冲突节点必须被重新洗牌、散列分流到各个新桶中 ASSERT_INT_EQ(C_ERR_OK, c_HashST_Resize(&map, 16)); ASSERT_INT_EQ(16, (int)map.capacity); ASSERT_INT_EQ(3, (int)map.size); // 全局大小守恒不变 // 4. 扩容分流后的碰撞指标必须自适应下降(通常随机散列到 16 个桶中后,碰撞数会锐减为 0) ASSERT_TRUE(c_HashST_NumCol(&map) < 2); // 5. 扩容变轨后,再次使用 Get 穿透读取,验证多态路由未丢失 const char* search_k3 = "Key_Coll_3"; void* get_res_ptr = c_HashST_Get(&map, &search_k3); ASSERT_TRUE(get_res_ptr != NULL); ASSERT_INT_EQ(30, (*(TestTask_t**)get_res_ptr)->payload); c_HashST_Destroy(&map); } TEST_CASE(test_c_HashST_Empty_And_Toxicity_Defenses) { c_HashST_t map; c_HashKeyOps_t key_ops = { test_key_string_hash, test_key_string_cp, test_key_string_free, test_key_string_eq, NULL }; c_HashValOps_t val_ops = { test_val_task_cp, test_val_task_free, test_val_task_eq, NULL }; c_HashST_Init(&map, 4, key_ops, val_ops, NULL); // 降级测试 const char* k = "Toxic_Key"; // 1. 空仓返回与毒入参前置拦截防御 ASSERT_TRUE(c_HashST_Get(&map, &k) == NULL); ASSERT_TRUE(!c_HashST_Contains(&map, &k)); ASSERT_INT_EQ(C_ERR_NOTFOUND, c_HashST_Remove(&map, &k)); ASSERT_INT_EQ(0, (int)c_HashST_NumCol(&map)); ASSERT_INT_EQ(C_ERR_PARAM, c_HashST_Init(NULL, 4, key_ops, val_ops, NULL)); c_HashST_Destroy(&map); } // ========================================== // 3. 独立测试运行入口 // ========================================== int main(void) { TEST_START(C_HashST_PolymorphicObject_TestSuite); // 顺序调度高级多态哈希表的各项极限业务场景 RUN_TEST(test_c_HashST_Base_CRUD_Flow); RUN_TEST(test_c_HashST_Resize_And_Collision); RUN_TEST(test_c_HashST_Empty_And_Toxicity_Defenses); TEST_REPORT(); RETURN_TEST_STATUS; }