/**
 * @file    test_list.c
 * @brief   侵入式链表单元测试 — 所有宏/函数全覆盖
 */
#include "list.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

static int g_pass = 0, g_fail = 0;
#define TEST(n) do { printf("  TEST: %s ... ", n); } while (0)
#define OK()    do { printf("OK\n"); g_pass++; } while (0)
#define FAIL(m) do { printf("FAIL: %s\n", m); g_fail++; } while (0)
#define CHECK(c, m) do { if (!(c)) { FAIL(m); return; } } while (0)

struct test_node { int val; struct list_head node; };

int main(void)
{
    printf("\n=== liblist 单元测试 ===\n\n");

    TEST("LIST_HEAD + list_empty");
    {
        LIST_HEAD(h);
        CHECK(list_empty(&h) == 1, "new list not empty");
    }
    OK();

    TEST("INIT_LIST_HEAD");
    {
        struct list_head h;
        INIT_LIST_HEAD(&h);
        CHECK(list_empty(&h) == 1, "init_list_head");
    }
    OK();

    TEST("list_add + list_for_each_entry");
    {
        LIST_HEAD(h);
        struct test_node n1 = {1, LIST_HEAD_INIT(n1.node)};
        struct test_node n2 = {2, LIST_HEAD_INIT(n2.node)};
        struct test_node n3 = {3, LIST_HEAD_INIT(n3.node)};

        list_add(&n1.node, &h);
        list_add(&n2.node, &h);
        list_add(&n3.node, &h);

        /* order: n3 → n2 → n1 */
        int vals[4], i = 0;
        struct test_node *cur;
        list_for_each_entry(cur, &h, node) { vals[i++] = cur->val; }
        CHECK(i == 3, "count");
        CHECK(vals[0] == 3 && vals[1] == 2 && vals[2] == 1, "order");
    }
    OK();

    TEST("list_add_tail (append)");
    {
        LIST_HEAD(h);
        struct test_node n1 = {1, LIST_HEAD_INIT(n1.node)};
        struct test_node n2 = {2, LIST_HEAD_INIT(n2.node)};
        list_add_tail(&n1.node, &h);
        list_add_tail(&n2.node, &h);
        struct test_node *f = list_first_entry(&h, struct test_node, node);
        struct test_node *l = list_last_entry(&h, struct test_node, node);
        CHECK(f->val == 1, "first");
        CHECK(l->val == 2, "last");
    }
    OK();

    TEST("list_del + list_del_init");
    {
        LIST_HEAD(h);
        struct test_node n = {42, LIST_HEAD_INIT(n.node)};
        list_add_tail(&n.node, &h);
        CHECK(list_empty(&h) == 0, "should have 1");

        list_del(&n.node);
        CHECK(list_empty(&h) == 1, "list_del should empty");

        list_add_tail(&n.node, &h);
        CHECK(list_empty(&h) == 0, "should have 1 after re-add");

        list_del_init(&n.node);
        CHECK(list_empty(&h) == 1, "list_del_init should empty");
        CHECK(n.node.next == &n.node, "del_init self-points"); /* no list_head on stack */
    }
    OK();

    TEST("list_move");
    {
        LIST_HEAD(h1);
        LIST_HEAD(h2);
        struct test_node n = {99, LIST_HEAD_INIT(n.node)};
        list_add_tail(&n.node, &h1);
        list_move(&n.node, &h2);
        CHECK(list_empty(&h1) == 1, "src empty");
        CHECK(list_empty(&h2) == 0, "dst not empty");
    }
    OK();

    TEST("list_replace");
    {
        LIST_HEAD(h);
        struct test_node n1 = {1, LIST_HEAD_INIT(n1.node)};
        struct test_node n2 = {2, LIST_HEAD_INIT(n2.node)};
        list_add_tail(&n1.node, &h);
        list_replace(&n1.node, &n2.node);
        struct test_node *f = list_first_entry(&h, struct test_node, node);
        CHECK(f->val == 2, "replaced");
    }
    OK();

    TEST("list_for_each_entry_safe (safe delete)");
    {
        LIST_HEAD(h);
        struct test_node nodes[5];
        for (int i = 0; i < 5; i++) { nodes[i].val = i; INIT_LIST_HEAD(&nodes[i].node); list_add_tail(&nodes[i].node, &h); }

        struct test_node *cur, *tmp;
        int count = 0;
        list_for_each_entry_safe(cur, tmp, &h, node)
        {
            if (cur->val % 2 == 0) { list_del(&cur->node); }
            count++;
        }
        CHECK(count == 5, "iterated 5");
        int remaining = 0;
        list_for_each_entry(cur, &h, node) { remaining++; }
        CHECK(remaining == 2, "2 remaining after safe del");
    }
    OK();

    TEST("list_splice (merge)");
    {
        LIST_HEAD(h1);
        LIST_HEAD(h2);
        struct test_node n1 = {10, LIST_HEAD_INIT(n1.node)};
        struct test_node n2 = {20, LIST_HEAD_INIT(n2.node)};
        list_add_tail(&n1.node, &h1);
        list_add_tail(&n2.node, &h2);
        list_splice_init(&h2, &h1);
        CHECK(list_empty(&h2) == 1, "src empty after splice");
        int count = 0;
        struct test_node *cur;
        list_for_each_entry(cur, &h1, node) { count++; }
        CHECK(count == 2, "dst has 2");
    }
    OK();

    printf("\n========================================\n");
    printf("  测试结果: %d pass, %d fail\n", g_pass, g_fail);
    printf("========================================\n");
    return (g_fail > 0) ? 1 : 0;
}
