Files

181 lines
6.3 KiB
C
Raw Permalink Normal View History

2026-08-29 00:53:40 +08:00
#ifndef INCLUDED_C_TEST_H
#define INCLUDED_C_TEST_H
#include <stdio.h>
2026-08-29 11:39:28 +08:00
#include <stdlib.h>
2026-08-29 00:53:40 +08:00
#include <string.h>
2026-08-29 11:39:28 +08:00
#include <time.h>
2026-08-29 00:53:40 +08:00
#include <math.h>
#include <float.h>
2026-08-29 11:39:28 +08:00
// ==========================================
// ANSI 终端颜色宏定义
// ==========================================
#define COLOR_RESET "\033[0m"
#define COLOR_GREEN "\033[32m"
#define COLOR_RED "\033[31m"
#define COLOR_YELLOW "\033[33m"
#define COLOR_BLUE "\033[34m"
#define COLOR_CYAN "\033[36m"
#define COLOR_BOLD "\033[1m"
2026-08-29 00:53:40 +08:00
2026-08-29 11:39:28 +08:00
// ==========================================
// 核心测试框架结构
// ==========================================
typedef struct {
int passed_count;
int failed_count;
double total_time_ms;
} TestRegistry;
2026-08-29 00:53:40 +08:00
2026-08-29 11:39:28 +08:00
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
2026-08-29 00:53:40 +08:00
2026-08-29 11:39:28 +08:00
static TestRegistry g_test_registry = {0, 0, 0.0};
2026-08-29 00:53:40 +08:00
2026-08-29 11:39:28 +08:00
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
2026-08-29 00:53:40 +08:00
2026-08-29 11:39:28 +08:00
#define ASSERT_MSG(condition, message) \
do { \
if (!(condition)) { \
printf(" " COLOR_RED "[FAIL] %s:%d: Assertion failed: (%s). Message: %s" COLOR_RESET "\n", __FILE__, __LINE__, #condition, message); \
g_test_registry.failed_count++; \
return; \
} \
} while(0)
2026-08-29 00:53:40 +08:00
2026-08-29 11:39:28 +08:00
#define ASSERT_INT_EQ_MSG(expected, actual, message) \
do { \
if ((expected) != (actual)) { \
printf(" " COLOR_RED "[FAIL] %s:%d: Expected %d, but got %d. Message: %s" COLOR_RESET "\n", __FILE__, __LINE__, (int)(expected), (int)(actual), message); \
g_test_registry.failed_count++; \
return; \
} \
} while(0)
2026-08-29 00:53:40 +08:00
2026-08-29 11:39:28 +08:00
#ifndef TEST_EPSILON
#define TEST_EPSILON 1e-6
#endif
2026-08-29 00:53:40 +08:00
2026-08-29 11:39:28 +08:00
#define ASSERT_DOUBLE_EQ_MSG(expected, actual, message) \
do { \
double __exp = (double)(expected); \
double __act = (double)(actual); \
/* 计算两个浮点数差值的绝对值,并与允许的误差进行比较 */ \
if (fabs(__exp - __act) > TEST_EPSILON) { \
printf(" " COLOR_RED "[FAIL] %s:%d: Expected %.6f, but got %.6f. Message: %s" COLOR_RESET "\n", \
__FILE__, __LINE__, __exp, __act, (message) ? (message) : "No message"); \
g_test_registry.failed_count++; \
return; \
} \
} while(0)
2026-08-29 00:53:40 +08:00
2026-08-29 11:39:28 +08:00
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
// 基础断言宏
#define ASSERT_TRUE(condition) \
do { \
if (!(condition)) { \
printf(" " COLOR_RED "[FAIL] %s:%d: Assertion failed: (%s)" COLOR_RESET "\n", __FILE__, __LINE__, #condition); \
g_test_registry.failed_count++; \
return; \
} \
} while(0)
2026-09-05 13:36:43 +08:00
#define ASSERT_FALSE(condition) ASSERT_TRUE(!(condition))
2026-08-29 11:39:28 +08:00
#define ASSERT_INT_EQ(expected, actual) \
do { \
if ((expected) != (actual)) { \
printf(" " COLOR_RED "[FAIL] %s:%d: Expected %d, but got %d" COLOR_RESET "\n", __FILE__, __LINE__, (int)(expected), (int)(actual)); \
g_test_registry.failed_count++; \
return; \
} \
} while(0)
#define ASSERT_LL_EQ(expected, actual) \
do { \
if ((expected) != (actual)) { \
printf(" " COLOR_RED "[FAIL] %s:%d: Expected %"PRId64", but got %"PRId64 COLOR_RESET "\n", __FILE__, __LINE__, (uint64_t)(expected), (uint64_t)(actual)); \
g_test_registry.failed_count++; \
return; \
} \
} while(0)
#define ASSERT_PTR_NOT_NULL(ptr) ASSERT_TRUE(ptr!=NULL)
// ==========================================
// 核心运行宏(支持自定义配置环境)
// ==========================================
// 核心通用运行宏(内部使用)
#define _RUN_TEST_CORE(test_func, setup, teardown) \
do { \
printf(COLOR_BLUE "[RUN ]" COLOR_RESET " %s\n", #test_func); \
\
/* 1. 执行专属启动函数 */ \
void (*st)(void) = (setup); \
if (st) st(); \
\
int initial_failed = g_test_registry.failed_count; \
clock_t start_time = clock(); \
\
/* 2. 执行测试函数 */ \
test_func(); \
\
clock_t end_time = clock(); \
double elapsed_ms = ((double)(end_time - start_time) / CLOCKS_PER_SEC) * 1000.0; \
g_test_registry.total_time_ms += elapsed_ms; \
\
/* 3. 执行专属关闭函数 */ \
void (*td)(void) = (teardown); \
if (td) td(); \
\
/* 4. 带颜色状态输出 */ \
if (g_test_registry.failed_count == initial_failed) { \
printf(COLOR_GREEN "[ OK]" COLOR_RESET " %s (%.2f ms)\n", #test_func, elapsed_ms); \
g_test_registry.passed_count++; \
} else { \
printf(COLOR_RED "[FAIL]" COLOR_RESET " %s (%.2f ms)\n", #test_func, elapsed_ms); \
} \
printf("-------------------------------------------\n"); \
} while(0)
// 宏 1:支持绑定专属环境的运行宏
#define RUN_TEST_FIXTURE(test_func, setup, teardown) _RUN_TEST_CORE(test_func, setup, teardown)
// 宏 2:普通运行宏(无需任何启动/关闭环境)
#define RUN_TEST(test_func) _RUN_TEST_CORE(test_func, NULL, NULL)
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
#define TEST_START(Name) do{ \
printf(COLOR_BOLD "===========================================\n"); \
printf(" %s \n", #Name);\
printf("===========================================\n" COLOR_RESET); }while(0)
#define TEST_REPORT()\
do{ \
printf(COLOR_BOLD "===========================================\n"); \
printf("TEST SUMMARY:\n" COLOR_RESET); \
printf(" Total Executed : %d\n", g_test_registry.passed_count + g_test_registry.failed_count); \
printf(COLOR_GREEN " Passed : %d\n" COLOR_RESET, g_test_registry.passed_count); \
printf(COLOR_RED " Failed : %d\n" COLOR_RESET, g_test_registry.failed_count); \
printf(" Total Time : %.2f ms\n", g_test_registry.total_time_ms); \
printf(COLOR_BOLD "===========================================\n" COLOR_RESET);\
}while (0)
#define RETURN_TEST_STATUS return (g_test_registry.failed_count > 0 ? 1 : 0)
#define TEST_CASE(name) static void name(void)
2026-08-29 00:53:40 +08:00
#endif /*INCLUDED_C_TEST_H*/