aboutsummaryrefslogtreecommitdiff
path: root/kernel/src/filesystem/ext2/filesystem.tests.cpp
diff options
context:
space:
mode:
authorMarcel Braun <marcel.braun@ost.ch>2026-04-12 19:15:38 +0200
committerMarcel Braun <marcel.braun@ost.ch>2026-04-12 19:15:38 +0200
commit4d2a1d028f8ba28b655026b93124e71a12562619 (patch)
treef49deef4dd3e8728fd1000b04c0908966f37663f /kernel/src/filesystem/ext2/filesystem.tests.cpp
parent21fd1281cf19572e202d583689b99c33ec68da50 (diff)
parentcb7edbe6d4454ee5b217b522f62f4a7b92475a32 (diff)
downloadteachos-develop-BA-FS26.tar.xz
teachos-develop-BA-FS26.zip
Merge branch 'ext2' into 'develop-BA-FS26'HEADdevelop-BA-FS26
ext2 and tests See merge request teachos/kernel!22
Diffstat (limited to 'kernel/src/filesystem/ext2/filesystem.tests.cpp')
-rw-r--r--kernel/src/filesystem/ext2/filesystem.tests.cpp132
1 files changed, 132 insertions, 0 deletions
diff --git a/kernel/src/filesystem/ext2/filesystem.tests.cpp b/kernel/src/filesystem/ext2/filesystem.tests.cpp
new file mode 100644
index 0000000..b13ebf3
--- /dev/null
+++ b/kernel/src/filesystem/ext2/filesystem.tests.cpp
@@ -0,0 +1,132 @@
+#include "kernel/filesystem/ext2/filesystem.hpp"
+
+#include "kernel/devices/storage/management.hpp"
+#include "kernel/filesystem/ext2/inode.hpp"
+#include "kernel/filesystem/filesystem.hpp"
+#include "kernel/test_support/devices/block_device.hpp"
+#include "kernel/test_support/filesystem/ext2.hpp"
+#include "kernel/test_support/filesystem/storage_boot_module_fixture.hpp"
+
+#include <kstd/memory>
+#include <kstd/vector>
+
+#include <catch2/catch_test_macros.hpp>
+
+#include <array>
+#include <cstdint>
+#include <filesystem>
+
+SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture,
+ "Ext2 filesystem mount and lookup with real image", "[filesystem][ext2][filesystem][img]")
+{
+ auto const image_path = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_1KB_fs.img";
+
+ GIVEN("a mounted ext2 filesystem from a real image")
+ {
+ REQUIRE(std::filesystem::exists(image_path));
+ REQUIRE_NOTHROW(setup_modules_from_img({"test_img_module"}, {image_path}));
+
+ auto boot_device = kernel::devices::storage::management::get().determine_boot_device();
+ REQUIRE(boot_device != nullptr);
+
+ auto fs = kernel::filesystem::ext2::filesystem{};
+ REQUIRE(fs.mount(boot_device) == kernel::filesystem::filesystem::operation_result::success);
+
+ THEN("the root inode is available and is a directory")
+ {
+ REQUIRE(fs.root_inode() != nullptr);
+ REQUIRE(fs.root_inode()->is_directory());
+ }
+
+ THEN("lookup resolves known entries from the image")
+ {
+ auto information = fs.lookup(fs.root_inode(), "information");
+ REQUIRE(information != nullptr);
+ REQUIRE(information->is_directory());
+
+ auto info_1 = fs.lookup(information, "info_1.txt");
+ REQUIRE(info_1 != nullptr);
+ REQUIRE(info_1->is_regular());
+ }
+
+ THEN("lookup returns null for invalid inputs")
+ {
+ REQUIRE(fs.lookup(nullptr, "information") == nullptr);
+
+ auto information = fs.lookup(fs.root_inode(), "information");
+ REQUIRE(information != nullptr);
+ auto info_1 = fs.lookup(information, "info_1.txt");
+ REQUIRE(info_1 != nullptr);
+
+ REQUIRE(fs.lookup(info_1, "anything") == nullptr);
+ REQUIRE(fs.lookup(fs.root_inode(), "does_not_exist") == nullptr);
+ }
+ }
+}
+
+SCENARIO("Ext2 filesystem rejects invalid magic", "[filesystem][ext2][filesystem]")
+{
+ auto const block_size = 1024;
+ GIVEN("a block device that does not contain an ext2 superblock")
+ {
+ auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 2 * block_size);
+ REQUIRE(device != nullptr);
+
+ auto fs = kernel::filesystem::ext2::filesystem{};
+
+ THEN("mount fails with invalid_magic_number")
+ {
+ REQUIRE(fs.mount(device) == kernel::filesystem::filesystem::operation_result::invalid_magic_number);
+ }
+ }
+}
+
+SCENARIO("Ext2 block mapping includes direct and all indirect levels", "[filesystem][ext2][filesystem]")
+{
+ auto const block_size = 1024;
+
+ GIVEN("a minimally valid ext2 layout with configured indirect block tables")
+ {
+ auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 128 * block_size);
+ REQUIRE(device != nullptr);
+
+ kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device);
+
+ auto fs = kernel::filesystem::ext2::filesystem{};
+ REQUIRE(fs.mount(device) == kernel::filesystem::filesystem::operation_result::success);
+
+ auto inode_data = kernel::filesystem::ext2::inode_data{};
+ inode_data.block[0] = 7;
+
+ inode_data.block[12] = 30;
+ kernel::tests::filesystem::ext2::write_u32(*device, 30 * block_size, 31);
+
+ inode_data.block[13] = 40;
+ kernel::tests::filesystem::ext2::write_u32(*device, 40 * block_size, 41);
+ kernel::tests::filesystem::ext2::write_u32(*device, 41 * block_size, 42);
+
+ inode_data.block[14] = 50;
+ kernel::tests::filesystem::ext2::write_u32(*device, 50 * block_size, 51);
+ kernel::tests::filesystem::ext2::write_u32(*device, 51 * block_size, 52);
+ kernel::tests::filesystem::ext2::write_u32(*device, 52 * block_size, 53);
+
+ auto const numbers_per_block = static_cast<uint32_t>(block_size / sizeof(uint32_t));
+ auto const singly_start = static_cast<uint32_t>(kernel::filesystem::ext2::constants::direct_block_count);
+ auto const doubly_start = singly_start + numbers_per_block;
+ auto const triply_start = doubly_start + numbers_per_block * numbers_per_block;
+
+ THEN("mapping resolves direct, singly, doubly and triply indirect indexes")
+ {
+ REQUIRE(fs.map_inode_block_index_to_global_block_number(0, inode_data) == 7);
+ REQUIRE(fs.map_inode_block_index_to_global_block_number(singly_start, inode_data) == 31);
+ REQUIRE(fs.map_inode_block_index_to_global_block_number(doubly_start, inode_data) == 42);
+ REQUIRE(fs.map_inode_block_index_to_global_block_number(triply_start, inode_data) == 53);
+ }
+
+ THEN("mapping returns zero for out-of-range indexes")
+ {
+ auto const beyond_triply = triply_start + numbers_per_block * numbers_per_block * numbers_per_block;
+ REQUIRE(fs.map_inode_block_index_to_global_block_number(beyond_triply, inode_data) == 0);
+ }
+ }
+}