DragonOS/user/apps/c_unitest/test_truncate.c

276 lines
8.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define TEST_FILE "/tmp/test_truncate.txt"
#define TEST_DIR "/tmp/test_truncate_dir"
#define TEST_SYMLINK "/tmp/test_truncate_symlink"
#define TEST_RO_MOUNT "/tmp/test_ro_mount"
// 测试辅助函数
static void test_assert(int condition, const char *message) {
if (!condition) {
printf("FAIL: %s\n", message);
exit(1);
}
}
static void test_success(const char *message) {
printf("PASS: %s\n", message);
}
// 测试正常文件截断
static void test_normal_truncate() {
printf("\n=== 测试正常文件截断 ===\n");
// 创建测试文件
FILE *fp = fopen(TEST_FILE, "w");
test_assert(fp != NULL, "创建测试文件");
fprintf(fp, "Hello, World! This is a test file.");
fclose(fp);
// 检查初始文件大小
struct stat st;
test_assert(stat(TEST_FILE, &st) == 0, "获取文件状态");
printf("初始文件大小: %ld bytes\n", st.st_size);
// 截断到较小大小
printf("DEBUG: 调用 truncate(%s, 10)\n", TEST_FILE);
int result = truncate(TEST_FILE, 10);
printf("DEBUG: truncate 返回值: %d, errno: %d\n", result, errno);
test_assert(result == 0, "截断到10字节");
test_assert(stat(TEST_FILE, &st) == 0, "获取截断后文件状态");
printf("DEBUG: 截断后文件大小: %ld bytes (期望: 10)\n", st.st_size);
if (st.st_size == 10) {
test_success("截断到较小大小");
} else {
printf("FAIL: 文件大小应为10字节实际为%ld字节\n", st.st_size);
// 继续测试其他情况
}
// 截断到较大大小
printf("DEBUG: 调用 truncate(%s, 100)\n", TEST_FILE);
result = truncate(TEST_FILE, 100);
printf("DEBUG: truncate 返回值: %d, errno: %d\n", result, errno);
test_assert(result == 0, "截断到100字节");
test_assert(stat(TEST_FILE, &st) == 0, "获取截断后文件状态");
printf("DEBUG: 截断后文件大小: %ld bytes (期望: 100)\n", st.st_size);
if (st.st_size == 100) {
test_success("截断到较大大小");
} else {
printf("FAIL: 文件大小应为100字节实际为%ld字节\n", st.st_size);
}
// 截断到0
printf("DEBUG: 调用 truncate(%s, 0)\n", TEST_FILE);
result = truncate(TEST_FILE, 0);
printf("DEBUG: truncate 返回值: %d, errno: %d\n", result, errno);
test_assert(result == 0, "截断到0字节");
test_assert(stat(TEST_FILE, &st) == 0, "获取截断后文件状态");
printf("DEBUG: 截断后文件大小: %ld bytes (期望: 0)\n", st.st_size);
if (st.st_size == 0) {
test_success("截断到0字节");
} else {
printf("FAIL: 文件大小应为0字节实际为%ld字节\n", st.st_size);
}
// 清理
unlink(TEST_FILE);
}
// 测试目录截断应返回EISDIR
static void test_directory_truncate() {
printf("\n=== 测试目录截断 ===\n");
// 创建测试目录
test_assert(mkdir(TEST_DIR, 0755) == 0, "创建测试目录");
// 尝试截断目录
int result = truncate(TEST_DIR, 10);
test_assert(result == -1, "截断目录应失败");
test_assert(errno == EISDIR, "错误码应为EISDIR");
test_success("目录截断正确返回EISDIR");
// 清理
rmdir(TEST_DIR);
}
// 测试符号链接截断
static void test_symlink_truncate() {
printf("\n=== 测试符号链接截断 ===\n");
// 创建目标文件
FILE *fp = fopen(TEST_FILE, "w");
test_assert(fp != NULL, "创建目标文件");
fprintf(fp, "Target file content");
fclose(fp);
// 创建符号链接
test_assert(symlink(TEST_FILE, TEST_SYMLINK) == 0, "创建符号链接");
// 截断符号链接(应跟随到目标文件)
test_assert(truncate(TEST_SYMLINK, 5) == 0, "截断符号链接");
// 检查目标文件大小
struct stat st;
test_assert(stat(TEST_FILE, &st) == 0, "获取目标文件状态");
test_assert(st.st_size == 5, "目标文件大小应为5字节");
test_success("符号链接截断正确跟随到目标");
// 清理
unlink(TEST_SYMLINK);
unlink(TEST_FILE);
}
// 测试不存在的文件
static void test_nonexistent_file() {
printf("\n=== 测试不存在文件 ===\n");
int result = truncate("/tmp/nonexistent_file", 10);
test_assert(result == -1, "截断不存在文件应失败");
test_assert(errno == ENOENT, "错误码应为ENOENT");
test_success("不存在文件正确返回ENOENT");
}
// 测试只读挂载点截断
static void test_readonly_mount() {
printf("\n=== 测试只读挂载点截断 ===\n");
// 创建挂载点目录
test_assert(mkdir(TEST_RO_MOUNT, 0755) == 0, "创建挂载点目录");
// 尝试以只读方式挂载(如果支持的话)
// 注意:这里可能需要根据实际文件系统支持情况调整
if (mount("", TEST_RO_MOUNT, "ramfs", MS_RDONLY, NULL) == 0) {
// 在挂载点创建文件
char test_path[256];
snprintf(test_path, sizeof(test_path), "%s/test_file", TEST_RO_MOUNT);
FILE *fp = fopen(test_path, "w");
if (fp != NULL) {
fprintf(fp, "Test content");
fclose(fp);
// 尝试截断只读挂载点上的文件
int result = truncate(test_path, 5);
if (result == -1 && errno == EROFS) {
test_success("只读挂载点截断正确返回EROFS");
} else {
printf("WARN: 只读挂载点测试未按预期返回EROFS\n");
}
unlink(test_path);
}
umount(TEST_RO_MOUNT);
} else {
printf("INFO: 跳过只读挂载测试(可能不支持或权限不足)\n");
}
// 清理
rmdir(TEST_RO_MOUNT);
}
// 测试边界条件
static void test_boundary_conditions() {
printf("\n=== 测试边界条件 ===\n");
// 创建测试文件
FILE *fp = fopen(TEST_FILE, "w");
test_assert(fp != NULL, "创建测试文件");
fprintf(fp, "Test content");
fclose(fp);
// 测试负长度应返回EINVAL
int result = truncate(TEST_FILE, -1);
if (result == -1 && errno == EINVAL) {
test_success("负长度正确返回EINVAL");
} else {
printf("WARN: 负长度测试未按预期返回EINVAL\n");
}
// 测试非常大的长度
test_assert(truncate(TEST_FILE, 0x7FFFFFFF) == 0, "大长度截断");
struct stat st;
test_assert(stat(TEST_FILE, &st) == 0, "获取大长度截断后状态");
printf("大长度截断后文件大小: %ld bytes\n", st.st_size);
test_success("大长度截断");
// 清理
unlink(TEST_FILE);
}
// 测试与ftruncate的一致性
static void test_ftruncate_consistency() {
printf("\n=== 测试与ftruncate的一致性 ===\n");
// 创建测试文件
FILE *fp = fopen(TEST_FILE, "w");
test_assert(fp != NULL, "创建测试文件");
fprintf(fp, "Test content for consistency");
fclose(fp);
// 使用truncate截断
printf("DEBUG: 调用 truncate(%s, 10)\n", TEST_FILE);
int result = truncate(TEST_FILE, 10);
printf("DEBUG: truncate 返回值: %d, errno: %d\n", result, errno);
test_assert(result == 0, "truncate截断");
struct stat st1;
test_assert(stat(TEST_FILE, &st1) == 0, "获取truncate后状态");
printf("DEBUG: truncate后文件大小: %ld bytes\n", st1.st_size);
// 使用ftruncate截断
int fd = open(TEST_FILE, O_RDWR);
test_assert(fd != -1, "打开文件");
printf("DEBUG: 调用 ftruncate(fd=%d, 5)\n", fd);
result = ftruncate(fd, 5);
printf("DEBUG: ftruncate 返回值: %d, errno: %d\n", result, errno);
test_assert(result == 0, "ftruncate截断");
close(fd);
struct stat st2;
test_assert(stat(TEST_FILE, &st2) == 0, "获取ftruncate后状态");
printf("DEBUG: ftruncate后文件大小: %ld bytes (期望: 5)\n", st2.st_size);
if (st2.st_size == 5) {
test_success("truncate和ftruncate行为一致");
} else {
printf("FAIL: ftruncate后文件大小应为5字节实际为%ld字节\n", st2.st_size);
}
// 清理
unlink(TEST_FILE);
}
int main() {
printf("开始 SYS_TRUNCATE 系统调用测试\n");
printf("================================\n");
// 运行所有测试
test_normal_truncate();
test_directory_truncate();
test_symlink_truncate();
test_nonexistent_file();
test_readonly_mount();
test_boundary_conditions();
test_ftruncate_consistency();
printf("\n================================\n");
printf("所有测试完成!\n");
return 0;
}