diff options
Diffstat (limited to 'kernel/kapi/devices/interface_registry.tests.cpp')
| -rw-r--r-- | kernel/kapi/devices/interface_registry.tests.cpp | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/kernel/kapi/devices/interface_registry.tests.cpp b/kernel/kapi/devices/interface_registry.tests.cpp new file mode 100644 index 00000000..ffd9f0d6 --- /dev/null +++ b/kernel/kapi/devices/interface_registry.tests.cpp @@ -0,0 +1,199 @@ +#include <kapi/devices.hpp> + +#include <kstd/memory.hpp> + +#include <catch2/catch_test_macros.hpp> + +namespace +{ + struct probe_device + { + constexpr auto static id = kapi::devices::interface{"probe"}; + + virtual ~probe_device() = default; + + [[nodiscard]] auto virtual get_value() const noexcept -> int = 0; + }; + + struct const_device + { + constexpr auto static id = kapi::devices::interface{"flip"}; + + virtual ~const_device() = default; + + [[nodiscard]] auto get_constant() const noexcept -> int + { + return 0; + } + }; + + struct test_device final : kapi::devices::device, probe_device + { + explicit test_device(int value, const_device & const_device) + : device{0, 0, "probeable"} + , m_value{value} + , m_const_device{&const_device} + {} + + auto init() -> bool override + { + return true; + } + + [[nodiscard]] constexpr auto get_value() const noexcept -> int override + { + return m_value; + } + + auto query_interface(kapi::devices::interface interface) -> void * override + { + if (interface == probe_device::id) + { + return static_cast<probe_device *>(this); + } + if (interface == const_device::id) + { + return m_const_device; + } + + return kapi::devices::device::query_interface(interface); + } + + private: + int m_value; + const_device * m_const_device; + }; + +} // namespace + +SCENARIO("Publishing and finding a device", "[kapi][devices][interface_registry]") +{ + GIVEN("An empty registry, a device, and an interface the device implements by inheritance") + { + auto registry = kapi::devices::interface_registry{}; + auto free_standing_interface = const_device{}; + auto device = kstd::make_shared<test_device>(128, free_standing_interface); + + THEN("Publishing an interface without a name fails") + { + REQUIRE_FALSE(registry.publish<probe_device>(device, "")); + } + + WHEN("publishing the interface for the device") + { + CHECK(device->is_a<probe_device>()); + CHECK(device->is_a<const_device>()); + auto published = registry.publish(device, "probe0", device->as<probe_device>()); + + THEN("publishing is successful") + { + REQUIRE(published); + } + + THEN("publishing the same device and interface with a different name fails") + { + REQUIRE_FALSE(registry.publish(device, "probe1", device->as<probe_device>())); + } + + THEN("publishing a second interface for the same device succeeds") + { + REQUIRE(registry.publish<const_device>(device, "probe0")); + } + + THEN("publishing a free standing second interface for the same device succeeds") + { + REQUIRE(registry.publish(device, "probe0", &free_standing_interface)); + } + + AND_WHEN("getting all devices implementing that interface") + { + auto probeable_devices = registry.all(probe_device::id); + + THEN("there is exactly one such device") + { + REQUIRE(probeable_devices.size() == 1); + } + + THEN("the name of the device is 'probe0'") + { + REQUIRE(probeable_devices[0].name() == "probe0"); + } + + THEN("the returned device pointer is lockable") + { + REQUIRE(probeable_devices[0].device().lock()); + } + + THEN("the returned implementation equals the result of device::as") + { + REQUIRE(probeable_devices[0].implementation() == device->as<probe_device>()); + } + + THEN("the interface provided function can be invoked") + { + auto implementation = probeable_devices[0].as<probe_device>(); + REQUIRE(implementation->get_value() == device->get_value()); + } + } + + THEN("find finds the published capability by name") + { + REQUIRE(registry.find<probe_device>("probe0")); + } + + THEN("find for an unpublished capability does not find a device") + { + REQUIRE_FALSE(registry.find<const_device>("probe0")); + } + + THEN("find for an unpublished device does not find a device") + { + REQUIRE_FALSE(registry.find<probe_device>("probe1")); + } + + THEN("withdrawing an interface for a device removes it from the registry") + { + registry.unpublish(*device, probe_device::id); + REQUIRE_FALSE(registry.find<probe_device>("probe0")); + } + } + + WHEN("the device is destroyed without withdrawing it") + { + CHECK(registry.publish(device, "probe0", device->as<probe_device>())); + device.reset(); + + THEN("querying all does no longer report it") + { + REQUIRE(registry.all(probe_device::id).empty()); + } + + THEN("find() no longer finds it") + { + REQUIRE_FALSE(registry.find<probe_device>("probe0")); + } + } + } + + GIVEN("no device has ever been published") + { + auto registry = kapi::devices::interface_registry{}; + + THEN("all() returns an empty vector") + { + REQUIRE(registry.all(probe_device::id).empty()); + } + } + + GIVEN("a null device") + { + auto registry = kapi::devices::interface_registry{}; + auto device = kstd::shared_ptr<kapi::devices::device>{}; + auto interface = const_device{}; + + THEN("publishing the interface for the device fails") + { + REQUIRE_FALSE(registry.publish(device, "probe0", &interface)); + } + } +} |
