SimpleKernel 1.17.0
Loading...
Searching...
No Matches
vfs_test.cpp
Go to the documentation of this file.
1
6#include "vfs.hpp"
7
8#include <gtest/gtest.h>
9
10#include "file_descriptor.hpp"
11#include "filesystem.hpp"
12#include "mount.hpp"
14
15using namespace filesystem;
16using namespace vfs;
17
18// Mock FileOps for testing
19class MockFileOps : public FileOps {
20 public:
21 auto Read(File*, void*, size_t) -> Expected<size_t> override {
22 return std::unexpected(Error(ErrorCode::kDeviceNotSupported));
23 }
24 auto Write(File*, const void*, size_t) -> Expected<size_t> override {
25 return std::unexpected(Error(ErrorCode::kDeviceNotSupported));
26 }
27 auto Seek(File*, int64_t, SeekWhence) -> Expected<uint64_t> override {
28 return std::unexpected(Error(ErrorCode::kDeviceNotSupported));
29 }
30 auto Close(File*) -> Expected<void> override { return {}; }
31 auto ReadDir(File*, DirEntry*, size_t) -> Expected<size_t> override {
32 return std::unexpected(Error(ErrorCode::kDeviceNotSupported));
33 }
34};
35
36// Mock file system for testing
37class MockFs : public FileSystem {
38 public:
39 mutable bool mount_called = false;
40 mutable bool unmount_called = false;
41 mutable bool sync_called = false;
42 mutable BlockDevice* last_device = nullptr;
44
46
48 root_inode.type = FileType::kDirectory;
49 root_inode.ino = 1;
50 root_inode.ops = nullptr; // MockFs doesn't provide InodeOps
51 }
52
53 [[nodiscard]] auto GetName() const -> const char* override {
54 return "mockfs";
55 }
56
57 auto Mount(BlockDevice* device) -> Expected<Inode*> override {
58 mount_called = true;
59 last_device = device;
60 return &root_inode;
61 }
62
63 auto Unmount() -> Expected<void> override {
64 unmount_called = true;
65 return {};
66 }
67
68 auto Sync() -> Expected<void> override {
69 sync_called = true;
70 return {};
71 }
72
73 auto AllocateInode() -> Expected<Inode*> override {
74 return std::unexpected(Error(ErrorCode::kOutOfMemory));
75 }
76
77 auto FreeInode(Inode* /*inode*/) -> Expected<void> override { return {}; }
78
79 auto GetFileOps() -> FileOps* override { return &mock_file_ops_; }
80};
81
82// VFS 基础测试
83class VfsTest : public ::testing::Test {
84 protected:
85 void SetUp() override {
88 env_state_.BindThreadToCore(std::this_thread::get_id(), 0);
89 auto result = vfs::Init();
90 EXPECT_TRUE(result.has_value());
91 }
92
94
96};
97
98class BaseEnvTest : public ::testing::Test {
99 protected:
100 void SetUp() override {
103 env_state_.BindThreadToCore(std::this_thread::get_id(), 0);
104 }
107};
108
109// 测试挂载表
110class MountTableTest : public BaseEnvTest {};
111TEST_F(MountTableTest, MountAndUnmount) {
112 MountTable mount_table;
113 MockFs mock_fs;
114
115 // 测试挂载
116 auto mount_result = mount_table.Mount("/", &mock_fs, nullptr);
117 EXPECT_TRUE(mount_result.has_value());
118 EXPECT_TRUE(mock_fs.mount_called);
119
120 // 测试重复挂载
121 mount_result = mount_table.Mount("/", &mock_fs, nullptr);
122 EXPECT_FALSE(mount_result.has_value());
123
124 // 测试卸载
125 auto unmount_result = mount_table.Unmount("/");
126 (void)unmount_result;
127 EXPECT_TRUE(unmount_result.has_value());
129
130 // 测试卸载未挂载的路径
131 unmount_result = mount_table.Unmount("/mnt");
132 EXPECT_FALSE(unmount_result.has_value());
133}
134
135TEST_F(MountTableTest, LookupMountPoint) {
136 MountTable mount_table;
137 MockFs mock_fs;
138
139 auto mount_result = mount_table.Mount("/", &mock_fs, nullptr);
140 EXPECT_TRUE(mount_result.has_value());
141
142 // 查找根挂载点
143 auto* mp = mount_table.Lookup("/file.txt");
144 EXPECT_NE(mp, nullptr);
145
146 // 查找不存在挂载的路径
147 mp = mount_table.Lookup("/mnt/nonexistent/file");
148 EXPECT_NE(mp, nullptr); // 应该返回根挂载点
149 (void)mount_table.Unmount("/");
150}
151
152// 测试文件描述符表
153class FdTableTest : public BaseEnvTest {
154 protected:
156
157 void SetUp() override {
160 }
161
162 void TearDown() override {
163 delete fd_table_;
165 }
166};
167
168TEST_F(FdTableTest, AllocAndFree) {
169 // 创建模拟文件
170 File mock_file;
171
172 // 分配 fd
173 auto alloc_result = fd_table_->Alloc(&mock_file);
174 EXPECT_TRUE(alloc_result.has_value());
175 int fd = alloc_result.value();
176 EXPECT_GE(fd, 3); // 0/1/2 预留给标准流
177
178 // 获取文件
179 File* file = fd_table_->Get(fd);
180 EXPECT_EQ(file, &mock_file);
181
182 // 释放 fd
183 auto free_result = fd_table_->Free(fd);
184 EXPECT_TRUE(free_result.has_value());
185
186 // 再次获取应该返回 nullptr
187 file = fd_table_->Get(fd);
188 EXPECT_EQ(file, nullptr);
189}
190
191TEST_F(FdTableTest, InvalidFd) {
192 // 无效 fd
193 File* file = fd_table_->Get(-1);
194 EXPECT_EQ(file, nullptr);
195
196 file = fd_table_->Get(999);
197 EXPECT_EQ(file, nullptr);
198
199 // 释放无效 fd
200 auto free_result = fd_table_->Free(-1);
201 EXPECT_FALSE(free_result.has_value());
202}
203
205 File mock_file;
206
207 // 分配 fd
208 auto alloc_result = fd_table_->Alloc(&mock_file);
209 EXPECT_TRUE(alloc_result.has_value());
210 int fd1 = alloc_result.value();
211
212 // 复制 fd
213 auto dup_result = fd_table_->Dup(fd1);
214 EXPECT_TRUE(dup_result.has_value());
215 int fd2 = dup_result.value();
216
217 // fd1 和 fd2 应该指向同一个文件
218 EXPECT_EQ(fd_table_->Get(fd1), fd_table_->Get(fd2));
219
220 // 清理
221 (void)fd_table_->Free(fd1);
222 (void)fd_table_->Free(fd2);
223}
224
225TEST_F(FdTableTest, SetupStandardFiles) {
226 File stdin_file;
227 File stdout_file;
228 File stderr_file;
229
230 auto setup_result =
231 fd_table_->SetupStandardFiles(&stdin_file, &stdout_file, &stderr_file);
232 EXPECT_TRUE(setup_result.has_value());
233
234 // 检查标准文件描述符
235 EXPECT_EQ(fd_table_->Get(0), &stdin_file);
236 EXPECT_EQ(fd_table_->Get(1), &stdout_file);
237 EXPECT_EQ(fd_table_->Get(2), &stderr_file);
238}
239
240// VFS 路径解析测试
241TEST_F(VfsTest, LookupRoot) {
242 // 挂载 mock 文件系统作为根
243 MockFs mock_fs;
244 auto& mount_table = GetMountTable();
245
246 auto mount_result = mount_table.Mount("/", &mock_fs, nullptr);
247 EXPECT_TRUE(mount_result.has_value());
248
249 // 查找根目录
250 auto lookup_result = vfs::Lookup("/");
251 EXPECT_TRUE(lookup_result.has_value());
252 EXPECT_NE(lookup_result.value(), nullptr);
253}
254
255TEST_F(VfsTest, LookupInvalidPaths) {
256 // 空路径
257 auto result = vfs::Lookup(nullptr);
258 EXPECT_FALSE(result.has_value());
259
260 // 相对路径
261 result = vfs::Lookup("relative/path");
262 EXPECT_FALSE(result.has_value());
263}
264
265// VFS 初始化测试
266class VfsInitTest : public BaseEnvTest {};
267TEST_F(VfsInitTest, DoubleInit) {
268 // 第一次初始化
269 auto result = vfs::Init();
270 EXPECT_TRUE(result.has_value());
271
272 // 重复初始化应该成功(幂等)
273 result = vfs::Init();
274 EXPECT_TRUE(result.has_value());
275}
276
277// File 结构测试
278TEST(FileStructTest, FileOperations) {
279 File file;
280 EXPECT_EQ(file.offset, 0);
281 EXPECT_EQ(file.flags, 0);
282 EXPECT_EQ(file.ops, nullptr);
283 EXPECT_EQ(file.inode, nullptr);
284 EXPECT_EQ(file.dentry, nullptr);
285}
286
287// Inode 结构测试
288TEST(InodeStructTest, InodeDefaults) {
289 Inode inode;
290 EXPECT_EQ(inode.ino, 0);
291 EXPECT_EQ(inode.type, FileType::kUnknown);
292 EXPECT_EQ(inode.size, 0);
293 EXPECT_EQ(inode.permissions, 0644);
294 EXPECT_EQ(inode.link_count, 1);
295 EXPECT_EQ(inode.fs_private, nullptr);
296 EXPECT_EQ(inode.fs, nullptr);
297 EXPECT_EQ(inode.ops, nullptr);
298}
299
300// Dentry 结构测试
301TEST(DentryStructTest, DentryDefaults) {
302 Dentry dentry;
303 EXPECT_EQ(dentry.name[0], '\0');
304 EXPECT_EQ(dentry.inode, nullptr);
305 EXPECT_EQ(dentry.parent, nullptr);
306 EXPECT_EQ(dentry.children, nullptr);
307 EXPECT_EQ(dentry.next_sibling, nullptr);
308 EXPECT_EQ(dentry.fs_private, nullptr);
309}
310
311// OpenFlags 测试
312TEST(OpenFlagsTest, FlagValues) {
313 EXPECT_EQ(static_cast<uint32_t>(OpenFlags::kOReadOnly), 0x0000u);
314 EXPECT_EQ(static_cast<uint32_t>(OpenFlags::kOWriteOnly), 0x0001u);
315 EXPECT_EQ(static_cast<uint32_t>(OpenFlags::kOReadWrite), 0x0002u);
316 EXPECT_EQ(static_cast<uint32_t>(OpenFlags::kOCreate), 0x0040u);
317 EXPECT_EQ(static_cast<uint32_t>(OpenFlags::kOTruncate), 0x0200u);
318 EXPECT_EQ(static_cast<uint32_t>(OpenFlags::kOAppend), 0x0400u);
319 EXPECT_EQ(static_cast<uint32_t>(OpenFlags::kODirectory), 0x010000u);
320}
321
322// SeekWhence 测试
323TEST(SeekWhenceTest, EnumValues) {
324 EXPECT_EQ(static_cast<int>(SeekWhence::kSet), 0);
325 EXPECT_EQ(static_cast<int>(SeekWhence::kCur), 1);
326 EXPECT_EQ(static_cast<int>(SeekWhence::kEnd), 2);
327}
void SetUp() override
Definition vfs_test.cpp:100
test_env::TestEnvironmentState env_state_
Definition vfs_test.cpp:106
void TearDown() override
Definition vfs_test.cpp:105
FileDescriptorTable * fd_table_
Definition vfs_test.cpp:155
void TearDown() override
Definition vfs_test.cpp:162
void SetUp() override
Definition vfs_test.cpp:157
auto Close(File *) -> Expected< void > override
关闭文件
Definition vfs_test.cpp:30
auto ReadDir(File *, DirEntry *, size_t) -> Expected< size_t > override
读取目录项
Definition vfs_test.cpp:31
auto Read(File *, void *, size_t) -> Expected< size_t > override
从文件读取数据
Definition vfs_test.cpp:21
auto Write(File *, const void *, size_t) -> Expected< size_t > override
向文件写入数据
Definition vfs_test.cpp:24
auto Seek(File *, int64_t, SeekWhence) -> Expected< uint64_t > override
调整文件偏移量
Definition vfs_test.cpp:27
auto FreeInode(Inode *) -> Expected< void > override
释放 inode
Definition vfs_test.cpp:77
auto AllocateInode() -> Expected< Inode * > override
分配新 inode
Definition vfs_test.cpp:73
MockFileOps mock_file_ops_
Definition vfs_test.cpp:43
Inode root_inode
Definition vfs_test.cpp:45
bool sync_called
Definition vfs_test.cpp:41
BlockDevice * last_device
Definition vfs_test.cpp:42
auto Sync() -> Expected< void > override
将缓存数据刷写到磁盘
Definition vfs_test.cpp:68
auto GetFileOps() -> FileOps *override
获取文件系统的文件操作接口
Definition vfs_test.cpp:79
bool mount_called
Definition vfs_test.cpp:39
bool unmount_called
Definition vfs_test.cpp:40
auto Unmount() -> Expected< void > override
卸载文件系统
Definition vfs_test.cpp:63
auto GetName() const -> const char *override
获取文件系统类型名(如 "ramfs", "fat32")
Definition vfs_test.cpp:53
auto Mount(BlockDevice *device) -> Expected< Inode * > override
挂载文件系统
Definition vfs_test.cpp:57
void TearDown() override
Definition vfs_test.cpp:93
void SetUp() override
Definition vfs_test.cpp:85
test_env::TestEnvironmentState env_state_
Definition vfs_test.cpp:95
进程级文件描述符表
void ClearCurrentThreadEnvironment()
清除当前线程的环境实例指针
void BindThreadToCore(std::thread::id tid, size_t core_id)
将指定线程绑定到核心
void InitializeCores(size_t num_cores)
初始化指定数量的核心
void SetCurrentThreadEnvironment()
设置当前线程的环境实例指针
块设备抽象基类
File 操作接口
文件系统类型基类
挂载表管理器
Definition mount.hpp:34
auto Unmount(const char *path) -> Expected< void >
卸载指定路径的文件系统
Definition mount.cpp:108
auto Mount(const char *path, FileSystem *fs, BlockDevice *device) -> Expected< void >
挂载文件系统到指定路径
Definition mount.cpp:16
auto Lookup(const char *path) -> MountPoint *
根据路径查找对应的挂载点
Definition mount.cpp:158
@ kDeviceNotSupported
std::expected< T, Error > Expected
std::expected 别名模板
Definition expected.hpp:365
SeekWhence
文件 seek 基准
Definition vfs_types.hpp:94
auto Lookup(const char *path) -> Expected< Dentry * >
路径解析,查找 dentry
Definition lookup.cpp:14
auto GetMountTable() -> MountTable &
获取全局挂载表实例
Definition mount.cpp:234
auto Init() -> Expected< void >
VFS 全局初始化
Definition vfs.cpp:80
错误类型,用于 std::expected
Definition expected.hpp:343
Dentry — 目录项缓存(路径名 ↔ Inode 的映射)
Definition vfs.hpp:41
void * fs_private
文件系统私有数据
Definition vfs.hpp:53
Dentry * children
子目录项链表头
Definition vfs.hpp:49
char name[256]
文件/目录名
Definition vfs.hpp:43
Dentry * parent
父目录项
Definition vfs.hpp:47
Inode * inode
关联的 inode
Definition vfs.hpp:45
Dentry * next_sibling
兄弟目录项(同一父目录下)
Definition vfs.hpp:51
目录项结构(用于 readdir)
File — 打开的文件实例(每次 open 产生一个)
Definition vfs.hpp:65
OpenFlags flags
打开标志 (OpenFlags)
Definition vfs.hpp:73
Dentry * dentry
关联的 dentry
Definition vfs.hpp:69
Inode * inode
关联的 inode
Definition vfs.hpp:67
uint64_t offset
当前读写偏移量
Definition vfs.hpp:71
FileOps * ops
文件操作接口
Definition vfs.hpp:76
Inode — 文件元数据(独立于路径名)
Definition vfs.hpp:16
FileSystem * fs
所属文件系统
Definition vfs.hpp:30
uint32_t link_count
硬链接计数
Definition vfs.hpp:26
uint32_t permissions
权限位(简化版)
Definition vfs.hpp:24
uint64_t size
文件大小(字节)
Definition vfs.hpp:22
FileType type
文件类型
Definition vfs.hpp:20
InodeOps * ops
文件操作接口
Definition vfs.hpp:33
uint64_t ino
inode 编号(文件系统内唯一)
Definition vfs.hpp:18
void * fs_private
文件系统私有数据指针
Definition vfs.hpp:28
#define EXPECT_TRUE(cond, msg)
#define EXPECT_NE(val1, val2, msg)
#define EXPECT_FALSE(cond, msg)
#define EXPECT_GE(val1, val2, msg)
#define EXPECT_EQ(val1, val2, msg)
TEST(FileStructTest, FileOperations)
Definition vfs_test.cpp:278
TEST_F(MountTableTest, MountAndUnmount)
Definition vfs_test.cpp:111