/**
 * @file    test_md5.cpp
 * @brief   MD5 算法单元测试 — RFC 1321 已知测试向量全覆盖
 */
#include "myMd5.h"
#include "myBase.h"
#include <cstdio>
#include <cstring>

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)

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

    /* RFC 1321 test suite — official test vectors */
    struct { const char *input; const char *expected; } tests[] = {
        {"",                              "D41D8CD98F00B204E9800998ECF8427E"},
        {"a",                             "0CC175B9C0F1B6A831C399E269772661"},
        {"abc",                           "900150983CD24FB0D6963F7D28E17F72"},
        {"message digest",                "F96B697D7CB7938D525A2F31AAF161D0"},
        {"abcdefghijklmnopqrstuvwxyz",    "C3FCD3D76192E4007DFB496CCA67E13B"},
        {"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
         "abcdefghijklmnopqrstuvwxyz"
         "0123456789",                    "D174AB98D277D9F5A5611C2C9F419D9F"},
        {"123456789012345678901234567890"
         "123456789012345678901234567890"
         "12345678901234567890",           "57EDF4A22BE3C955AC49DA2E2107B67A"},
    };
    int n = sizeof(tests) / sizeof(tests[0]);

    for (int i = 0; i < n; i++)
    {
        char tag[80];
        snprintf(tag, sizeof(tag), "RFC1321 vector #%d [%s]", i + 1,
                 strlen(tests[i].input) > 20 ? "..." : tests[i].input);
        TEST(tag);
        {
            char out[33] = {0};
            md5_string(tests[i].input, out);
            if (strcmp(out, tests[i].expected) == 0)
            {
                OK();
            }
            else
            {
                printf("got=%s exp=%s ", out, tests[i].expected);
                FAIL("hash mismatch");
            }
        }
    }

    TEST("streaming API: start/update/final = md5_string");
    {
        const char *input = "The quick brown fox jumps over the lazy dog";
        /* expected: 9E107D9D372BB6826BD81D3542A419D6 */
        const char *expected = "9E107D9D372BB6826BD81D3542A419D6";

        /* one-shot */
        char out1[33];
        md5_string(input, out1);

        /* streaming: split at each char */
        stru_md5_ctx ctx;
        md5_start(&ctx);
        for (int i = 0; input[i]; i++)
        {
            md5_update(&ctx, (const unsigned char *)&input[i], 1);
        }
        unsigned char raw[16];
        md5_final(&ctx, raw);

        char out2[33];
        for (int i = 0; i < 16; i++)
        {
            sprintf(out2 + i * 2, "%02X", raw[i]);
        }
        out2[32] = '\0';

        if (strcmp(out1, expected) == 0 && strcmp(out2, expected) == 0)
        {
            OK();
        }
        else
        {
            printf("s=%s stream=%s exp=%s ", out1, out2, expected);
            FAIL("hash mismatch");
        }
    }

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