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 #ifdef wxHAS_EVENT_BIND
164 CPPUNIT_TEST( BindFunction
);
165 CPPUNIT_TEST( BindStaticMethod
);
166 CPPUNIT_TEST( BindFunctor
);
167 CPPUNIT_TEST( BindMethod
);
168 CPPUNIT_TEST( BindMethodUsingBaseEvent
);
169 CPPUNIT_TEST( BindFunctionUsingBaseEvent
);
170 CPPUNIT_TEST( BindNonHandler
);
171 CPPUNIT_TEST( InvalidBind
);
172 #endif // wxHAS_EVENT_BIND
173 CPPUNIT_TEST_SUITE_END();
175 void BuiltinConnect();
176 void LegacyConnect();
177 #ifdef wxHAS_EVENT_BIND
179 void BindStaticMethod();
182 void BindMethodUsingBaseEvent();
183 void BindFunctionUsingBaseEvent();
184 void BindNonHandler();
186 #endif // wxHAS_EVENT_BIND
189 // these member variables exceptionally don't use "m_" prefix because
190 // they're used so many times
194 DECLARE_NO_COPY_CLASS(EvtHandlerTestCase
)
197 // register in the unnamed registry so that these tests are run by default
198 CPPUNIT_TEST_SUITE_REGISTRATION( EvtHandlerTestCase
);
200 // also include in its own registry so that these tests can be run alone
201 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtHandlerTestCase
, "EvtHandlerTestCase" );
203 void EvtHandlerTestCase::BuiltinConnect()
205 handler
.Connect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
));
206 handler
.Disconnect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
));
208 handler
.Connect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &handler
);
209 handler
.Disconnect(wxEVT_IDLE
, wxIdleEventHandler(MyHandler::OnIdle
), NULL
, &handler
);
211 // using casts like this is even uglier than using wxIdleEventHandler but
212 // it should still continue to work for compatibility
213 handler
.Connect(wxEVT_IDLE
, (wxObjectEventFunction
)(wxEventFunction
)&MyHandler::OnIdle
);
214 handler
.Disconnect(wxEVT_IDLE
, (wxObjectEventFunction
)(wxEventFunction
)&MyHandler::OnIdle
);
216 #ifdef wxHAS_EVENT_BIND
217 handler
.Bind(wxEVT_IDLE
, GlobalOnIdle
);
218 handler
.Unbind(wxEVT_IDLE
, GlobalOnIdle
);
221 handler
.Bind(wxEVT_IDLE
, f
);
222 handler
.Unbind(wxEVT_IDLE
, f
);
224 handler
.Bind(wxEVT_IDLE
, &MyHandler::OnIdle
, &handler
);
225 handler
.Unbind(wxEVT_IDLE
, &MyHandler::OnIdle
, &handler
);
227 handler
.Bind(wxEVT_IDLE
, &MyHandler::StaticOnIdle
);
228 handler
.Unbind(wxEVT_IDLE
, &MyHandler::StaticOnIdle
);
229 #endif // wxHAS_EVENT_BIND
232 void EvtHandlerTestCase::LegacyConnect()
234 handler
.Connect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
235 handler
.Connect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
236 handler
.Connect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
238 handler
.Disconnect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
239 handler
.Disconnect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
240 handler
.Disconnect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
);
243 handler
.Connect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
244 handler
.Connect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
245 handler
.Connect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
247 handler
.Disconnect( LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
248 handler
.Disconnect( 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
249 handler
.Disconnect( 0, 0, LegacyEventType
, (wxObjectEventFunction
)&MyHandler::OnEvent
, NULL
, &handler
);
252 #ifdef wxHAS_EVENT_BIND
254 void EvtHandlerTestCase::BindFunction()
257 handler
.Bind( MyEventType
, GlobalOnMyEvent
);
259 handler
.ProcessEvent(e
);
260 CPPUNIT_ASSERT( g_called
.function
);
261 handler
.Unbind( MyEventType
, GlobalOnMyEvent
);
263 handler
.ProcessEvent(e
);
264 CPPUNIT_ASSERT( !g_called
.function
); // check that it was disconnected
266 handler
.Bind( MyEventType
, GlobalOnMyEvent
, 0 );
267 handler
.Unbind( MyEventType
, GlobalOnMyEvent
, 0 );
269 handler
.Bind( MyEventType
, GlobalOnMyEvent
, 0, 0 );
270 handler
.Unbind( MyEventType
, GlobalOnMyEvent
, 0, 0 );
273 void EvtHandlerTestCase::BindStaticMethod()
275 // static method tests (this is same as functions but still test it just in
276 // case we hit some strange compiler bugs)
277 handler
.Bind( MyEventType
, &MyHandler::StaticOnMyEvent
);
279 handler
.ProcessEvent(e
);
280 CPPUNIT_ASSERT( g_called
.smethod
);
281 handler
.Unbind( MyEventType
, &MyHandler::StaticOnMyEvent
);
283 handler
.ProcessEvent(e
);
284 CPPUNIT_ASSERT( !g_called
.smethod
);
286 handler
.Bind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0 );
287 handler
.Unbind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0 );
289 handler
.Bind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0, 0 );
290 handler
.Unbind( MyEventType
, &MyHandler::StaticOnMyEvent
, 0, 0 );
293 void EvtHandlerTestCase::BindFunctor()
295 // generalized functor tests
298 handler
.Bind( MyEventType
, functor
);
300 handler
.ProcessEvent(e
);
301 CPPUNIT_ASSERT( g_called
.functor
);
302 handler
.Unbind( MyEventType
, functor
);
304 handler
.ProcessEvent(e
);
305 CPPUNIT_ASSERT( !g_called
.functor
);
307 handler
.Bind( MyEventType
, functor
, 0 );
308 handler
.Unbind( MyEventType
, functor
, 0 );
310 handler
.Bind( MyEventType
, functor
, 0, 0 );
311 handler
.Unbind( MyEventType
, functor
, 0, 0 );
313 // test that a temporary functor is working as well and also test that
314 // unbinding a different (though equal) instance of the same functor does
317 handler
.Bind( MyEventType
, MyFunctor() );
318 CPPUNIT_ASSERT( !handler
.Unbind( MyEventType
, func
));
320 handler
.Bind( MyEventType
, MyFunctor(), 0 );
321 CPPUNIT_ASSERT( !handler
.Unbind( MyEventType
, func
, 0 ));
323 handler
.Bind( MyEventType
, MyFunctor(), 0, 0 );
324 CPPUNIT_ASSERT( !handler
.Unbind( MyEventType
, func
, 0, 0 ));
327 void EvtHandlerTestCase::BindMethod()
329 // class method tests
330 handler
.Bind( MyEventType
, &MyHandler::OnMyEvent
, &handler
);
332 handler
.ProcessEvent(e
);
333 CPPUNIT_ASSERT( g_called
.method
);
334 handler
.Unbind( MyEventType
, &MyHandler::OnMyEvent
, &handler
);
336 handler
.ProcessEvent(e
);
337 CPPUNIT_ASSERT( !g_called
.method
);
339 handler
.Bind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0 );
340 handler
.Unbind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0 );
342 handler
.Bind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0, 0 );
343 handler
.Unbind( MyEventType
, &MyHandler::OnMyEvent
, &handler
, 0, 0 );
346 void EvtHandlerTestCase::BindMethodUsingBaseEvent()
348 // test connecting a method taking just wxEvent and not MyEvent: this
349 // should work too if we don't need any MyEvent-specific information in the
351 handler
.Bind( MyEventType
, &MyHandler::OnEvent
, &handler
);
353 handler
.ProcessEvent(e
);
354 CPPUNIT_ASSERT( g_called
.method
);
355 handler
.Unbind( MyEventType
, &MyHandler::OnEvent
, &handler
);
357 handler
.ProcessEvent(e
);
358 CPPUNIT_ASSERT( !g_called
.method
);
360 handler
.Bind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0 );
361 handler
.Unbind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0 );
363 handler
.Bind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0, 0 );
364 handler
.Unbind( MyEventType
, &MyHandler::OnEvent
, &handler
, 0, 0 );
368 void EvtHandlerTestCase::BindFunctionUsingBaseEvent()
370 // test connecting a function taking just wxEvent and not MyEvent: this
371 // should work too if we don't need any MyEvent-specific information in the
373 handler
.Bind( MyEventType
, GlobalOnEvent
);
375 handler
.ProcessEvent(e
);
376 CPPUNIT_ASSERT( g_called
.function
);
377 handler
.Unbind( MyEventType
, GlobalOnEvent
);
379 handler
.ProcessEvent(e
);
380 CPPUNIT_ASSERT( !g_called
.function
);
382 handler
.Bind( MyEventType
, GlobalOnEvent
, 0 );
383 handler
.Unbind( MyEventType
, GlobalOnEvent
, 0 );
385 handler
.Bind( MyEventType
, GlobalOnEvent
, 0, 0 );
386 handler
.Unbind( MyEventType
, GlobalOnEvent
, 0, 0 );
391 void EvtHandlerTestCase::BindNonHandler()
393 // class method tests for class not derived from wxEvtHandler
396 handler
.Bind( MyEventType
, &MySink::OnMyEvent
, &sink
);
398 handler
.ProcessEvent(e
);
399 CPPUNIT_ASSERT( g_called
.method
);
400 handler
.Unbind( MyEventType
, &MySink::OnMyEvent
, &sink
);
402 handler
.ProcessEvent(e
);
403 CPPUNIT_ASSERT( !g_called
.method
);
406 void EvtHandlerTestCase::InvalidBind()
408 // these calls shouldn't compile but we unfortunately can't check this
409 // automatically, you need to uncomment them manually and test that
410 // compilation does indeed fail
412 // connecting a handler with incompatible signature shouldn't work
413 #ifdef TEST_INVALID_BIND_GLOBAL
414 handler
.Bind(MyEventType
, GlobalOnAnotherEvent
);
416 #ifdef TEST_INVALID_BIND_STATIC
417 handler
.Bind(MyEventType
, &MyHandler::StaticOnAnotherEvent
);
419 #ifdef TEST_INVALID_BIND_METHOD
420 handler
.Bind(MyEventType
, &MyHandler::OnAnotherEvent
, &handler
);
422 #ifdef TEST_INVALID_BIND_FUNCTOR
424 handler
.Bind(MyEventType
, f
);
427 // the handler can't be omitted when calling Bind()
428 #ifdef TEST_INVALID_BIND_NO_HANDLER
429 handler
.Bind(MyEventType
, &MyHandler::OnMyEvent
);
432 // calling a derived class method with a base class pointer must not work
433 #ifdef TEST_INVALID_BIND_DERIVED
434 struct C1
: wxEvtHandler
{ };
435 struct C2
: wxEvtHandler
{ void OnWhatever(wxEvent
&); };
437 c1
.Bind(&C2::OnWhatever
);
440 // using object pointer incompatible with the method must not work
441 #ifdef TEST_INVALID_BIND_WRONG_CLASS
444 myHandler
.Bind(MyEventType
, &MyHandler::OnMyEvent
, &mySink
);
448 #endif // wxHAS_EVENT_BIND