Files

127 lines
5.8 KiB
C
Raw Permalink Normal View History

2026-08-30 02:51:25 +08:00
#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 進行生命周期宣告
2026-08-30 03:52:23 +08:00
c_SmartPtr_t master_sptr = c_SmartPtr_Make(raw_obj, test_resource_free, &free_args, 0);
2026-08-30 02:51:25 +08:00
// 剛出生,使用計數必須精準等於 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;
2026-08-30 03:52:23 +08:00
c_SmartPtr_t master_sptr2 = c_SmartPtr_Make(raw_obj2, test_resource_free, &free_args, 0);
2026-08-30 02:51:25 +08:00
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;
}