1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/events/evthandler.cpp
3 // Purpose: Test the new event types and wxEvtHandler-methods
6 // Copyright: (c) 2009 Peter Most
7 ///////////////////////////////////////////////////////////////////////////////
9 // ----------------------------------------------------------------------------
11 // ----------------------------------------------------------------------------
21 // ----------------------------------------------------------------------------
22 // test events and their handlers
23 // ----------------------------------------------------------------------------
25 const wxEventType LegacyEventType
= wxNewEventType();
28 wxDEFINE_EVENT(MyEventType
, MyEvent
);
30 class MyEvent
: public wxEvent
33 MyEvent() : wxEvent(0, MyEventType
) { }
35 virtual wxEvent
*Clone() const { return new MyEvent
; }
38 typedef void (wxEvtHandler::*MyEventFunction
)(MyEvent
&);
39 #ifndef wxHAS_EVENT_BIND
40 #define MyEventHandler(func) wxEVENT_HANDLER_CAST(MyEventFunction, func)
42 #define MyEventHandler(func) &func
44 #define EVT_MYEVENT(func) \
45 wx__DECLARE_EVT0(MyEventType, MyEventHandler(func))
47 class AnotherEvent
: public wxEvent
72 void GlobalOnMyEvent(MyEvent
&)
74 g_called
.function
= true;
77 void GlobalOnEvent(wxEvent
&)
79 g_called
.function
= true;
82 #ifdef TEST_INVALID_BIND_GLOBAL
83 void GlobalOnAnotherEvent(AnotherEvent
&);
86 void GlobalOnIdle(wxIdleEvent
&)
88 g_called
.function
= true;
93 void operator()(MyEvent
&) { g_called
.functor
= true; }
98 void operator()(wxIdleEvent
&) { g_called
.functor
= true; }
101 class MyHandler
: public wxEvtHandler
104 static void StaticOnMyEvent(MyEvent
&) { g_called
.smethod
= true; }
105 static void StaticOnAnotherEvent(AnotherEvent
&);
106 static void StaticOnIdle(wxIdleEvent
&) { g_called
.smethod
= true; }
108 void OnMyEvent(MyEvent
&) { g_called
.method
= true; }
109 void OnEvent(wxEvent
&) { g_called
.method
= true; }
110 void OnAnotherEvent(AnotherEvent
&);
111 void OnIdle(wxIdleEvent
&) { g_called
.method
= true; }
114 // we can also handle events in classes not deriving from wxEvtHandler
117 void OnMyEvent(MyEvent
&) { g_called
.method
= true; }
118 void OnEvent(wxEvent
&) { g_called
.method
= true; }
119 void OnIdle(wxIdleEvent
&) { g_called
.method
= true; }
122 // also test event table compilation
123 class MyClassWithEventTable
: public wxEvtHandler
126 void OnMyEvent(MyEvent
&) { g_called
.method
= true; }
127 void OnEvent(wxEvent
&) { g_called
.method
= true; }
128 void OnAnotherEvent(AnotherEvent
&);
129 void OnIdle(wxIdleEvent
&) { g_called
.method
= true; }
132 DECLARE_EVENT_TABLE()
135 BEGIN_EVENT_TABLE(MyClassWithEventTable
, wxEvtHandler
)
136 EVT_IDLE(MyClassWithEventTable::OnIdle
)
138 EVT_MYEVENT(MyClassWithEventTable::OnMyEvent
)
139 #ifdef wxHAS_EVENT_BIND
140 EVT_MYEVENT(MyClassWithEventTable::OnEvent
)
143 // this shouldn't compile:
144 //EVT_MYEVENT(MyClassWithEventTable::OnIdle)
145 //EVT_IDLE(MyClassWithEventTable::OnAnotherEvent)
148 } // anonymous namespace
151 // --------------------------------------------------------------------------
153 // --------------------------------------------------------------------------
155 class EvtHandlerTestCase
: public CppUnit::TestCase
158 EvtHandlerTestCase() {}
161 CPPUNIT_TEST_SUITE( EvtHandlerTestCase
);
162 CPPUNIT_TEST( BuiltinConnect
);
163 CPPUNIT_TEST( LegacyConnect
);
164 CPPUNIT_TEST( DisconnectWildcard
);
165 CPPUNIT_TEST( AutoDisconnect
);
166 #ifdef wxHAS_EVENT_BIND
167 CPPUNIT_TEST( BindFunction
);
168 CPPUNIT_TEST( BindStaticMethod
);
169 CPPUNIT_TEST( BindFunctor
);
170 CPPUNIT_TEST( BindMethod
);
171 CPPUNIT_TEST( BindMethodUsingBaseEvent
);
172 CPPUNIT_TEST( BindFunctionUsingBaseEvent
);
173 CPPUNIT_TEST( BindNonHandler
);
174 CPPUNIT_TEST( InvalidBind
);
175 #endif // wxHAS_EVENT_BIND
176 CPPUNIT_TEST_SUITE_END();
178 void BuiltinConnect();
179 void LegacyConnect();
180 void DisconnectWildcard();
181 void AutoDisconnect();
182 #ifdef wxHAS_EVENT_BIND
184 void BindStaticMethod();
187 void BindMethodUsingBaseEvent();
188 void BindFunctionUsingBaseEvent();
189 void BindNonHandler();
191 #endif // wxHAS_EVENT_BIND
194 // these member variables exceptionally don't use "m_" prefix because
195 // they're used so many times
199 DECLARE_NO_COPY_CLASS(EvtHandlerTestCase
)
202 // register in the unnamed registry so that these tests are run by default
203 CPPUNIT_TEST_SUITE_REGISTRATION( EvtHandlerTestCase
);
205 // also include in its own registry so that these tests can be run alone
206 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtHandlerTestCase
, "EvtHandlerTestCase" );
208 void EvtHandlerTestCase::BuiltinConnect()
210 handler
.Connect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
));
211 handler
.Disconnect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
));
213 handler
.Connect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &handler
);
214 handler
.Disconnect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &handler
);
216 // using casts like this is even uglier than using wxIdleEventHandler but
217 // it should still continue to work for compatibility
218 handler
.Connect(wxEVT_IDLE
, (wxObjectEventFunction
)(wxEventFunction
)&MyHandler::OnIdle
);
219 handler
.Disconnect(wxEVT_IDLE
, (wxObjectEventFunction
)(wxEventFunction
)&MyHandler::OnIdle
);
221 #ifdef wxHAS_EVENT_BIND
222 handler
.Bind(wxEVT_IDLE
, GlobalOnIdle
);
223 handler
.Unbind(wxEVT_IDLE
, GlobalOnIdle
);
226 handler
.Bind(wxEVT_IDLE
, f
);
227 handler
.Unbind(wxEVT_IDLE
, f
);
229 handler
.Bind(wxEVT_IDLE
, &MyHandler::OnIdle
, &handler
);
230 handler
.Unbind(wxEVT_IDLE
, &MyHandler::OnIdle
, &handler
);
232 handler
.Bind(wxEVT_IDLE
, &MyHandler::StaticOnIdle
);
233 handler
.Unbind(wxEVT_IDLE
, &MyHandler::StaticOnIdle
);
234 #endif // wxHAS_EVENT_BIND
237 void EvtHandlerTestCase::LegacyConnect()
239 handler
.Connect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
240 handler
.Connect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
241 handler
.Connect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
243 handler
.Disconnect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
244 handler
.Disconnect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
245 handler
.Disconnect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
248 handler
.Connect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
249 handler
.Connect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
250 handler
.Connect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
252 handler
.Disconnect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
253 handler
.Disconnect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
254 handler
.Disconnect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
257 void EvtHandlerTestCase::DisconnectWildcard()
259 // should be able to disconnect a different handler using "wildcard search"
262 source
.Connect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &sink
);
263 CPPUNIT_ASSERT(source
.Disconnect(wxID_ANY
, wxEVT_IDLE
));
264 // destruction of source and sink here should properly clean up the
265 // wxEventConnectionRef without crashing
268 void EvtHandlerTestCase::AutoDisconnect()
273 source
.Connect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &sink
);
274 // mismatched event type, so nothing should be disconnected
275 CPPUNIT_ASSERT(!source
.Disconnect(wxEVT_THREAD
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &sink
));
277 // destruction of sink should have automatically disconnected it, so
278 // there should be nothing to disconnect anymore
279 CPPUNIT_ASSERT(!source
.Disconnect(wxID_ANY
, wxEVT_IDLE
));
282 #ifdef wxHAS_EVENT_BIND
284 void EvtHandlerTestCase::BindFunction()
287 handler
.Bind( MyEventType
, GlobalOnMyEvent
);
289 handler
.ProcessEvent(e
);
290 CPPUNIT_ASSERT( g_called
.function
);
291 handler
.Unbind( MyEventType
, GlobalOnMyEvent
);
293 handler
.ProcessEvent(e
);
294 CPPUNIT_ASSERT( !g_called
.function
); // check that it was disconnected
296 handler
.Bind( MyEventType
, GlobalOnMyEvent
, 0 );
297 handler
.Unbind( MyEventType
, GlobalOnMyEvent
, 0 );
299 handler
.Bind( MyEventType
, GlobalOnMyEvent
, 0, 0 );
300 handler
.Unbind( MyEventType
, GlobalOnMyEvent
, 0, 0 );
303 void EvtHandlerTestCase::BindStaticMethod()
305 // static method tests (this is same as functions but still test it just in
306 // case we hit some strange compiler bugs)
307 handler
.Bind( MyEventType
, &MyHandler::StaticOnMyEvent
);
309 handler
.ProcessEvent(e
);
310 CPPUNIT_ASSERT( g_called
.smethod
);
311 handler
.Unbind( MyEventType
, &MyHandler::StaticOnMyEvent
);
313 handler
.ProcessEvent(e
);
314 CPPUNIT_ASSERT( !g_called
.smethod
);
316 handler
.Bind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0 );
317 handler
.Unbind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0 );
319 handler
.Bind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0, 0 );
320 handler
.Unbind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0, 0 );
323 void EvtHandlerTestCase::BindFunctor()
325 // generalized functor tests
328 handler
.Bind( MyEventType
, functor
);
330 handler
.ProcessEvent(e
);
331 CPPUNIT_ASSERT( g_called
.functor
);
332 handler
.Unbind( MyEventType
, functor
);
334 handler
.ProcessEvent(e
);
335 CPPUNIT_ASSERT( !g_called
.functor
);
337 handler
.Bind( MyEventType
, functor
, 0 );
338 handler
.Unbind( MyEventType
, functor
, 0 );
340 handler
.Bind( MyEventType
, functor
, 0, 0 );
341 handler
.Unbind( MyEventType
, functor
, 0, 0 );
343 // test that a temporary functor is working as well and also test that
344 // unbinding a different (though equal) instance of the same functor does
347 handler
.Bind( MyEventType
, MyFunctor() );
348 CPPUNIT_ASSERT( !handler
.Unbind( MyEventType
, func
));
350 handler
.Bind( MyEventType
, MyFunctor(), 0 );
351 CPPUNIT_ASSERT( !handler
.Unbind( MyEventType
, func
, 0 ));
353 handler
.Bind( MyEventType
, MyFunctor(), 0, 0 );
354 CPPUNIT_ASSERT( !handler
.Unbind( MyEventType
, func
, 0, 0 ));
357 void EvtHandlerTestCase::BindMethod()
359 // class method tests
360 handler
.Bind( MyEventType
, &MyHandler::OnMyEvent
, &handler
);
362 handler
.ProcessEvent(e
);
363 CPPUNIT_ASSERT( g_called
.method
);
364 handler
.Unbind( MyEventType
, &MyHandler::OnMyEvent
, &handler
);
366 handler
.ProcessEvent(e
);
367 CPPUNIT_ASSERT( !g_called
.method
);
369 handler
.Bind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0 );
370 handler
.Unbind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0 );
372 handler
.Bind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0, 0 );
373 handler
.Unbind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0, 0 );
376 void EvtHandlerTestCase::BindMethodUsingBaseEvent()
378 // test connecting a method taking just wxEvent and not MyEvent: this
379 // should work too if we don't need any MyEvent-specific information in the
381 handler
.Bind( MyEventType
, &MyHandler::OnEvent
, &handler
);
383 handler
.ProcessEvent(e
);
384 CPPUNIT_ASSERT( g_called
.method
);
385 handler
.Unbind( MyEventType
, &MyHandler::OnEvent
, &handler
);
387 handler
.ProcessEvent(e
);
388 CPPUNIT_ASSERT( !g_called
.method
);
390 handler
.Bind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0 );
391 handler
.Unbind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0 );
393 handler
.Bind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0, 0 );
394 handler
.Unbind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0, 0 );
398 void EvtHandlerTestCase::BindFunctionUsingBaseEvent()
400 // test connecting a function taking just wxEvent and not MyEvent: this
401 // should work too if we don't need any MyEvent-specific information in the
403 handler
.Bind( MyEventType
, GlobalOnEvent
);
405 handler
.ProcessEvent(e
);
406 CPPUNIT_ASSERT( g_called
.function
);
407 handler
.Unbind( MyEventType
, GlobalOnEvent
);
409 handler
.ProcessEvent(e
);
410 CPPUNIT_ASSERT( !g_called
.function
);
412 handler
.Bind( MyEventType
, GlobalOnEvent
, 0 );
413 handler
.Unbind( MyEventType
, GlobalOnEvent
, 0 );
415 handler
.Bind( MyEventType
, GlobalOnEvent
, 0, 0 );
416 handler
.Unbind( MyEventType
, GlobalOnEvent
, 0, 0 );
421 void EvtHandlerTestCase::BindNonHandler()
423 // class method tests for class not derived from wxEvtHandler
426 handler
.Bind( MyEventType
, &MySink::OnMyEvent
, &sink
);
428 handler
.ProcessEvent(e
);
429 CPPUNIT_ASSERT( g_called
.method
);
430 handler
.Unbind( MyEventType
, &MySink::OnMyEvent
, &sink
);
432 handler
.ProcessEvent(e
);
433 CPPUNIT_ASSERT( !g_called
.method
);
436 void EvtHandlerTestCase::InvalidBind()
438 // these calls shouldn't compile but we unfortunately can't check this
439 // automatically, you need to uncomment them manually and test that
440 // compilation does indeed fail
442 // connecting a handler with incompatible signature shouldn't work
443 #ifdef TEST_INVALID_BIND_GLOBAL
444 handler
.Bind(MyEventType
, GlobalOnAnotherEvent
);
446 #ifdef TEST_INVALID_BIND_STATIC
447 handler
.Bind(MyEventType
, &MyHandler::StaticOnAnotherEvent
);
449 #ifdef TEST_INVALID_BIND_METHOD
450 handler
.Bind(MyEventType
, &MyHandler::OnAnotherEvent
, &handler
);
452 #ifdef TEST_INVALID_BIND_FUNCTOR
454 handler
.Bind(MyEventType
, f
);
457 // the handler can't be omitted when calling Bind()
458 #ifdef TEST_INVALID_BIND_NO_HANDLER
459 handler
.Bind(MyEventType
, &MyHandler::OnMyEvent
);
462 // calling a derived class method with a base class pointer must not work
463 #ifdef TEST_INVALID_BIND_DERIVED
464 struct C1
: wxEvtHandler
{ };
465 struct C2
: wxEvtHandler
{ void OnWhatever(wxEvent
&); };
467 c1
.Bind(&C2::OnWhatever
);
470 // using object pointer incompatible with the method must not work
471 #ifdef TEST_INVALID_BIND_WRONG_CLASS
474 myHandler
.Bind(MyEventType
, &MyHandler::OnMyEvent
, &mySink
);
478 #endif // wxHAS_EVENT_BIND