]> git.saurik.com Git - wxWidgets.git/blame_incremental - tests/events/evthandler.cpp
Applied patch #15540: wxRichTextTable: crashes due to an invalid focus object (dghart)
[wxWidgets.git] / tests / events / evthandler.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: tests/events/evthandler.cpp
3// Purpose: Test the new event types and wxEvtHandler-methods
4// Author: Peter Most
5// Created: 2009-01-24
6// Copyright: (c) 2009 Peter Most
7///////////////////////////////////////////////////////////////////////////////
8
9// ----------------------------------------------------------------------------
10// headers
11// ----------------------------------------------------------------------------
12
13#include "testprec.h"
14
15#ifdef __BORLANDC__
16 #pragma hdrstop
17#endif
18
19#include "wx/event.h"
20
21// ----------------------------------------------------------------------------
22// test events and their handlers
23// ----------------------------------------------------------------------------
24
25const wxEventType LegacyEventType = wxNewEventType();
26
27class MyEvent;
28wxDEFINE_EVENT(MyEventType, MyEvent);
29
30class MyEvent : public wxEvent
31{
32public:
33 MyEvent() : wxEvent(0, MyEventType) { }
34
35 virtual wxEvent *Clone() const { return new MyEvent; }
36};
37
38typedef void (wxEvtHandler::*MyEventFunction)(MyEvent&);
39#ifndef wxHAS_EVENT_BIND
40 #define MyEventHandler(func) wxEVENT_HANDLER_CAST(MyEventFunction, func)
41#else
42 #define MyEventHandler(func) &func
43#endif
44#define EVT_MYEVENT(func) \
45 wx__DECLARE_EVT0(MyEventType, MyEventHandler(func))
46
47class AnotherEvent : public wxEvent
48{
49};
50
51namespace
52{
53
54struct Called
55{
56 Called() { Reset(); }
57
58 void Reset()
59 {
60 function =
61 functor =
62 method =
63 smethod = false;
64 }
65
66 bool function,
67 functor,
68 method,
69 smethod;
70} g_called;
71
72void GlobalOnMyEvent(MyEvent&)
73{
74 g_called.function = true;
75}
76
77void GlobalOnEvent(wxEvent&)
78{
79 g_called.function = true;
80}
81
82#ifdef TEST_INVALID_BIND_GLOBAL
83void GlobalOnAnotherEvent(AnotherEvent&);
84#endif
85
86void GlobalOnIdle(wxIdleEvent&)
87{
88 g_called.function = true;
89}
90
91struct MyFunctor
92{
93 void operator()(MyEvent &) { g_called.functor = true; }
94};
95
96struct IdleFunctor
97{
98 void operator()(wxIdleEvent &) { g_called.functor = true; }
99};
100
101class MyHandler : public wxEvtHandler
102{
103public:
104 static void StaticOnMyEvent(MyEvent &) { g_called.smethod = true; }
105 static void StaticOnAnotherEvent(AnotherEvent &);
106 static void StaticOnIdle(wxIdleEvent&) { g_called.smethod = true; }
107
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; }
112};
113
114// we can also handle events in classes not deriving from wxEvtHandler
115struct MySink
116{
117 void OnMyEvent(MyEvent&) { g_called.method = true; }
118 void OnEvent(wxEvent&) { g_called.method = true; }
119 void OnIdle(wxIdleEvent&) { g_called.method = true; }
120};
121
122// also test event table compilation
123class MyClassWithEventTable : public wxEvtHandler
124{
125public:
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; }
130
131private:
132 DECLARE_EVENT_TABLE()
133};
134
135BEGIN_EVENT_TABLE(MyClassWithEventTable, wxEvtHandler)
136 EVT_IDLE(MyClassWithEventTable::OnIdle)
137
138 EVT_MYEVENT(MyClassWithEventTable::OnMyEvent)
139#ifdef wxHAS_EVENT_BIND
140 EVT_MYEVENT(MyClassWithEventTable::OnEvent)
141#endif
142
143 // this shouldn't compile:
144 //EVT_MYEVENT(MyClassWithEventTable::OnIdle)
145 //EVT_IDLE(MyClassWithEventTable::OnAnotherEvent)
146END_EVENT_TABLE()
147
148} // anonymous namespace
149
150
151// --------------------------------------------------------------------------
152// test class
153// --------------------------------------------------------------------------
154
155class EvtHandlerTestCase : public CppUnit::TestCase
156{
157public:
158 EvtHandlerTestCase() {}
159
160private:
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();
177
178 void BuiltinConnect();
179 void LegacyConnect();
180 void DisconnectWildcard();
181 void AutoDisconnect();
182#ifdef wxHAS_EVENT_BIND
183 void BindFunction();
184 void BindStaticMethod();
185 void BindFunctor();
186 void BindMethod();
187 void BindMethodUsingBaseEvent();
188 void BindFunctionUsingBaseEvent();
189 void BindNonHandler();
190 void InvalidBind();
191#endif // wxHAS_EVENT_BIND
192
193
194 // these member variables exceptionally don't use "m_" prefix because
195 // they're used so many times
196 MyHandler handler;
197 MyEvent e;
198
199 DECLARE_NO_COPY_CLASS(EvtHandlerTestCase)
200};
201
202// register in the unnamed registry so that these tests are run by default
203CPPUNIT_TEST_SUITE_REGISTRATION( EvtHandlerTestCase );
204
205// also include in its own registry so that these tests can be run alone
206CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtHandlerTestCase, "EvtHandlerTestCase" );
207
208void EvtHandlerTestCase::BuiltinConnect()
209{
210 handler.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle));
211 handler.Disconnect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle));
212
213 handler.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &handler);
214 handler.Disconnect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &handler);
215
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);
220
221#ifdef wxHAS_EVENT_BIND
222 handler.Bind(wxEVT_IDLE, GlobalOnIdle);
223 handler.Unbind(wxEVT_IDLE, GlobalOnIdle);
224
225 IdleFunctor f;
226 handler.Bind(wxEVT_IDLE, f);
227 handler.Unbind(wxEVT_IDLE, f);
228
229 handler.Bind(wxEVT_IDLE, &MyHandler::OnIdle, &handler);
230 handler.Unbind(wxEVT_IDLE, &MyHandler::OnIdle, &handler);
231
232 handler.Bind(wxEVT_IDLE, &MyHandler::StaticOnIdle);
233 handler.Unbind(wxEVT_IDLE, &MyHandler::StaticOnIdle);
234#endif // wxHAS_EVENT_BIND
235}
236
237void EvtHandlerTestCase::LegacyConnect()
238{
239 handler.Connect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
240 handler.Connect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
241 handler.Connect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
242
243 handler.Disconnect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
244 handler.Disconnect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
245 handler.Disconnect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
246
247
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 );
251
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 );
255}
256
257void EvtHandlerTestCase::DisconnectWildcard()
258{
259 // should be able to disconnect a different handler using "wildcard search"
260 MyHandler sink;
261 wxEvtHandler source;
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
266}
267
268void EvtHandlerTestCase::AutoDisconnect()
269{
270 wxEvtHandler source;
271 {
272 MyHandler sink;
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));
276 }
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));
280}
281
282#ifdef wxHAS_EVENT_BIND
283
284void EvtHandlerTestCase::BindFunction()
285{
286 // function tests
287 handler.Bind( MyEventType, GlobalOnMyEvent );
288 g_called.Reset();
289 handler.ProcessEvent(e);
290 CPPUNIT_ASSERT( g_called.function );
291 handler.Unbind( MyEventType, GlobalOnMyEvent );
292 g_called.Reset();
293 handler.ProcessEvent(e);
294 CPPUNIT_ASSERT( !g_called.function ); // check that it was disconnected
295
296 handler.Bind( MyEventType, GlobalOnMyEvent, 0 );
297 handler.Unbind( MyEventType, GlobalOnMyEvent, 0 );
298
299 handler.Bind( MyEventType, GlobalOnMyEvent, 0, 0 );
300 handler.Unbind( MyEventType, GlobalOnMyEvent, 0, 0 );
301}
302
303void EvtHandlerTestCase::BindStaticMethod()
304{
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 );
308 g_called.Reset();
309 handler.ProcessEvent(e);
310 CPPUNIT_ASSERT( g_called.smethod );
311 handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent );
312 g_called.Reset();
313 handler.ProcessEvent(e);
314 CPPUNIT_ASSERT( !g_called.smethod );
315
316 handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent, 0 );
317 handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent, 0 );
318
319 handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent, 0, 0 );
320 handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent, 0, 0 );
321}
322
323void EvtHandlerTestCase::BindFunctor()
324{
325 // generalized functor tests
326 MyFunctor functor;
327
328 handler.Bind( MyEventType, functor );
329 g_called.Reset();
330 handler.ProcessEvent(e);
331 CPPUNIT_ASSERT( g_called.functor );
332 handler.Unbind( MyEventType, functor );
333 g_called.Reset();
334 handler.ProcessEvent(e);
335 CPPUNIT_ASSERT( !g_called.functor );
336
337 handler.Bind( MyEventType, functor, 0 );
338 handler.Unbind( MyEventType, functor, 0 );
339
340 handler.Bind( MyEventType, functor, 0, 0 );
341 handler.Unbind( MyEventType, functor, 0, 0 );
342
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
345 // not work
346 MyFunctor func;
347 handler.Bind( MyEventType, MyFunctor() );
348 CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func ));
349
350 handler.Bind( MyEventType, MyFunctor(), 0 );
351 CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func, 0 ));
352
353 handler.Bind( MyEventType, MyFunctor(), 0, 0 );
354 CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func, 0, 0 ));
355}
356
357void EvtHandlerTestCase::BindMethod()
358{
359 // class method tests
360 handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler );
361 g_called.Reset();
362 handler.ProcessEvent(e);
363 CPPUNIT_ASSERT( g_called.method );
364 handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler );
365 g_called.Reset();
366 handler.ProcessEvent(e);
367 CPPUNIT_ASSERT( !g_called.method );
368
369 handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler, 0 );
370 handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler, 0 );
371
372 handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler, 0, 0 );
373 handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler, 0, 0 );
374}
375
376void EvtHandlerTestCase::BindMethodUsingBaseEvent()
377{
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
380 // handler
381 handler.Bind( MyEventType, &MyHandler::OnEvent, &handler );
382 g_called.Reset();
383 handler.ProcessEvent(e);
384 CPPUNIT_ASSERT( g_called.method );
385 handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler );
386 g_called.Reset();
387 handler.ProcessEvent(e);
388 CPPUNIT_ASSERT( !g_called.method );
389
390 handler.Bind( MyEventType, &MyHandler::OnEvent, &handler, 0 );
391 handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler, 0 );
392
393 handler.Bind( MyEventType, &MyHandler::OnEvent, &handler, 0, 0 );
394 handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler, 0, 0 );
395}
396
397
398void EvtHandlerTestCase::BindFunctionUsingBaseEvent()
399{
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
402 // handler
403 handler.Bind( MyEventType, GlobalOnEvent );
404 g_called.Reset();
405 handler.ProcessEvent(e);
406 CPPUNIT_ASSERT( g_called.function );
407 handler.Unbind( MyEventType, GlobalOnEvent );
408 g_called.Reset();
409 handler.ProcessEvent(e);
410 CPPUNIT_ASSERT( !g_called.function );
411
412 handler.Bind( MyEventType, GlobalOnEvent, 0 );
413 handler.Unbind( MyEventType, GlobalOnEvent, 0 );
414
415 handler.Bind( MyEventType, GlobalOnEvent, 0, 0 );
416 handler.Unbind( MyEventType, GlobalOnEvent, 0, 0 );
417}
418
419
420
421void EvtHandlerTestCase::BindNonHandler()
422{
423 // class method tests for class not derived from wxEvtHandler
424 MySink sink;
425
426 handler.Bind( MyEventType, &MySink::OnMyEvent, &sink );
427 g_called.Reset();
428 handler.ProcessEvent(e);
429 CPPUNIT_ASSERT( g_called.method );
430 handler.Unbind( MyEventType, &MySink::OnMyEvent, &sink );
431 g_called.Reset();
432 handler.ProcessEvent(e);
433 CPPUNIT_ASSERT( !g_called.method );
434}
435
436void EvtHandlerTestCase::InvalidBind()
437{
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
441
442 // connecting a handler with incompatible signature shouldn't work
443#ifdef TEST_INVALID_BIND_GLOBAL
444 handler.Bind(MyEventType, GlobalOnAnotherEvent);
445#endif
446#ifdef TEST_INVALID_BIND_STATIC
447 handler.Bind(MyEventType, &MyHandler::StaticOnAnotherEvent);
448#endif
449#ifdef TEST_INVALID_BIND_METHOD
450 handler.Bind(MyEventType, &MyHandler::OnAnotherEvent, &handler);
451#endif
452#ifdef TEST_INVALID_BIND_FUNCTOR
453 IdleFunctor f;
454 handler.Bind(MyEventType, f);
455#endif
456
457 // the handler can't be omitted when calling Bind()
458#ifdef TEST_INVALID_BIND_NO_HANDLER
459 handler.Bind(MyEventType, &MyHandler::OnMyEvent);
460#endif
461
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&); };
466 C1 c1;
467 c1.Bind(&C2::OnWhatever);
468#endif
469
470 // using object pointer incompatible with the method must not work
471#ifdef TEST_INVALID_BIND_WRONG_CLASS
472 MySink mySink;
473 MyHandler myHandler;
474 myHandler.Bind(MyEventType, &MyHandler::OnMyEvent, &mySink);
475#endif
476}
477
478#endif // wxHAS_EVENT_BIND