#include "c_LinkQueue.h" #include #include #include typedef struct { char text[16]; int id; } Message_t; void test_log(const char* test_name) { printf("[PASS] %s\n", test_name); } typedef struct { char* data_str; int id; } DataPacket_t; static void test_iter(void) { printf("==================================================\n"); printf(" 開始執行 c_LinkQueueIter_Remove 單元測試\n"); printf("==================================================\n\n"); c_LinkQueue_t queue; c_LinkQueue_Init(&queue, sizeof(DataPacket_t)); DataPacket_t p1 = {"PacketA", 101}; DataPacket_t p2 = {"PacketB", 102}; DataPacket_t p3 = {"PacketC", 103}; // 推入三筆資料 (FIFO 順序: head -> p1 -> p2 -> p3 <- tail) c_LinkQueue_Push(&queue, &p1); c_LinkQueue_Push(&queue, &p2); c_LinkQueue_Push(&queue, &p3); assert(queue.size == 3); assert(((DataPacket_t*)queue.tail->data)->id == 103); // 確任目前尾端是 p3 c_LinkQueueIter_t iter; // ========================================== // 測試 1:刪除中間節點 (p2: 102) // ========================================== c_LinkQueueIter_Init(&iter, &queue); while (c_LinkQueueIter_HasNext(&iter)) { DataPacket_t* pkt = (DataPacket_t*)c_LinkQueueIter_Get(&iter); if (pkt->id == 102) { c_LinkQueueIter_Remove(&iter); // 刪除 PacketB printf("[PASS] 成功刪除中間節點 (102)\n"); } else { c_LinkQueueIter_Next(&iter); } } assert(queue.size == 2); assert(((DataPacket_t*)queue.tail->data)->id == 103); // 尾端應維持 103 // ========================================== // 測試 2:刪除尾端節點 (p3: 103) -> 測試 tail 更新 // ========================================== c_LinkQueueIter_Init(&iter, &queue); while (c_LinkQueueIter_HasNext(&iter)) { DataPacket_t* pkt = (DataPacket_t*)c_LinkQueueIter_Get(&iter); if (pkt->id == 103) { c_LinkQueueIter_Remove(&iter); // 刪除 PacketC (當前的尾端) printf("[PASS] 成功刪除尾端節點 (103)\n"); } else { c_LinkQueueIter_Next(&iter); } } assert(queue.size == 1); // 關鍵斷言:刪除原本的尾端 103 後,queue->tail 必須自動往前更新為 101 (PacketA) assert(queue.tail != NULL); assert(((DataPacket_t*)queue.tail->data)->id == 101); assert(queue.head == queue.tail); // 只剩一個元素時,head 應等於 tail // ========================================== // 3. 測試 3:刪除最後一個節點 (p1: 101) -> 測試佇列歸零 // ========================================== c_LinkQueueIter_Init(&iter, &queue); assert(c_LinkQueueIter_HasNext(&iter) == C_TRUE); c_LinkQueueIter_Remove(&iter); // 刪除僅存的 PacketA printf("[PASS] 成功刪除最後一個節點 (101)\n"); assert(queue.size == 0); assert(queue.head == NULL); assert(queue.tail == NULL); // 關鍵斷言:完全空了之後 tail 必須回歸 NULL assert(c_LinkQueueIter_HasNext(&iter) == C_FALSE); // 清理資源 c_LinkQueue_Destroy(&queue); printf("\n==================================================\n"); printf(" 恭喜!c_LinkQueueIter_Remove 所有特例驗證全數通過!\n"); printf("==================================================\n"); } int main() { printf("==================================================\n"); printf(" 開始執行 c_LinkQueue 完整版測試用例\n"); printf("==================================================\n\n"); // ========================================== // 1. 測試初始化 // ========================================== c_LinkQueue_t q; c_err_t err = c_LinkQueue_Init(&q, sizeof(Message_t)); assert(err == C_ERR_OK); assert(q.size == 0); assert(q.head == NULL); test_log("1. 鏈結佇列初始化成功"); // ========================================== // 2. 測試資料推入 (Push) // ========================================== Message_t msg1 = {"MsgA", 101}; Message_t msg2 = {"MsgB", 102}; Message_t msg3 = {"MsgC", 103}; err = c_LinkQueue_Push(&q, &msg1); assert(err == C_ERR_OK); err = c_LinkQueue_Push(&q, &msg2); assert(err == C_ERR_OK); err = q.size == 2; err = c_LinkQueue_Push(&q, &msg3); assert(err == C_ERR_OK); assert(q.size == 3); test_log("2. 三筆資料成功推入佇列 (尾端追加)"); // ========================================== // 3. 測試迭代器走訪 (應符合 Push 的先進順序:A -> B -> C) // ========================================== c_LinkQueueIter_t iter; c_LinkQueueIter_Init(&iter, &q); int check_idx = 0; while (c_LinkQueueIter_HasNext(&iter)) { Message_t* m = (Message_t*)c_LinkQueueIter_Next(&iter); if (check_idx == 0) assert(strcmp(m->text, "MsgA") == 0); if (check_idx == 1) assert(strcmp(m->text, "MsgB") == 0); if (check_idx == 2) assert(strcmp(m->text, "MsgC") == 0); check_idx++; } assert(check_idx == 3); test_log("3. 迭代器順序走訪驗證成功 (符合 FIFO 順序)"); // ========================================== // 4. 測試查看最前端元素 (Peek) // ========================================== Message_t local_buf; err = c_LinkQueue_Peek(&q, &local_buf); assert(err == C_ERR_OK); assert(strcmp(local_buf.text, "MsgA") == 0); assert(local_buf.id == 101); assert(q.size == 3); // 驗證 Peek 不會減少佇列大小 test_log("4. 隨機查看最前端元素 (Peek) 成功"); // ========================================== // 5. 測試先進先出彈出 (Pop) // ========================================== // 第一次 Pop:預期拿到最先進入的 MsgA err = c_LinkQueue_Pop(&q, &local_buf); assert(err == C_ERR_OK); assert(strcmp(local_buf.text, "MsgA") == 0); assert(q.size == 2); // 彈出後再次 Peek,最前端應該變成 MsgB err = c_LinkQueue_Peek(&q, &local_buf); assert(err == C_ERR_OK); assert(strcmp(local_buf.text, "MsgB") == 0); // 第二次與第三次 Pop err = c_LinkQueue_Pop(&q, &local_buf); assert(err == C_ERR_OK); // 彈出 MsgB err = c_LinkQueue_Pop(&q, &local_buf); assert(err == C_ERR_OK); // 彈出 MsgC assert(q.size == 0); // 空佇列彈出與查看測試,預期回傳越界錯誤 err = c_LinkQueue_Pop(&q, &local_buf); assert(err == C_ERR_EMPTY); err = c_LinkQueue_Peek(&q, &local_buf); assert(err == C_ERR_EMPTY); test_log("5. 彈出 (Pop) 邏輯與空佇列防呆驗證成功"); // ========================================== // 6. 參數安全檢查 // ========================================== assert(c_LinkQueue_Init(NULL, sizeof(Message_t)) == C_ERR_PARAM); assert(c_LinkQueue_Push(NULL, &msg1) == C_ERR_PARAM); // assert(c_LinkQueue_Pop(&q, NULL) == C_ERR_PARAM); test_log("6. 介面 NULL 指標防呆驗證成功"); // ========================================== // 7. 銷毀佇列 // ========================================== c_LinkQueue_Destroy(&q); assert(q.head == NULL); assert(q.size == 0); test_log("7. 佇列銷毀與記憶體釋放成功"); printf("\n==================================================\n"); printf(" 恭喜!所有 c_LinkQueue 測試皆順利通過!\n"); printf("==================================================\n"); test_iter(); return 0; }