127 lines
5.8 KiB
C
127 lines
5.8 KiB
C
#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;
|
|||
|
|
}
|