#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