mirror of
https://github.com/LHY0125/PathEditor.git
synced 2026-06-29 18:15:55 +08:00
feat: CSV 导入导出、导入撤销支持及多项 bug 修复
功能: - 新增 CSV 格式导入导出支持(含 BOM 处理、引号转义、智能标题行检测) - 导入操作支持撤销/重做 - 保存时 PATH 长度检查与警告 - 深色模式状态持久化(darkmode.txt) - 提取 get_current_target/push_record 为共享函数,消除控制器层重复代码 - 新增 string_list_insert_at,修复撤销删除时的索引恢复 - 新增 undo_redo、error_code、import_export 单元测试 Bug 修复: - 修复备份目录对话框和失败原因的硬编码中文字符串 - 提取 get_exe_dir 到 os_env 消除 i18n.c/ui_utils.c 重复定义 - 修复导入撤销 old_sys/old_user 内存管理(push 后置 NULL 防止重复释放) - 修复 CSV 导出转义与导入解析不一致(移除反斜杠转义,依赖 CSV 引号机制) - 修正 PATH 长度 8191 限制描述为 "command line safe limit"
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
# undo_redo 单元测试
|
||||
add_executable(test_undo_redo test_undo_redo.c
|
||||
${CMAKE_SOURCE_DIR}/src/core/undo_redo.c
|
||||
${CMAKE_SOURCE_DIR}/src/core/path_manager.c
|
||||
${CMAKE_SOURCE_DIR}/src/utils/string_ext.c
|
||||
${CMAKE_SOURCE_DIR}/src/utils/safe_string.c
|
||||
${CMAKE_SOURCE_DIR}/src/utils/error_code.c
|
||||
)
|
||||
|
||||
target_link_libraries(test_undo_redo cmocka)
|
||||
|
||||
target_include_directories(test_undo_redo PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
target_compile_definitions(test_undo_redo PRIVATE TESTING)
|
||||
|
||||
add_custom_command(TARGET test_undo_redo POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${CMAKE_BINARY_DIR}/_deps/cmocka-build/src/cmocka.dll
|
||||
$<TARGET_FILE_DIR:test_undo_redo>
|
||||
)
|
||||
|
||||
add_test(NAME undo_redo_test COMMAND test_undo_redo)
|
||||
@@ -0,0 +1,637 @@
|
||||
/*
|
||||
* undo_redo.c 单元测试
|
||||
* 测试撤销/重做管理器
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <cmocka.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "core/undo_redo.h"
|
||||
#include "core/path_manager.h"
|
||||
#include "utils/string_ext.h"
|
||||
|
||||
/* ==================== Mock 函数 ==================== */
|
||||
|
||||
#ifdef TESTING
|
||||
|
||||
int is_path_valid(const char *path)
|
||||
{
|
||||
(void)path;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void log_info(const char *fmt, ...) { (void)fmt; }
|
||||
void log_debug(const char *fmt, ...) { (void)fmt; }
|
||||
void log_warn(const char *fmt, ...) { (void)fmt; }
|
||||
void log_error(const char *fmt, ...) { (void)fmt; }
|
||||
|
||||
#endif
|
||||
|
||||
/* ==================== 辅助函数 ==================== */
|
||||
|
||||
static OpRecord make_add_record(TargetType target, const char *path)
|
||||
{
|
||||
OpRecord rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
rec.type = OP_ADD;
|
||||
rec.target = target;
|
||||
rec.index = -1;
|
||||
rec.count = 1;
|
||||
rec.old_paths = NULL;
|
||||
char **np = (char **)malloc(sizeof(char *));
|
||||
np[0] = _strdup(path);
|
||||
rec.new_paths = np;
|
||||
return rec;
|
||||
}
|
||||
|
||||
static OpRecord make_delete_record(TargetType target, int index, const char *path)
|
||||
{
|
||||
OpRecord rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
rec.type = OP_DELETE;
|
||||
rec.target = target;
|
||||
rec.index = index;
|
||||
rec.count = 1;
|
||||
char **op = (char **)malloc(sizeof(char *));
|
||||
op[0] = _strdup(path);
|
||||
rec.old_paths = op;
|
||||
rec.new_paths = NULL;
|
||||
return rec;
|
||||
}
|
||||
|
||||
static OpRecord make_edit_record(TargetType target, int index, const char *old_path, const char *new_path)
|
||||
{
|
||||
OpRecord rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
rec.type = OP_EDIT;
|
||||
rec.target = target;
|
||||
rec.index = index;
|
||||
rec.count = 1;
|
||||
char **op = (char **)malloc(sizeof(char *));
|
||||
op[0] = _strdup(old_path);
|
||||
rec.old_paths = op;
|
||||
char **np = (char **)malloc(sizeof(char *));
|
||||
np[0] = _strdup(new_path);
|
||||
rec.new_paths = np;
|
||||
return rec;
|
||||
}
|
||||
|
||||
static OpRecord make_move_record(OperationType type, TargetType target, int index)
|
||||
{
|
||||
OpRecord rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
rec.type = type;
|
||||
rec.target = target;
|
||||
rec.index = index;
|
||||
rec.count = 1;
|
||||
rec.old_paths = NULL;
|
||||
rec.new_paths = NULL;
|
||||
return rec;
|
||||
}
|
||||
|
||||
static OpRecord make_clean_record(TargetType target, StringList *old_list)
|
||||
{
|
||||
OpRecord rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
rec.type = OP_CLEAN;
|
||||
rec.target = target;
|
||||
rec.index = -1;
|
||||
rec.count = old_list->count;
|
||||
if (old_list->count > 0)
|
||||
{
|
||||
char **op = (char **)malloc(old_list->count * sizeof(char *));
|
||||
for (int i = 0; i < old_list->count; i++)
|
||||
op[i] = _strdup(old_list->items[i]);
|
||||
rec.old_paths = op;
|
||||
}
|
||||
else
|
||||
{
|
||||
rec.old_paths = NULL;
|
||||
}
|
||||
rec.new_paths = NULL;
|
||||
return rec;
|
||||
}
|
||||
|
||||
/* ==================== 创建/销毁测试 ==================== */
|
||||
|
||||
static void test_create_manager(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
assert_non_null(mgr);
|
||||
assert_int_equal(mgr->max_size, 10);
|
||||
assert_int_equal(mgr->current, -1);
|
||||
assert_int_equal(mgr->count, 0);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
static void test_create_manager_default_size(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(0);
|
||||
assert_non_null(mgr);
|
||||
assert_int_equal(mgr->max_size, 50); /* DEFAULT_MAX_UNDO_RECORDS */
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
static void test_destroy_null(void **state)
|
||||
{
|
||||
(void)state;
|
||||
destroy_undo_redo_manager(NULL); /* 不应崩溃 */
|
||||
}
|
||||
|
||||
/* ==================== can_undo/can_redo 测试 ==================== */
|
||||
|
||||
static void test_can_undo_redo_empty(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
assert_int_equal(can_undo(mgr), 0);
|
||||
assert_int_equal(can_redo(mgr), 0);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
static void test_can_undo_null(void **state)
|
||||
{
|
||||
(void)state;
|
||||
assert_int_equal(can_undo(NULL), 0);
|
||||
assert_int_equal(can_redo(NULL), 0);
|
||||
}
|
||||
|
||||
/* ==================== push_undo_record 测试 ==================== */
|
||||
|
||||
static void test_push_record(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
OpRecord rec = make_add_record(TARGET_USER, "C:\\Test");
|
||||
|
||||
int result = push_undo_record(mgr, &rec);
|
||||
|
||||
assert_int_equal(result, 0);
|
||||
assert_int_equal(mgr->count, 1);
|
||||
assert_int_equal(mgr->current, 0);
|
||||
assert_int_equal(can_undo(mgr), 1);
|
||||
assert_int_equal(can_redo(mgr), 0);
|
||||
|
||||
/* 清理 */
|
||||
free(rec.new_paths[0]);
|
||||
free(rec.new_paths);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
static void test_push_null_mgr(void **state)
|
||||
{
|
||||
(void)state;
|
||||
OpRecord rec = make_add_record(TARGET_USER, "C:\\Test");
|
||||
int result = push_undo_record(NULL, &rec);
|
||||
assert_int_equal(result, -1);
|
||||
free(rec.new_paths[0]);
|
||||
free(rec.new_paths);
|
||||
}
|
||||
|
||||
static void test_push_null_record(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
int result = push_undo_record(mgr, NULL);
|
||||
assert_int_equal(result, -1);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
/* ==================== OP_ADD undo/redo 测试 ==================== */
|
||||
|
||||
static void test_undo_add(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
StringList sys, user;
|
||||
init_string_list(&sys);
|
||||
init_string_list(&user);
|
||||
|
||||
/* 添加路径 */
|
||||
add_string_list(&user, "C:\\Test");
|
||||
OpRecord rec = make_add_record(TARGET_USER, "C:\\Test");
|
||||
push_undo_record(mgr, &rec);
|
||||
|
||||
/* 撤销添加 */
|
||||
int result = undo(mgr, &sys, &user);
|
||||
assert_int_equal(result, 0);
|
||||
assert_int_equal(user.count, 0);
|
||||
assert_int_equal(can_redo(mgr), 1);
|
||||
|
||||
free(rec.new_paths[0]);
|
||||
free(rec.new_paths);
|
||||
clear_string_list(&sys);
|
||||
clear_string_list(&user);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
static void test_redo_add(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
StringList sys, user;
|
||||
init_string_list(&sys);
|
||||
init_string_list(&user);
|
||||
|
||||
add_string_list(&user, "C:\\Test");
|
||||
OpRecord rec = make_add_record(TARGET_USER, "C:\\Test");
|
||||
push_undo_record(mgr, &rec);
|
||||
|
||||
undo(mgr, &sys, &user);
|
||||
assert_int_equal(user.count, 0);
|
||||
|
||||
/* 重做添加 */
|
||||
int result = redo(mgr, &sys, &user);
|
||||
assert_int_equal(result, 0);
|
||||
assert_int_equal(user.count, 1);
|
||||
assert_string_equal(string_list_get(&user, 0), "C:\\Test");
|
||||
|
||||
free(rec.new_paths[0]);
|
||||
free(rec.new_paths);
|
||||
clear_string_list(&sys);
|
||||
clear_string_list(&user);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
/* ==================== OP_DELETE undo/redo 测试 ==================== */
|
||||
|
||||
static void test_undo_delete(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
StringList sys, user;
|
||||
init_string_list(&sys);
|
||||
init_string_list(&user);
|
||||
|
||||
add_string_list(&user, "C:\\Path1");
|
||||
add_string_list(&user, "C:\\Path2");
|
||||
|
||||
/* 记录删除操作 */
|
||||
OpRecord rec = make_delete_record(TARGET_USER, 0, "C:\\Path1");
|
||||
push_undo_record(mgr, &rec);
|
||||
|
||||
/* 模拟删除 */
|
||||
path_manager_remove_at(&user, 0);
|
||||
assert_int_equal(user.count, 1);
|
||||
|
||||
/* 撤销删除 */
|
||||
int result = undo(mgr, &sys, &user);
|
||||
assert_int_equal(result, 0);
|
||||
assert_int_equal(user.count, 2);
|
||||
|
||||
free(rec.old_paths[0]);
|
||||
free(rec.old_paths);
|
||||
clear_string_list(&sys);
|
||||
clear_string_list(&user);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
static void test_redo_delete(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
StringList sys, user;
|
||||
init_string_list(&sys);
|
||||
init_string_list(&user);
|
||||
|
||||
add_string_list(&user, "C:\\Path1");
|
||||
add_string_list(&user, "C:\\Path2");
|
||||
|
||||
OpRecord rec = make_delete_record(TARGET_USER, 0, "C:\\Path1");
|
||||
push_undo_record(mgr, &rec);
|
||||
|
||||
path_manager_remove_at(&user, 0);
|
||||
undo(mgr, &sys, &user);
|
||||
assert_int_equal(user.count, 2);
|
||||
|
||||
/* 重做删除 */
|
||||
int result = redo(mgr, &sys, &user);
|
||||
assert_int_equal(result, 0);
|
||||
assert_int_equal(user.count, 1);
|
||||
assert_string_equal(string_list_get(&user, 0), "C:\\Path2");
|
||||
|
||||
free(rec.old_paths[0]);
|
||||
free(rec.old_paths);
|
||||
clear_string_list(&sys);
|
||||
clear_string_list(&user);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
/* ==================== OP_EDIT undo/redo 测试 ==================== */
|
||||
|
||||
static void test_undo_edit(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
StringList sys, user;
|
||||
init_string_list(&sys);
|
||||
init_string_list(&user);
|
||||
|
||||
add_string_list(&user, "C:\\Old");
|
||||
|
||||
OpRecord rec = make_edit_record(TARGET_USER, 0, "C:\\Old", "C:\\New");
|
||||
push_undo_record(mgr, &rec);
|
||||
|
||||
/* 模拟编辑 */
|
||||
string_list_set(&user, 0, "C:\\New");
|
||||
assert_string_equal(string_list_get(&user, 0), "C:\\New");
|
||||
|
||||
/* 撤销编辑 */
|
||||
undo(mgr, &sys, &user);
|
||||
assert_string_equal(string_list_get(&user, 0), "C:\\Old");
|
||||
|
||||
free(rec.old_paths[0]);
|
||||
free(rec.old_paths);
|
||||
free(rec.new_paths[0]);
|
||||
free(rec.new_paths);
|
||||
clear_string_list(&sys);
|
||||
clear_string_list(&user);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
static void test_redo_edit(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
StringList sys, user;
|
||||
init_string_list(&sys);
|
||||
init_string_list(&user);
|
||||
|
||||
add_string_list(&user, "C:\\Old");
|
||||
|
||||
OpRecord rec = make_edit_record(TARGET_USER, 0, "C:\\Old", "C:\\New");
|
||||
push_undo_record(mgr, &rec);
|
||||
|
||||
string_list_set(&user, 0, "C:\\New");
|
||||
undo(mgr, &sys, &user);
|
||||
|
||||
/* 重做编辑 */
|
||||
redo(mgr, &sys, &user);
|
||||
assert_string_equal(string_list_get(&user, 0), "C:\\New");
|
||||
|
||||
free(rec.old_paths[0]);
|
||||
free(rec.old_paths);
|
||||
free(rec.new_paths[0]);
|
||||
free(rec.new_paths);
|
||||
clear_string_list(&sys);
|
||||
clear_string_list(&user);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
/* ==================== OP_MOVE undo/redo 测试 ==================== */
|
||||
|
||||
static void test_undo_move_up(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
StringList sys, user;
|
||||
init_string_list(&sys);
|
||||
init_string_list(&user);
|
||||
|
||||
add_string_list(&user, "A");
|
||||
add_string_list(&user, "B");
|
||||
add_string_list(&user, "C");
|
||||
|
||||
/* 记录上移操作 (index=2, C 上移到 B 前面) */
|
||||
OpRecord rec = make_move_record(OP_MOVE_UP, TARGET_USER, 2);
|
||||
push_undo_record(mgr, &rec);
|
||||
|
||||
/* 模拟上移 */
|
||||
path_manager_move_up(&user, 2);
|
||||
assert_string_equal(string_list_get(&user, 0), "A");
|
||||
assert_string_equal(string_list_get(&user, 1), "C");
|
||||
assert_string_equal(string_list_get(&user, 2), "B");
|
||||
|
||||
/* 撤销上移 */
|
||||
undo(mgr, &sys, &user);
|
||||
assert_string_equal(string_list_get(&user, 0), "A");
|
||||
assert_string_equal(string_list_get(&user, 1), "B");
|
||||
assert_string_equal(string_list_get(&user, 2), "C");
|
||||
|
||||
clear_string_list(&sys);
|
||||
clear_string_list(&user);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
static void test_redo_move_up(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
StringList sys, user;
|
||||
init_string_list(&sys);
|
||||
init_string_list(&user);
|
||||
|
||||
add_string_list(&user, "A");
|
||||
add_string_list(&user, "B");
|
||||
add_string_list(&user, "C");
|
||||
|
||||
OpRecord rec = make_move_record(OP_MOVE_UP, TARGET_USER, 2);
|
||||
push_undo_record(mgr, &rec);
|
||||
|
||||
path_manager_move_up(&user, 2);
|
||||
undo(mgr, &sys, &user);
|
||||
|
||||
/* 重做上移 */
|
||||
redo(mgr, &sys, &user);
|
||||
assert_string_equal(string_list_get(&user, 1), "C");
|
||||
assert_string_equal(string_list_get(&user, 2), "B");
|
||||
|
||||
clear_string_list(&sys);
|
||||
clear_string_list(&user);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
/* ==================== OP_CLEAN undo/redo 测试 ==================== */
|
||||
|
||||
static void test_undo_clean(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
StringList sys, user;
|
||||
init_string_list(&sys);
|
||||
init_string_list(&user);
|
||||
|
||||
add_string_list(&user, "C:\\Valid");
|
||||
add_string_list(&user, "C:\\Invalid");
|
||||
add_string_list(&user, "C:\\AlsoValid");
|
||||
|
||||
/* 记录清理前的列表 */
|
||||
OpRecord rec = make_clean_record(TARGET_USER, &user);
|
||||
push_undo_record(mgr, &rec);
|
||||
|
||||
/* 模拟清理(清空) */
|
||||
clear_string_list(&user);
|
||||
assert_int_equal(user.count, 0);
|
||||
|
||||
/* 撤销清理 */
|
||||
undo(mgr, &sys, &user);
|
||||
assert_int_equal(user.count, 3);
|
||||
assert_string_equal(string_list_get(&user, 0), "C:\\Valid");
|
||||
assert_string_equal(string_list_get(&user, 1), "C:\\Invalid");
|
||||
assert_string_equal(string_list_get(&user, 2), "C:\\AlsoValid");
|
||||
|
||||
/* 清理 OpRecord 中的 old_paths */
|
||||
for (int i = 0; i < rec.count; i++)
|
||||
free(rec.old_paths[i]);
|
||||
free(rec.old_paths);
|
||||
|
||||
clear_string_list(&sys);
|
||||
clear_string_list(&user);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
/* ==================== 连续 undo/redo 测试 ==================== */
|
||||
|
||||
static void test_multiple_undo_redo(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
StringList sys, user;
|
||||
init_string_list(&sys);
|
||||
init_string_list(&user);
|
||||
|
||||
/* 3 次添加 */
|
||||
OpRecord r1 = make_add_record(TARGET_USER, "A");
|
||||
OpRecord r2 = make_add_record(TARGET_USER, "B");
|
||||
OpRecord r3 = make_add_record(TARGET_USER, "C");
|
||||
|
||||
add_string_list(&user, "A");
|
||||
push_undo_record(mgr, &r1);
|
||||
add_string_list(&user, "B");
|
||||
push_undo_record(mgr, &r2);
|
||||
add_string_list(&user, "C");
|
||||
push_undo_record(mgr, &r3);
|
||||
|
||||
assert_int_equal(user.count, 3);
|
||||
|
||||
/* 连续撤销 3 次 */
|
||||
undo(mgr, &sys, &user);
|
||||
undo(mgr, &sys, &user);
|
||||
undo(mgr, &sys, &user);
|
||||
assert_int_equal(user.count, 0);
|
||||
assert_int_equal(can_undo(mgr), 0);
|
||||
assert_int_equal(can_redo(mgr), 1);
|
||||
|
||||
/* 连续重做 3 次 */
|
||||
redo(mgr, &sys, &user);
|
||||
redo(mgr, &sys, &user);
|
||||
redo(mgr, &sys, &user);
|
||||
assert_int_equal(user.count, 3);
|
||||
assert_int_equal(can_redo(mgr), 0);
|
||||
|
||||
free(r1.new_paths[0]); free(r1.new_paths);
|
||||
free(r2.new_paths[0]); free(r2.new_paths);
|
||||
free(r3.new_paths[0]); free(r3.new_paths);
|
||||
clear_string_list(&sys);
|
||||
clear_string_list(&user);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
/* ==================== 空栈 undo/redo 测试 ==================== */
|
||||
|
||||
static void test_undo_empty_stack(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
StringList sys, user;
|
||||
init_string_list(&sys);
|
||||
init_string_list(&user);
|
||||
|
||||
int result = undo(mgr, &sys, &user);
|
||||
assert_int_equal(result, -1);
|
||||
|
||||
clear_string_list(&sys);
|
||||
clear_string_list(&user);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
static void test_redo_empty_stack(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
StringList sys, user;
|
||||
init_string_list(&sys);
|
||||
init_string_list(&user);
|
||||
|
||||
int result = redo(mgr, &sys, &user);
|
||||
assert_int_equal(result, -1);
|
||||
|
||||
clear_string_list(&sys);
|
||||
clear_string_list(&user);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
/* ==================== clear_undo_redo_history 测试 ==================== */
|
||||
|
||||
static void test_clear_history(void **state)
|
||||
{
|
||||
(void)state;
|
||||
UndoRedoManager *mgr = create_undo_redo_manager(10);
|
||||
|
||||
OpRecord rec = make_add_record(TARGET_USER, "C:\\Test");
|
||||
push_undo_record(mgr, &rec);
|
||||
assert_int_equal(mgr->count, 1);
|
||||
|
||||
clear_undo_redo_history(mgr);
|
||||
assert_int_equal(mgr->count, 0);
|
||||
assert_int_equal(mgr->current, -1);
|
||||
assert_int_equal(can_undo(mgr), 0);
|
||||
|
||||
free(rec.new_paths[0]);
|
||||
free(rec.new_paths);
|
||||
destroy_undo_redo_manager(mgr);
|
||||
}
|
||||
|
||||
/* ==================== 主函数 ==================== */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
/* 创建/销毁 */
|
||||
cmocka_unit_test(test_create_manager),
|
||||
cmocka_unit_test(test_create_manager_default_size),
|
||||
cmocka_unit_test(test_destroy_null),
|
||||
|
||||
/* can_undo/can_redo */
|
||||
cmocka_unit_test(test_can_undo_redo_empty),
|
||||
cmocka_unit_test(test_can_undo_null),
|
||||
|
||||
/* push_undo_record */
|
||||
cmocka_unit_test(test_push_record),
|
||||
cmocka_unit_test(test_push_null_mgr),
|
||||
cmocka_unit_test(test_push_null_record),
|
||||
|
||||
/* OP_ADD */
|
||||
cmocka_unit_test(test_undo_add),
|
||||
cmocka_unit_test(test_redo_add),
|
||||
|
||||
/* OP_DELETE */
|
||||
cmocka_unit_test(test_undo_delete),
|
||||
cmocka_unit_test(test_redo_delete),
|
||||
|
||||
/* OP_EDIT */
|
||||
cmocka_unit_test(test_undo_edit),
|
||||
cmocka_unit_test(test_redo_edit),
|
||||
|
||||
/* OP_MOVE */
|
||||
cmocka_unit_test(test_undo_move_up),
|
||||
cmocka_unit_test(test_redo_move_up),
|
||||
|
||||
/* OP_CLEAN */
|
||||
cmocka_unit_test(test_undo_clean),
|
||||
|
||||
/* 连续操作 */
|
||||
cmocka_unit_test(test_multiple_undo_redo),
|
||||
|
||||
/* 边界情况 */
|
||||
cmocka_unit_test(test_undo_empty_stack),
|
||||
cmocka_unit_test(test_redo_empty_stack),
|
||||
cmocka_unit_test(test_clear_history),
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
Reference in New Issue
Block a user