#include "c_Arena.h" #include #include #include "assert.h" static void test_arena_basic_alloc() { printf("[測試] 基礎分配...\n"); uint8_t backing_buffer[1024]; c_Arena_t arena; // 初始化 c_Arena_Init(&arena, backing_buffer, sizeof(backing_buffer)); assert(arena.buf == backing_buffer); assert(arena.buf_len == 1024); assert(arena.curr_offset == 0); // 第一次分配 void* p1 = c_Arena_Alloc(&arena, 100); assert(p1 != NULL); assert(arena.curr_offset >= 100); // 考慮到對齊,可能大於等於 100 // 第二次分配 void* p2 = c_Arena_Alloc(&arena, 200); assert(p2 != NULL); assert(p2 > p1); // 記憶體地址應是連續向後的 printf(" => 基礎分配測試成功\n"); } // ========================================== // 測試用例 2:記憶體溢出(Out of Memory) // ========================================== static void test_arena_oom() { printf("[測試] 記憶體溢出邊界...\n"); uint8_t backing_buffer[256]; c_Arena_t arena; c_Arena_Init(&arena, backing_buffer, sizeof(backing_buffer)); // 嘗試分配超出整塊 Arena 大小的記憶體 void* p1 = c_Arena_Alloc(&arena, 300); assert(p1 == NULL); // 應返回 NULL // 分配剛好極限的記憶體 void* p2 = c_Arena_Alloc(&arena, 256); assert(p2 != NULL); // 已經滿了,再次分配應失敗 void* p3 = c_Arena_Alloc(&arena, 1); assert(p3 == NULL); printf(" => OOM 邊界測試成功\n"); } // ========================================== // 測試用例 3:Resize 原地擴展(最速路徑) // ========================================== // 說明:若舊記憶體剛好是最後一次分配的區塊(curr_offset 緊鄰它), // Arena 應該直接移動 curr_offset 實現原地擴展,而不需搬移資料。 static void test_arena_resize_inplace() { printf("[測試] Resize 原地擴展(最後一個分配物)...\n"); uint8_t backing_buffer[1024]; c_Arena_t arena; c_Arena_Init(&arena, backing_buffer, sizeof(backing_buffer)); // 分配 p1,並寫入測試資料 char* p1 = (char*)c_Arena_Alloc(&arena, 10); strcpy(p1, "Hello"); c_size_t offset_before_resize = arena.curr_offset; // 將 p1 擴大到 50 字節 char* p1_new = (char*)c_Arena_Resize(&arena, p1, 10, 50); // 驗證:因為 p1 是最後分配的,它的地址不應該改變(原地擴展) assert(p1_new == p1); assert(strcmp(p1_new, "Hello") == 0); // 資料必須完整保留 assert(arena.curr_offset > offset_before_resize); // 偏移量正確推移 printf(" => Resize 原地擴展測試成功\n"); } // ========================================== // 測試用例 4:Resize 重新分配(非最後分配物) // ========================================== // 說明:若舊記憶體後面已經有其他分配物(p1 後面有 p2), // 此時對 p1 做 Resize 必須當作全新分配,並拷貝舊資料。 static void test_arena_resize_realloc() { printf("[測試] Resize 重新分配(中間的分配物)...\n"); uint8_t backing_buffer[1024]; c_Arena_t arena; c_Arena_Init(&arena, backing_buffer, sizeof(backing_buffer)); // 連續分配 p1 與 p2 char* p1 = (char*)c_Arena_Alloc(&arena, 16); strcpy(p1, "Data1"); char* p2 = (char*)c_Arena_Alloc(&arena, 16); strcpy(p2, "Data2"); // 對 p1(此時不是最後一個分配物)進行 Resize char* p1_new = (char*)c_Arena_Resize(&arena, p1, 16, 32); // 驗證: assert(p1_new != NULL); assert(p1_new != p1); // 必須分配在 p2 之後的新位置 assert(p1_new > p2); // 確保在新地址 assert(strcmp(p1_new, "Data1") == 0); // 舊資料必須被 memcpy 過去 assert(strcmp(p2, "Data2") == 0); // 隔壁的 p2 資料不能被破壞 printf(" => Resize 重新分配測試成功\n"); } int main(int argc, char** argv){ printf("--- Test Begin ---\n"); test_arena_basic_alloc(); test_arena_oom(); test_arena_resize_inplace(); test_arena_resize_realloc(); printf("--- Test End! ---\n"); return 0; }