From 85590192d44f7b9b9d15b17477397d157b136ed3 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Thu, 20 Nov 2025 21:24:16 -0600 Subject: [PATCH] chore(style): clean up line endings in event tests --- test/Event.cpp | 1225 ++++++++++++++++++++++---------------------- test/EventTest.cpp | 57 +-- test/EventTest.hpp | 139 +++-- 3 files changed, 708 insertions(+), 713 deletions(-) diff --git a/test/Event.cpp b/test/Event.cpp index 0b8a687..01a9e41 100644 --- a/test/Event.cpp +++ b/test/Event.cpp @@ -1,613 +1,612 @@ -#include "EventTest.hpp" - - -static void STORMAPI TestBreakEventHandlerSelf(void* data) { - EventHandlerTest::RegisterCall(10, data); - - CHECK(SEvtBreakHandlerChain(data) == 1); -} - -static void STORMAPI TestBreakEventHandlerOther(void* data) { - EventHandlerTest::RegisterCall(10, data); - - CHECK(SEvtBreakHandlerChain(nullptr) == 1); -} - -TEST_CASE("SEvtBreakHandlerChain", "[event]") { - EventHandlerTest test; - - SECTION("can use nullptr as data") { - CHECK(SEvtBreakHandlerChain(nullptr) == 1); - - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); - CHECK(SEvtDispatch(7357, 1, 0, nullptr) == 0); - CHECK(SEvtDispatch(7357, 1, 0, nullptr) == 1); - } - - SECTION("causes SEvtDispatch to break early if one of many data matches") { - int data1 = 42, data2 = 1337, data3 = 0xFFFFFFFF; - - CHECK(SEvtBreakHandlerChain(nullptr) == 1); - CHECK(SEvtBreakHandlerChain(&data1) == 1); - CHECK(SEvtBreakHandlerChain(&data2) == 1); - CHECK(SEvtBreakHandlerChain(&data3) == 1); - - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); - CHECK(SEvtDispatch(7357, 1, 0, &data2) == 0); - - // CLEANUP - SEvtDestroy doesn't erase registered breaks, avoid polluting other tests - CHECK(SEvtDispatch(7357, 1, 0, nullptr) == 0); - CHECK(SEvtDispatch(7357, 1, 0, &data1) == 0); - CHECK(SEvtDispatch(7357, 1, 0, &data3) == 0); - } - - SECTION("doesn't break SEvtDispatch if no data matches") { - int data1 = 42, data2 = 1337, data3 = 0xFFFFFFFF; - - CHECK(SEvtBreakHandlerChain(nullptr) == 1); - CHECK(SEvtBreakHandlerChain(&data1) == 1); - CHECK(SEvtBreakHandlerChain(&data2) == 1); - CHECK(SEvtBreakHandlerChain(&data3) == 1); - - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); - CHECK(SEvtDispatch(7357, 1, 0, &test) == 1); - - // CLEANUP - SEvtDestroy doesn't erase registered breaks, avoid polluting other tests - CHECK(SEvtDispatch(7357, 1, 0, nullptr) == 0); - CHECK(SEvtDispatch(7357, 1, 0, &data1) == 0); - CHECK(SEvtDispatch(7357, 1, 0, &data2) == 0); - CHECK(SEvtDispatch(7357, 1, 0, &data3) == 0); - } - - SECTION("deduplicates multiple same-data breaks") { - CHECK(SEvtBreakHandlerChain(&test) == 1); - CHECK(SEvtBreakHandlerChain(&test) == 1); - CHECK(SEvtBreakHandlerChain(&test) == 1); - - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); - CHECK(SEvtDispatch(7357, 1, 0, &test) == 0); - CHECK(SEvtDispatch(7357, 1, 0, &test) == 1); - } - - SECTION("causes a dispatch to stop during handling") { - SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); - SEvtRegisterHandler(0, 0, 0, 0, &TestBreakEventHandlerSelf); - SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler2); - - CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); - CHECK(test.NumCalls() == 2); - // Calls are reverse order, TestEventHandler1 doesn't get called - CHECK_THAT(test.CallResult(), MatchesCall({ 2, nullptr })); - CHECK_THAT(test.CallResult(), MatchesCall({ 10, nullptr })); - } - - SECTION("doesn't cause a dispatch to stop during handling if data differs") { - SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); - SEvtRegisterHandler(0, 0, 0, 0, &TestBreakEventHandlerOther); - SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler2); - - int data = 42; - CHECK(SEvtDispatch(0, 0, 0, &data) == 1); - CHECK(test.NumCalls() == 3); - // Calls are reverse order, TestEventHandler1 doesn't get called - CHECK_THAT(test.CallResult(), MatchesCall({ 2, &data })); - CHECK_THAT(test.CallResult(), MatchesCall({ 10, &data })); - CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); - - // CLEANUP - SEvtDestroy doesn't erase registered breaks, avoid polluting other tests - CHECK(SEvtDispatch(0, 0, 0, nullptr) == 0); - } -} - -#if !defined(WHOA_TEST_STORMDLL) -TEST_CASE("SEvtDestroy", "[event]") { - EventHandlerTest test; - - SECTION("always returns 1") { - CHECK(SEvtDestroy() == 1); - } - - SECTION("destroys all event handlers") { - SEvtRegisterHandler(1, 1, 1, 0, &TestEventHandler1); - CHECK(SEvtDispatch(1, 1, 1, nullptr) == 1); - CHECK(test.NumCalls() == 1); - - CHECK(SEvtDispatch(1, 1, 1, nullptr) == 1); - CHECK(test.NumCalls() == 2); - - CHECK(SEvtDestroy() == 1); - - // Can't increment calls since the handler was destroyed - CHECK(SEvtDispatch(1, 1, 1, nullptr) == 0); - CHECK(test.NumCalls() == 2); - } - - SECTION("doesn't destroy break data") { - // not ideal but it's official behaviour - SEvtBreakHandlerChain(nullptr); - - CHECK(SEvtDestroy() == 1); - - SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); - CHECK(SEvtDispatch(0, 0, 0, nullptr) == 0); - CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); - } -} -#endif - -static void STORMAPI TestNestedDispatchEventHandler(void* data) { - EventHandlerTest::RegisterCall(20, data); - - CHECK(SEvtDispatch(1337, 420, 69, nullptr) == 1); -} - -TEST_CASE("SEvtDispatch", "[event]") { - EventHandlerTest test; - - SECTION("sends data to an event handler") { - SEvtRegisterHandler(1337, 42, 5, 0, &TestEventHandler1); - - int data = 5; - CHECK(SEvtDispatch(1337, 42, 5, &data) == 1); - - REQUIRE(test.NumCalls() == 1); - CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); - } - - SECTION("can use 0 as valid handler ids") { - SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); - - int data = 5; - CHECK(SEvtDispatch(0, 0, 0, &data) == 1); - - REQUIRE(test.NumCalls() == 1); - CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); - } - - SECTION("can pass nullptr to a handler") { - SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); - - CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); - - REQUIRE(test.NumCalls() == 1); - CHECK_THAT(test.CallResult(), MatchesCall({ 1, nullptr })); - } - - SECTION("sends data to multiple event handlers") { - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler2); - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler3); - - int data = 1; - CHECK(SEvtDispatch(7357, 1, 0, &data) == 1); - - REQUIRE(test.NumCalls() == 3); - CHECK_THAT(test.CallResult(), MatchesCall({ 3, &data })); - CHECK_THAT(test.CallResult(), MatchesCall({ 2, &data })); - CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); - } - - SECTION("sends data to multiple event handlers with reverse ordering") { - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler3); - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler2); - - int data = 1; - CHECK(SEvtDispatch(7357, 1, 0, &data) == 1); - - REQUIRE(test.NumCalls() == 3); - CHECK_THAT(test.CallResult(), MatchesCall({ 2, &data })); - CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); - CHECK_THAT(test.CallResult(), MatchesCall({ 3, &data })); - } - - SECTION("sends data to duplicate handlers") { - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); - - int data = 1; - CHECK(SEvtDispatch(7357, 1, 0, &data) == 1); - - REQUIRE(test.NumCalls() == 3); - CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); - CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); - CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); - } - - SECTION("does nothing if there are no handlers in the type") { - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); - - CHECK(SEvtDispatch(42, 1, 0, nullptr) == 0); - CHECK(test.NumCalls() == 0); - } - - SECTION("does nothing if there are no handlers that match the subtype") { - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); - - CHECK(SEvtDispatch(7357, 2, 0, nullptr) == 0); - CHECK(test.NumCalls() == 0); - } - - SECTION("does nothing if there are no handlers that match the id") { - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); - - CHECK(SEvtDispatch(7357, 1, 1, nullptr) == 0); - CHECK(test.NumCalls() == 0); - } - - SECTION("breaks the next dispatch if data matches any in break chain") { - int data = 42; - SEvtBreakHandlerChain(&data); - - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); - - // doesn't call because data matches the break chain - CHECK(SEvtDispatch(7357, 1, 0, &data) == 0); - CHECK(test.NumCalls() == 0); - - // calls because the break already occurred - CHECK(SEvtDispatch(7357, 1, 0, &data) == 1); - CHECK(test.NumCalls() == 1); - } - - SECTION("calls handlers if data doesn't match any in break chain") { - int data = 42; - int data2 = 1337; - SEvtBreakHandlerChain(&data); - - SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); - - CHECK(SEvtDispatch(7357, 1, 0, &data2) == 1); - CHECK(test.NumCalls() == 1); - } - - SECTION("finds the correct handler among many") { - SEvtRegisterHandler(9000, 0, 0, 0, &TestEventHandler1); - SEvtRegisterHandler(9000, 1, 0, 0, &TestEventHandler1); - SEvtRegisterHandler(9000, 1, 1, 0, &TestEventHandler1); - SEvtRegisterHandler(420, 0, 0, 0, &TestEventHandler1); - SEvtRegisterHandler(420, 1, 0, 0, &TestEventHandler1); - SEvtRegisterHandler(420, 1, 1, 0, &TestEventHandler2); - SEvtRegisterHandler(420, 1, 2, 0, &TestEventHandler1); - SEvtRegisterHandler(42, 0, 0, 0, &TestEventHandler1); - - CHECK(SEvtDispatch(420, 1, 1, nullptr) == 1); - - CHECK(test.NumCalls() == 1); - CHECK_THAT(test.CallResult(), MatchesCall({2, nullptr})); - } - - SECTION("can use a non-pointer as data") { - SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); - - CHECK(SEvtDispatch(0, 0, 0, reinterpret_cast(42)) == 1); - CHECK_THAT(test.CallResult(), MatchesCall({1, reinterpret_cast(42)})); - } - - SECTION("broken handler chain still results in success if at least 1 handler called") { - SEvtRegisterHandler(0, 0, 0, 0, &TestBreakEventHandlerOther); - - CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); - CHECK(test.NumCalls() == 1); - } - - SECTION("can be called from handlers") { - SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); - SEvtRegisterHandler(1337, 420, 69, 0, &TestEventHandler1); - SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler2); - SEvtRegisterHandler(0, 0, 0, 0, &TestNestedDispatchEventHandler); - SEvtRegisterHandler(1337, 420, 69, 0, &TestEventHandler3); - SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler4); - - CHECK(SEvtDispatch(0, 0, 0, &test) == 1); - CHECK(test.NumCalls() == 6); - CHECK_THAT(test.CallResult(), MatchesCall({ 4, &test })); - CHECK_THAT(test.CallResult(), MatchesCall({ 20, &test })); - CHECK_THAT(test.CallResult(), MatchesCall({ 3, nullptr })); - CHECK_THAT(test.CallResult(), MatchesCall({ 1, nullptr })); - CHECK_THAT(test.CallResult(), MatchesCall({ 2, &test })); - CHECK_THAT(test.CallResult(), MatchesCall({ 1, &test })); - } -} - -TEST_CASE("SEvtPopState", "[event]") { - EventHandlerTest test; - - SECTION("fails if there are no handlers") { - CHECK(SEvtPopState(0, 0) == 0); - } - - SECTION("unregisters type if it is already top level") { - SEvtRegisterHandler(1337, 420, 69, 0, &TestEventHandler1); - - CHECK(SEvtPopState(1337, 420) == 1); - CHECK(SEvtUnregisterType(1337, 420) == 0); - } - - SECTION("popped state can receive callbacks again") { - SEvtRegisterHandler(1337, 420, 69, 0, &TestEventHandler1); - CHECK(SEvtPushState(1337, 420) == 1); - - // State is duplicated, remove our duplicated handler - SEvtUnregisterHandler(1337, 420, 69, &TestEventHandler1); - - CHECK(SEvtDispatch(1337, 420, 69, nullptr) == 0); - CHECK(test.NumCalls() == 0); - - CHECK(SEvtPopState(1337, 420) == 0); - - CHECK(SEvtDispatch(1337, 420, 69, nullptr) == 1); - CHECK(test.NumCalls() == 1); - } - - SECTION("popped state can be unregistered again") { - SEvtRegisterHandler(1337, 420, 69, 0, &TestEventHandler1); - CHECK(SEvtPushState(1337, 420) == 1); - - // Unregisters the duplicated instance - CHECK(SEvtUnregisterHandler(1337, 420, 69, &TestEventHandler1) == 1); - - CHECK(SEvtPopState(1337, 420) == 0); - CHECK(SEvtUnregisterHandler(1337, 420, 69, &TestEventHandler1) == 1); - } -} - -TEST_CASE("SEvtPushState", "[event]") { - EventHandlerTest test; - - SECTION("fails if there are no handlers") { - CHECK(SEvtPushState(0, 0) == 0); - } - - SECTION("fails if the type does not match any registered types") { - SEvtRegisterHandler(0, 0, 1, 0, &TestEventHandler1); - SEvtRegisterHandler(10, 0, 1, 0, &TestEventHandler1); - SEvtRegisterHandler(0, 9, 1, 0, &TestEventHandler1); - - CHECK(SEvtPushState(10, 9) == 0); - } - - SECTION("succeeds if the handler type exists") { - SEvtRegisterHandler(0, 0, 1, 0, &TestEventHandler1); - CHECK(SEvtPushState(0, 0) == 1); - } - - SECTION("pushed state duplicates its callbacks") { - SEvtRegisterHandler(1337, 420, 69, 0, &TestEventHandler1); - CHECK(SEvtPushState(1337, 420) == 1); - - CHECK(SEvtDispatch(1337, 420, 69, nullptr) == 1); - CHECK(test.NumCalls() == 1); - } - - SECTION("pushed state applies to all ids") { - SEvtRegisterHandler(0, 0, 9, 0, &TestEventHandler1); - SEvtRegisterHandler(0, 0, 8, 0, &TestEventHandler1); - SEvtRegisterHandler(0, 0, 66, 0, &TestEventHandler1); - - CHECK(SEvtPushState(0, 0) == 1); - - CHECK(SEvtDispatch(0, 0, 9, nullptr) == 1); - CHECK(SEvtDispatch(0, 0, 8, nullptr) == 1); - CHECK(SEvtDispatch(0, 0, 66, nullptr) == 1); - CHECK(test.NumCalls() == 3); - } - - SECTION("pushed state can be unregistered") { - SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); - SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler2); - - CHECK(SEvtPushState(0, 0) == 1); - CHECK(SEvtUnregisterHandler(0, 0, 0, &TestEventHandler1) == 1); - } -} - -static void STORMAPI TestRegisterEventHandler(void* data) { - EventHandlerTest::RegisterCall(30, data); - - CHECK(SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler4) == 1); -} - -TEST_CASE("SEvtRegisterHandler", "[event]") { - EventHandlerTest test; - - SECTION("registers an event handler") { - CHECK(SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1) == 1); - // true if found and removed - CHECK(SEvtUnregisterHandler(7357, 1, 2, &TestEventHandler1) == 1); - } - - SECTION("registers event handlers with different types") { - CHECK(SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1) == 1); - CHECK(SEvtRegisterHandler(69, 1, 2, 0, &TestEventHandler1) == 1); - - CHECK(SEvtUnregisterHandler(69, 1, 2, &TestEventHandler1) == 1); - CHECK(SEvtRegisterHandler(777, 1, 2, 0, &TestEventHandler1) == 1); - - CHECK(SEvtUnregisterHandler(7357, 1, 2, &TestEventHandler1) == 1); - CHECK(SEvtUnregisterHandler(777, 1, 2, &TestEventHandler1) == 1); - } - - SECTION("adds a new handler while being processed") { - CHECK(SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1) == 1); - CHECK(SEvtRegisterHandler(0, 0, 0, 0, &TestRegisterEventHandler) == 1); - - SEvtDispatch(0, 0, 0, nullptr); - CHECK(test.NumCalls() == 2); - CHECK_THAT(test.CallResult(), MatchesCall({30})); - CHECK_THAT(test.CallResult(), MatchesCall({1})); - - SEvtDispatch(0, 0, 0, nullptr); - CHECK(test.NumCalls() == 3); - CHECK_THAT(test.CallResult(), MatchesCall({4})); - CHECK_THAT(test.CallResult(), MatchesCall({30})); - CHECK_THAT(test.CallResult(), MatchesCall({1})); - - SEvtDispatch(0, 0, 0, nullptr); - CHECK(test.NumCalls() == 4); - CHECK_THAT(test.CallResult(), MatchesCall({4})); - CHECK_THAT(test.CallResult(), MatchesCall({4})); - CHECK_THAT(test.CallResult(), MatchesCall({30})); - CHECK_THAT(test.CallResult(), MatchesCall({1})); - } -} - -static void STORMAPI TestUnregisterEventHandler(void* data) { - EventHandlerTest::RegisterCall(30, data); - - CHECK(SEvtUnregisterHandler(0, 0, 0, &TestUnregisterEventHandler) == 1); -} - -TEST_CASE("SEvtUnregisterHandler", "[event]") { - EventHandlerTest test; - - SECTION("does nothing if handler doesn't exist") { - CHECK(SEvtUnregisterHandler(7357, 2, 1, &TestEventHandler1) == 0); - CHECK(SEvtUnregisterHandler(7357, 2, 1, nullptr) == 0); - } - - SECTION("removes multiple handler functions if handler is null") { - SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1); - SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler2); - - CHECK(SEvtUnregisterHandler(7357, 1, 2, nullptr) == 1); - - // Make sure nothing gets called - CHECK(SEvtDispatch(7357, 1, 2, nullptr) == 0); - CHECK(test.NumCalls() == 0); - } - - SECTION("removes a specific event handler") { - SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1); - SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler2); - - CHECK(SEvtUnregisterHandler(7357, 1, 2, &TestEventHandler1) == 1); - - // Make sure the other handler wasn't removed by checking if it is called - CHECK(SEvtDispatch(7357, 1, 2, nullptr) == 1); - CHECK_THAT(test.CallResult(), MatchesCall({ 2, nullptr })); - } - - SECTION("removes nothing if only type differs") { - SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1); - - CHECK(SEvtUnregisterHandler(42, 1, 2, nullptr) == 0); - - CHECK(SEvtDispatch(7357, 1, 2, nullptr) == 1); - CHECK(test.NumCalls() == 1); - } - - SECTION("removes nothing if only subtype differs") { - SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1); - - CHECK(SEvtUnregisterHandler(7357, 2, 2, nullptr) == 0); - - CHECK(SEvtDispatch(7357, 1, 2, nullptr) == 1); - CHECK(test.NumCalls() == 1); - } - - SECTION("removes nothing if only id differs") { - SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1); - - CHECK(SEvtUnregisterHandler(7357, 1, 3, nullptr) == 0); - - CHECK(SEvtDispatch(7357, 1, 2, nullptr) == 1); - CHECK(test.NumCalls() == 1); - } - - SECTION("allows a handler to remove itself while being called") { - SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterEventHandler); - - CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); - CHECK(test.NumCalls() == 1); - - CHECK(SEvtDispatch(0, 0, 0, nullptr) == 0); - } - - SECTION("stops calls once a handler removes itself") { - SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterEventHandler); - SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterEventHandler); - SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterEventHandler); - - CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); - CHECK(test.NumCalls() == 1); - CHECK(SEvtDispatch(0, 0, 0, nullptr) == 0); - } -} - -static void STORMAPI TestUnregisterTypeHandler(void* data) { - EventHandlerTest::RegisterCall(30, data); - - CHECK(SEvtUnregisterType(0, 0) == 1); -} - -TEST_CASE("SEvtUnregisterType", "[event]") { - EventHandlerTest test; - - SECTION("removes all event handlers in matching type and subtype") { - SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1); - SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler2); - - CHECK(SEvtUnregisterType(7357, 1) == 1); - - CHECK(SEvtDispatch(7357, 1, 2, nullptr) == 0); - CHECK(test.NumCalls() == 0); - } - - SECTION("removes nothing if only type matches") { - SEvtRegisterHandler(7357, 2, 2, 0, &TestEventHandler1); - - CHECK(SEvtUnregisterType(7357, 1) == 0); - - CHECK(SEvtDispatch(7357, 2, 2, nullptr) == 1); - CHECK(test.NumCalls() == 1); - } - - SECTION("removes nothing if only subtype matches") { - SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1); - - CHECK(SEvtUnregisterType(42, 1) == 0); - - CHECK(SEvtDispatch(7357, 1, 2, nullptr) == 1); - CHECK(test.NumCalls() == 1); - } - - SECTION("removes only matching handlers among many") { - SEvtRegisterHandler(123, 1, 2, 0, &TestEventHandler1); - SEvtRegisterHandler(123, 2, 2, 0, &TestEventHandler2); - SEvtRegisterHandler(123, 2, 3, 0, &TestEventHandler3); - SEvtRegisterHandler(123, 1, 1, 0, &TestEventHandler4); - SEvtRegisterHandler(123, 2, 1, 0, &TestEventHandler1); - - CHECK(SEvtUnregisterType(123, 2) == 1); - - CHECK(SEvtDispatch(123, 2, 1, nullptr) == 0); - CHECK(SEvtDispatch(123, 2, 2, nullptr) == 0); - CHECK(SEvtDispatch(123, 2, 3, nullptr) == 0); - - CHECK(SEvtDispatch(123, 1, 1, nullptr) == 1); - CHECK(test.NumCalls() == 1); - CHECK(SEvtDispatch(123, 1, 2, nullptr) == 1); - CHECK(test.NumCalls() == 2); - } - - SECTION("allows a handler to remove itself while being called") { - SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterTypeHandler); - - CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); - CHECK(test.NumCalls() == 1); - - CHECK(SEvtDispatch(0, 0, 0, nullptr) == 0); - } - - SECTION("stops calls once a handler removes itself") { - SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterTypeHandler); - SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterTypeHandler); - SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterTypeHandler); - - CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); - CHECK(test.NumCalls() == 1); - CHECK(SEvtDispatch(0, 0, 0, nullptr) == 0); - } -} +#include "EventTest.hpp" + +static void STORMAPI TestBreakEventHandlerSelf(void* data) { + EventHandlerTest::RegisterCall(10, data); + + CHECK(SEvtBreakHandlerChain(data) == 1); +} + +static void STORMAPI TestBreakEventHandlerOther(void* data) { + EventHandlerTest::RegisterCall(10, data); + + CHECK(SEvtBreakHandlerChain(nullptr) == 1); +} + +TEST_CASE("SEvtBreakHandlerChain", "[event]") { + EventHandlerTest test; + + SECTION("can use nullptr as data") { + CHECK(SEvtBreakHandlerChain(nullptr) == 1); + + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); + CHECK(SEvtDispatch(7357, 1, 0, nullptr) == 0); + CHECK(SEvtDispatch(7357, 1, 0, nullptr) == 1); + } + + SECTION("causes SEvtDispatch to break early if one of many data matches") { + int data1 = 42, data2 = 1337, data3 = 0xFFFFFFFF; + + CHECK(SEvtBreakHandlerChain(nullptr) == 1); + CHECK(SEvtBreakHandlerChain(&data1) == 1); + CHECK(SEvtBreakHandlerChain(&data2) == 1); + CHECK(SEvtBreakHandlerChain(&data3) == 1); + + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); + CHECK(SEvtDispatch(7357, 1, 0, &data2) == 0); + + // CLEANUP - SEvtDestroy doesn't erase registered breaks, avoid polluting other tests + CHECK(SEvtDispatch(7357, 1, 0, nullptr) == 0); + CHECK(SEvtDispatch(7357, 1, 0, &data1) == 0); + CHECK(SEvtDispatch(7357, 1, 0, &data3) == 0); + } + + SECTION("doesn't break SEvtDispatch if no data matches") { + int data1 = 42, data2 = 1337, data3 = 0xFFFFFFFF; + + CHECK(SEvtBreakHandlerChain(nullptr) == 1); + CHECK(SEvtBreakHandlerChain(&data1) == 1); + CHECK(SEvtBreakHandlerChain(&data2) == 1); + CHECK(SEvtBreakHandlerChain(&data3) == 1); + + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); + CHECK(SEvtDispatch(7357, 1, 0, &test) == 1); + + // CLEANUP - SEvtDestroy doesn't erase registered breaks, avoid polluting other tests + CHECK(SEvtDispatch(7357, 1, 0, nullptr) == 0); + CHECK(SEvtDispatch(7357, 1, 0, &data1) == 0); + CHECK(SEvtDispatch(7357, 1, 0, &data2) == 0); + CHECK(SEvtDispatch(7357, 1, 0, &data3) == 0); + } + + SECTION("deduplicates multiple same-data breaks") { + CHECK(SEvtBreakHandlerChain(&test) == 1); + CHECK(SEvtBreakHandlerChain(&test) == 1); + CHECK(SEvtBreakHandlerChain(&test) == 1); + + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); + CHECK(SEvtDispatch(7357, 1, 0, &test) == 0); + CHECK(SEvtDispatch(7357, 1, 0, &test) == 1); + } + + SECTION("causes a dispatch to stop during handling") { + SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); + SEvtRegisterHandler(0, 0, 0, 0, &TestBreakEventHandlerSelf); + SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler2); + + CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); + CHECK(test.NumCalls() == 2); + // Calls are reverse order, TestEventHandler1 doesn't get called + CHECK_THAT(test.CallResult(), MatchesCall({ 2, nullptr })); + CHECK_THAT(test.CallResult(), MatchesCall({ 10, nullptr })); + } + + SECTION("doesn't cause a dispatch to stop during handling if data differs") { + SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); + SEvtRegisterHandler(0, 0, 0, 0, &TestBreakEventHandlerOther); + SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler2); + + int data = 42; + CHECK(SEvtDispatch(0, 0, 0, &data) == 1); + CHECK(test.NumCalls() == 3); + // Calls are reverse order, TestEventHandler1 doesn't get called + CHECK_THAT(test.CallResult(), MatchesCall({ 2, &data })); + CHECK_THAT(test.CallResult(), MatchesCall({ 10, &data })); + CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); + + // CLEANUP - SEvtDestroy doesn't erase registered breaks, avoid polluting other tests + CHECK(SEvtDispatch(0, 0, 0, nullptr) == 0); + } +} + +#if !defined(WHOA_TEST_STORMDLL) +TEST_CASE("SEvtDestroy", "[event]") { + EventHandlerTest test; + + SECTION("always returns 1") { + CHECK(SEvtDestroy() == 1); + } + + SECTION("destroys all event handlers") { + SEvtRegisterHandler(1, 1, 1, 0, &TestEventHandler1); + CHECK(SEvtDispatch(1, 1, 1, nullptr) == 1); + CHECK(test.NumCalls() == 1); + + CHECK(SEvtDispatch(1, 1, 1, nullptr) == 1); + CHECK(test.NumCalls() == 2); + + CHECK(SEvtDestroy() == 1); + + // Can't increment calls since the handler was destroyed + CHECK(SEvtDispatch(1, 1, 1, nullptr) == 0); + CHECK(test.NumCalls() == 2); + } + + SECTION("doesn't destroy break data") { + // not ideal but it's official behaviour + SEvtBreakHandlerChain(nullptr); + + CHECK(SEvtDestroy() == 1); + + SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); + CHECK(SEvtDispatch(0, 0, 0, nullptr) == 0); + CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); + } +} +#endif + +static void STORMAPI TestNestedDispatchEventHandler(void* data) { + EventHandlerTest::RegisterCall(20, data); + + CHECK(SEvtDispatch(1337, 420, 69, nullptr) == 1); +} + +TEST_CASE("SEvtDispatch", "[event]") { + EventHandlerTest test; + + SECTION("sends data to an event handler") { + SEvtRegisterHandler(1337, 42, 5, 0, &TestEventHandler1); + + int data = 5; + CHECK(SEvtDispatch(1337, 42, 5, &data) == 1); + + REQUIRE(test.NumCalls() == 1); + CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); + } + + SECTION("can use 0 as valid handler ids") { + SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); + + int data = 5; + CHECK(SEvtDispatch(0, 0, 0, &data) == 1); + + REQUIRE(test.NumCalls() == 1); + CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); + } + + SECTION("can pass nullptr to a handler") { + SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); + + CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); + + REQUIRE(test.NumCalls() == 1); + CHECK_THAT(test.CallResult(), MatchesCall({ 1, nullptr })); + } + + SECTION("sends data to multiple event handlers") { + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler2); + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler3); + + int data = 1; + CHECK(SEvtDispatch(7357, 1, 0, &data) == 1); + + REQUIRE(test.NumCalls() == 3); + CHECK_THAT(test.CallResult(), MatchesCall({ 3, &data })); + CHECK_THAT(test.CallResult(), MatchesCall({ 2, &data })); + CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); + } + + SECTION("sends data to multiple event handlers with reverse ordering") { + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler3); + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler2); + + int data = 1; + CHECK(SEvtDispatch(7357, 1, 0, &data) == 1); + + REQUIRE(test.NumCalls() == 3); + CHECK_THAT(test.CallResult(), MatchesCall({ 2, &data })); + CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); + CHECK_THAT(test.CallResult(), MatchesCall({ 3, &data })); + } + + SECTION("sends data to duplicate handlers") { + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); + + int data = 1; + CHECK(SEvtDispatch(7357, 1, 0, &data) == 1); + + REQUIRE(test.NumCalls() == 3); + CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); + CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); + CHECK_THAT(test.CallResult(), MatchesCall({ 1, &data })); + } + + SECTION("does nothing if there are no handlers in the type") { + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); + + CHECK(SEvtDispatch(42, 1, 0, nullptr) == 0); + CHECK(test.NumCalls() == 0); + } + + SECTION("does nothing if there are no handlers that match the subtype") { + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); + + CHECK(SEvtDispatch(7357, 2, 0, nullptr) == 0); + CHECK(test.NumCalls() == 0); + } + + SECTION("does nothing if there are no handlers that match the id") { + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); + + CHECK(SEvtDispatch(7357, 1, 1, nullptr) == 0); + CHECK(test.NumCalls() == 0); + } + + SECTION("breaks the next dispatch if data matches any in break chain") { + int data = 42; + SEvtBreakHandlerChain(&data); + + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); + + // doesn't call because data matches the break chain + CHECK(SEvtDispatch(7357, 1, 0, &data) == 0); + CHECK(test.NumCalls() == 0); + + // calls because the break already occurred + CHECK(SEvtDispatch(7357, 1, 0, &data) == 1); + CHECK(test.NumCalls() == 1); + } + + SECTION("calls handlers if data doesn't match any in break chain") { + int data = 42; + int data2 = 1337; + SEvtBreakHandlerChain(&data); + + SEvtRegisterHandler(7357, 1, 0, 0, &TestEventHandler1); + + CHECK(SEvtDispatch(7357, 1, 0, &data2) == 1); + CHECK(test.NumCalls() == 1); + } + + SECTION("finds the correct handler among many") { + SEvtRegisterHandler(9000, 0, 0, 0, &TestEventHandler1); + SEvtRegisterHandler(9000, 1, 0, 0, &TestEventHandler1); + SEvtRegisterHandler(9000, 1, 1, 0, &TestEventHandler1); + SEvtRegisterHandler(420, 0, 0, 0, &TestEventHandler1); + SEvtRegisterHandler(420, 1, 0, 0, &TestEventHandler1); + SEvtRegisterHandler(420, 1, 1, 0, &TestEventHandler2); + SEvtRegisterHandler(420, 1, 2, 0, &TestEventHandler1); + SEvtRegisterHandler(42, 0, 0, 0, &TestEventHandler1); + + CHECK(SEvtDispatch(420, 1, 1, nullptr) == 1); + + CHECK(test.NumCalls() == 1); + CHECK_THAT(test.CallResult(), MatchesCall({2, nullptr})); + } + + SECTION("can use a non-pointer as data") { + SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); + + CHECK(SEvtDispatch(0, 0, 0, reinterpret_cast(42)) == 1); + CHECK_THAT(test.CallResult(), MatchesCall({1, reinterpret_cast(42)})); + } + + SECTION("broken handler chain still results in success if at least 1 handler called") { + SEvtRegisterHandler(0, 0, 0, 0, &TestBreakEventHandlerOther); + + CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); + CHECK(test.NumCalls() == 1); + } + + SECTION("can be called from handlers") { + SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); + SEvtRegisterHandler(1337, 420, 69, 0, &TestEventHandler1); + SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler2); + SEvtRegisterHandler(0, 0, 0, 0, &TestNestedDispatchEventHandler); + SEvtRegisterHandler(1337, 420, 69, 0, &TestEventHandler3); + SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler4); + + CHECK(SEvtDispatch(0, 0, 0, &test) == 1); + CHECK(test.NumCalls() == 6); + CHECK_THAT(test.CallResult(), MatchesCall({ 4, &test })); + CHECK_THAT(test.CallResult(), MatchesCall({ 20, &test })); + CHECK_THAT(test.CallResult(), MatchesCall({ 3, nullptr })); + CHECK_THAT(test.CallResult(), MatchesCall({ 1, nullptr })); + CHECK_THAT(test.CallResult(), MatchesCall({ 2, &test })); + CHECK_THAT(test.CallResult(), MatchesCall({ 1, &test })); + } +} + +TEST_CASE("SEvtPopState", "[event]") { + EventHandlerTest test; + + SECTION("fails if there are no handlers") { + CHECK(SEvtPopState(0, 0) == 0); + } + + SECTION("unregisters type if it is already top level") { + SEvtRegisterHandler(1337, 420, 69, 0, &TestEventHandler1); + + CHECK(SEvtPopState(1337, 420) == 1); + CHECK(SEvtUnregisterType(1337, 420) == 0); + } + + SECTION("popped state can receive callbacks again") { + SEvtRegisterHandler(1337, 420, 69, 0, &TestEventHandler1); + CHECK(SEvtPushState(1337, 420) == 1); + + // State is duplicated, remove our duplicated handler + SEvtUnregisterHandler(1337, 420, 69, &TestEventHandler1); + + CHECK(SEvtDispatch(1337, 420, 69, nullptr) == 0); + CHECK(test.NumCalls() == 0); + + CHECK(SEvtPopState(1337, 420) == 0); + + CHECK(SEvtDispatch(1337, 420, 69, nullptr) == 1); + CHECK(test.NumCalls() == 1); + } + + SECTION("popped state can be unregistered again") { + SEvtRegisterHandler(1337, 420, 69, 0, &TestEventHandler1); + CHECK(SEvtPushState(1337, 420) == 1); + + // Unregisters the duplicated instance + CHECK(SEvtUnregisterHandler(1337, 420, 69, &TestEventHandler1) == 1); + + CHECK(SEvtPopState(1337, 420) == 0); + CHECK(SEvtUnregisterHandler(1337, 420, 69, &TestEventHandler1) == 1); + } +} + +TEST_CASE("SEvtPushState", "[event]") { + EventHandlerTest test; + + SECTION("fails if there are no handlers") { + CHECK(SEvtPushState(0, 0) == 0); + } + + SECTION("fails if the type does not match any registered types") { + SEvtRegisterHandler(0, 0, 1, 0, &TestEventHandler1); + SEvtRegisterHandler(10, 0, 1, 0, &TestEventHandler1); + SEvtRegisterHandler(0, 9, 1, 0, &TestEventHandler1); + + CHECK(SEvtPushState(10, 9) == 0); + } + + SECTION("succeeds if the handler type exists") { + SEvtRegisterHandler(0, 0, 1, 0, &TestEventHandler1); + CHECK(SEvtPushState(0, 0) == 1); + } + + SECTION("pushed state duplicates its callbacks") { + SEvtRegisterHandler(1337, 420, 69, 0, &TestEventHandler1); + CHECK(SEvtPushState(1337, 420) == 1); + + CHECK(SEvtDispatch(1337, 420, 69, nullptr) == 1); + CHECK(test.NumCalls() == 1); + } + + SECTION("pushed state applies to all ids") { + SEvtRegisterHandler(0, 0, 9, 0, &TestEventHandler1); + SEvtRegisterHandler(0, 0, 8, 0, &TestEventHandler1); + SEvtRegisterHandler(0, 0, 66, 0, &TestEventHandler1); + + CHECK(SEvtPushState(0, 0) == 1); + + CHECK(SEvtDispatch(0, 0, 9, nullptr) == 1); + CHECK(SEvtDispatch(0, 0, 8, nullptr) == 1); + CHECK(SEvtDispatch(0, 0, 66, nullptr) == 1); + CHECK(test.NumCalls() == 3); + } + + SECTION("pushed state can be unregistered") { + SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1); + SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler2); + + CHECK(SEvtPushState(0, 0) == 1); + CHECK(SEvtUnregisterHandler(0, 0, 0, &TestEventHandler1) == 1); + } +} + +static void STORMAPI TestRegisterEventHandler(void* data) { + EventHandlerTest::RegisterCall(30, data); + + CHECK(SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler4) == 1); +} + +TEST_CASE("SEvtRegisterHandler", "[event]") { + EventHandlerTest test; + + SECTION("registers an event handler") { + CHECK(SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1) == 1); + // true if found and removed + CHECK(SEvtUnregisterHandler(7357, 1, 2, &TestEventHandler1) == 1); + } + + SECTION("registers event handlers with different types") { + CHECK(SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1) == 1); + CHECK(SEvtRegisterHandler(69, 1, 2, 0, &TestEventHandler1) == 1); + + CHECK(SEvtUnregisterHandler(69, 1, 2, &TestEventHandler1) == 1); + CHECK(SEvtRegisterHandler(777, 1, 2, 0, &TestEventHandler1) == 1); + + CHECK(SEvtUnregisterHandler(7357, 1, 2, &TestEventHandler1) == 1); + CHECK(SEvtUnregisterHandler(777, 1, 2, &TestEventHandler1) == 1); + } + + SECTION("adds a new handler while being processed") { + CHECK(SEvtRegisterHandler(0, 0, 0, 0, &TestEventHandler1) == 1); + CHECK(SEvtRegisterHandler(0, 0, 0, 0, &TestRegisterEventHandler) == 1); + + SEvtDispatch(0, 0, 0, nullptr); + CHECK(test.NumCalls() == 2); + CHECK_THAT(test.CallResult(), MatchesCall({30})); + CHECK_THAT(test.CallResult(), MatchesCall({1})); + + SEvtDispatch(0, 0, 0, nullptr); + CHECK(test.NumCalls() == 3); + CHECK_THAT(test.CallResult(), MatchesCall({4})); + CHECK_THAT(test.CallResult(), MatchesCall({30})); + CHECK_THAT(test.CallResult(), MatchesCall({1})); + + SEvtDispatch(0, 0, 0, nullptr); + CHECK(test.NumCalls() == 4); + CHECK_THAT(test.CallResult(), MatchesCall({4})); + CHECK_THAT(test.CallResult(), MatchesCall({4})); + CHECK_THAT(test.CallResult(), MatchesCall({30})); + CHECK_THAT(test.CallResult(), MatchesCall({1})); + } +} + +static void STORMAPI TestUnregisterEventHandler(void* data) { + EventHandlerTest::RegisterCall(30, data); + + CHECK(SEvtUnregisterHandler(0, 0, 0, &TestUnregisterEventHandler) == 1); +} + +TEST_CASE("SEvtUnregisterHandler", "[event]") { + EventHandlerTest test; + + SECTION("does nothing if handler doesn't exist") { + CHECK(SEvtUnregisterHandler(7357, 2, 1, &TestEventHandler1) == 0); + CHECK(SEvtUnregisterHandler(7357, 2, 1, nullptr) == 0); + } + + SECTION("removes multiple handler functions if handler is null") { + SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1); + SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler2); + + CHECK(SEvtUnregisterHandler(7357, 1, 2, nullptr) == 1); + + // Make sure nothing gets called + CHECK(SEvtDispatch(7357, 1, 2, nullptr) == 0); + CHECK(test.NumCalls() == 0); + } + + SECTION("removes a specific event handler") { + SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1); + SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler2); + + CHECK(SEvtUnregisterHandler(7357, 1, 2, &TestEventHandler1) == 1); + + // Make sure the other handler wasn't removed by checking if it is called + CHECK(SEvtDispatch(7357, 1, 2, nullptr) == 1); + CHECK_THAT(test.CallResult(), MatchesCall({ 2, nullptr })); + } + + SECTION("removes nothing if only type differs") { + SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1); + + CHECK(SEvtUnregisterHandler(42, 1, 2, nullptr) == 0); + + CHECK(SEvtDispatch(7357, 1, 2, nullptr) == 1); + CHECK(test.NumCalls() == 1); + } + + SECTION("removes nothing if only subtype differs") { + SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1); + + CHECK(SEvtUnregisterHandler(7357, 2, 2, nullptr) == 0); + + CHECK(SEvtDispatch(7357, 1, 2, nullptr) == 1); + CHECK(test.NumCalls() == 1); + } + + SECTION("removes nothing if only id differs") { + SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1); + + CHECK(SEvtUnregisterHandler(7357, 1, 3, nullptr) == 0); + + CHECK(SEvtDispatch(7357, 1, 2, nullptr) == 1); + CHECK(test.NumCalls() == 1); + } + + SECTION("allows a handler to remove itself while being called") { + SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterEventHandler); + + CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); + CHECK(test.NumCalls() == 1); + + CHECK(SEvtDispatch(0, 0, 0, nullptr) == 0); + } + + SECTION("stops calls once a handler removes itself") { + SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterEventHandler); + SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterEventHandler); + SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterEventHandler); + + CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); + CHECK(test.NumCalls() == 1); + CHECK(SEvtDispatch(0, 0, 0, nullptr) == 0); + } +} + +static void STORMAPI TestUnregisterTypeHandler(void* data) { + EventHandlerTest::RegisterCall(30, data); + + CHECK(SEvtUnregisterType(0, 0) == 1); +} + +TEST_CASE("SEvtUnregisterType", "[event]") { + EventHandlerTest test; + + SECTION("removes all event handlers in matching type and subtype") { + SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1); + SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler2); + + CHECK(SEvtUnregisterType(7357, 1) == 1); + + CHECK(SEvtDispatch(7357, 1, 2, nullptr) == 0); + CHECK(test.NumCalls() == 0); + } + + SECTION("removes nothing if only type matches") { + SEvtRegisterHandler(7357, 2, 2, 0, &TestEventHandler1); + + CHECK(SEvtUnregisterType(7357, 1) == 0); + + CHECK(SEvtDispatch(7357, 2, 2, nullptr) == 1); + CHECK(test.NumCalls() == 1); + } + + SECTION("removes nothing if only subtype matches") { + SEvtRegisterHandler(7357, 1, 2, 0, &TestEventHandler1); + + CHECK(SEvtUnregisterType(42, 1) == 0); + + CHECK(SEvtDispatch(7357, 1, 2, nullptr) == 1); + CHECK(test.NumCalls() == 1); + } + + SECTION("removes only matching handlers among many") { + SEvtRegisterHandler(123, 1, 2, 0, &TestEventHandler1); + SEvtRegisterHandler(123, 2, 2, 0, &TestEventHandler2); + SEvtRegisterHandler(123, 2, 3, 0, &TestEventHandler3); + SEvtRegisterHandler(123, 1, 1, 0, &TestEventHandler4); + SEvtRegisterHandler(123, 2, 1, 0, &TestEventHandler1); + + CHECK(SEvtUnregisterType(123, 2) == 1); + + CHECK(SEvtDispatch(123, 2, 1, nullptr) == 0); + CHECK(SEvtDispatch(123, 2, 2, nullptr) == 0); + CHECK(SEvtDispatch(123, 2, 3, nullptr) == 0); + + CHECK(SEvtDispatch(123, 1, 1, nullptr) == 1); + CHECK(test.NumCalls() == 1); + CHECK(SEvtDispatch(123, 1, 2, nullptr) == 1); + CHECK(test.NumCalls() == 2); + } + + SECTION("allows a handler to remove itself while being called") { + SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterTypeHandler); + + CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); + CHECK(test.NumCalls() == 1); + + CHECK(SEvtDispatch(0, 0, 0, nullptr) == 0); + } + + SECTION("stops calls once a handler removes itself") { + SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterTypeHandler); + SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterTypeHandler); + SEvtRegisterHandler(0, 0, 0, 0, &TestUnregisterTypeHandler); + + CHECK(SEvtDispatch(0, 0, 0, nullptr) == 1); + CHECK(test.NumCalls() == 1); + CHECK(SEvtDispatch(0, 0, 0, nullptr) == 0); + } +} diff --git a/test/EventTest.cpp b/test/EventTest.cpp index b76fa21..15b4c4f 100644 --- a/test/EventTest.cpp +++ b/test/EventTest.cpp @@ -1,29 +1,28 @@ -#include "EventTest.hpp" - -std::deque EventHandlerCallResults; - - -void STORMAPI TestEventHandler1(void* data) { - EventHandlerTest::RegisterCall(1, data); -} - -void STORMAPI TestEventHandler2(void* data) { - EventHandlerTest::RegisterCall(2, data); -} - -void STORMAPI TestEventHandler3(void* data) { - EventHandlerTest::RegisterCall(3, data); -} - -void STORMAPI TestEventHandler4(void* data) { - EventHandlerTest::RegisterCall(4, data); -} - -std::ostream& operator <<(std::ostream& os, EventHandlerCalledWith const& value) { - os << "{ TestEventHandler" << value.handler << ", " << value.data << " }"; - return os; -} - -EventHandlerCalledWithMatcher MatchesCall(EventHandlerCalledWith arg) { - return { arg }; -} +#include "EventTest.hpp" + +std::deque EventHandlerCallResults; + +void STORMAPI TestEventHandler1(void* data) { + EventHandlerTest::RegisterCall(1, data); +} + +void STORMAPI TestEventHandler2(void* data) { + EventHandlerTest::RegisterCall(2, data); +} + +void STORMAPI TestEventHandler3(void* data) { + EventHandlerTest::RegisterCall(3, data); +} + +void STORMAPI TestEventHandler4(void* data) { + EventHandlerTest::RegisterCall(4, data); +} + +std::ostream& operator <<(std::ostream& os, EventHandlerCalledWith const& value) { + os << "{ TestEventHandler" << value.handler << ", " << value.data << " }"; + return os; +} + +EventHandlerCalledWithMatcher MatchesCall(EventHandlerCalledWith arg) { + return { arg }; +} diff --git a/test/EventTest.hpp b/test/EventTest.hpp index ec64c25..6e889f4 100644 --- a/test/EventTest.hpp +++ b/test/EventTest.hpp @@ -1,71 +1,68 @@ -#include "test/Test.hpp" -#include "storm/Core.hpp" -#include "storm/Event.hpp" - -#include -#include - - -struct EventHandlerCalledWith { - int handler; - void* data; -}; - -extern std::deque EventHandlerCallResults; - -struct EventHandlerTest { - EventHandlerTest() { - EventHandlerCallResults.clear(); - StormDestroy(); - } - - static void RegisterCall(int handler, void* data) { - EventHandlerCalledWith calledWith = {handler, data}; - EventHandlerCallResults.push_back(calledWith); - } - - static size_t NumCalls() { - return EventHandlerCallResults.size(); - } - - static EventHandlerCalledWith CallResult() { - if (EventHandlerCallResults.empty()) { - return {-1, nullptr}; - } - - EventHandlerCalledWith result = EventHandlerCallResults.front(); - EventHandlerCallResults.pop_front(); - return result; - } -}; - - -void STORMAPI TestEventHandler1(void* data); -void STORMAPI TestEventHandler2(void* data); -void STORMAPI TestEventHandler3(void* data); -void STORMAPI TestEventHandler4(void* data); - - -// Helpers for comparing EventHandlerCalledWith structs -std::ostream& operator <<(std::ostream& os, EventHandlerCalledWith const& value); - -template -class EventHandlerCalledWithMatcher : public Catch::MatcherBase { -private: - T cmp; - -public: - EventHandlerCalledWithMatcher(T arg) : cmp(arg) {} - - bool match(T const& in) const override { - return cmp.handler == in.handler && cmp.data == in.data; - } - - std::string describe() const override { - std::ostringstream ss; - ss << "equals " << cmp; - return ss.str(); - } -}; - -EventHandlerCalledWithMatcher MatchesCall(EventHandlerCalledWith arg); +#include "test/Test.hpp" +#include "storm/Core.hpp" +#include "storm/Event.hpp" + +#include +#include + +struct EventHandlerCalledWith { + int handler; + void* data; +}; + +extern std::deque EventHandlerCallResults; + +struct EventHandlerTest { + EventHandlerTest() { + EventHandlerCallResults.clear(); + StormDestroy(); + } + + static void RegisterCall(int handler, void* data) { + EventHandlerCalledWith calledWith = {handler, data}; + EventHandlerCallResults.push_back(calledWith); + } + + static size_t NumCalls() { + return EventHandlerCallResults.size(); + } + + static EventHandlerCalledWith CallResult() { + if (EventHandlerCallResults.empty()) { + return {-1, nullptr}; + } + + EventHandlerCalledWith result = EventHandlerCallResults.front(); + EventHandlerCallResults.pop_front(); + return result; + } +}; + +void STORMAPI TestEventHandler1(void* data); +void STORMAPI TestEventHandler2(void* data); +void STORMAPI TestEventHandler3(void* data); +void STORMAPI TestEventHandler4(void* data); + +// Helpers for comparing EventHandlerCalledWith structs +std::ostream& operator <<(std::ostream& os, EventHandlerCalledWith const& value); + +template +class EventHandlerCalledWithMatcher : public Catch::MatcherBase { +private: + T cmp; + +public: + EventHandlerCalledWithMatcher(T arg) : cmp(arg) {} + + bool match(T const& in) const override { + return cmp.handler == in.handler && cmp.data == in.data; + } + + std::string describe() const override { + std::ostringstream ss; + ss << "equals " << cmp; + return ss.str(); + } +}; + +EventHandlerCalledWithMatcher MatchesCall(EventHandlerCalledWith arg);