From ce14236bd08469737185962d0be11d72c442b60e Mon Sep 17 00:00:00 2001 From: WBoerenkamps Date: Wed, 20 Nov 2024 15:39:27 +0100 Subject: most tests done --- src/crepe/api/Event.h | 12 +- src/crepe/api/EventHandler.cpp | 3 +- src/crepe/api/EventHandler.h | 6 +- src/crepe/api/EventHandler.hpp | 8 +- src/crepe/api/EventManager.cpp | 11 +- src/crepe/api/EventManager.h | 32 ++- src/crepe/api/EventManager.hpp | 24 +- src/crepe/api/IKeyListener.cpp | 35 +-- src/crepe/api/IKeyListener.h | 21 +- src/crepe/api/IMouseListener.cpp | 34 +-- src/crepe/api/IMouseListener.h | 22 +- src/crepe/facade/SDLContext.cpp | 1 - src/example/events.cpp | 74 +++--- src/test/CMakeLists.txt | 1 + src/test/EventTest.cpp | 470 +++++++++++++++++++++++++++++++++++++++ 15 files changed, 584 insertions(+), 170 deletions(-) create mode 100644 src/test/EventTest.cpp diff --git a/src/crepe/api/Event.h b/src/crepe/api/Event.h index d5ddf0a..33f3add 100644 --- a/src/crepe/api/Event.h +++ b/src/crepe/api/Event.h @@ -7,17 +7,15 @@ /** * \brief Base class for all event types in the system. */ -class Event { -public: -}; +class Event {}; /** * \brief Event triggered when a key is pressed. */ class KeyPressEvent : public Event { public: - //! Number of times the key press is repeated (e.g., for long presses). - int repeat = 0; + //! false if first time press, true if key is repeated + bool repeat = false; //! The key that was pressed. Keycode key = Keycode::NONE; @@ -110,6 +108,4 @@ public: /** * \brief Event triggered to indicate the application is shutting down. */ -class ShutDownEvent : public Event { -public: -}; +class ShutDownEvent : public Event {}; diff --git a/src/crepe/api/EventHandler.cpp b/src/crepe/api/EventHandler.cpp index 186ec9c..4dc232f 100644 --- a/src/crepe/api/EventHandler.cpp +++ b/src/crepe/api/EventHandler.cpp @@ -2,5 +2,4 @@ using namespace crepe; -// Implementation of IEventHandlerWrapper::exec -bool IEventHandlerWrapper::exec(const Event & e) { return call(e); } +bool IEventHandlerWrapper::exec(const Event & e) { return this->call(e); } diff --git a/src/crepe/api/EventHandler.h b/src/crepe/api/EventHandler.h index db51d04..90886aa 100644 --- a/src/crepe/api/EventHandler.h +++ b/src/crepe/api/EventHandler.h @@ -13,6 +13,8 @@ namespace crepe { * indicating whether the event is handled. * * \tparam EventType The type of event this handler will handle. + * + * Returning \c false from an event handler results in the event being propogated to other listeners for the same event type, while returning \c true stops propogation altogether. */ template using EventHandler = std::function; @@ -105,9 +107,9 @@ private: std::string get_type() const override; //! The event handler function. - EventHandler m_handler; + EventHandler handler; //! The type name of the handler function. - const std::string m_handler_type; + const std::string handler_type; }; } // namespace crepe diff --git a/src/crepe/api/EventHandler.hpp b/src/crepe/api/EventHandler.hpp index 9c47da2..a1e774d 100644 --- a/src/crepe/api/EventHandler.hpp +++ b/src/crepe/api/EventHandler.hpp @@ -8,19 +8,19 @@ namespace crepe { // Implementation of EventHandlerWrapper constructor template EventHandlerWrapper::EventHandlerWrapper(const EventHandler & handler) - : m_handler(handler), - m_handler_type(m_handler.target_type().name()) {} + : handler(handler), + handler_type(handler.target_type().name()) {} // Implementation of EventHandlerWrapper::call template bool EventHandlerWrapper::call(const Event & e) { - return m_handler(static_cast(e)); + return this->handler(static_cast(e)); } // Implementation of EventHandlerWrapper::get_type template std::string EventHandlerWrapper::get_type() const { - return m_handler_type; + return this->handler_type; } } //namespace crepe diff --git a/src/crepe/api/EventManager.cpp b/src/crepe/api/EventManager.cpp index b465e89..27a304f 100644 --- a/src/crepe/api/EventManager.cpp +++ b/src/crepe/api/EventManager.cpp @@ -13,9 +13,9 @@ void EventManager::dispatch_events() { using HandlersVec = std::vector>; for (auto event_it = this->events_queue.begin(); event_it != this->events_queue.end();) { - std::unique_ptr & event = std::get<0>(*event_it); - int channel = std::get<1>(*event_it); - std::type_index event_type = std::get<2>(*event_it); + std::unique_ptr & event = (*event_it).event; + int channel = (*event_it).channel; + std::type_index event_type = (*event_it).type; bool event_handled = false; @@ -58,3 +58,8 @@ void EventManager::dispatch_events() { } } } +void EventManager::clear(){ + this->subscribers.clear(); + this->events_queue.clear(); + this->subscribers_by_event_id.clear(); +} diff --git a/src/crepe/api/EventManager.h b/src/crepe/api/EventManager.h index 92273df..8fd22f4 100644 --- a/src/crepe/api/EventManager.h +++ b/src/crepe/api/EventManager.h @@ -11,7 +11,7 @@ #include "EventHandler.h" namespace crepe { - +static constexpr int CHANNEL_ALL = -1; /** * \class EventManager * \brief The EventManager class is responsible for managing the subscription, triggering, @@ -19,6 +19,7 @@ namespace crepe { */ class EventManager { public: + /** * \brief Get the singleton instance of the EventManager. * @@ -38,7 +39,7 @@ public: * \param channel The channel number to subscribe to (default is 0). */ template - void subscribe(EventHandler && callback, int channel = 0); + void subscribe(const EventHandler & callback, int channel = CHANNEL_ALL, int priority = 0); /** * \brief Unsubscribe from an event. @@ -50,7 +51,7 @@ public: * \param channel The event ID to unsubscribe from. */ template - void unsubscribe(const EventHandler &, int channel = 0); + void unsubscribe(const EventHandler &, int channel = CHANNEL_ALL); /** * \brief Trigger an event. @@ -62,7 +63,7 @@ public: * \param channel The channel from which to trigger the event (default is 0). */ template - void trigger_event(const EventType & event, int channel = 0); + void trigger_event(const EventType & event, int channel = CHANNEL_ALL); /** * \brief Queue an event for later processing. @@ -75,7 +76,7 @@ public: * \param channel The channel number for the event (default is 0). */ template - void queue_event(EventType && event, int channel = 0); + void queue_event(const EventType & event, int channel = CHANNEL_ALL,int priority = 0); /** * \brief Dispatch all queued events. @@ -84,8 +85,24 @@ public: * callbacks for each event. */ void dispatch_events(); - + /** + * \brief clears all subscribers + * + */ + void clear(); private: + struct QueueEntry { + std::unique_ptr event; + int channel = 0; + std::type_index type; + int priority = 0; + }; + struct CallbackEntry { + std::unique_ptr callback; + int channel = 0; + std::type_index type; + int priority = 0; + }; /** * \brief Default constructor for the EventManager. * @@ -94,7 +111,7 @@ private: EventManager() = default; //! The queue of events to be processed. - std::vector, int, std::type_index>> events_queue; + std::vector events_queue; //! Registered event handlers. std::unordered_map>> subscribers; @@ -103,6 +120,7 @@ private: std::type_index, std::unordered_map>>> subscribers_by_event_id; + }; } // namespace crepe diff --git a/src/crepe/api/EventManager.hpp b/src/crepe/api/EventManager.hpp index b20b88f..9090a3f 100644 --- a/src/crepe/api/EventManager.hpp +++ b/src/crepe/api/EventManager.hpp @@ -3,7 +3,7 @@ namespace crepe { template -void EventManager::subscribe(EventHandler && callback, int channel) { +void EventManager::subscribe(const EventHandler & callback, int channel, int priority) { using HandlersMap = std::unordered_map>>; using HandlersVec = std::vector>; @@ -27,14 +27,20 @@ void EventManager::subscribe(EventHandler && callback, int channel) { } template -void EventManager::queue_event(EventType && event, int channel) { - std::type_index event_type = std::type_index(typeid(EventType)); +void EventManager::queue_event(const EventType & event, int channel,int priority) { + static_assert(std::is_base_of::value, "EventType must derive from Event"); + std::type_index event_type = typeid(EventType); - auto event_ptr = std::make_unique(std::forward(event)); + auto event_ptr = std::make_unique(event); - std::tuple, int, std::type_index> tuple(std::move(event_ptr), - channel, event_type); - this->events_queue.push_back(std::move(tuple)); + + this->events_queue.push_back( + QueueEntry{ + .event = std::move(event_ptr), + .channel = channel, + .type = event_type + } + ); } template @@ -43,7 +49,7 @@ void EventManager::trigger_event(const EventType & event, int channel) { = std::unordered_map>>; using HandlersVec = std::vector>; - std::type_index event_type = std::type_index(typeid(EventType)); + std::type_index event_type = typeid(EventType); if (channel > 0) { HandlersMap & handlers_map = this->subscribers_by_event_id[event_type]; @@ -75,7 +81,7 @@ void EventManager::unsubscribe(const EventHandler & callback, int cha = std::unordered_map>>; using HandlersVec = std::vector>; - std::type_index event_type(typeid(EventType)); + std::type_index event_type = typeid(EventType); std::string handler_name = callback.target_type().name(); if (channel) { diff --git a/src/crepe/api/IKeyListener.cpp b/src/crepe/api/IKeyListener.cpp index f5426be..5e7d9bb 100644 --- a/src/crepe/api/IKeyListener.cpp +++ b/src/crepe/api/IKeyListener.cpp @@ -2,13 +2,6 @@ using namespace crepe; -// Constructor with default channel -IKeyListener::IKeyListener() - : channel(0), - active(true), - event_manager(EventManager::get_instance()) { - this->subscribe_events(); -} // Constructor with specified channel IKeyListener::IKeyListener(int channel) @@ -28,9 +21,9 @@ void IKeyListener::subscribe_events() { key_released_handler = [this](const KeyReleaseEvent & event) { return this->on_key_released(event); }; - event_manager.subscribe(std::move(this->key_pressed_handler), + event_manager.subscribe(this->key_pressed_handler, this->channel); - event_manager.subscribe(std::move(this->key_released_handler), + event_manager.subscribe(this->key_released_handler, this->channel); } @@ -40,27 +33,3 @@ void IKeyListener::unsubscribe_events() { event_manager.unsubscribe(this->key_released_handler, this->channel); } -// Activate key listening -void IKeyListener::activate_keys() { - if (this->active) { - return; - } - this->active = true; - this->subscribe_events(); -} - -// Deactivate key listening -void IKeyListener::deactivate_keys() { - if (!this->active) { - return; - } - this->active = false; - this->unsubscribe_events(); -} - -// Set a new channel for key events -void IKeyListener::set_channel(int channel) { - this->unsubscribe_events(); - this->channel = channel; - this->subscribe_events(); -} diff --git a/src/crepe/api/IKeyListener.h b/src/crepe/api/IKeyListener.h index d492387..70243b4 100644 --- a/src/crepe/api/IKeyListener.h +++ b/src/crepe/api/IKeyListener.h @@ -16,11 +16,11 @@ public: * \brief Constructs an IKeyListener with a specified channel. * \param channel The channel ID for event handling. */ - IKeyListener(int channel); - IKeyListener(); + IKeyListener(int channel = CHANNEL_ALL); virtual ~IKeyListener(); IKeyListener(const IKeyListener &) = delete; IKeyListener & operator=(const IKeyListener &) = delete; + IKeyListener & operator=(IKeyListener &&) = delete; IKeyListener(IKeyListener &&) = delete; /** @@ -36,23 +36,6 @@ public: * \return True if the event was handled, false otherwise. */ virtual bool on_key_released(const KeyReleaseEvent & event) = 0; - - /** - * \brief Activates key listening. - */ - void activate_keys(); - - /** - * \brief Deactivates key listening. - */ - void deactivate_keys(); - - /** - * \brief Sets the channel ID for event handling. - * \param channel The channel ID to set. - */ - void set_channel(int channel); - protected: /** * \brief Subscribes to key events. diff --git a/src/crepe/api/IMouseListener.cpp b/src/crepe/api/IMouseListener.cpp index 5ee2814..6fd6c4b 100644 --- a/src/crepe/api/IMouseListener.cpp +++ b/src/crepe/api/IMouseListener.cpp @@ -8,10 +8,6 @@ IMouseListener::IMouseListener(int channel) this->subscribe_events(); } -IMouseListener::IMouseListener() : event_manager(EventManager::get_instance()) { - this->subscribe_events(); -} - IMouseListener::~IMouseListener() { this->unsubscribe_events(); } void IMouseListener::subscribe_events() { @@ -26,11 +22,11 @@ void IMouseListener::subscribe_events() { = [this](const MouseMoveEvent & event) { return this->on_mouse_moved(event); }; // Subscribe event handlers (no need for std::move) - event_manager.subscribe(std::move(mouse_click_handler), this->channel); - event_manager.subscribe(std::move(mouse_press_handler), this->channel); - event_manager.subscribe(std::move(mouse_release_handler), + event_manager.subscribe(mouse_click_handler, this->channel); + event_manager.subscribe(mouse_press_handler, this->channel); + event_manager.subscribe(mouse_release_handler, this->channel); - event_manager.subscribe(std::move(mouse_move_handler), this->channel); + event_manager.subscribe(mouse_move_handler, this->channel); } void IMouseListener::unsubscribe_events() { @@ -40,25 +36,3 @@ void IMouseListener::unsubscribe_events() { event_manager.unsubscribe(mouse_release_handler, this->channel); event_manager.unsubscribe(mouse_move_handler, this->channel); } - -void IMouseListener::activate_mouse() { - if (this->active) { - return; - } - this->subscribe_events(); - this->active = true; -} - -void IMouseListener::deactivate_mouse() { - if (!this->active) { - return; - } - this->unsubscribe_events(); - this->active = false; -} - -void IMouseListener::set_channel(int channel) { - this->unsubscribe_events(); - this->channel = channel; - this->subscribe_events(); -} diff --git a/src/crepe/api/IMouseListener.h b/src/crepe/api/IMouseListener.h index 921a760..1195a4e 100644 --- a/src/crepe/api/IMouseListener.h +++ b/src/crepe/api/IMouseListener.h @@ -12,16 +12,15 @@ namespace crepe { */ class IMouseListener { public: - IMouseListener(); /** * \brief Constructs an IMouseListener with a specified channel. * \param channel The channel ID for event handling. */ - IMouseListener(int channel); + IMouseListener(int channel = CHANNEL_ALL); virtual ~IMouseListener(); IMouseListener & operator=(const IMouseListener &) = delete; IMouseListener(const IMouseListener &) = delete; - IMouseListener && operator=(const IMouseListener &&) = delete; + IMouseListener & operator=(const IMouseListener &&) = delete; IMouseListener(IMouseListener &&) = delete; /** @@ -56,23 +55,6 @@ public: * \return True if the event was handled, false otherwise. */ virtual bool on_mouse_moved(const MouseMoveEvent & event) = 0; - - /** - * \brief Activates mouse listening. - */ - void activate_mouse(); - - /** - * \brief Deactivates mouse listening. - */ - void deactivate_mouse(); - - /** - * \brief Sets the channel ID for event handling. - * \param channel The channel ID to set. - */ - void set_channel(int channel); - protected: /** * \brief Subscribes to mouse events on the specified channel. diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index 83e91f8..9464c31 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -78,7 +78,6 @@ SDLContext::~SDLContext() { IMG_Quit(); SDL_Quit(); } - void SDLContext::handle_events(bool & running) { //TODO: wouter i need events /* diff --git a/src/example/events.cpp b/src/example/events.cpp index 6431c67..402a857 100644 --- a/src/example/events.cpp +++ b/src/example/events.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -27,7 +26,6 @@ class MyScript : public Script, public IKeyListener, public IMouseListener { bool on_key_pressed(const KeyPressEvent & event) override { std::cout << "KeyPressed function" << std::endl; - this->deactivate_keys(); return false; } bool on_key_released(const KeyReleaseEvent & event) override { @@ -65,48 +63,60 @@ public: } }; int main() { - // two events to trigger - KeyPressEvent key_press; - key_press.key = Keycode::A; - key_press.repeat = 0; - MouseClickEvent click_event; - click_event.button = MouseButton::LEFT_MOUSE; - click_event.mouse_x = 100; - click_event.mouse_y = 200; - // queue events to test queue - EventManager::get_instance().queue_event(std::move(key_press), 0); - EventManager::get_instance().queue_event(std::move(click_event), 0); + { + // two events to trigger + KeyPressEvent key_press; + key_press.key = Keycode::A; + key_press.repeat = 0; + MouseClickEvent click_event; + click_event.button = MouseButton::LEFT_MOUSE; + click_event.mouse_x = 100; + click_event.mouse_y = 200; + // queue events to test queue + EventManager::get_instance().queue_event(key_press); + EventManager::get_instance().queue_event(click_event); TestKeyListener test_listener; - test_listener.set_channel(1); - auto obj = GameObject(0, "name", "tag", Vector2{1.2, 3.4}, 0, 1); - obj.add_component().set_script(); + //auto obj = GameObject(0, "name", "tag", Vector2{1.2, 3.4}, 0, 1); + //obj.add_component().set_script(); - ScriptSystem sys; - sys.update(); + //ScriptSystem sys; + //sys.update(); // Trigger the events while `testListener` is in scope - EventManager::get_instance().trigger_event(key_press, 1); - EventManager::get_instance().trigger_event( - MouseClickEvent{ - .mouse_x = 100, - .mouse_y = 100, - .button = MouseButton::LEFT_MOUSE, - }, - 1); + //EventManager::get_instance().trigger_event(key_press, 1); + // EventManager::get_instance().trigger_event( + // MouseClickEvent{ + // .mouse_x = 100, + // .mouse_y = 100, + // .button = MouseButton::LEFT_MOUSE, + // }, + // 1); + //EventManager::get_instance().trigger_event(click_event, 0); } // custom lambda event handler EventHandler event_handler = [](const KeyPressEvent & e) { - std::cout << "lambda test" << std::endl; + std::cout << "key lambda test" << std::endl; + return true; + }; + EventHandler event_handler2 = [](const MouseClickEvent & e) { + std::cout << "mouse lambda test" << std::endl; return false; }; - EventManager::get_instance().subscribe(std::move(event_handler), 0); + EventManager::get_instance().subscribe(event_handler, CHANNEL_ALL); + EventManager::get_instance().subscribe(event_handler, CHANNEL_ALL); + EventManager::get_instance().subscribe(event_handler2, CHANNEL_ALL); + EventManager::get_instance().trigger_event(KeyPressEvent{ + .repeat = false, + .key = Keycode::A + }); + //EventManager::get_instance().unsubscribe(event_handler, 0); // testing trigger with testListener not in scope (unsubscribed) - EventManager::get_instance().trigger_event(key_press, 0); - EventManager::get_instance().trigger_event(click_event, 0); + // EventManager::get_instance().trigger_event(key_press, 0); + // EventManager::get_instance().trigger_event(click_event, 0); // dispatching queued events - EventManager::get_instance().dispatch_events(); + //EventManager::get_instance().dispatch_events(); - EventManager::get_instance().unsubscribe(event_handler, 0); + EventManager::get_instance().unsubscribe(event_handler); return EXIT_SUCCESS; } diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 49c8151..6f6ad79 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -3,5 +3,6 @@ target_sources(test_main PUBLIC PhysicsTest.cpp ScriptTest.cpp ParticleTest.cpp + EventTest.cpp ) diff --git a/src/test/EventTest.cpp b/src/test/EventTest.cpp new file mode 100644 index 0000000..19f6d2e --- /dev/null +++ b/src/test/EventTest.cpp @@ -0,0 +1,470 @@ + +#include "api/EventManager.h" +#include "api/Event.h" +#include "api/IKeyListener.h" +#include "api/IMouseListener.h" +#include +#include +#include +using namespace std; +using namespace std::chrono_literals; +using namespace crepe; + + +class EventManagerTest : public ::testing::Test { +protected: + void SetUp() override { + // Clear any existing subscriptions or events before each test + EventManager::get_instance().clear(); + } + + void TearDown() override { + // Ensure cleanup after each test + EventManager::get_instance().clear(); + } +}; +class MockKeyListener : public IKeyListener { +public: + MOCK_METHOD(bool, on_key_pressed, (const KeyPressEvent& event), (override)); + MOCK_METHOD(bool, on_key_released, (const KeyReleaseEvent& event), (override)); +}; + +class MockMouseListener : public IMouseListener { +public: + MOCK_METHOD(bool, on_mouse_clicked, (const MouseClickEvent& event), (override)); + MOCK_METHOD(bool, on_mouse_pressed, (const MousePressEvent& event), (override)); + MOCK_METHOD(bool, on_mouse_released, (const MouseReleaseEvent& event), (override)); + MOCK_METHOD(bool, on_mouse_moved, (const MouseMoveEvent& event), (override)); +}; +TEST_F(EventManagerTest, EventSubscription) { + EventHandler key_handler = [](const KeyPressEvent& e) { + std::cout << "Key Event Triggered" << std::endl; + return true; + }; + + // Subscribe to KeyPressEvent + EventManager::get_instance().subscribe(key_handler, 1); + + // Verify subscription (not directly verifiable; test by triggering event) + + EventManager::get_instance().trigger_event(KeyPressEvent{ + .repeat = true, + .key = Keycode::A, + }, 1); + EventManager::get_instance().trigger_event(KeyPressEvent{ + .repeat = true, + .key = Keycode::A, + + }, CHANNEL_ALL); + +} +TEST_F(EventManagerTest, EventManagerTest_trigger_all_channels) { + bool triggered = false; + + EventHandler mouse_handler = [&](const MouseClickEvent& e) { + triggered = true; + std::cout << "mouse handled" <(mouse_handler, CHANNEL_ALL); + + MouseClickEvent click_event{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }; + EventManager::get_instance().trigger_event(click_event, CHANNEL_ALL); + + EXPECT_TRUE(triggered); +} + +TEST_F(EventManagerTest, EventManagerTest_priority_order) { + EventManager& event_manager = EventManager::get_instance(); + + // Vector to track call order + std::vector call_order; + + // Handlers with different priorities + EventHandler handler_priority_3 = [&](const MouseClickEvent& e) { + call_order.push_back(3); + return false; // Allow propagation + }; + + EventHandler handler_priority_1 = [&](const MouseClickEvent& e) { + call_order.push_back(1); + return false; // Allow propagation + }; + + EventHandler handler_priority_2 = [&](const MouseClickEvent& e) { + call_order.push_back(2); + return false; // Allow propagation + }; + + // Subscribe handlers with different priorities + event_manager.subscribe(handler_priority_1, CHANNEL_ALL, 1); + event_manager.subscribe(handler_priority_2, CHANNEL_ALL, 2); + event_manager.subscribe(handler_priority_3, CHANNEL_ALL, 3); + + // Trigger the event + event_manager.trigger_event(MouseClickEvent{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }, CHANNEL_ALL); + + // Check the call order matches the expected priority order + std::vector expected_order = {3, 2, 1}; + EXPECT_EQ(call_order, expected_order); + +} + +TEST_F(EventManagerTest, EventManagerTest_callback_propagation) { + EventManager& event_manager = EventManager::get_instance(); + + // Flags to track handler calls + bool triggered_true = false; + bool triggered_false = false; + + // Handlers + EventHandler mouse_handler_true = [&](const MouseClickEvent& e) { + triggered_true = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return true; // Stops propagation + }; + + EventHandler mouse_handler_false = [&](const MouseClickEvent& e) { + triggered_false = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + + // Test event + MouseClickEvent click_event{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }; + + // First Scenario: True handler has higher priority + event_manager.subscribe(mouse_handler_true, CHANNEL_ALL, 1); + event_manager.subscribe(mouse_handler_false, CHANNEL_ALL, 0); + + // Trigger event + event_manager.trigger_event(click_event, CHANNEL_ALL); + + // Check that only the true handler was triggered + EXPECT_TRUE(triggered_true); + EXPECT_FALSE(triggered_false); + + // Reset and clear + triggered_true = false; + triggered_false = false; + event_manager.clear(); + + // Second Scenario: False handler has higher priority + event_manager.subscribe(mouse_handler_true, CHANNEL_ALL, 0); + event_manager.subscribe(mouse_handler_false, CHANNEL_ALL, 1); + + // Trigger event again + event_manager.trigger_event(click_event, CHANNEL_ALL); + + // Check that both handlers were triggered + EXPECT_TRUE(triggered_true); + EXPECT_TRUE(triggered_false); +} + +TEST_F(EventManagerTest, EventManagerTest_queue_dispatch) { + EventManager& event_manager = EventManager::get_instance(); + bool triggered1 = false; + bool triggered2 = false; + int test_channel = 1; + EventHandler mouse_handler1 = [&](const MouseClickEvent& e) { + triggered1 = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + EventHandler mouse_handler2 = [&](const MouseClickEvent& e) { + triggered2 = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + event_manager.subscribe(mouse_handler1); + event_manager.subscribe(mouse_handler2,test_channel); + + event_manager.queue_event(MouseClickEvent{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }); + event_manager.queue_event(MouseClickEvent{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + },test_channel); + event_manager.dispatch_events(); + EXPECT_TRUE(triggered1); + EXPECT_TRUE(triggered2); +} + +TEST_F(EventManagerTest, EventManagerTest_dispatch_priority) { + EventManager& event_manager = EventManager::get_instance(); + std::vector call_order; + int test_channel = 1; + EventHandler mouse_handler1 = [&](const MouseClickEvent& e) { + call_order.push_back(1); + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + EventHandler mouse_handler2 = [&](const MouseClickEvent& e) { + call_order.push_back(2); + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + EventHandler mouse_handler3 = [&](const MouseClickEvent& e) { + call_order.push_back(3); + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + event_manager.subscribe(mouse_handler1,CHANNEL_ALL,1); + event_manager.subscribe(mouse_handler2,CHANNEL_ALL,2); + event_manager.subscribe(mouse_handler2,CHANNEL_ALL,3); + event_manager.queue_event(MouseClickEvent{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }); + event_manager.dispatch_events(); + std::vector expected_order = {3, 2, 1}; + EXPECT_EQ(call_order, expected_order); +} + +TEST_F(EventManagerTest, EventManagerTest_unsubscribe) { + EventManager& event_manager = EventManager::get_instance(); + + // Flags to track if handlers are triggered + bool triggered1 = false; + bool triggered2 = false; + + // Define EventHandlers + EventHandler mouse_handler1 = [&](const MouseClickEvent& e) { + triggered1 = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + + EventHandler mouse_handler2 = [&](const MouseClickEvent& e) { + triggered2 = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + + // Subscribe handlers + event_manager.subscribe(mouse_handler1); + event_manager.subscribe(mouse_handler2); + + // Queue events + event_manager.queue_event(MouseClickEvent{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }); + + // Dispatch events - both handlers should be triggered + event_manager.dispatch_events(); + EXPECT_TRUE(triggered1); // Handler 1 should be triggered + EXPECT_TRUE(triggered2); // Handler 2 should be triggered + + // Reset flags + triggered1 = false; + triggered2 = false; + + // Unsubscribe handler1 + event_manager.unsubscribe(mouse_handler1); + + // Queue the same event again + event_manager.queue_event(MouseClickEvent{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }); + + // Dispatch events - only handler 2 should be triggered, handler 1 should NOT + event_manager.dispatch_events(); + EXPECT_FALSE(triggered1); // Handler 1 should NOT be triggered + EXPECT_TRUE(triggered2); // Handler 2 should be triggered + + // Reset flags + triggered2 = false; + + // Unsubscribe handler2 + event_manager.unsubscribe(mouse_handler2); + + // Queue the event again + event_manager.queue_event(MouseClickEvent{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }); + + // Dispatch events - no handler should be triggered + event_manager.dispatch_events(); + EXPECT_FALSE(triggered1); // Handler 1 should NOT be triggered + EXPECT_FALSE(triggered2); // Handler 2 should NOT be triggered +} + +// TEST_F(EventManagerTest, OnKeyPressedTest) { +// MockKeyListener mock_key_listener; +// EventManager& event_manager = EventManager::get_instance(); + +// // Create the KeyPressEvent object +// KeyPressEvent key_event = KeyPressEvent{ +// .key = Keycode::A, +// .repeat = false +// }; + +// // Set up the mock expectation with direct object passing +// EXPECT_CALL(mock_key_listener, on_key_pressed(key_event)) +// .Times(1) // Expect it to be called exactly once +// .WillOnce(::testing::Return(true)); // Return value (can be true/false) + + +// // Queue the event +// event_manager.queue_event(key_event); + +// // Dispatch the event to trigger the mock +// event_manager.dispatch_events(); // Trigger event dispatch + +// // The mock will ensure the on_key_pressed method is called +// } + + + +// TEST_F(EventManagerTest, OnKeyReleaseTest) { +// MockKeyListener mock_key_listener; +// EventManager& event_manager = EventManager::get_instance(); + +// // Create the KeyPressEvent object +// KeyReleaseEvent key_event = KeyReleaseEvent{ +// .key = Keycode::A, +// }; + +// // Set up the mock expectation with direct object passing +// EXPECT_CALL(mock_key_listener, on_key_released(key_event)) +// .Times(1) // Expect it to be called exactly once +// .WillOnce(::testing::Return(true)); // Return value (can be true/false) + + +// // Queue the event +// event_manager.queue_event(key_event); + +// // Dispatch the event to trigger the mock +// event_manager.dispatch_events(); // Trigger event dispatch + +// // The mock will ensure the on_key_pressed method is called +// } + +// TEST_F(EventManagerTest, UnsubscribeEventsTest) { +// EventManager& event_manager = EventManager::get_instance(); +// KeyPressEvent key_event{ +// .key = Keycode::A, +// .repeat = false +// }; + +// // Create the mock listener +// MockKeyListener mock_key_listener; + +// // Set up the mock expectation that on_key_pressed will be called once initially +// EXPECT_CALL(mock_key_listener, on_key_pressed(key_event)) +// .Times(1) // Expect it to be called exactly once +// .WillOnce(::testing::Return(true)); // Return value (can be true/false) + +// event_manager.queue_event(key_event); +// event_manager.dispatch_events(); // Should trigger on_key_pressed once + +// // Now unsubscribe the listener +// event_manager.unsubscribe(std::bind(&MockKeyListener::on_key_pressed, &mock_key_listener, std::placeholders::_1)); + +// // Set up the expectation that on_key_pressed will NOT be called after unsubscribing +// EXPECT_CALL(mock_key_listener, on_key_pressed(key_event)) +// .Times(0); // Should not be called after unsubscribe + +// // Queue and dispatch the event again (after unsubscribe) +// event_manager.queue_event(key_event); +// event_manager.dispatch_events(); // Should NOT trigger on_key_pressed after unsubscribe +// } + +// TEST_F(EventManagerTest, OnMouseButtonPressedTest) { +// MockMouseListener mock_mouse_listener; +// EventManager& event_manager = EventManager::get_instance(); + +// // Create the MouseButtonPressEvent object +// MousePressEvent mouse_event{ +// .mouse_x = 100, +// .mouse_y = 150, +// .button = MouseButton::LEFT_MOUSE +// }; + +// // Set up the mock expectation with direct object passing +// EXPECT_CALL(mock_mouse_listener, on_mouse_pressed(mouse_event)) +// .Times(1) // Expect it to be called exactly once +// .WillOnce(::testing::Return(true)); // Return value (can be true/false) + +// // Queue the event +// event_manager.queue_event(mouse_event); + +// // Dispatch the event to trigger the mock +// event_manager.dispatch_events(); // Should trigger on_mouse_button_pressed once +// } + +// TEST_F(EventManagerTest, UnsubscribeMouseEventsTest) { +// EventManager& event_manager = EventManager::get_instance(); +// MousePressEvent mouse_event{ +// .mouse_x = 100, +// .mouse_y = 150, +// .button = MouseButton::LEFT_MOUSE +// }; + +// // Create the mock listener +// MockMouseListener mock_mouse_listener; + +// // Set up the mock expectation that on_mouse_button_pressed will be called once initially +// EXPECT_CALL(mock_mouse_listener, on_mouse_pressed(mouse_event)) +// .Times(1) // Expect it to be called exactly once +// .WillOnce(::testing::Return(true)); // Return value (can be true/false) + +// // Queue and dispatch the event (should trigger on_mouse_button_pressed) +// event_manager.queue_event(mouse_event); +// event_manager.dispatch_events(); // Should trigger on_mouse_button_pressed once + +// // Now unsubscribe the listener +// event_manager.unsubscribe(std::bind(&MockMouseListener::on_mouse_pressed, &mock_mouse_listener, std::placeholders::_1)); + +// // Set up the expectation that on_mouse_button_pressed will NOT be called after unsubscribing +// EXPECT_CALL(mock_mouse_listener, on_mouse_pressed(mouse_event)) +// .Times(0); // Should not be called after unsubscribe + +// // Queue and dispatch the event again (after unsubscribe) +// event_manager.queue_event(mouse_event); +// event_manager.dispatch_events(); // Should NOT trigger on_mouse_button_pressed after unsubscribe +// } -- cgit v1.2.3