1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/events/evthandler.cpp
3 // Purpose: Test the new event types and wxEvtHandler-methods
7 // Copyright: (c) 2009 Peter Most
8 ///////////////////////////////////////////////////////////////////////////////
10 // ----------------------------------------------------------------------------
12 // ----------------------------------------------------------------------------
22 // ----------------------------------------------------------------------------
23 // test events and their handlers
24 // ----------------------------------------------------------------------------
26 const wxEventType LegacyEventType
= wxNewEventType();
29 wxDEFINE_EVENT(MyEventType
, MyEvent
);
31 class MyEvent
: public wxEvent
34 MyEvent() : wxEvent(0, MyEventType
) { }
36 virtual wxEvent
*Clone() const { return new MyEvent
; }
39 typedef void (wxEvtHandler::*MyEventFunction
)(MyEvent
&);
40 #ifndef wxHAS_EVENT_BIND
41 #define MyEventHandler(func) wxEVENT_HANDLER_CAST(MyEventFunction, func)
43 #define MyEventHandler(func) &func
45 #define EVT_MYEVENT(func) \
46 wx__DECLARE_EVT0(MyEventType, MyEventHandler(func))
48 class AnotherEvent
: public wxEvent
73 void GlobalOnMyEvent(MyEvent
&)
75 g_called
.function
= true;
78 void GlobalOnEvent(wxEvent
&)
80 g_called
.function
= true;
83 void GlobalOnAnotherEvent(AnotherEvent
&);
85 void GlobalOnIdle(wxIdleEvent
&)
87 g_called
.function
= true;
92 void operator()(MyEvent
&) { g_called
.functor
= true; }
97 void operator()(wxIdleEvent
&) { g_called
.functor
= true; }
100 class MyHandler
: public wxEvtHandler
103 static void StaticOnMyEvent(MyEvent
&) { g_called
.smethod
= true; }
104 static void StaticOnAnotherEvent(AnotherEvent
&);
105 static void StaticOnIdle(wxIdleEvent
&) { g_called
.smethod
= true; }
107 void OnMyEvent(MyEvent
&) { g_called
.method
= true; }
108 void OnEvent(wxEvent
&) { g_called
.method
= true; }
109 void OnAnotherEvent(AnotherEvent
&);
110 void OnIdle(wxIdleEvent
&) { g_called
.method
= true; }
113 // we can also handle events in classes not deriving from wxEvtHandler
116 void OnMyEvent(MyEvent
&) { g_called
.method
= true; }
117 void OnEvent(wxEvent
&) { g_called
.method
= true; }
118 void OnIdle(wxIdleEvent
&) { g_called
.method
= true; }
121 // also test event table compilation
122 class MyClassWithEventTable
: public wxEvtHandler
125 void OnMyEvent(MyEvent
&) { g_called
.method
= true; }
126 void OnEvent(wxEvent
&) { g_called
.method
= true; }
127 void OnAnotherEvent(AnotherEvent
&);
128 void OnIdle(wxIdleEvent
&) { g_called
.method
= true; }
131 DECLARE_EVENT_TABLE()
134 BEGIN_EVENT_TABLE(MyClassWithEventTable
, wxEvtHandler
)
135 EVT_IDLE(MyClassWithEventTable::OnIdle
)
137 EVT_MYEVENT(MyClassWithEventTable::OnMyEvent
)
138 #ifdef wxHAS_EVENT_BIND
139 EVT_MYEVENT(MyClassWithEventTable::OnEvent
)
142 // this shouldn't compile:
143 //EVT_MYEVENT(MyClassWithEventTable::OnIdle)
144 //EVT_IDLE(MyClassWithEventTable::OnAnotherEvent)
147 } // anonymous namespace
150 // --------------------------------------------------------------------------
152 // --------------------------------------------------------------------------
154 class EvtHandlerTestCase
: public CppUnit::TestCase
157 EvtHandlerTestCase() {}
160 CPPUNIT_TEST_SUITE( EvtHandlerTestCase
);
161 CPPUNIT_TEST( BuiltinConnect
);
162 CPPUNIT_TEST( LegacyConnect
);
163 CPPUNIT_TEST( DisconnectWildcard
);
164 CPPUNIT_TEST( AutoDisconnect
);
165 #ifdef wxHAS_EVENT_BIND
166 CPPUNIT_TEST( BindFunction
);
167 CPPUNIT_TEST( BindStaticMethod
);
168 CPPUNIT_TEST( BindFunctor
);
169 CPPUNIT_TEST( BindMethod
);
170 CPPUNIT_TEST( BindMethodUsingBaseEvent
);
171 CPPUNIT_TEST( BindFunctionUsingBaseEvent
);
172 CPPUNIT_TEST( BindNonHandler
);
173 CPPUNIT_TEST( InvalidBind
);
174 #endif // wxHAS_EVENT_BIND
175 CPPUNIT_TEST_SUITE_END();
177 void BuiltinConnect();
178 void LegacyConnect();
179 void DisconnectWildcard();
180 void AutoDisconnect();
181 #ifdef wxHAS_EVENT_BIND
183 void BindStaticMethod();
186 void BindMethodUsingBaseEvent();
187 void BindFunctionUsingBaseEvent();
188 void BindNonHandler();
190 #endif // wxHAS_EVENT_BIND
193 // these member variables exceptionally don't use "m_" prefix because
194 // they're used so many times
198 DECLARE_NO_COPY_CLASS(EvtHandlerTestCase
)
201 // register in the unnamed registry so that these tests are run by default
202 CPPUNIT_TEST_SUITE_REGISTRATION( EvtHandlerTestCase
);
204 // also include in its own registry so that these tests can be run alone
205 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtHandlerTestCase
, "EvtHandlerTestCase" );
207 void EvtHandlerTestCase::BuiltinConnect()
209 handler
.Connect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
));
210 handler
.Disconnect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
));
212 handler
.Connect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &handler
);
213 handler
.Disconnect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &handler
);
215 // using casts like this is even uglier than using wxIdleEventHandler but
216 // it should still continue to work for compatibility
217 handler
.Connect(wxEVT_IDLE
, (wxObjectEventFunction
)(wxEventFunction
)&MyHandler::OnIdle
);
218 handler
.Disconnect(wxEVT_IDLE
, (wxObjectEventFunction
)(wxEventFunction
)&MyHandler::OnIdle
);
220 #ifdef wxHAS_EVENT_BIND
221 handler
.Bind(wxEVT_IDLE
, GlobalOnIdle
);
222 handler
.Unbind(wxEVT_IDLE
, GlobalOnIdle
);
225 handler
.Bind(wxEVT_IDLE
, f
);
226 handler
.Unbind(wxEVT_IDLE
, f
);
228 handler
.Bind(wxEVT_IDLE
, &MyHandler::OnIdle
, &handler
);
229 handler
.Unbind(wxEVT_IDLE
, &MyHandler::OnIdle
, &handler
);
231 handler
.Bind(wxEVT_IDLE
, &MyHandler::StaticOnIdle
);
232 handler
.Unbind(wxEVT_IDLE
, &MyHandler::StaticOnIdle
);
233 #endif // wxHAS_EVENT_BIND
236 void EvtHandlerTestCase::LegacyConnect()
238 handler
.Connect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
239 handler
.Connect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
240 handler
.Connect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
242 handler
.Disconnect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
243 handler
.Disconnect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
244 handler
.Disconnect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
247 handler
.Connect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
248 handler
.Connect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
249 handler
.Connect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
251 handler
.Disconnect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
252 handler
.Disconnect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
253 handler
.Disconnect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
256 void EvtHandlerTestCase::DisconnectWildcard()
258 // should be able to disconnect a different handler using "wildcard search"
261 source
.Connect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &sink
);
262 CPPUNIT_ASSERT(source
.Disconnect(wxID_ANY
, wxEVT_IDLE
));
263 // destruction of source and sink here should properly clean up the
264 // wxEventConnectionRef without crashing
267 void EvtHandlerTestCase::AutoDisconnect()
272 source
.Connect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &sink
);
273 // mismatched event type, so nothing should be disconnected
274 CPPUNIT_ASSERT(!source
.Disconnect(wxEVT_THREAD
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &sink
));
276 // destruction of sink should have automatically disconnected it, so
277 // there should be nothing to disconnect anymore
278 CPPUNIT_ASSERT(!source
.Disconnect(wxID_ANY
, wxEVT_IDLE
));
281 #ifdef wxHAS_EVENT_BIND
283 void EvtHandlerTestCase::BindFunction()
286 handler
.Bind( MyEventType
, GlobalOnMyEvent
);
288 handler
.ProcessEvent(e
);
289 CPPUNIT_ASSERT( g_called
.function
);
290 handler
.Unbind( MyEventType
, GlobalOnMyEvent
);
292 handler
.ProcessEvent(e
);
293 CPPUNIT_ASSERT( !g_called
.function
); // check that it was disconnected
295 handler
.Bind( MyEventType
, GlobalOnMyEvent
, 0 );
296 handler
.Unbind( MyEventType
, GlobalOnMyEvent
, 0 );
298 handler
.Bind( MyEventType
, GlobalOnMyEvent
, 0, 0 );
299 handler
.Unbind( MyEventType
, GlobalOnMyEvent
, 0, 0 );
302 void EvtHandlerTestCase::BindStaticMethod()
304 // static method tests (this is same as functions but still test it just in
305 // case we hit some strange compiler bugs)
306 handler
.Bind( MyEventType
, &MyHandler::StaticOnMyEvent
);
308 handler
.ProcessEvent(e
);
309 CPPUNIT_ASSERT( g_called
.smethod
);
310 handler
.Unbind( MyEventType
, &MyHandler::StaticOnMyEvent
);
312 handler
.ProcessEvent(e
);
313 CPPUNIT_ASSERT( !g_called
.smethod
);
315 handler
.Bind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0 );
316 handler
.Unbind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0 );
318 handler
.Bind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0, 0 );
319 handler
.Unbind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0, 0 );
322 void EvtHandlerTestCase::BindFunctor()
324 // generalized functor tests
327 handler
.Bind( MyEventType
, functor
);
329 handler
.ProcessEvent(e
);
330 CPPUNIT_ASSERT( g_called
.functor
);
331 handler
.Unbind( MyEventType
, functor
);
333 handler
.ProcessEvent(e
);
334 CPPUNIT_ASSERT( !g_called
.functor
);
336 handler
.Bind( MyEventType
, functor
, 0 );
337 handler
.Unbind( MyEventType
, functor
, 0 );
339 handler
.Bind( MyEventType
, functor
, 0, 0 );
340 handler
.Unbind( MyEventType
, functor
, 0, 0 );
342 // test that a temporary functor is working as well and also test that
343 // unbinding a different (though equal) instance of the same functor does
346 handler
.Bind( MyEventType
, MyFunctor() );
347 CPPUNIT_ASSERT( !handler
.Unbind( MyEventType
, func
));
349 handler
.Bind( MyEventType
, MyFunctor(), 0 );
350 CPPUNIT_ASSERT( !handler
.Unbind( MyEventType
, func
, 0 ));
352 handler
.Bind( MyEventType
, MyFunctor(), 0, 0 );
353 CPPUNIT_ASSERT( !handler
.Unbind( MyEventType
, func
, 0, 0 ));
356 void EvtHandlerTestCase::BindMethod()
358 // class method tests
359 handler
.Bind( MyEventType
, &MyHandler::OnMyEvent
, &handler
);
361 handler
.ProcessEvent(e
);
362 CPPUNIT_ASSERT( g_called
.method
);
363 handler
.Unbind( MyEventType
, &MyHandler::OnMyEvent
, &handler
);
365 handler
.ProcessEvent(e
);
366 CPPUNIT_ASSERT( !g_called
.method
);
368 handler
.Bind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0 );
369 handler
.Unbind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0 );
371 handler
.Bind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0, 0 );
372 handler
.Unbind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0, 0 );
375 void EvtHandlerTestCase::BindMethodUsingBaseEvent()
377 // test connecting a method taking just wxEvent and not MyEvent: this
378 // should work too if we don't need any MyEvent-specific information in the
380 handler
.Bind( MyEventType
, &MyHandler::OnEvent
, &handler
);
382 handler
.ProcessEvent(e
);
383 CPPUNIT_ASSERT( g_called
.method
);
384 handler
.Unbind( MyEventType
, &MyHandler::OnEvent
, &handler
);
386 handler
.ProcessEvent(e
);
387 CPPUNIT_ASSERT( !g_called
.method
);
389 handler
.Bind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0 );
390 handler
.Unbind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0 );
392 handler
.Bind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0, 0 );
393 handler
.Unbind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0, 0 );
397 void EvtHandlerTestCase::BindFunctionUsingBaseEvent()
399 // test connecting a function taking just wxEvent and not MyEvent: this
400 // should work too if we don't need any MyEvent-specific information in the
402 handler
.Bind( MyEventType
, GlobalOnEvent
);
404 handler
.ProcessEvent(e
);
405 CPPUNIT_ASSERT( g_called
.function
);
406 handler
.Unbind( MyEventType
, GlobalOnEvent
);
408 handler
.ProcessEvent(e
);
409 CPPUNIT_ASSERT( !g_called
.function
);
411 handler
.Bind( MyEventType
, GlobalOnEvent
, 0 );
412 handler
.Unbind( MyEventType
, GlobalOnEvent
, 0 );
414 handler
.Bind( MyEventType
, GlobalOnEvent
, 0, 0 );
415 handler
.Unbind( MyEventType
, GlobalOnEvent
, 0, 0 );
420 void EvtHandlerTestCase::BindNonHandler()
422 // class method tests for class not derived from wxEvtHandler
425 handler
.Bind( MyEventType
, &MySink::OnMyEvent
, &sink
);
427 handler
.ProcessEvent(e
);
428 CPPUNIT_ASSERT( g_called
.method
);
429 handler
.Unbind( MyEventType
, &MySink::OnMyEvent
, &sink
);
431 handler
.ProcessEvent(e
);
432 CPPUNIT_ASSERT( !g_called
.method
);
435 void EvtHandlerTestCase::InvalidBind()
437 // these calls shouldn't compile but we unfortunately can't check this
438 // automatically, you need to uncomment them manually and test that
439 // compilation does indeed fail
441 // connecting a handler with incompatible signature shouldn't work
442 #ifdef TEST_INVALID_BIND_GLOBAL
443 handler
.Bind(MyEventType
, GlobalOnAnotherEvent
);
445 #ifdef TEST_INVALID_BIND_STATIC
446 handler
.Bind(MyEventType
, &MyHandler::StaticOnAnotherEvent
);
448 #ifdef TEST_INVALID_BIND_METHOD
449 handler
.Bind(MyEventType
, &MyHandler::OnAnotherEvent
, &handler
);
451 #ifdef TEST_INVALID_BIND_FUNCTOR
453 handler
.Bind(MyEventType
, f
);
456 // the handler can't be omitted when calling Bind()
457 #ifdef TEST_INVALID_BIND_NO_HANDLER
458 handler
.Bind(MyEventType
, &MyHandler::OnMyEvent
);
461 // calling a derived class method with a base class pointer must not work
462 #ifdef TEST_INVALID_BIND_DERIVED
463 struct C1
: wxEvtHandler
{ };
464 struct C2
: wxEvtHandler
{ void OnWhatever(wxEvent
&); };
466 c1
.Bind(&C2::OnWhatever
);
469 // using object pointer incompatible with the method must not work
470 #ifdef TEST_INVALID_BIND_WRONG_CLASS
473 myHandler
.Bind(MyEventType
, &MyHandler::OnMyEvent
, &mySink
);
477 #endif // wxHAS_EVENT_BIND