| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478 |
- ///////////////////////////////////////////////////////////////////////////////
- // Name: tests/events/evthandler.cpp
- // Purpose: Test the new event types and wxEvtHandler-methods
- // Author: Peter Most
- // Created: 2009-01-24
- // Copyright: (c) 2009 Peter Most
- ///////////////////////////////////////////////////////////////////////////////
- // ----------------------------------------------------------------------------
- // headers
- // ----------------------------------------------------------------------------
- #include "testprec.h"
- #ifdef __BORLANDC__
- #pragma hdrstop
- #endif
- #include "wx/event.h"
- // ----------------------------------------------------------------------------
- // test events and their handlers
- // ----------------------------------------------------------------------------
- const wxEventType LegacyEventType = wxNewEventType();
- class MyEvent;
- wxDEFINE_EVENT(MyEventType, MyEvent);
- class MyEvent : public wxEvent
- {
- public:
- MyEvent() : wxEvent(0, MyEventType) { }
- virtual wxEvent *Clone() const { return new MyEvent; }
- };
- 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))
- class AnotherEvent : public wxEvent
- {
- };
- namespace
- {
- 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;
- }
- void GlobalOnEvent(wxEvent&)
- {
- g_called.function = true;
- }
- #ifdef TEST_INVALID_BIND_GLOBAL
- void GlobalOnAnotherEvent(AnotherEvent&);
- #endif
- void GlobalOnIdle(wxIdleEvent&)
- {
- g_called.function = true;
- }
- struct MyFunctor
- {
- void operator()(MyEvent &) { g_called.functor = true; }
- };
- struct IdleFunctor
- {
- void operator()(wxIdleEvent &) { g_called.functor = true; }
- };
- class MyHandler : public wxEvtHandler
- {
- 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; }
- };
- // 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; }
- };
- // 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()
- };
- BEGIN_EVENT_TABLE(MyClassWithEventTable, wxEvtHandler)
- EVT_IDLE(MyClassWithEventTable::OnIdle)
- EVT_MYEVENT(MyClassWithEventTable::OnMyEvent)
- #ifdef wxHAS_EVENT_BIND
- EVT_MYEVENT(MyClassWithEventTable::OnEvent)
- #endif
- // this shouldn't compile:
- //EVT_MYEVENT(MyClassWithEventTable::OnIdle)
- //EVT_IDLE(MyClassWithEventTable::OnAnotherEvent)
- END_EVENT_TABLE()
- } // anonymous namespace
- // --------------------------------------------------------------------------
- // test class
- // --------------------------------------------------------------------------
- class EvtHandlerTestCase : public CppUnit::TestCase
- {
- public:
- EvtHandlerTestCase() {}
- private:
- CPPUNIT_TEST_SUITE( EvtHandlerTestCase );
- CPPUNIT_TEST( BuiltinConnect );
- CPPUNIT_TEST( LegacyConnect );
- CPPUNIT_TEST( DisconnectWildcard );
- CPPUNIT_TEST( AutoDisconnect );
- #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();
- void BuiltinConnect();
- void LegacyConnect();
- void DisconnectWildcard();
- void AutoDisconnect();
- #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;
- DECLARE_NO_COPY_CLASS(EvtHandlerTestCase)
- };
- // register in the unnamed registry so that these tests are run by default
- CPPUNIT_TEST_SUITE_REGISTRATION( EvtHandlerTestCase );
- // also include in its own registry so that these tests can be run alone
- CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtHandlerTestCase, "EvtHandlerTestCase" );
- 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);
- #ifdef wxHAS_EVENT_BIND
- handler.Bind(wxEVT_IDLE, GlobalOnIdle);
- handler.Unbind(wxEVT_IDLE, GlobalOnIdle);
- 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
- }
- 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( 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 );
- 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 );
- }
- void EvtHandlerTestCase::DisconnectWildcard()
- {
- // should be able to disconnect a different handler using "wildcard search"
- MyHandler sink;
- wxEvtHandler source;
- source.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &sink);
- CPPUNIT_ASSERT(source.Disconnect(wxID_ANY, wxEVT_IDLE));
- // destruction of source and sink here should properly clean up the
- // wxEventConnectionRef without crashing
- }
- void EvtHandlerTestCase::AutoDisconnect()
- {
- wxEvtHandler source;
- {
- MyHandler sink;
- source.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &sink);
- // mismatched event type, so nothing should be disconnected
- CPPUNIT_ASSERT(!source.Disconnect(wxEVT_THREAD, wxIdleEventHandler(MyHandler::OnIdle), NULL, &sink));
- }
- // destruction of sink should have automatically disconnected it, so
- // there should be nothing to disconnect anymore
- CPPUNIT_ASSERT(!source.Disconnect(wxID_ANY, wxEVT_IDLE));
- }
- #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.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 ));
- }
- 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::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
|