测试用例

This commit is contained in:
2026-08-29 11:39:28 +08:00
parent a0758766c5
commit 8fd65b0de0
19 changed files with 1723 additions and 432 deletions
+155 -122
View File
@@ -2,144 +2,177 @@
#define INCLUDED_C_TEST_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.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; /* 整个套件的总耗时 */
// ==========================================
// 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"
/* ==============================================================================
* 🎯 2. 核心断言宏矩阵(严格以 C_ASSERT_ 开头)
* ============================================================================== */
// ==========================================
// 核心测试框架结构
// ==========================================
typedef struct {
int passed_count;
int failed_count;
double total_time_ms;
} TestRegistry;
/* 统一的断言失败内部打印函数 */
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)
static TestRegistry g_test_registry = {0, 0, 0.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)
#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)
/* 浮点数安全相等断言(内置之前讨论的 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)
#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)
/* ==============================================================================
* 🎯 3. 测试套件生命周期控制宏
* ============================================================================== */
#ifndef TEST_EPSILON
#define TEST_EPSILON 1e-6
#endif
/* 初始化一个测试套件文件 */
#define C_TEST_SUITE_BEGIN(name) \
printf("==================================================\n"); \
printf("🧪 运行测试套件: %s [%s环境]\n", #name, C_CURRENT_OS_NAME); \
printf("==================================================\n");
#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)
/* 结束测试套件并返回标准状态码给 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)
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
// 基础断言宏
#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)
#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)
#endif /*INCLUDED_C_TEST_H*/
+47 -24
View File
@@ -4,36 +4,59 @@
// Math/matrix.t.c
#include "c_Test.h"
void heavy_calculation(void) {
double sum = 0.0;
for (int i = 0; i < 5000000; ++i) {
sum += sin((double)i) * cos((double)i);
}
// 随便加一个没意义的断言防止被编译器完全优化掉
C_ASSERT(sum != 12345.6, "密集数学计算检验");
// ==========================================
// 模拟业务环境与测试用例
// ==========================================
int* file_mock_data = NULL;
// 环境 A 的启动与关闭(针对内存/文件操作)
static void setup() {
file_mock_data = (int*)malloc(sizeof(int) * 3);
file_mock_data[0] = 10; file_mock_data[1] = 20; file_mock_data[2] = 30;
printf(" " COLOR_CYAN "[INFO] Setup: Memory initialized." COLOR_RESET "\n");
}
// ------------------------------------------------------------------------------
// 🛠️ 步骤 A: 编写独立的测试用例函数 (C_TEST_CASE)
// ------------------------------------------------------------------------------
C_TEST_CASE(test_quick_operations) {
int a = 1, b = 1;
C_ASSERT_INT_EQ(a, b, "极速操作验证");
static void teardown() {
free(file_mock_data);
file_mock_data = NULL;
printf(" " COLOR_CYAN "[INFO] Teardown: Memory released." COLOR_RESET "\n");
}
C_TEST_CASE(test_heavy_workload) {
heavy_calculation();
// --- 具体测试用例 ---
// 用例 1:需要内存环境
static void test_with_memory() {
ASSERT_INT_EQ(20, file_mock_data[1]);
}
// ------------------------------------------------------------------------------
// 🚀 步骤 B: 在主执行块中注册并依次运行它们
// ------------------------------------------------------------------------------
int main(int argc, char** argv) {
C_TEST_SUITE_BEGIN(MathMatrixFunctionSuite)
// 用例 2:故意制造失败,检查内存是否能安全释放,且颜色是否正确
static void test_with_memory_failure() {
ASSERT_INT_EQ(99, file_mock_data[0]); // 这里会失败并 return 退出
}
C_RUN_TEST_CASE(test_quick_operations);
C_RUN_TEST_CASE(test_heavy_workload);
// 用例 3:纯数学计算,完全不需要任何专属启动和关闭环境
static void test_pure_math() {
int result = 1 + 1;
ASSERT_INT_EQ(2, result);
}
C_TEST_SUITE_END()
// ==========================================
// 主程序入口
// ==========================================
int main() {
TEST_START(Starting Unit Tests);
// 运行需要内存环境的用例
RUN_TEST_FIXTURE(test_with_memory, setup, teardown);
RUN_TEST_FIXTURE(test_with_memory_failure, setup, teardown);
// 运行普通无环境要求的用例
RUN_TEST(test_pure_math);
// 打印最终统计报告
TEST_REPORT();
RETURN_TEST_STATUS;
}
+8 -8
View File
@@ -101,16 +101,16 @@ typedef int c_err_t;
#define C_ERR_OK 0
#define C_ERR_FAIL (-1)
#define C_ERR_NOTFOUND (-2)
#define C_ERR_NOMEM (-3)
#define C_ERR_NOTIMPLEMENTED (-4)
#define C_ERR_PARAM (-5)
#define C_ERR_OUTOFBOUND (-6)
#define C_ERR_EMPTY (-7)
#define C_ERR_FULL (-8)
#define C_ERR_ALREADY_EXISTS (-9)
#define C_ERR_NOMEM (-2)
#define C_ERR_NOTIMPLEMENTED (-3)
#define C_ERR_PARAM (-4)
#define C_ERR_EMPTY (-5)
#define C_ERR_FULL (-6)
#define C_ERR_ALREADY_EXISTS (-7)
#define C_SUCCESS C_ERR_OK
#define C_ERR_NOTFOUND C_ERR_FAIL
#define C_ERR_OUTOFBOUND C_ERR_FAIL
/* ------------------------------------------------------------------------------------------------------------------ */
/* */