Files

133 lines
4.1 KiB
C
Raw Permalink Normal View History

2026-08-10 01:21:15 +08:00
#include "c_Arena.h"
#include <stdlib.h>
#include <stdio.h>
#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;
}