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*/
|