X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b2238cc3156f4e15e567d2218c88301bc2af9adb..fd5907ffd9b0785bb6eb6f2546101623b23827c5:/tests/events/evthandler.cpp diff --git a/tests/events/evthandler.cpp b/tests/events/evthandler.cpp index b6de473373..366fb8e775 100644 --- a/tests/events/evthandler.cpp +++ b/tests/events/evthandler.cpp @@ -17,172 +17,432 @@ #pragma hdrstop #endif -#ifndef WX_PRECOMP -#endif // WX_PRECOMP - #include "wx/event.h" +// ---------------------------------------------------------------------------- +// test events and their handlers +// ---------------------------------------------------------------------------- -// -------------------------------------------------------------------------- -// test class -// -------------------------------------------------------------------------- +const wxEventType LegacyEventType = wxNewEventType(); -class EvtHandlerTestCase : public CppUnit::TestCase +class MyEvent; +wxDEFINE_EVENT(MyEventType, MyEvent); + +class MyEvent : public wxEvent { public: - EvtHandlerTestCase() {} + MyEvent() : wxEvent(0, MyEventType) { } -private: - CPPUNIT_TEST_SUITE( EvtHandlerTestCase ); - CPPUNIT_TEST( TestConnectCompilation ); - CPPUNIT_TEST( TestEventFunctorCompare ); - CPPUNIT_TEST_SUITE_END(); - - void TestConnectCompilation(); - void TestEventFunctorCompare(); - - DECLARE_NO_COPY_CLASS(EvtHandlerTestCase) + virtual wxEvent *Clone() const { return new MyEvent; } }; -// register in the unnamed registry so that these tests are run by default -CPPUNIT_TEST_SUITE_REGISTRATION( EvtHandlerTestCase ); +typedef void (wxEvtHandler::*MyEventFunction)(MyEvent&); +#ifndef wxHAS_EVENT_BIND + #define MyEventHandler(func) wxEVENT_HANDLER_CAST(MyEventFunction, func) +#else + #define MyEventHandler(func) &func +#endif +#define EVT_MYEVENT(func) \ + wx__DECLARE_EVT0(MyEventType, MyEventHandler(func)) -// also include in it's own registry so that these tests can be run alone -CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtHandlerTestCase, "EvtHandlerTestCase" ); +class AnotherEvent : public wxEvent +{ +}; -const wxEventType EVT_LEGACY = wxNewEventType(); +namespace +{ -class MyEvent : public wxEvent +struct Called { -}; + Called() { Reset(); } + + void Reset() + { + function = + functor = + method = + smethod = false; + } + + bool function, + functor, + method, + smethod; +} g_called; + +void GlobalOnMyEvent(MyEvent&) +{ + g_called.function = true; +} -wxDEFINE_EVENT( EVT_EVENT, MyEvent ) +void GlobalOnEvent(wxEvent&) +{ + g_called.function = true; +} -// An arbitrary functor: +void GlobalOnAnotherEvent(AnotherEvent&); -class MyFunctor +void GlobalOnIdle(wxIdleEvent&) { - public: - void operator () ( MyEvent & ) - { } + g_called.function = true; +} - bool operator == ( const MyFunctor & ) const - { return ( true ); } +struct MyFunctor +{ + void operator()(MyEvent &) { g_called.functor = true; } }; +struct IdleFunctor +{ + void operator()(wxIdleEvent &) { g_called.functor = true; } +}; class MyHandler : public wxEvtHandler { - public: - void handleMethod( MyEvent & ) - { } +public: + static void StaticOnMyEvent(MyEvent &) { g_called.smethod = true; } + static void StaticOnAnotherEvent(AnotherEvent &); + static void StaticOnIdle(wxIdleEvent&) { g_called.smethod = true; } + + void OnMyEvent(MyEvent&) { g_called.method = true; } + void OnEvent(wxEvent&) { g_called.method = true; } + void OnAnotherEvent(AnotherEvent&); + void OnIdle(wxIdleEvent&) { g_called.method = true; } +}; - static void handleFunction( MyEvent & ) - { } +// we can also handle events in classes not deriving from wxEvtHandler +struct MySink +{ + void OnMyEvent(MyEvent&) { g_called.method = true; } + void OnEvent(wxEvent&) { g_called.method = true; } + void OnIdle(wxIdleEvent&) { g_called.method = true; } +}; - void handleEvent( wxEvent & ) - { } +// also test event table compilation +class MyClassWithEventTable : public wxEvtHandler +{ +public: + void OnMyEvent(MyEvent&) { g_called.method = true; } + void OnEvent(wxEvent&) { g_called.method = true; } + void OnAnotherEvent(AnotherEvent&); + void OnIdle(wxIdleEvent&) { g_called.method = true; } +private: + DECLARE_EVENT_TABLE() }; -void EvtHandlerTestCase::TestConnectCompilation() -{ - // Test that connecting the 'legacy' events still compiles: +BEGIN_EVENT_TABLE(MyClassWithEventTable, wxEvtHandler) + EVT_IDLE(MyClassWithEventTable::OnIdle) - MyHandler handler; + EVT_MYEVENT(MyClassWithEventTable::OnMyEvent) +#ifdef wxHAS_EVENT_BIND + EVT_MYEVENT(MyClassWithEventTable::OnEvent) +#endif - handler.Connect( EVT_LEGACY, (wxObjectEventFunction)&MyHandler::handleEvent, NULL, &handler ); - handler.Connect( 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::handleEvent, NULL, &handler ); - handler.Connect( 0, 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::handleEvent, NULL, &handler ); + // this shouldn't compile: + //EVT_MYEVENT(MyClassWithEventTable::OnIdle) + //EVT_IDLE(MyClassWithEventTable::OnAnotherEvent) +END_EVENT_TABLE() - handler.Disconnect( EVT_LEGACY, (wxObjectEventFunction)&MyHandler::handleEvent, NULL, &handler ); - handler.Disconnect( 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::handleEvent, NULL, &handler ); - handler.Disconnect( 0, 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::handleEvent, NULL, &handler ); +} // anonymous namespace +// -------------------------------------------------------------------------- +// test class +// -------------------------------------------------------------------------- - handler.Connect( EVT_LEGACY, (wxObjectEventFunction)&MyHandler::handleEvent ); - handler.Connect( 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::handleEvent ); - handler.Connect( 0, 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::handleEvent ); +class EvtHandlerTestCase : public CppUnit::TestCase +{ +public: + EvtHandlerTestCase() {} + +private: + CPPUNIT_TEST_SUITE( EvtHandlerTestCase ); + CPPUNIT_TEST( BuiltinConnect ); + CPPUNIT_TEST( LegacyConnect ); +#ifdef wxHAS_EVENT_BIND + CPPUNIT_TEST( BindFunction ); + CPPUNIT_TEST( BindStaticMethod ); + CPPUNIT_TEST( BindFunctor ); + CPPUNIT_TEST( BindMethod ); + CPPUNIT_TEST( BindMethodUsingBaseEvent ); + CPPUNIT_TEST( BindFunctionUsingBaseEvent ); + CPPUNIT_TEST( BindNonHandler ); + CPPUNIT_TEST( InvalidBind ); +#endif // wxHAS_EVENT_BIND + CPPUNIT_TEST_SUITE_END(); - handler.Disconnect( EVT_LEGACY, (wxObjectEventFunction)&MyHandler::handleEvent ); - handler.Disconnect( 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::handleEvent ); - handler.Disconnect( 0, 0, EVT_LEGACY, (wxObjectEventFunction)&MyHandler::handleEvent ); + void BuiltinConnect(); + void LegacyConnect(); +#ifdef wxHAS_EVENT_BIND + void BindFunction(); + void BindStaticMethod(); + void BindFunctor(); + void BindMethod(); + void BindMethodUsingBaseEvent(); + void BindFunctionUsingBaseEvent(); + void BindNonHandler(); + void InvalidBind(); +#endif // wxHAS_EVENT_BIND + + + // these member variables exceptionally don't use "m_" prefix because + // they're used so many times + MyHandler handler; + MyEvent e; - // Call (and therefore instantiate) all Connect() variants to detect template - // errors: + DECLARE_NO_COPY_CLASS(EvtHandlerTestCase) +}; -#if !wxEVENTS_COMPATIBILITY_2_8 +// register in the unnamed registry so that these tests are run by default +CPPUNIT_TEST_SUITE_REGISTRATION( EvtHandlerTestCase ); - handler.Connect( EVT_EVENT, &MyHandler::handleFunction ); - handler.Connect( 0, EVT_EVENT, &MyHandler::handleFunction ); - handler.Connect( 0, 0, EVT_EVENT, &MyHandler::handleFunction ); +// also include in it's own registry so that these tests can be run alone +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtHandlerTestCase, "EvtHandlerTestCase" ); - handler.Disconnect( EVT_EVENT, &MyHandler::handleFunction ); - handler.Disconnect( 0, EVT_EVENT, &MyHandler::handleFunction ); - handler.Disconnect( 0, 0, EVT_EVENT, &MyHandler::handleFunction ); +void EvtHandlerTestCase::BuiltinConnect() +{ + handler.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle)); + handler.Disconnect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle)); + handler.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &handler); + handler.Disconnect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &handler); + // using casts like this is even uglier than using wxIdleEventHandler but + // it should still continue to work for compatibility + handler.Connect(wxEVT_IDLE, (wxObjectEventFunction)(wxEventFunction)&MyHandler::OnIdle); + handler.Disconnect(wxEVT_IDLE, (wxObjectEventFunction)(wxEventFunction)&MyHandler::OnIdle); - handler.Connect( EVT_EVENT, &MyHandler::handleMethod ); - handler.Connect( 0, EVT_EVENT, &MyHandler::handleMethod ); - handler.Connect( 0, 0, EVT_EVENT, &MyHandler::handleMethod ); +#ifdef wxHAS_EVENT_BIND + handler.Bind(wxEVT_IDLE, GlobalOnIdle); + handler.Unbind(wxEVT_IDLE, GlobalOnIdle); - handler.Disconnect( EVT_EVENT, &MyHandler::handleMethod ); - handler.Disconnect( 0, EVT_EVENT, &MyHandler::handleMethod ); - handler.Disconnect( 0, 0, EVT_EVENT, &MyHandler::handleMethod ); + IdleFunctor f; + handler.Bind(wxEVT_IDLE, f); + handler.Unbind(wxEVT_IDLE, f); + handler.Bind(wxEVT_IDLE, &MyHandler::OnIdle, &handler); + handler.Unbind(wxEVT_IDLE, &MyHandler::OnIdle, &handler); + handler.Bind(wxEVT_IDLE, &MyHandler::StaticOnIdle); + handler.Unbind(wxEVT_IDLE, &MyHandler::StaticOnIdle); +#endif // wxHAS_EVENT_BIND +} - handler.Connect( EVT_EVENT, &MyHandler::handleMethod, NULL, &handler ); - handler.Connect( 0, EVT_EVENT, &MyHandler::handleMethod, NULL, &handler ); - handler.Connect( 0, 0, EVT_EVENT, &MyHandler::handleMethod, NULL, &handler ); +void EvtHandlerTestCase::LegacyConnect() +{ + handler.Connect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent ); + handler.Connect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent ); + handler.Connect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent ); - handler.Disconnect( EVT_EVENT, &MyHandler::handleMethod, NULL, &handler ); - handler.Disconnect( 0, EVT_EVENT, &MyHandler::handleMethod, NULL, &handler ); - handler.Disconnect( 0, 0, EVT_EVENT, &MyHandler::handleMethod, NULL, &handler ); + handler.Disconnect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent ); + handler.Disconnect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent ); + handler.Disconnect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent ); + handler.Connect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); + handler.Connect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); + handler.Connect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); - wxEvtHandler::Connect( &handler, EVT_EVENT, &MyHandler::handleMethod, NULL, &handler ); - wxEvtHandler::Connect( &handler, 0, EVT_EVENT, &MyHandler::handleMethod, NULL, &handler ); - wxEvtHandler::Connect( &handler, 0, 0, EVT_EVENT, &MyHandler::handleMethod, NULL, &handler ); + handler.Disconnect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); + handler.Disconnect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); + handler.Disconnect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler ); +} - wxEvtHandler::Disconnect( &handler, EVT_EVENT, &MyHandler::handleMethod, NULL, &handler ); - wxEvtHandler::Disconnect( &handler, 0, EVT_EVENT, &MyHandler::handleMethod, NULL, &handler ); - wxEvtHandler::Disconnect( &handler, 0, 0, EVT_EVENT, &MyHandler::handleMethod, NULL, &handler ); +#ifdef wxHAS_EVENT_BIND +void EvtHandlerTestCase::BindFunction() +{ + // function tests + handler.Bind( MyEventType, GlobalOnMyEvent ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( g_called.function ); + handler.Unbind( MyEventType, GlobalOnMyEvent ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( !g_called.function ); // check that it was disconnected + + handler.Bind( MyEventType, GlobalOnMyEvent, 0 ); + handler.Unbind( MyEventType, GlobalOnMyEvent, 0 ); + + handler.Bind( MyEventType, GlobalOnMyEvent, 0, 0 ); + handler.Unbind( MyEventType, GlobalOnMyEvent, 0, 0 ); +} +void EvtHandlerTestCase::BindStaticMethod() +{ + // static method tests (this is same as functions but still test it just in + // case we hit some strange compiler bugs) + handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( g_called.smethod ); + handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( !g_called.smethod ); + + handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent, 0 ); + handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent, 0 ); + + handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent, 0, 0 ); + handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent, 0, 0 ); +} +void EvtHandlerTestCase::BindFunctor() +{ + // generalized functor tests MyFunctor functor; - handler.Connect( EVT_EVENT, functor ); - handler.Connect( 0, EVT_EVENT, functor ); - handler.Connect( 0, 0, EVT_EVENT, functor ); + handler.Bind( MyEventType, functor ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( g_called.functor ); + handler.Unbind( MyEventType, functor ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( !g_called.functor ); + + handler.Bind( MyEventType, functor, 0 ); + handler.Unbind( MyEventType, functor, 0 ); + + handler.Bind( MyEventType, functor, 0, 0 ); + handler.Unbind( MyEventType, functor, 0, 0 ); + + // test that a temporary functor is working as well and also test that + // unbinding a different (though equal) instance of the same functor does + // not work + MyFunctor func; + handler.Bind( MyEventType, MyFunctor() ); + CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func )); + + handler.Bind( MyEventType, MyFunctor(), 0 ); + CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func, 0 )); + + handler.Bind( MyEventType, MyFunctor(), 0, 0 ); + CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func, 0, 0 )); +} - handler.Disconnect( EVT_EVENT, functor ); - handler.Disconnect( 0, EVT_EVENT, functor ); - handler.Disconnect( 0, 0, EVT_EVENT, functor ); -#endif +void EvtHandlerTestCase::BindMethod() +{ + // class method tests + handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( g_called.method ); + handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( !g_called.method ); + + handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler, 0 ); + handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler, 0 ); + + handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler, 0, 0 ); + handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler, 0, 0 ); +} + +void EvtHandlerTestCase::BindMethodUsingBaseEvent() +{ + // test connecting a method taking just wxEvent and not MyEvent: this + // should work too if we don't need any MyEvent-specific information in the + // handler + handler.Bind( MyEventType, &MyHandler::OnEvent, &handler ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( g_called.method ); + handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( !g_called.method ); + + handler.Bind( MyEventType, &MyHandler::OnEvent, &handler, 0 ); + handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler, 0 ); + + handler.Bind( MyEventType, &MyHandler::OnEvent, &handler, 0, 0 ); + handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler, 0, 0 ); +} + + +void EvtHandlerTestCase::BindFunctionUsingBaseEvent() +{ + // test connecting a function taking just wxEvent and not MyEvent: this + // should work too if we don't need any MyEvent-specific information in the + // handler + handler.Bind( MyEventType, GlobalOnEvent ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( g_called.function ); + handler.Unbind( MyEventType, GlobalOnEvent ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( !g_called.function ); + + handler.Bind( MyEventType, GlobalOnEvent, 0 ); + handler.Unbind( MyEventType, GlobalOnEvent, 0 ); + + handler.Bind( MyEventType, GlobalOnEvent, 0, 0 ); + handler.Unbind( MyEventType, GlobalOnEvent, 0, 0 ); } -void EvtHandlerTestCase::TestEventFunctorCompare() -{ -//#if !wxEVENTS_COMPATIBILITY_2_8 -// MyHandler handler1; -// wxEventFunctor *connectFunctor = wxNewEventFunctor( EVT_EVENT, &MyHandler::handleMethod, &handler1 ); -// wxEventFunctor *disconnectFunctor = wxNewEventFunctor( EVT_EVENT, &MyHandler::handleMethod, &handler1 ); -// wxEventFunctor *nullFunctor = wxNewEventFunctor( EVT_EVENT, &MyHandler::handleMethod ); -// -// CPPUNIT_ASSERT( connectFunctor->Matches( *disconnectFunctor )); -// CPPUNIT_ASSERT( disconnectFunctor->Matches( *connectFunctor )); -// -// CPPUNIT_ASSERT( connectFunctor->Matches( *nullFunctor )); -// CPPUNIT_ASSERT( nullFunctor->Matches( *connectFunctor )); -// -// CPPUNIT_ASSERT( disconnectFunctor->Matches( *nullFunctor )); -// CPPUNIT_ASSERT( nullFunctor->Matches( *disconnectFunctor )); -//#endif + + +void EvtHandlerTestCase::BindNonHandler() +{ + // class method tests for class not derived from wxEvtHandler + MySink sink; + + handler.Bind( MyEventType, &MySink::OnMyEvent, &sink ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( g_called.method ); + handler.Unbind( MyEventType, &MySink::OnMyEvent, &sink ); + g_called.Reset(); + handler.ProcessEvent(e); + CPPUNIT_ASSERT( !g_called.method ); } +void EvtHandlerTestCase::InvalidBind() +{ + // these calls shouldn't compile but we unfortunately can't check this + // automatically, you need to uncomment them manually and test that + // compilation does indeed fail + + // connecting a handler with incompatible signature shouldn't work +#ifdef TEST_INVALID_BIND_GLOBAL + handler.Bind(MyEventType, GlobalOnAnotherEvent); +#endif +#ifdef TEST_INVALID_BIND_STATIC + handler.Bind(MyEventType, &MyHandler::StaticOnAnotherEvent); +#endif +#ifdef TEST_INVALID_BIND_METHOD + handler.Bind(MyEventType, &MyHandler::OnAnotherEvent, &handler); +#endif +#ifdef TEST_INVALID_BIND_FUNCTOR + IdleFunctor f; + handler.Bind(MyEventType, f); +#endif + + // the handler can't be omitted when calling Bind() +#ifdef TEST_INVALID_BIND_NO_HANDLER + handler.Bind(MyEventType, &MyHandler::OnMyEvent); +#endif + + // calling a derived class method with a base class pointer must not work +#ifdef TEST_INVALID_BIND_DERIVED + struct C1 : wxEvtHandler { }; + struct C2 : wxEvtHandler { void OnWhatever(wxEvent&); }; + C1 c1; + c1.Bind(&C2::OnWhatever); +#endif + + // using object pointer incompatible with the method must not work +#ifdef TEST_INVALID_BIND_WRONG_CLASS + MySink mySink; + MyHandler myHandler; + myHandler.Bind(MyEventType, &MyHandler::OnMyEvent, &mySink); +#endif +} +#endif // wxHAS_EVENT_BIND