From 32e34486215b46a1a244962998c893640b18a792 Mon Sep 17 00:00:00 2001 From: manuel Date: Thu, 29 Oct 2026 10:03:17 +0000 Subject: kernel/filesystem: Add inode:read --- kernel/kapi/filesystem.tests.cpp | 92 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) (limited to 'kernel/kapi/filesystem.tests.cpp') diff --git a/kernel/kapi/filesystem.tests.cpp b/kernel/kapi/filesystem.tests.cpp index efcb4fd3..f46c6bb8 100644 --- a/kernel/kapi/filesystem.tests.cpp +++ b/kernel/kapi/filesystem.tests.cpp @@ -12,7 +12,9 @@ #include #include #include +#include #include +#include #include using namespace kstd::units_literals; @@ -339,4 +341,94 @@ SCENARIO_METHOD(kernel::tests::vfs::storage_boot_module_vfs_fixture, } } +SCENARIO_METHOD(kernel::tests::vfs::storage_boot_module_vfs_fixture, "Kapi filesystem with a mounted fat32 image", + "[kapi][filesystem][fat32]") +{ + auto const ext2_image_path = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_1KB_fs.img"; + auto const fat32_image_path = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "fat32.img"; + + GIVEN("an ext2 root filesystem with a fat32 image mounted on /information") + { + REQUIRE(std::filesystem::exists(ext2_image_path)); + REQUIRE(std::filesystem::exists(fat32_image_path)); + REQUIRE_NOTHROW(setup_modules_from_img_and_init_vfs({"test_img_module_1", "test_img_module_2"}, + {ext2_image_path, fat32_image_path})); + REQUIRE(kapi::filesystem::mount("/dev/ram1", "/information")); + + auto const read_text = [](std::size_t fd, std::size_t chunk_size) { + auto text = std::string{}; + auto buffer = std::vector(chunk_size); + while (true) + { + auto const bytes_read = kapi::filesystem::read(fd, buffer); + REQUIRE(bytes_read); + if (*bytes_read == 0_B) + { + return text; + } + text.append(std::bit_cast(buffer.data()), bytes_read->value); + } + }; + + THEN("a file can be opened by its lowercase name, read and closed again") + { + auto const fd = kapi::filesystem::open("/information/hello.txt"); + REQUIRE(fd); + REQUIRE(read_text(*fd, 64) == "Hello World!"); + REQUIRE(kapi::filesystem::close(*fd)); + } + + THEN("a file can be read in small chunks through its file descriptor") + { + auto const fd = kapi::filesystem::open("/information/hello.txt"); + REQUIRE(fd); + REQUIRE(read_text(*fd, 5) == "Hello World!"); + REQUIRE(kapi::filesystem::close(*fd)); + } + + THEN("reading continues at a seeked position") + { + auto const fd = kapi::filesystem::open("/information/hello.txt"); + REQUIRE(fd); + REQUIRE(kapi::filesystem::seek(*fd, 6_B_off, kapi::filesystem::seek_origin::beginning) == 6_B); + REQUIRE(read_text(*fd, 16) == "World!"); + REQUIRE(kapi::filesystem::close(*fd)); + } + + THEN("the status of a file reports its type and size") + { + auto const status = kapi::filesystem::status("/information/hello.txt"); + REQUIRE(status); + REQUIRE(status->mode == std::to_underlying(kapi::filesystem::file_type::regular)); + REQUIRE(status->size == 12_B); + } + + THEN("the mounted root directory can be listed") + { + auto const directory = kapi::filesystem::open("/information"); + REQUIRE(directory); + + auto buffer = std::vector{10}; + REQUIRE(kapi::filesystem::read_directory(*directory, buffer) == 1); + REQUIRE(buffer[0].name == "HELLO.TXT"); + REQUIRE(kapi::filesystem::read_directory(*directory, buffer) == 0); + } + + THEN("writing to a file fails because the filesystem is read only") + { + auto const fd = kapi::filesystem::open("/information/hello.txt"); + REQUIRE(fd); + + auto const buffer = std::vector{std::byte{'X'}}; + REQUIRE(kapi::filesystem::write(*fd, buffer).error() == kstd::errc::read_only_file_system); + REQUIRE(kapi::filesystem::close(*fd)); + } + + THEN("opening a missing file fails") + { + REQUIRE(kapi::filesystem::open("/information/missing.txt").error() == kstd::errc::no_such_file_or_directory); + } + } +} + // NOLINTEND (readability-magic-numbers) \ No newline at end of file -- cgit v1.2.3