#include "c_SmartPtrVector.h" #include "c_Test.h" // 模擬業務層的實體資源 typedef struct { int resource_id; int payload; } TestObject_t; static int g_resource_destroy_count = 0; // 全局計數器:監控實體被真正 free 的次數 // 匹配你定義的 c_SmartPtrFreeFn_t 簽名 static void test_resource_free(void* ptr, void* args) { if (ptr) { TestObject_t* obj = (TestObject_t*)ptr; int custom_flag = *(int*)args; printf("[FreeFn Triggered] Object ID: %d, Args Flag: %d\n", obj->resource_id, custom_flag); free(obj); // 釋放真實業務對象 g_resource_destroy_count++; // 被物理火化銷毀次數遞增 } } // 模擬分配器的樁實現(用於驅動 Vector 的內置多態分配鏈) static size_t g_tracker_active_allocs = 0; static void* mock_vector_alloc(size_t size, void* ctx) { (void)ctx; g_tracker_active_allocs++; return malloc(size); } static void mock_vector_free(void* ptr, void* ctx) { (void)ctx; if (ptr) g_tracker_active_allocs--; free(ptr); } TEST_CASE(test_real_smart_ptr_vector_atomic_closure) { g_resource_destroy_count = 0; g_tracker_active_allocs = 0; // 1. 初始化多態記憶體管理器底座 c_Allocator_t pool_allocator = { .alloc = mock_vector_alloc, .realloc = NULL, .free = mock_vector_free, .dtor = NULL, .ud = NULL }; c_SmartPtrVector_t vector; // 初始化容量為 2 的向量,並綁定專屬分配器 ASSERT_INT_EQ(C_ERR_OK, c_SmartPtrVector_Init(&vector, 2, &pool_allocator)); ASSERT_INT_EQ(1, g_tracker_active_allocs); // 內置分配器成功申請了大底座 // 2. 建立一具真實的智慧指標(指向在堆上動態開闢的 TestObject_t) TestObject_t* raw_obj = (TestObject_t*)malloc(sizeof(TestObject_t)); raw_obj->resource_id = 8899; raw_obj->payload = 100; int free_args = 2026; // 自定義銷毀引數 // 使用你編寫的 c_SmartPtr_Make / Init 進行生命周期宣告 c_SmartPtr_t master_sptr = c_SmartPtr_Make(raw_obj, test_resource_free, &free_args); // 剛出生,使用計數必須精準等於 1 ASSERT_INT_EQ(1, c_SmartPtr_UseCount(&master_sptr)); // 3. 測試 PushBack 自動引用計數增長 // 將智慧指標塞入 Vector 槽位 0 中,內部呼叫 c_SmartPtr_Copy,計數應原子遞增至 2 ASSERT_INT_EQ(C_ERR_OK, c_SmartPtrVector_PushBack(&vector, &master_sptr)); ASSERT_INT_EQ(2, c_SmartPtr_UseCount(&master_sptr)); ASSERT_INT_EQ(2, c_SmartPtr_UseCount(c_SmartPtrVector_Get(&vector, 0))); // 4. 建立第二具獨立智慧指標,迫使 Vector 翻倍自動擴容(2 -> 4) TestObject_t* raw_obj2 = (TestObject_t*)malloc(sizeof(TestObject_t)); raw_obj2->resource_id = 1122; c_SmartPtr_t master_sptr2 = c_SmartPtr_Make(raw_obj2, test_resource_free, &free_args); c_SmartPtrVector_PushBack(&vector, &master_sptr2); // 槽位 1 // 核心觀察點:塞入第三個元素,強行觸展 EnsureCapacity 翻倍搬迁! // 搬遷時內部使用 c_SmartPtr_Move 做轉移,所有權安全平移,兩具老智慧指標的引用計數絕不應發生任何變化! ASSERT_INT_EQ(C_ERR_OK, c_SmartPtrVector_PushBack(&vector, &master_sptr2)); // 槽位 2 重複掛接 sptr2 ASSERT_INT_EQ(3, vector.size); ASSERT_INT_EQ(4, vector.capacity); ASSERT_INT_EQ(1, g_tracker_active_allocs); // 搬遷成功後,老緩衝區被內置分配器乾淨 Free 釋放 // 驗證搬遷後,sptr1 的計數依然穩健維持在 2,完全沒有受到內存重組的交叉干擾 ASSERT_INT_EQ(2, c_SmartPtr_UseCount(&master_sptr)); // 5. 測試中段任意位置定点裁剪(Remove 靜默抹殺) // 移除槽位 0 的 sptr1,這會扣減其引用計數(2 降到 1)。此時資源依然活在外部持有的 master_sptr 中 ASSERT_INT_EQ(C_ERR_OK, c_SmartPtrVector_Remove(&vector, 0)); ASSERT_INT_EQ(1, c_SmartPtr_UseCount(&master_sptr)); ASSERT_INT_EQ(0, g_resource_destroy_count); // 資源依然安全存活,尚未觸發真正的物理 free_fn // 6. 測試 RemoveAndTake 控制權完全接管倒騰 c_SmartPtr_t external_receiver = {0}; // 將槽位 0 (因前移,此時存放的是 sptr2 的重複項) 自主剝离倒騰給 external_receiver // 由於是 Move 倒騰,sptr2 的計數和所有權無痛轉交,完全符合直覺 ASSERT_INT_EQ(C_ERR_OK, c_SmartPtrVector_RemoveAndTake(&vector, 0, &external_receiver)); ASSERT_TRUE(external_receiver.ptr == raw_obj2); // 7. 外部主動銷毀釋放所有本地變數,將計數往物理火化終點推進 c_SmartPtr_Destroy(&external_receiver); c_SmartPtr_Destroy(&master_sptr2); // 8. 終極解體:摧毀 Vector c_SmartPtrVector_Destroy(&vector); // 槽位 0 之前剩下一具 sptr2。Vector 銷毀時會將其釋放,此時 raw_obj2 的引用計數徹底歸 0,自動觸發物理銷毀! ASSERT_INT_EQ(1, g_resource_destroy_count); // raw_obj2 已經在 Vector 解體時被閉環火化 // 9. 外部最後銷毀外部唯一的 master_sptr c_SmartPtr_Destroy(&master_sptr); // 引用計數歸 0,raw_obj1 自動物理火化! // 10. 終極一致性雙向審判断言: // 所有變數與容器全部解體後,兩具堆實體資源必須無一遺漏、百分之百被自動物理銷毀歸還! ASSERT_INT_EQ_MSG(2, g_resource_destroy_count, "CRITICAL: Smart Pointer Vector Caused Reference Counting Mismatch or Memory Leak!"); // 分配器活躍塊重歸於 0,物理堆記憶體 0 滯留 ASSERT_INT_EQ_MSG(0, g_tracker_active_allocs, "Vector internal allocator leaked heap space!"); } int main(void) { TEST_START(C_Real_SmartPtrVector_System_Tests); RUN_TEST(test_real_smart_ptr_vector_atomic_closure); TEST_REPORT(); RETURN_TEST_STATUS; }