/** * @file tests/unit/test_input.cpp * @brief Tests for retained stream input and virtual gamepad lifecycle behavior. */ // standard includes #include #include // local includes #include "../tests_common.h" #include "src/config.h" #include "src/input.h" #include "src/platform/virtualhid_input.h" namespace { /** * @brief Fixture that installs a fake global virtual input backend. */ class InputGamepadSessionTest: public ::testing::Test { protected: /** * @brief Preserve configuration and install observable fake devices. */ void SetUp() override { original_input_ = config::input; config::input.controller = true; config::input.gamepad = "xseries"; auto platform_input = platf::input(); ASSERT_TRUE(platform_input); auto &context = platf::virtualhid::get_input_context(platform_input); context = platf::virtualhid::input_context_t {lvh::BackendKind::fake}; runtime_ = context.runtime.get(); ASSERT_NE(runtime_, nullptr); input::testing::set_platform_input(std::move(platform_input)); } /** * @brief Destroy retained test sessions and restore configuration. */ void TearDown() override { input::terminate_gamepads(); input::testing::set_platform_input({}); runtime_ = nullptr; config::input = std::move(original_input_); } /** * @brief Access the fake runtime installed for the current test. * * @return Fake libvirtualhid runtime. */ lvh::Runtime &runtime() const { return *runtime_; } private: lvh::Runtime *runtime_ = nullptr; ///< Fake runtime installed in the global input backend. config::input_t original_input_; ///< Input configuration restored after each test. }; } // namespace TEST_F(InputGamepadSessionTest, ReusesGamepadsAcrossPauseAndDestroysThemOnTermination) { const std::string session_id = "paired-client-certificate"; auto first_mail = std::make_shared(); auto first = input::alloc(first_mail, session_id); ASSERT_NE(first, nullptr); const auto active_devices_before_gamepad = runtime().active_device_count(); const platf::gamepad_arrival_t metadata {LI_CTYPE_XBOX, 0, 0}; const auto original_id = input::testing::alloc_gamepad(first, 0, metadata); ASSERT_GE(original_id, 0); EXPECT_EQ(runtime().active_device_count(), active_devices_before_gamepad + 1); const std::weak_ptr paused = first; first.reset(); EXPECT_FALSE(paused.expired()); EXPECT_EQ(runtime().active_device_count(), active_devices_before_gamepad + 1); auto resumed_mail = std::make_shared(); auto resumed = input::alloc(resumed_mail, session_id); ASSERT_NE(resumed, nullptr); EXPECT_EQ(paused.lock(), resumed); EXPECT_EQ(input::testing::gamepad_id(resumed, 0), original_id); EXPECT_EQ(runtime().active_device_count(), active_devices_before_gamepad + 1); input::terminate_gamepads(session_id); EXPECT_EQ(input::testing::gamepad_id(resumed, 0), -1); EXPECT_EQ(runtime().active_device_count(), active_devices_before_gamepad); auto replacement = input::alloc(std::make_shared(), session_id); EXPECT_NE(replacement, resumed); }