#include #include #include "c_StringList.h" #include "c_Test.h" static size_t g_list_pool_active_chunks = 0; // 监控多态内存池中处于活跃分配态的物理块个数 // 模拟伙伴系统或 Arena 内存池的分配监控桩实现 static void* mock_list_pool_alloc(size_t size, void* ctx) { (void)ctx; g_list_pool_active_chunks++; return malloc(size); } static void mock_list_pool_free(void* ptr, void* ctx) { (void)ctx; if (ptr) g_list_pool_active_chunks--; free(ptr); } static void* mock_list_pool_realloc(void* ptr, size_t old_size, size_t new_size, void* ctx) { (void)ctx; (void)old_size; return realloc(ptr, new_size); } TEST_CASE(test_string_list_polymorphic_deep_copy_closure) { g_list_pool_active_chunks = 0; // 1. 原地构建自定义专属内存池分配器 c_Allocator_t my_pool = { .alloc = mock_list_pool_alloc, .realloc = mock_list_pool_realloc, .free = mock_list_pool_free, .dtor = NULL, .ud = NULL }; c_StringList list; // 初始化容量为 2 的特化字符串链表,并注入分配器 ASSERT_INT_EQ(C_ERR_OK, c_StringList_Init(&list, 2, &my_pool)); // 审计校准:此时内存池只分配了 1 个矩阵控制大底座,活跃物理块精确定格为 1 ASSERT_INT_EQ(1, (int)g_list_pool_active_chunks); ASSERT_INT_EQ(0, (int)c_StringList_Size(&list)); // 2. 验证元素填充、深度值复制、以及内部自适应动态翻倍扩容 char stack_buffer[] = "STACK_TXT_A"; // 分配在局部栈上的临时垃圾包 ASSERT_INT_EQ(C_ERR_OK, c_StringList_Add(&list, stack_buffer)); ASSERT_INT_EQ(C_ERR_OK, c_StringList_Add(&list, "STACK_TXT_B")); // 此时触发 2 -> 4 自动扩容:内部 realloc 成功原地续约底座,并塞入第三行 ASSERT_INT_EQ(C_ERR_OK, c_StringList_Add(&list, "STACK_TXT_A")); // 故意塞入重复项用于后续去重 ASSERT_INT_EQ(3, (int)c_StringList_Size(&list)); ASSERT_INT_EQ(4, (int)list.capacity); // 活跃物理块计算:1个指针矩阵大底座 + 3个行级独立分配的独占堆字符串 = 4 个活跃块 ASSERT_INT_EQ(4, (int)g_list_pool_active_chunks); // 3. 强隔离隔离性判定:故意洗刷外部栈变量,内部持有的内容必须坚若磐石 memset(stack_buffer, 'X', sizeof(stack_buffer)); ASSERT_TRUE(strcmp(c_StringList_Get(&list, 0), "STACK_TXT_A") == 0); // 必须依旧是原值,证明深度值复制成立 // 4. 验证中段定点随机插入(InsertAt)及相对物理寻址 ASSERT_INT_EQ(C_ERR_OK, c_StringList_InsertAt(&list, 1, "INSERTED_VAL")); ASSERT_INT_EQ(4, (int)c_StringList_Size(&list)); // 确认原本在索引 1 的项被 memmove 完美向右推挤到了索引 2 位置 ASSERT_TRUE(strcmp(c_StringList_Get(&list, 1), "INSERTED_VAL") == 0); ASSERT_TRUE(strcmp(c_StringList_Get(&list, 2), "STACK_TXT_B") == 0); ASSERT_INT_EQ(5, (int)g_list_pool_active_chunks); // 5. 验证中段定点删除(RemoveAt)与后续行指针平移重组 ASSERT_INT_EQ(C_ERR_OK, c_StringList_RemoveAt(&list, 1)); // 抹杀刚插入的项 ASSERT_INT_EQ(3, (int)c_StringList_Size(&list)); ASSERT_TRUE(strcmp(c_StringList_Get(&list, 1), "STACK_TXT_B") == 0); // 后面重新前滑补缺 ASSERT_INT_EQ(4, (int)g_list_pool_active_chunks); // 行物理壳资源被精准火化扣减 1 // 6. 验证高级全词原位去重机制 (Deduplicate) // 当前排列为: "STACK_TXT_A", "STACK_TXT_B", "STACK_TXT_A" ASSERT_INT_EQ(C_ERR_OK, c_StringList_Deduplicate(&list)); ASSERT_INT_EQ(2, (int)c_StringList_Size(&list)); // 末尾重复的 A 被定点剔除 ASSERT_TRUE(strcmp(c_StringList_Get(&list, 0), "STACK_TXT_A") == 0); ASSERT_TRUE(strcmp(c_StringList_Get(&list, 1), "STACK_TXT_B") == 0); ASSERT_INT_EQ(3, (int)g_list_pool_active_chunks); // 重复行的物理资源被内置分配器在底层连根拔起 // 7. 验证克隆体深拷贝承袭能力 (Clone) c_StringList clone_list; c_StringList_Init(&clone_list, 1, &my_pool); // 给个小容量 1 ASSERT_INT_EQ(C_ERR_OK, c_StringList_Clone(&clone_list, &list)); ASSERT_INT_EQ(2, (int)c_StringList_Size(&clone_list)); ASSERT_TRUE(strcmp(c_StringList_Get(&clone_list, 0), "STACK_TXT_A") == 0); // 8. 终极连环解体大清算 c_StringList_Destroy(&list); c_StringList_Destroy(&clone_list); // 终极双向一致性账目审判: // 当两个大容器彻底解体消亡后,无论是行级独立开辟的变长串,还是指针底座大矩阵,必须全数物理火化! // 挂载的多态池活跃计数量 g_list_pool_active_chunks 必须以极致优美的姿态完美重归于 0(0 空间泄漏,0 碎片滞留) ASSERT_INT_EQ_MSG(0, (int)g_list_pool_active_chunks, "CRITICAL: c_StringList leaked exclusive heap elements inside the polymorphic allocator pool!"); } int main(void) { printf("\n"); TEST_START(C_StringList_Polymorphic_DeepCopy_Tests); // 驱动高防御型特化字符串顺序表全功能单元测试验证 RUN_TEST(test_string_list_polymorphic_deep_copy_closure); TEST_REPORT(); RETURN_TEST_STATUS; }