Files
cKit/Base/c_Test.h
T
2026-08-29 00:53:40 +08:00

146 lines
5.9 KiB
C

#ifndef INCLUDED_C_TEST_H
#define INCLUDED_C_TEST_H
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <float.h>
#include <time.h>
#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*/