#ifndef INCLUDED_C_TEST_H #define INCLUDED_C_TEST_H #include #include #include #include #include #include "c_Compiler.h" /* ============================================================================== * 🎯 1. 测试上下文状态追踪 * ============================================================================== */ static int c_test_suite_failed = 0; /* 当前套件是否有失败的断言 */ static int c_test_case_failed = 0; /* 当前正在运行的测试用例是否有失败 */ static int c_test_total_assertions = 0; /* 总断言数 */ static int c_test_passed_assertions = 0; /* 成功的断言数 */ static int c_test_cases_run = 0; /* 运行的用例数 */ static int c_test_cases_passed = 0; /* 成功的用例数 */ static double c_test_suite_total_ms = 0.0; /* 整个套件的总耗时 */ /* ============================================================================== * 🎯 2. 核心断言宏矩阵(严格以 C_ASSERT_ 开头) * ============================================================================== */ /* 统一的断言失败内部打印函数 */ C_STATIC_FORCE_INLINE void c_test_print_fail(const char* file, int line, const char* expr, const char* msg) { c_test_suite_failed = 1; c_test_case_failed = 1; printf(" [FAIL] %s:%d -> 断言失败: (%s) ", file, line, expr); if (msg && strlen(msg) > 0) { printf("| 说明: %s", msg); } printf("\n"); } /* 基础布尔断言 */ #define C_ASSERT(expr, msg) do { \ c_test_total_assertions++; \ if (C_LIKELY(expr)) { \ c_test_passed_assertions++; \ } else { \ c_test_print_fail(__FILE__, __LINE__, #expr, msg); \ } \ } while(0) /* 整型相等断言 */ #define C_ASSERT_INT_EQ(actual, expected, msg) do { \ c_test_total_assertions++; \ long long act = (long long)(actual); \ long long exp = (long long)(expected); \ if (C_LIKELY(act == exp)) { \ c_test_passed_assertions++; \ } else { \ char buf[256]; \ snprintf(buf, sizeof(buf), "期望值: %lld, 实际值: %lld | %s", exp, act, msg); \ c_test_print_fail(__FILE__, __LINE__, #actual " == " #expected, buf); \ } \ } while(0) /* 字符串相等断言 */ #define C_ASSERT_STR_EQ(actual, expected, msg) do { \ c_test_total_assertions++; \ const char* act = (const char*)(actual); \ const char* exp = (const char*)(expected); \ if (C_LIKELY(act && exp && strcmp(act, exp) == 0)) { \ c_test_passed_assertions++; \ } else { \ char buf[256]; \ snprintf(buf, sizeof(buf), "期望: \"%s\", 实际: \"%s\" | %s", exp ? exp : "NULL", act ? act : "NULL", msg); \ c_test_print_fail(__FILE__, __LINE__, "strcmp(" #actual ", " #expected ") == 0", buf); \ } \ } while(0) /* 浮点数安全相等断言(内置之前讨论的 IEEE 754 Epsilon 比较) */ #define C_ASSERT_DOUBLE_EQ(actual, expected, msg) do { \ c_test_total_assertions++; \ double act = (double)(actual); \ double exp = (double)(expected); \ int is_eq = 0; \ if (isnan(act) && isnan(exp) || (fabs(act - exp) < DBL_EPSILON) ) { is_eq = 1; } \ if (C_LIKELY(is_eq)) { \ c_test_passed_assertions++; \ } else { \ char buf[256]; \ snprintf(buf, sizeof(buf), "期望: %.32f, 实际: %.32f (误差 > DBL_EPSILON[%.32f]) | %s", exp, act, DBL_EPSILON, msg); \ c_test_print_fail(__FILE__, __LINE__, "fabs(" #actual " - " #expected ") < DBL_EPSILON", buf); \ } \ } while(0) /* ============================================================================== * 🎯 3. 测试套件生命周期控制宏 * ============================================================================== */ /* 初始化一个测试套件文件 */ #define C_TEST_SUITE_BEGIN(name) \ printf("==================================================\n"); \ printf("🧪 运行测试套件: %s [%s环境]\n", #name, C_CURRENT_OS_NAME); \ printf("==================================================\n"); /* 结束测试套件并返回标准状态码给 CMake CTest */ #define C_TEST_SUITE_END() \ printf("\n--------------------------------------------------------------------\n"); \ printf("📊 测试结果统计:\n"); \ printf(" 测试用例数: %d 运行, %d 通过, %d 失败\n", \ c_test_cases_run, c_test_cases_passed, c_test_cases_run - c_test_cases_passed); \ printf(" 底层断言数: %d 总计, %d 成功, %d 失败\n", \ c_test_total_assertions, c_test_passed_assertions, c_test_total_assertions - c_test_passed_assertions); \ printf(" 套件总耗时: %.3f ms\n", c_test_suite_total_ms); \ if (c_test_suite_failed) { \ printf("🚨 结论 : [ FAILURE ] 有测试未通过!\n"); \ printf("====================================================================\n"); \ return 1; \ } \ printf("🎉 结论 : [ SUCCESS ] 全套单元测试完美通过!\n"); \ printf("====================================================================\n"); \ return 0; /* 声明一个测试用例块 */ #define C_TEST_CASE(name) static void name(void) #define C_RUN_TEST_CASE(name) do { \ c_test_cases_run++; \ c_test_case_failed = 0; \ printf(" ▶ 运行测试用例: %-30s ... ", #name); \ fflush(stdout); \ struct timespec c_start_time, c_end_time; \ timespec_get(&c_start_time, TIME_UTC); \ name(); \ timespec_get(&c_end_time, TIME_UTC); \ double c_elapsed_ms = (double)(c_end_time.tv_sec - c_start_time.tv_sec) * 1000.0 + \ (double)(c_end_time.tv_nsec - c_start_time.tv_nsec) / 1000000.0; \ c_test_suite_total_ms += c_elapsed_ms; \ if (c_test_case_failed) { \ printf("[ ❌ 失败 ] (耗时: %8.3f ms)\n", c_elapsed_ms); \ } else { \ c_test_cases_passed++; \ printf("[ ✨ 通过 ] (耗时: %8.3f ms)\n", c_elapsed_ms); \ } \ } while(0) #endif /*INCLUDED_C_TEST_H*/