From e2c08ddb3d79f946399ca5d3bc07b4e6c4de9328 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Wed, 8 Apr 2026 16:21:33 +0200 Subject: add dentry tests --- kernel/CMakeLists.txt | 3 + kernel/include/kernel/filesystem/dentry.hpp | 15 ++- kernel/src/filesystem/dentry.cpp | 9 +- kernel/src/filesystem/dentry.tests.cpp | 136 ++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 kernel/src/filesystem/dentry.tests.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 74233cb..85c7661 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -126,6 +126,9 @@ else() "src/memory/bitmap_allocator.tests.cpp" "src/memory/block_list_allocator.tests.cpp" + # Filesystem Subsystem Tests + "src/filesystem/dentry.tests.cpp" + # Storage Subsystem Tests "src/devices/storage/ram_disk/device.tests.cpp" ) diff --git a/kernel/include/kernel/filesystem/dentry.hpp b/kernel/include/kernel/filesystem/dentry.hpp index 72d758f..58a918f 100644 --- a/kernel/include/kernel/filesystem/dentry.hpp +++ b/kernel/include/kernel/filesystem/dentry.hpp @@ -28,10 +28,13 @@ namespace kernel::filesystem }; /** - @brief Create a dentry with the given @p parent, associated @p node, and optional @p name. The dentry is initialized - with the provided parent and inode, and the name is stored for lookup purposes. + @brief Create a dentry with the given @p parent, associated @p inode, and optional @p name. The dentry is + initialized with the provided parent and inode, and the name is stored for lookup purposes. + @param parent The parent dentry. + @param inode The associated inode for this dentry. + @param name The name of the dentry (optional). */ - dentry(kstd::shared_ptr const & parent, kstd::shared_ptr const & node, std::string_view name = {}); + dentry(kstd::shared_ptr const & parent, kstd::shared_ptr const & inode, std::string_view name = {}); /** @brief Get the associated inode. @@ -45,6 +48,12 @@ namespace kernel::filesystem */ [[nodiscard]] auto get_parent() const -> kstd::shared_ptr const &; + /** + @brief Get the name of the dentry. + @return The name of the dentry. + */ + [[nodiscard]] auto get_name() const -> std::string_view; + /** @brief Add a @p child dentry. @param child The child dentry to add. diff --git a/kernel/src/filesystem/dentry.cpp b/kernel/src/filesystem/dentry.cpp index 2f99e91..6591011 100644 --- a/kernel/src/filesystem/dentry.cpp +++ b/kernel/src/filesystem/dentry.cpp @@ -12,10 +12,10 @@ namespace kernel::filesystem { - dentry::dentry(kstd::shared_ptr const & parent, kstd::shared_ptr const & node, std::string_view name) + dentry::dentry(kstd::shared_ptr const & parent, kstd::shared_ptr const & inode, std::string_view name) : m_name(name) , m_parent(parent) - , m_inode(node) + , m_inode(inode) { if (!m_inode) { @@ -33,6 +33,11 @@ namespace kernel::filesystem return m_parent; } + auto dentry::get_name() const -> std::string_view + { + return m_name.view(); + } + auto dentry::add_child(kstd::shared_ptr const & child) -> void { m_children.push_back(child); diff --git a/kernel/src/filesystem/dentry.tests.cpp b/kernel/src/filesystem/dentry.tests.cpp new file mode 100644 index 0000000..f82024a --- /dev/null +++ b/kernel/src/filesystem/dentry.tests.cpp @@ -0,0 +1,136 @@ +#include "kernel/filesystem/dentry.hpp" + +#include "kernel/filesystem/devfs/inode.hpp" +#include "kernel/test_support/cio.hpp" +#include "kernel/test_support/cpu.hpp" + +#include +#include + +#include + +SCENARIO("Dentry construction", "[filesystem][dentry]") +{ + GIVEN("A parent dentry and inode") + { + auto inode = kstd::make_shared(); + auto parent_dentry = kstd::make_shared(nullptr, inode); + + WHEN("constructing a dentry") + { + auto child_dentry = kernel::filesystem::dentry{parent_dentry, inode, "child"}; + + THEN("the dentry has the correct parent, inode, and name") + { + REQUIRE(child_dentry.get_parent() == parent_dentry); + REQUIRE(child_dentry.get_inode() == inode); + REQUIRE(child_dentry.get_name() == "child"); + } + + THEN("no flag is set") + { + REQUIRE_FALSE(child_dentry.has_flag(kernel::filesystem::dentry::dentry_flags::dcache_mounted)); + } + } + + WHEN("constructing a dentry with an empty name") + { + auto child_dentry = kernel::filesystem::dentry{parent_dentry, inode}; + + THEN("the dentry has the correct parent and inode, and an empty name") + { + REQUIRE(child_dentry.get_parent() == parent_dentry); + REQUIRE(child_dentry.get_inode() == inode); + REQUIRE(child_dentry.get_name().empty()); + } + + THEN("no flag is set") + { + REQUIRE_FALSE(child_dentry.has_flag(kernel::filesystem::dentry::dentry_flags::dcache_mounted)); + } + } + + WHEN("constructing a dentry with a null parent") + { + auto child_dentry = kernel::filesystem::dentry{nullptr, inode, "child"}; + + THEN("the dentry has a null parent, the correct inode, and the correct name") + { + REQUIRE(child_dentry.get_parent() == nullptr); + REQUIRE(child_dentry.get_inode() == inode); + REQUIRE(child_dentry.get_name() == "child"); + } + + THEN("no flag is set") + { + REQUIRE_FALSE(child_dentry.has_flag(kernel::filesystem::dentry::dentry_flags::dcache_mounted)); + } + } + + WHEN("constructing a dentry with a null inode") + { + THEN("the system panics") + { + REQUIRE_THROWS_AS((kernel::filesystem::dentry{parent_dentry, nullptr, "child"}), kernel::tests::cpu::halt); + } + } + } +} + +SCENARIO("Dentry child logic", "[filesystem][dentry]") +{ + GIVEN("A parent dentry and inode") + { + auto inode = kstd::make_shared(); + auto parent_dentry = kstd::make_shared(nullptr, inode); + + WHEN("adding child dentries") + { + auto child1 = kstd::make_shared(parent_dentry, inode, "child1"); + auto child2 = kstd::make_shared(parent_dentry, inode, "child2"); + parent_dentry->add_child(child1); + parent_dentry->add_child(child2); + + THEN("the children can be found by name") + { + REQUIRE(parent_dentry->find_child("child1") == child1); + REQUIRE(parent_dentry->find_child("child2") == child2); + } + + THEN("finding a non-existent child returns null") + { + REQUIRE(parent_dentry->find_child("nonexistent") == nullptr); + } + } + } +} + +SCENARIO("Dentry Flag logic", "[filesystem][dentry]") +{ + GIVEN("A dentry") + { + auto inode = kstd::make_shared(); + auto dentry = kernel::filesystem::dentry{nullptr, inode, "test"}; + + WHEN("setting a flag") + { + dentry.set_flag(kernel::filesystem::dentry::dentry_flags::dcache_mounted); + + THEN("the flag is set") + { + REQUIRE(dentry.has_flag(kernel::filesystem::dentry::dentry_flags::dcache_mounted)); + } + } + + WHEN("unsetting a flag") + { + dentry.set_flag(kernel::filesystem::dentry::dentry_flags::dcache_mounted); + dentry.unset_flag(kernel::filesystem::dentry::dentry_flags::dcache_mounted); + + THEN("the flag is unset") + { + REQUIRE_FALSE(dentry.has_flag(kernel::filesystem::dentry::dentry_flags::dcache_mounted)); + } + } + } +} -- cgit v1.2.3