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 #ifdef TEST_INVALID_BIND_GLOBAL
84 void GlobalOnAnotherEvent(AnotherEvent
&);
87 void GlobalOnIdle(wxIdleEvent
&)
89 g_called
.function
= true;
94 void operator()(MyEvent
&) { g_called
.functor
= true; }
99 void operator()(wxIdleEvent
&) { g_called
.functor
= true; }
102 class MyHandler
: public wxEvtHandler
105 static void StaticOnMyEvent(MyEvent
&) { g_called
.smethod
= true; }
106 static void StaticOnAnotherEvent(AnotherEvent
&);
107 static void StaticOnIdle(wxIdleEvent
&) { g_called
.smethod
= true; }
109 void OnMyEvent(MyEvent
&) { g_called
.method
= true; }
110 void OnEvent(wxEvent
&) { g_called
.method
= true; }
111 void OnAnotherEvent(AnotherEvent
&);
112 void OnIdle(wxIdleEvent
&) { g_called
.method
= true; }
115 // we can also handle events in classes not deriving from wxEvtHandler
118 void OnMyEvent(MyEvent
&) { g_called
.method
= true; }
119 void OnEvent(wxEvent
&) { g_called
.method
= true; }
120 void OnIdle(wxIdleEvent
&) { g_called
.method
= true; }
123 // also test event table compilation
124 class MyClassWithEventTable
: public wxEvtHandler
127 void OnMyEvent(MyEvent
&) { g_called
.method
= true; }
128 void OnEvent(wxEvent
&) { g_called
.method
= true; }
129 void OnAnotherEvent(AnotherEvent
&);
130 void OnIdle(wxIdleEvent
&) { g_called
.method
= true; }
133 DECLARE_EVENT_TABLE()
136 BEGIN_EVENT_TABLE(MyClassWithEventTable
, wxEvtHandler
)
137 EVT_IDLE(MyClassWithEventTable::OnIdle
)
139 EVT_MYEVENT(MyClassWithEventTable::OnMyEvent
)
140 #ifdef wxHAS_EVENT_BIND
141 EVT_MYEVENT(MyClassWithEventTable::OnEvent
)
144 // this shouldn't compile:
145 //EVT_MYEVENT(MyClassWithEventTable::OnIdle)
146 //EVT_IDLE(MyClassWithEventTable::OnAnotherEvent)
149 } // anonymous namespace
152 // --------------------------------------------------------------------------
154 // --------------------------------------------------------------------------
156 class EvtHandlerTestCase
: public CppUnit::TestCase
159 EvtHandlerTestCase() {}
162 CPPUNIT_TEST_SUITE( EvtHandlerTestCase
);
163 CPPUNIT_TEST( BuiltinConnect
);
164 CPPUNIT_TEST( LegacyConnect
);
165 CPPUNIT_TEST( DisconnectWildcard
);
166 CPPUNIT_TEST( AutoDisconnect
);
167 #ifdef wxHAS_EVENT_BIND
168 CPPUNIT_TEST( BindFunction
);
169 CPPUNIT_TEST( BindStaticMethod
);
170 CPPUNIT_TEST( BindFunctor
);
171 CPPUNIT_TEST( BindMethod
);
172 CPPUNIT_TEST( BindMethodUsingBaseEvent
);
173 CPPUNIT_TEST( BindFunctionUsingBaseEvent
);
174 CPPUNIT_TEST( BindNonHandler
);
175 CPPUNIT_TEST( InvalidBind
);
176 #endif // wxHAS_EVENT_BIND
177 CPPUNIT_TEST_SUITE_END();
179 void BuiltinConnect();
180 void LegacyConnect();
181 void DisconnectWildcard();
182 void AutoDisconnect();
183 #ifdef wxHAS_EVENT_BIND
185 void BindStaticMethod();
188 void BindMethodUsingBaseEvent();
189 void BindFunctionUsingBaseEvent();
190 void BindNonHandler();
192 #endif // wxHAS_EVENT_BIND
195 // these member variables exceptionally don't use "m_" prefix because
196 // they're used so many times
200 DECLARE_NO_COPY_CLASS(EvtHandlerTestCase
)
203 // register in the unnamed registry so that these tests are run by default
204 CPPUNIT_TEST_SUITE_REGISTRATION( EvtHandlerTestCase
);
206 // also include in its own registry so that these tests can be run alone
207 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtHandlerTestCase
, "EvtHandlerTestCase" );
209 void EvtHandlerTestCase::BuiltinConnect()
211 handler
.Connect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
));
212 handler
.Disconnect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
));
214 handler
.Connect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &handler
);
215 handler
.Disconnect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &handler
);
217 // using casts like this is even uglier than using wxIdleEventHandler but
218 // it should still continue to work for compatibility
219 handler
.Connect(wxEVT_IDLE
, (wxObjectEventFunction
)(wxEventFunction
)&MyHandler::OnIdle
);
220 handler
.Disconnect(wxEVT_IDLE
, (wxObjectEventFunction
)(wxEventFunction
)&MyHandler::OnIdle
);
222 #ifdef wxHAS_EVENT_BIND
223 handler
.Bind(wxEVT_IDLE
, GlobalOnIdle
);
224 handler
.Unbind(wxEVT_IDLE
, GlobalOnIdle
);
227 handler
.Bind(wxEVT_IDLE
, f
);
228 handler
.Unbind(wxEVT_IDLE
, f
);
230 handler
.Bind(wxEVT_IDLE
, &MyHandler::OnIdle
, &handler
);
231 handler
.Unbind(wxEVT_IDLE
, &MyHandler::OnIdle
, &handler
);
233 handler
.Bind(wxEVT_IDLE
, &MyHandler::StaticOnIdle
);
234 handler
.Unbind(wxEVT_IDLE
, &MyHandler::StaticOnIdle
);
235 #endif // wxHAS_EVENT_BIND
238 void EvtHandlerTestCase::LegacyConnect()
240 handler
.Connect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
241 handler
.Connect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
242 handler
.Connect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
244 handler
.Disconnect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
245 handler
.Disconnect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
246 handler
.Disconnect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
249 handler
.Connect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
250 handler
.Connect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
251 handler
.Connect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
253 handler
.Disconnect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
254 handler
.Disconnect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
255 handler
.Disconnect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
258 void EvtHandlerTestCase::DisconnectWildcard()
260 // should be able to disconnect a different handler using "wildcard search"
263 source
.Connect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &sink
);
264 CPPUNIT_ASSERT(source
.Disconnect(wxID_ANY
, wxEVT_IDLE
));
265 // destruction of source and sink here should properly clean up the
266 // wxEventConnectionRef without crashing
269 void EvtHandlerTestCase::AutoDisconnect()
274 source
.Connect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &sink
);
275 // mismatched event type, so nothing should be disconnected
276 CPPUNIT_ASSERT(!source
.Disconnect(wxEVT_THREAD
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &sink
));
278 // destruction of sink should have automatically disconnected it, so
279 // there should be nothing to disconnect anymore
280 CPPUNIT_ASSERT(!source
.Disconnect(wxID_ANY
, wxEVT_IDLE
));
283 #ifdef wxHAS_EVENT_BIND
285 void EvtHandlerTestCase::BindFunction()
288 handler
.Bind( MyEventType
, GlobalOnMyEvent
);
290 handler
.ProcessEvent(e
);
291 CPPUNIT_ASSERT( g_called
.function
);
292 handler
.Unbind( MyEventType
, GlobalOnMyEvent
);
294 handler
.ProcessEvent(e
);
295 CPPUNIT_ASSERT( !g_called
.function
); // check that it was disconnected
297 handler
.Bind( MyEventType
, GlobalOnMyEvent
, 0 );
298 handler
.Unbind( MyEventType
, GlobalOnMyEvent
, 0 );
300 handler
.Bind( MyEventType
, GlobalOnMyEvent
, 0, 0 );
301 handler
.Unbind( MyEventType
, GlobalOnMyEvent
, 0, 0 );
304 void EvtHandlerTestCase::BindStaticMethod()
306 // static method tests (this is same as functions but still test it just in
307 // case we hit some strange compiler bugs)
308 handler
.Bind( MyEventType
, &MyHandler::StaticOnMyEvent
);
310 handler
.ProcessEvent(e
);
311 CPPUNIT_ASSERT( g_called
.smethod
);
312 handler
.Unbind( MyEventType
, &MyHandler::StaticOnMyEvent
);
314 handler
.ProcessEvent(e
);
315 CPPUNIT_ASSERT( !g_called
.smethod
);
317 handler
.Bind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0 );
318 handler
.Unbind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0 );
320 handler
.Bind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0, 0 );
321 handler
.Unbind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0, 0 );
324 void EvtHandlerTestCase::BindFunctor()
326 // generalized functor tests
329 handler
.Bind( MyEventType
, functor
);
331 handler
.ProcessEvent(e
);
332 CPPUNIT_ASSERT( g_called
.functor
);
333 handler
.Unbind( MyEventType
, functor
);
335 handler
.ProcessEvent(e
);
336 CPPUNIT_ASSERT( !g_called
.functor
);
338 handler
.Bind( MyEventType
, functor
, 0 );
339 handler
.Unbind( MyEventType
, functor
, 0 );
341 handler
.Bind( MyEventType
, functor
, 0, 0 );
342 handler
.Unbind( MyEventType
, functor
, 0, 0 );
344 // test that a temporary functor is working as well and also test that
345 // unbinding a different (though equal) instance of the same functor does
348 handler
.Bind( MyEventType
, MyFunctor() );
349 CPPUNIT_ASSERT( !handler
.Unbind( MyEventType
, func
));
351 handler
.Bind( MyEventType
, MyFunctor(), 0 );
352 CPPUNIT_ASSERT( !handler
.Unbind( MyEventType
, func
, 0 ));
354 handler
.Bind( MyEventType
, MyFunctor(), 0, 0 );
355 CPPUNIT_ASSERT( !handler
.Unbind( MyEventType
, func
, 0, 0 ));
358 void EvtHandlerTestCase::BindMethod()
360 // class method tests
361 handler
.Bind( MyEventType
, &MyHandler::OnMyEvent
, &handler
);
363 handler
.ProcessEvent(e
);
364 CPPUNIT_ASSERT( g_called
.method
);
365 handler
.Unbind( MyEventType
, &MyHandler::OnMyEvent
, &handler
);
367 handler
.ProcessEvent(e
);
368 CPPUNIT_ASSERT( !g_called
.method
);
370 handler
.Bind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0 );
371 handler
.Unbind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0 );
373 handler
.Bind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0, 0 );
374 handler
.Unbind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0, 0 );
377 void EvtHandlerTestCase::BindMethodUsingBaseEvent()
379 // test connecting a method taking just wxEvent and not MyEvent: this
380 // should work too if we don't need any MyEvent-specific information in the
382 handler
.Bind( MyEventType
, &MyHandler::OnEvent
, &handler
);
384 handler
.ProcessEvent(e
);
385 CPPUNIT_ASSERT( g_called
.method
);
386 handler
.Unbind( MyEventType
, &MyHandler::OnEvent
, &handler
);
388 handler
.ProcessEvent(e
);
389 CPPUNIT_ASSERT( !g_called
.method
);
391 handler
.Bind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0 );
392 handler
.Unbind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0 );
394 handler
.Bind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0, 0 );
395 handler
.Unbind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0, 0 );
399 void EvtHandlerTestCase::BindFunctionUsingBaseEvent()
401 // test connecting a function taking just wxEvent and not MyEvent: this
402 // should work too if we don't need any MyEvent-specific information in the
404 handler
.Bind( MyEventType
, GlobalOnEvent
);
406 handler
.ProcessEvent(e
);
407 CPPUNIT_ASSERT( g_called
.function
);
408 handler
.Unbind( MyEventType
, GlobalOnEvent
);
410 handler
.ProcessEvent(e
);
411 CPPUNIT_ASSERT( !g_called
.function
);
413 handler
.Bind( MyEventType
, GlobalOnEvent
, 0 );
414 handler
.Unbind( MyEventType
, GlobalOnEvent
, 0 );
416 handler
.Bind( MyEventType
, GlobalOnEvent
, 0, 0 );
417 handler
.Unbind( MyEventType
, GlobalOnEvent
, 0, 0 );
422 void EvtHandlerTestCase::BindNonHandler()
424 // class method tests for class not derived from wxEvtHandler
427 handler
.Bind( MyEventType
, &MySink::OnMyEvent
, &sink
);
429 handler
.ProcessEvent(e
);
430 CPPUNIT_ASSERT( g_called
.method
);
431 handler
.Unbind( MyEventType
, &MySink::OnMyEvent
, &sink
);
433 handler
.ProcessEvent(e
);
434 CPPUNIT_ASSERT( !g_called
.method
);
437 void EvtHandlerTestCase::InvalidBind()
439 // these calls shouldn't compile but we unfortunately can't check this
440 // automatically, you need to uncomment them manually and test that
441 // compilation does indeed fail
443 // connecting a handler with incompatible signature shouldn't work
444 #ifdef TEST_INVALID_BIND_GLOBAL
445 handler
.Bind(MyEventType
, GlobalOnAnotherEvent
);
447 #ifdef TEST_INVALID_BIND_STATIC
448 handler
.Bind(MyEventType
, &MyHandler::StaticOnAnotherEvent
);
450 #ifdef TEST_INVALID_BIND_METHOD
451 handler
.Bind(MyEventType
, &MyHandler::OnAnotherEvent
, &handler
);
453 #ifdef TEST_INVALID_BIND_FUNCTOR
455 handler
.Bind(MyEventType
, f
);
458 // the handler can't be omitted when calling Bind()
459 #ifdef TEST_INVALID_BIND_NO_HANDLER
460 handler
.Bind(MyEventType
, &MyHandler::OnMyEvent
);
463 // calling a derived class method with a base class pointer must not work
464 #ifdef TEST_INVALID_BIND_DERIVED
465 struct C1
: wxEvtHandler
{ };
466 struct C2
: wxEvtHandler
{ void OnWhatever(wxEvent
&); };
468 c1
.Bind(&C2::OnWhatever
);
471 // using object pointer incompatible with the method must not work
472 #ifdef TEST_INVALID_BIND_WRONG_CLASS
475 myHandler
.Bind(MyEventType
, &MyHandler::OnMyEvent
, &mySink
);
479 #endif // wxHAS_EVENT_BIND