20260829 Redesign
This commit is contained in:
+145
@@ -0,0 +1,145 @@
|
||||
#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*/
|
||||
Reference in New Issue
Block a user