Files
2026-08-10 01:21:15 +08:00

133 lines
4.1 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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;
}