重构
This commit is contained in:
+75
-109
@@ -1,118 +1,84 @@
|
||||
#include "c_LinkStack.h"
|
||||
#include "c_Test.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
typedef struct {
|
||||
char name[16];
|
||||
int id;
|
||||
} Frame_t;
|
||||
int thread_id;
|
||||
uint32_t pc_register;
|
||||
} ThreadContext_t;
|
||||
|
||||
void test_log(const char* test_name) {
|
||||
printf("[PASS] %s\n", test_name);
|
||||
TEST_CASE(test_link_stack_closure_and_lifo_flow) {
|
||||
c_LinkStack_t stack;
|
||||
|
||||
// 初始化一个专门存放 ThreadContext_t 结构的泛型单向链式栈
|
||||
ASSERT_INT_EQ(C_ERR_OK, c_LinkStack_Init(&stack, sizeof(ThreadContext_t), NULL));
|
||||
ASSERT_TRUE(c_LinkStack_IsEmpty(&stack));
|
||||
ASSERT_TRUE(stack.top == NULL);
|
||||
|
||||
ThreadContext_t ctx1 = { .thread_id = 10, .pc_register = 0x00A0 };
|
||||
ThreadContext_t ctx2 = { .thread_id = 20, .pc_register = 0x00B0 };
|
||||
ThreadContext_t ctx3 = { .thread_id = 30, .pc_register = 0x00C0 };
|
||||
|
||||
// 1. 验证入栈操作 (Push) 与 LIFO 排列
|
||||
ASSERT_INT_EQ(C_ERR_OK, c_LinkStack_Push(&stack, &ctx1)); // 第一次插入:top -> ctx1
|
||||
ASSERT_PTR_NOT_NULL(stack.top);
|
||||
ASSERT_TRUE(stack.top->next == NULL);
|
||||
|
||||
ASSERT_INT_EQ(C_ERR_OK, c_LinkStack_Push(&stack, &ctx2)); // 此时排列:top -> ctx2 -> ctx1
|
||||
ASSERT_INT_EQ(C_ERR_OK, c_LinkStack_Push(&stack, &ctx3)); // 此时排列:top -> ctx3 -> ctx2 -> ctx1
|
||||
|
||||
ASSERT_INT_EQ(3, c_LinkStack_Size(&stack));
|
||||
|
||||
// 强隔离隔离性检查:修改外部临时变量,内部数据必须牢不可破
|
||||
ctx3.thread_id = 999;
|
||||
|
||||
// 2. 验证 Peek 窥探能力
|
||||
ThreadContext_t* peeked = (ThreadContext_t*)c_LinkStack_Peek(&stack);
|
||||
ASSERT_PTR_NOT_NULL(peeked);
|
||||
ASSERT_INT_EQ(30, peeked->thread_id); // 应该依旧是原值 30,证明深度值复制有效
|
||||
|
||||
// 3. 【严苛验证变长内存布局的拓扑对齐情况】
|
||||
// 根据变长公式寻址:STACK_NODE_DATA(node) 必须与抛出的数据指针完全吻合
|
||||
ASSERT_TRUE(c_LinkStackNode_Get(stack.top) == peeked);
|
||||
|
||||
// 验证更深一层的 LIFO 相对位置节点:
|
||||
// top 的下一个应当是 ctx2 对应的控制头,提取其内部用户数据区地址
|
||||
ThreadContext_t* second_data = (ThreadContext_t*)c_LinkStackNode_Get(stack.top->next);
|
||||
ASSERT_INT_EQ(20, second_data->thread_id);
|
||||
|
||||
// 4. 出栈顺序与后进先出(LIFO)及边界复位断言 (Pop)
|
||||
ThreadContext_t out_res;
|
||||
|
||||
// 弹出第 1 个:应当是最后进来的 ctx3
|
||||
ASSERT_INT_EQ(C_ERR_OK, c_LinkStack_Pop(&stack, &out_res));
|
||||
ASSERT_INT_EQ(30, out_res.thread_id);
|
||||
ASSERT_INT_EQ(0, c_LinkStack_IsEmpty(&stack));
|
||||
|
||||
// 弹出第 2 个:应当是 ctx2
|
||||
ASSERT_INT_EQ(C_ERR_OK, c_LinkStack_Pop(&stack, &out_res));
|
||||
ASSERT_INT_EQ(20, out_res.thread_id);
|
||||
|
||||
// 弹出第 3 个:应当是最早进来的 ctx1
|
||||
ASSERT_INT_EQ(C_ERR_OK, c_LinkStack_Pop(&stack, &out_res));
|
||||
ASSERT_INT_EQ(10, out_res.thread_id);
|
||||
|
||||
// 终极下溢与纯净复位检查
|
||||
ASSERT_TRUE(c_LinkStack_IsEmpty(&stack));
|
||||
ASSERT_TRUE(stack.top == NULL);
|
||||
ASSERT_INT_EQ(0, c_LinkStack_Size(&stack));
|
||||
|
||||
// 防御重复下溢出栈,应当优雅报错
|
||||
ASSERT_INT_EQ(C_ERR_OUTOFBOUND, c_LinkStack_Pop(&stack, &out_res));
|
||||
ASSERT_TRUE(c_LinkStack_Peek(&stack) == NULL);
|
||||
|
||||
c_LinkStack_Destroy(&stack);
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("==================================================\n");
|
||||
printf(" 開始執行 c_LinkStack 完整單元測試用例\n");
|
||||
printf("==================================================\n\n");
|
||||
|
||||
// ==========================================
|
||||
// 1. 初始化測試
|
||||
// ==========================================
|
||||
c_LinkStack_t s;
|
||||
c_err_t err = c_LinkStack_Init(&s, sizeof(Frame_t));
|
||||
assert(err == C_ERR_OK);
|
||||
assert(s.size == 0);
|
||||
assert(s.head == NULL);
|
||||
test_log("1. 鏈結堆疊初始化狀態驗證成功");
|
||||
|
||||
// ==========================================
|
||||
// 2. 資料推入測試 (Push)
|
||||
// ==========================================
|
||||
Frame_t f1 = {"MainFrame", 100};
|
||||
Frame_t f2 = {"RenderFrame", 200};
|
||||
Frame_t f3 = {"UpdateFrame", 300};
|
||||
|
||||
// 依序推入,預期最新推入的會待在鏈結最前端 (head)
|
||||
err = c_LinkStack_Push(&s, &f1); assert(err == C_ERR_OK);
|
||||
err = c_LinkStack_Push(&s, &f2); assert(err == C_ERR_OK);
|
||||
err = c_LinkStack_Push(&s, &f3); assert(err == C_ERR_OK);
|
||||
assert(s.size == 3);
|
||||
test_log("2. 三筆資料成功推入堆疊 (頭插法 O(1))");
|
||||
|
||||
// ==========================================
|
||||
// 3. 迭代器走訪測試 (應符合後進先出順序:f3 -> f2 -> f1)
|
||||
// ==========================================
|
||||
c_LinkStackIter_t iter;
|
||||
c_LinkStackIter_Init(&iter, &s);
|
||||
int check_idx = 0;
|
||||
while (c_LinkStackIter_HasNext(&iter)) {
|
||||
Frame_t* f = (Frame_t*)c_LinkStackIter_Next(&iter);
|
||||
if (check_idx == 0) assert(strcmp(f->name, "UpdateFrame") == 0);
|
||||
if (check_idx == 1) assert(strcmp(f->name, "RenderFrame") == 0);
|
||||
if (check_idx == 2) assert(strcmp(f->name, "MainFrame") == 0);
|
||||
check_idx++;
|
||||
}
|
||||
assert(check_idx == 3);
|
||||
test_log("3. 迭代器走訪順序驗證成功 (符合 LIFO 頂端到探底順序)");
|
||||
|
||||
// ==========================================
|
||||
// 4. 查看堆疊頂端 (Peek)
|
||||
// ==========================================
|
||||
// 目前最頂端應該依然是最後推進去的 UpdateFrame
|
||||
Frame_t* p_peek = (Frame_t*)c_LinkStack_Peek(&s);
|
||||
assert(p_peek != NULL);
|
||||
assert(strcmp(p_peek->name, "UpdateFrame") == 0);
|
||||
assert(p_peek->id == 300);
|
||||
assert(s.size == 3); // 驗證 Peek 不會移除元素
|
||||
test_log("4. 唯讀查看堆疊頂端元素 (Peek) 成功");
|
||||
|
||||
// ==========================================
|
||||
// 5. 先進後出彈出測試 (Pop)
|
||||
// ==========================================
|
||||
Frame_t local_buf;
|
||||
|
||||
// 第一次 Pop:預期取出最上方的 UpdateFrame
|
||||
err = c_LinkStack_Pop(&s, &local_buf);
|
||||
assert(err == C_ERR_OK);
|
||||
assert(strcmp(local_buf.name, "UpdateFrame") == 0);
|
||||
assert(s.size == 2);
|
||||
|
||||
// 再次 Peek,頂端應更新為 RenderFrame
|
||||
p_peek = (Frame_t*)c_LinkStack_Peek(&s);
|
||||
assert(strcmp(p_peek->name, "RenderFrame") == 0);
|
||||
|
||||
// 連續彈出剩下的兩個元素
|
||||
err = c_LinkStack_Pop(&s, &local_buf); assert(err == C_ERR_OK); // 取出 RenderFrame
|
||||
err = c_LinkStack_Pop(&s, &local_buf); assert(err == C_ERR_OK); // 取出 MainFrame
|
||||
assert(s.size == 0);
|
||||
assert(s.head == NULL);
|
||||
|
||||
// 空堆疊彈出與查看測試,預期回傳越界錯誤
|
||||
err = c_LinkStack_Pop(&s, &local_buf);
|
||||
assert(err == C_ERR_EMPTY);
|
||||
assert(c_LinkStack_Peek(&s) == NULL);
|
||||
test_log("5. 後進先出彈出 (Pop) 邏輯與空防呆驗證成功");
|
||||
|
||||
// ==========================================
|
||||
// 6. 介面安全指標檢查
|
||||
// ==========================================
|
||||
assert(c_LinkStack_Init(NULL, sizeof(Frame_t)) == C_ERR_PARAM);
|
||||
assert(c_LinkStack_Push(NULL, &f1) == C_ERR_PARAM);
|
||||
assert(c_LinkStack_Pop(&s, NULL) == C_ERR_PARAM);
|
||||
test_log("6. 介面 NULL 指標防呆驗證成功");
|
||||
|
||||
// ==========================================
|
||||
// 7. 銷毀堆疊 (Destroy)
|
||||
// ==========================================
|
||||
c_LinkStack_Destroy(&s);
|
||||
assert(s.head == NULL);
|
||||
assert(s.size == 0);
|
||||
test_log("7. 堆疊資源銷毀與記憶體釋放成功");
|
||||
|
||||
printf("\n==================================================\n");
|
||||
printf(" 恭喜!c_LinkStack 優化版單元測試全數順利通過!\n");
|
||||
printf("==================================================\n");
|
||||
return 0;
|
||||
int main(void) {
|
||||
printf("\n");
|
||||
TEST_START(C_LinkStack_Generic_Layout_Tests);
|
||||
RUN_TEST(test_link_stack_closure_and_lifo_flow);
|
||||
TEST_REPORT();
|
||||
RETURN_TEST_STATUS;
|
||||
}
|
||||
Reference in New Issue
Block a user