diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/kapi/devices/bus.tests.cpp | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/kernel/kapi/devices/bus.tests.cpp b/kernel/kapi/devices/bus.tests.cpp new file mode 100644 index 00000000..d5a2d1cf --- /dev/null +++ b/kernel/kapi/devices/bus.tests.cpp @@ -0,0 +1,104 @@ +#include <kapi/devices.hpp> + +#include <kstd/memory.hpp> +#include <kstd/string.hpp> + +#include <catch2/catch_test_macros.hpp> + +namespace +{ + + struct test_bus final : kapi::devices::bus + { + using kapi::devices::bus::bus; + }; + + struct test_device final : kapi::devices::device + { + using kapi::devices::device::device; + + auto init() -> bool override + { + return true; + } + }; + + struct flagging_device final : kapi::devices::device + { + flagging_device(kstd::string const & name, bool & destroyed_flag) + : device{name} + , m_destroyed_flag{&destroyed_flag} + {} + + ~flagging_device() override + { + *m_destroyed_flag = true; + } + + auto init() -> bool override + { + return true; + } + + private: + bool * m_destroyed_flag; + }; + +} // namespace + +SCENARIO("A bus shares ownership of its children, holding a weak link to its parent", "[devices][bus]") +{ + GIVEN("A bus with one attached child device") + { + auto parent_bus = kstd::make_shared<test_bus>("bus_ownership_parent"); + auto child = kstd::make_shared<test_device>("bus_ownership_child"); + + parent_bus->add_child(child); + + THEN("the child is reachable through children()") + { + REQUIRE(parent_bus->children().size() == 1); + REQUIRE(parent_bus->children()[0]->name() == "bus_ownership_child"); + } + + THEN("the child's parent resolves back to the bus") + { + auto locked_parent = child->parent(); + REQUIRE(locked_parent); + REQUIRE(locked_parent->name() == "bus_ownership_parent"); + } + + WHEN("the bus is destroyed while the caller still holds the child directly") + { + parent_bus.reset(); + + THEN("the child outlives the bus") + { + REQUIRE(child != nullptr); + } + + THEN("the child's parent link no longer resolves") + { + REQUIRE(child->parent() == nullptr); + } + } + } + + GIVEN("a bus that is the only thing keeping its child alive") + { + auto destroyed = false; + auto parent_bus = kstd::make_shared<test_bus>("bus_lifetime_parent"); + parent_bus->add_child(kstd::make_shared<flagging_device>("bus_lifetime_child", destroyed)); + + WHEN("the bus is destroyed") + { + CHECK_FALSE(destroyed); + parent_bus.reset(); + + THEN("the child is destroyed along with it") + { + REQUIRE(destroyed); + } + } + } +} |
