diff options
Diffstat (limited to 'kernel/src/filesystem/ext2/inode.tests.cpp')
| -rw-r--r-- | kernel/src/filesystem/ext2/inode.tests.cpp | 376 |
1 files changed, 0 insertions, 376 deletions
diff --git a/kernel/src/filesystem/ext2/inode.tests.cpp b/kernel/src/filesystem/ext2/inode.tests.cpp deleted file mode 100644 index 4aecc04a..00000000 --- a/kernel/src/filesystem/ext2/inode.tests.cpp +++ /dev/null @@ -1,376 +0,0 @@ -#include <kernel/filesystem/ext2/inode.hpp> - -#include <kernel/devices/storage/management.hpp> -#include <kernel/filesystem/device_inode.hpp> -#include <kernel/filesystem/ext2/filesystem.hpp> -#include <kernel/filesystem/ext2/superblock.hpp> -#include <kernel/filesystem/filesystem.hpp> -#include <kernel/test_support/cpu.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 <algorithm> -#include <cstddef> -#include <filesystem> -#include <string_view> - -SCENARIO("Ext2 inode initialization and properties", "[filesystem][ext2][inode]") -{ - GIVEN("an ext2 filesystem") - { - auto fs = kernel::filesystem::ext2::filesystem{}; - auto data = kernel::filesystem::ext2::inode_data{}; - - THEN("the inode is initialized with regular file mode in data and has the kind regular") - { - data.mode = kernel::filesystem::ext2::constants::mode_regular; - auto inode = kernel::filesystem::ext2::inode(&fs, data); - - REQUIRE(inode.is_regular()); - REQUIRE_FALSE(inode.is_directory()); - REQUIRE_FALSE(inode.is_device()); - REQUIRE_FALSE(inode.is_symbolic_link()); - } - - THEN("the inode is initialized with directory mode in data and has the kind directory") - { - data.mode = kernel::filesystem::ext2::constants::mode_directory; - auto inode = kernel::filesystem::ext2::inode(&fs, data); - - REQUIRE_FALSE(inode.is_regular()); - REQUIRE(inode.is_directory()); - REQUIRE_FALSE(inode.is_device()); - REQUIRE_FALSE(inode.is_symbolic_link()); - } - - THEN("the inode is initialized with symbolic link mode in data and has the kind symbolic link") - { - data.mode = kernel::filesystem::ext2::constants::mode_symbolic_link; - auto inode = kernel::filesystem::ext2::inode(&fs, data); - - REQUIRE_FALSE(inode.is_regular()); - REQUIRE_FALSE(inode.is_directory()); - REQUIRE_FALSE(inode.is_device()); - REQUIRE(inode.is_symbolic_link()); - } - - THEN("the inode is initialized with zero mode in data and has no specific kind") - { - data.mode = 0; - auto inode = kernel::filesystem::ext2::inode(&fs, data); - - REQUIRE_FALSE(inode.is_regular()); - REQUIRE_FALSE(inode.is_directory()); - REQUIRE_FALSE(inode.is_device()); - REQUIRE_FALSE(inode.is_symbolic_link()); - } - } - - GIVEN("no filesystem (null pointer)") - { - THEN("constructing an inode with a null filesystem pointer panics") - { - REQUIRE_THROWS_AS(kernel::filesystem::ext2::inode(nullptr, {}), kernel::tests::cpu::halt); - } - } -} - -SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 inode reads from real image", - "[filesystem][ext2][inode][img]") -{ - auto const image_path = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_1KB_fs.img"; - - GIVEN("a mounted ext2 filesystem and a regular file inode") - { - 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 dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(boot_device); - - auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); - - auto information = fs.lookup(fs.root_inode(), "information"); - REQUIRE(information != nullptr); - auto file = fs.lookup(information, "info_1.txt"); - REQUIRE(file != nullptr); - REQUIRE(file->is_regular()); - - THEN("reading from offset zero returns expected file prefix") - { - auto buffer = kstd::vector<std::byte>(6); - auto const bytes_read = file->read(buffer.data(), 0, buffer.size()); - - REQUIRE(bytes_read == 6); - - auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), bytes_read}; - REQUIRE(text == "info_1"); - } - - THEN("reading with an offset returns the expected byte") - { - auto buffer = kstd::vector<std::byte>(1); - auto const bytes_read = file->read(buffer.data(), 5, buffer.size()); - - REQUIRE(bytes_read == 1); - REQUIRE(static_cast<char>(buffer[0]) == '1'); - } - } -} - -SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesystem][ext2][inode]") -{ - auto const block_size = 1024uz; - GIVEN("an ext2 inode with only direct mapped data blocks") - { - auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 64 * block_size); - REQUIRE(device != nullptr); - kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device); - - auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device); - - auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); - - auto data = kernel::filesystem::ext2::inode_data{}; - data.block[0] = 30; - data.block[1] = 0; - data.block[2] = 31; - data.size = block_size * 3; - - kernel::tests::filesystem::ext2::write_bytes(*device, 30 * block_size, "Hello", 5); - kernel::tests::filesystem::ext2::write_bytes(*device, 31 * block_size, "World!", 6); - - auto inode = kernel::filesystem::ext2::inode{&fs, data}; - - auto buffer = kstd::vector<std::byte>(data.size, std::byte{0xAB}); - - THEN("correct number of bytes are read and holes are returned as zeros") - { - auto const bytes_read = inode.read(buffer.data(), 0, buffer.size()); - REQUIRE(bytes_read == data.size); - - auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), bytes_read}; - REQUIRE(text.substr(0, 5) == "Hello"); - REQUIRE(std::ranges::all_of(text.substr(5, block_size - 5), [](char c) { return c == '\0'; })); - REQUIRE(text.substr(2 * block_size, 6) == "World!"); - REQUIRE(std::ranges::all_of(text.substr(2 * block_size + 6, 3 * block_size), [](char c) { return c == '\0'; })); - } - } - - GIVEN("an ext2 indode with file holes in singly indirect blocks") - { - auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 64 * block_size); - REQUIRE(device != nullptr); - kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device); - - auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device); - - auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); - - auto data = kernel::filesystem::ext2::inode_data{}; - data.block[0] = 30; - data.block[12] = 31; - data.size = block_size * 15; - - kernel::tests::filesystem::ext2::write_u32(*device, 31 * block_size, 50); - kernel::tests::filesystem::ext2::write_u32(*device, 31 * block_size + 4, 0); - kernel::tests::filesystem::ext2::write_u32(*device, 31 * block_size + 8, 51); - - kernel::tests::filesystem::ext2::write_bytes(*device, 30 * block_size, "Hello", 5); - kernel::tests::filesystem::ext2::write_bytes(*device, 50 * block_size, "Blub", 4); - kernel::tests::filesystem::ext2::write_bytes(*device, 51 * block_size, "World!", 6); - - auto inode = kernel::filesystem::ext2::inode{&fs, data}; - - auto buffer = kstd::vector<std::byte>(data.size, std::byte{0xAB}); - - THEN("correct number of bytes are read and holes are returned as zeros") - { - auto const bytes_read = inode.read(buffer.data(), 0, buffer.size()); - REQUIRE(bytes_read == data.size); - - auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), bytes_read}; - REQUIRE(text.substr(0, 5) == "Hello"); - REQUIRE(std::ranges::all_of(text.substr(5, 12 * block_size - 5), [](char c) { return c == '\0'; })); - REQUIRE(text.substr(12 * block_size, 4) == "Blub"); - REQUIRE( - std::ranges::all_of(text.substr(12 * block_size + 4, 2 * block_size - 4), [](char c) { return c == '\0'; })); - REQUIRE(text.substr(14 * block_size, 6) == "World!"); - REQUIRE( - std::ranges::all_of(text.substr(14 * block_size + 6, 1 * block_size - 6), [](char c) { return c == '\0'; })); - } - } - - GIVEN("an ext2 inode with zero singly indirect block pointer") - { - auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 64 * block_size); - REQUIRE(device != nullptr); - kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device); - - auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device); - - auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); - - auto data = kernel::filesystem::ext2::inode_data{}; - data.block[12] = 0; - data.size = block_size * 15; - - auto inode = kernel::filesystem::ext2::inode{&fs, data}; - - auto buffer = kstd::vector<std::byte>(block_size * 15, std::byte{0xAB}); - - THEN("all direct blocks are zero when singly indirect block pointer is zero") - { - auto const bytes_read = inode.read(buffer.data(), 0, buffer.size()); - REQUIRE(bytes_read == buffer.size()); - REQUIRE(std::ranges::all_of(buffer, [](std::byte c) { return c == std::byte{0x00}; })); - } - } -} - -SCENARIO("Ext2 inode read across block boundaries", "[filesystem][ext2][inode]") -{ - auto const block_size = 1024uz; - GIVEN("an ext2 inode with two direct blocks and a block size of 1024 bytes") - { - auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 64 * block_size); - REQUIRE(device != nullptr); - kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device); - - auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device); - - auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); - - auto inode_data = kernel::filesystem::ext2::inode_data{}; - inode_data.size = block_size * 2; - inode_data.block[0] = 20; - kernel::tests::filesystem::ext2::write_bytes(*device, 21 * block_size - 6, "Hello ", 6); - inode_data.block[1] = 21; - kernel::tests::filesystem::ext2::write_bytes(*device, 21 * block_size, "World!", 6); - auto inode = kernel::filesystem::ext2::inode{&fs, inode_data}; - - auto buffer = kstd::vector<std::byte>(12, std::byte{0x00}); - - THEN("reading across the block boundary returns the combined content") - { - auto const bytes_read = inode.read(buffer.data(), block_size - 6, buffer.size()); - REQUIRE(bytes_read == 12); - - auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), bytes_read}; - REQUIRE(text == "Hello World!"); - } - } -} - -SCENARIO("Ext2 inode write is not implemented", "[filesystem][ext2][inode]") -{ - GIVEN("an ext2 inode") - { - auto fs = kernel::filesystem::ext2::filesystem{}; - auto inode = kernel::filesystem::ext2::inode{&fs, kernel::filesystem::ext2::inode_data{}}; - - THEN("writing to the inode panics") - { - auto buffer = kstd::vector<std::byte>(32, std::byte{0x00}); - REQUIRE_THROWS_AS(inode.write(buffer.data(), 0, buffer.size()), kernel::tests::cpu::halt); - } - } -} - -SCENARIO("Ext2 inode get_size() correctly returns size depending on revision level", "[filesystem][ext2][inode]") -{ - auto const block_size = 1024uz; - - auto superblock = kernel::filesystem::ext2::superblock{}; - superblock.magic = kernel::filesystem::ext2::constants::magic_number; - superblock.log_block_size = 0; - superblock.blocks_count = 64; - superblock.blocks_per_group = 64; - superblock.inodes_per_group = 32; - superblock.inode_size = 128; - - GIVEN("an ext2 inode with good old revision and inode_data.size = 256, inode_data.dir_acl = 32") - { - superblock.rev_level = 0; - - auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 64 * block_size); - REQUIRE(device != nullptr); - kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device, superblock); - - auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device); - - auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); - - auto data = kernel::filesystem::ext2::inode_data{}; - data.size = 256; - data.dir_acl = 32; - - THEN("the inode size is 256 if mode = regular") - { - data.mode = kernel::filesystem::ext2::constants::mode_regular; - - auto inode = kernel::filesystem::ext2::inode{&fs, data}; - - REQUIRE(inode.size() == 256); - } - - THEN("the inode size is 256 if mode = directory") - { - data.mode = kernel::filesystem::ext2::constants::mode_directory; - - auto inode = kernel::filesystem::ext2::inode{&fs, data}; - - REQUIRE(inode.size() == 256); - } - } - - GIVEN("an ext2 inode with good dynamic revision and inode_data.size = 256, inode_data.dir_acl = 32") - { - superblock.rev_level = 1; - - auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 64 * block_size); - REQUIRE(device != nullptr); - kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device, superblock); - - auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device); - - auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); - - auto data = kernel::filesystem::ext2::inode_data{}; - data.size = 256; - data.dir_acl = 32; - - THEN("the inode size is 256 if mode = regular") - { - data.mode = kernel::filesystem::ext2::constants::mode_regular; - - auto inode = kernel::filesystem::ext2::inode{&fs, data}; - - REQUIRE(inode.size() == 0x0000'0020'0000'0100); - } - - THEN("the inode size is 256 if mode = directory") - { - data.mode = kernel::filesystem::ext2::constants::mode_directory; - - auto inode = kernel::filesystem::ext2::inode{&fs, data}; - - REQUIRE(inode.size() == 256); - } - } -}
\ No newline at end of file |
