feat(test): 添加单元测试框架并完善国际化支持

- 新增 CMake 测试框架配置,支持 safe_string、string_ext 和 path_manager 模块的单元测试
- 实现 Windows API Mock 机制,便于测试编码转换函数
- 添加 error_code 模块的字符串表示函数,支持英文错误日志
- 在 UI 回调函数中集成国际化翻译,覆盖新建、编辑、导入导出等操作提示
- 扩展 string_list 功能,新增重复路径检查函数
- 更新翻译文件,同步所有用户界面的中英文文本
This commit is contained in:
2026-04-30 11:38:05 +08:00
parent ceed90aea8
commit cf19a37a97
20 changed files with 1778 additions and 55 deletions
+209
View File
@@ -0,0 +1,209 @@
/*
* safe_string.c 单元测试
* 测试安全字符串操作函数
*/
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include <string.h>
#include <stdlib.h>
#include "utils/safe_string.h"
/* ==================== safe_strcpy 测试 ==================== */
static void test_safe_strcpy_normal(void **state)
{
(void)state;
char dst[32];
const char *src = "Hello, World!";
char *result = safe_strcpy(dst, sizeof(dst), src);
assert_non_null(result);
assert_string_equal(dst, src);
}
static void test_safe_strcpy_truncation(void **state)
{
(void)state;
char dst[8];
const char *src = "This is a long string";
char *result = safe_strcpy(dst, sizeof(dst), src);
assert_non_null(result);
assert_int_equal(strlen(dst), 7); /* 截断到 7 字符 */
assert_memory_equal(dst, src, 7); /* 前 7 字符相同 */
assert_int_equal(dst[7], '\0');
}
static void test_safe_strcpy_null_dst(void **state)
{
(void)state;
const char *src = "test";
char *result = safe_strcpy(NULL, 10, src);
assert_null(result);
}
static void test_safe_strcpy_null_src(void **state)
{
(void)state;
char dst[32];
char *result = safe_strcpy(dst, sizeof(dst), NULL);
assert_null(result);
}
static void test_safe_strcpy_zero_size(void **state)
{
(void)state;
char dst[32];
char *result = safe_strcpy(dst, 0, "test");
assert_null(result);
}
static void test_safe_strcpy_exact_fit(void **state)
{
(void)state;
char dst[6];
const char *src = "12345"; /* 5字符 + 1终止符 = 6 */
char *result = safe_strcpy(dst, sizeof(dst), src);
assert_non_null(result);
assert_string_equal(dst, "12345");
}
/* ==================== safe_strcat 测试 ==================== */
static void test_safe_strcat_normal(void **state)
{
(void)state;
char dst[32] = "Hello";
const char *src = ", World!";
char *result = safe_strcat(dst, sizeof(dst), src);
assert_non_null(result);
assert_string_equal(dst, "Hello, World!");
}
static void test_safe_strcat_truncation(void **state)
{
(void)state;
char dst[12] = "Hello";
const char *src = ", World!"; /* 总长 12,但最后一个位置要放 \0 */
char *result = safe_strcat(dst, sizeof(dst), src);
assert_non_null(result);
/* dst 有 11 可用位置 (12-1)"Hello" 占 5,还剩 6 */
/* ", World!" 有 9 字符,只能放 6 个字符 + \0 */
assert_true(strlen(dst) <= 11);
}
static void test_safe_strcat_null_dst(void **state)
{
(void)state;
char dst[32] = "test";
char *result = safe_strcat(NULL, sizeof(dst), "src");
assert_null(result);
}
static void test_safe_strcat_null_src(void **state)
{
(void)state;
char dst[32] = "test";
char *result = safe_strcat(dst, sizeof(dst), NULL);
/* src 为 NULL 时函数返回 NULL */
assert_null(result);
}
static void test_safe_strcat_empty_dst(void **state)
{
(void)state;
char dst[32] = "";
const char *src = "Hello";
char *result = safe_strcat(dst, sizeof(dst), src);
assert_non_null(result);
assert_string_equal(dst, "Hello");
}
/* ==================== safe_strdup 测试 ==================== */
static void test_safe_strdup_normal(void **state)
{
(void)state;
const char *src = "Hello, World!";
char *result = safe_strdup(src);
assert_non_null(result);
assert_string_equal(result, src);
assert_ptr_not_equal(result, src); /* 必须是新分配的内存 */
free(result);
}
static void test_safe_strdup_null(void **state)
{
(void)state;
char *result = safe_strdup(NULL);
assert_null(result);
}
static void test_safe_strdup_empty_string(void **state)
{
(void)state;
const char *src = "";
char *result = safe_strdup(src);
assert_non_null(result);
assert_string_equal(result, "");
free(result);
}
static void test_safe_strdup_long_string(void **state)
{
(void)state;
/* 构造一个 510 字符的字符串 */
char src[511];
for (int i = 0; i < 510; i++) {
src[i] = 'A';
}
src[510] = '\0';
char *result = safe_strdup(src);
assert_non_null(result);
assert_int_equal(strlen(result), 510);
assert_memory_equal(result, src, 510);
free(result);
}
/* ==================== 主函数 ==================== */
int main(void)
{
const struct CMUnitTest tests[] = {
/* safe_strcpy 测试 */
cmocka_unit_test(test_safe_strcpy_normal),
cmocka_unit_test(test_safe_strcpy_truncation),
cmocka_unit_test(test_safe_strcpy_null_dst),
cmocka_unit_test(test_safe_strcpy_null_src),
cmocka_unit_test(test_safe_strcpy_zero_size),
cmocka_unit_test(test_safe_strcpy_exact_fit),
/* safe_strcat 测试 */
cmocka_unit_test(test_safe_strcat_normal),
cmocka_unit_test(test_safe_strcat_truncation),
cmocka_unit_test(test_safe_strcat_null_dst),
cmocka_unit_test(test_safe_strcat_null_src),
cmocka_unit_test(test_safe_strcat_empty_dst),
/* safe_strdup 测试 */
cmocka_unit_test(test_safe_strdup_normal),
cmocka_unit_test(test_safe_strdup_null),
cmocka_unit_test(test_safe_strdup_empty_string),
cmocka_unit_test(test_safe_strdup_long_string),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}