]> git.saurik.com Git - wxWidgets.git/blame - tests/events/evthandler.cpp
Applied patch #15540: wxRichTextTable: crashes due to an invalid focus object (dghart)
[wxWidgets.git] / tests / events / evthandler.cpp
CommitLineData
b2238cc3
VZ
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
b2238cc3
VZ
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
b2238cc3
VZ
19#include "wx/event.h"
20
f3ff831f
VZ
21// ----------------------------------------------------------------------------
22// test events and their handlers
23// ----------------------------------------------------------------------------
b2238cc3 24
a01ada05 25const wxEventType LegacyEventType = wxNewEventType();
b2238cc3 26
9b3ff3c0 27class MyEvent;
16be58c1 28wxDEFINE_EVENT(MyEventType, MyEvent);
9b3ff3c0 29
b2238cc3
VZ
30class MyEvent : public wxEvent
31{
9b3ff3c0 32public:
a01ada05 33 MyEvent() : wxEvent(0, MyEventType) { }
9b3ff3c0
VZ
34
35 virtual wxEvent *Clone() const { return new MyEvent; }
b2238cc3
VZ
36};
37
bb87b19b 38typedef void (wxEvtHandler::*MyEventFunction)(MyEvent&);
890d70eb 39#ifndef wxHAS_EVENT_BIND
5293e4b7
VZ
40 #define MyEventHandler(func) wxEVENT_HANDLER_CAST(MyEventFunction, func)
41#else
42 #define MyEventHandler(func) &func
43#endif
bb87b19b
VZ
44#define EVT_MYEVENT(func) \
45 wx__DECLARE_EVT0(MyEventType, MyEventHandler(func))
a01ada05 46
9b3ff3c0
VZ
47class AnotherEvent : public wxEvent
48{
49};
b2238cc3 50
9b3ff3c0
VZ
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}
b2238cc3 76
890d70eb
VZ
77void GlobalOnEvent(wxEvent&)
78{
79 g_called.function = true;
80}
81
1ed753dc 82#ifdef TEST_INVALID_BIND_GLOBAL
f3ff831f 83void GlobalOnAnotherEvent(AnotherEvent&);
1ed753dc 84#endif
f3ff831f
VZ
85
86void GlobalOnIdle(wxIdleEvent&)
87{
88 g_called.function = true;
89}
90
91struct MyFunctor
b2238cc3 92{
9b3ff3c0 93 void operator()(MyEvent &) { g_called.functor = true; }
f3ff831f 94};
b2238cc3 95
f3ff831f
VZ
96struct IdleFunctor
97{
98 void operator()(wxIdleEvent &) { g_called.functor = true; }
b2238cc3
VZ
99};
100
b2238cc3
VZ
101class MyHandler : public wxEvtHandler
102{
9b3ff3c0 103public:
f3ff831f
VZ
104 static void StaticOnMyEvent(MyEvent &) { g_called.smethod = true; }
105 static void StaticOnAnotherEvent(AnotherEvent &);
106 static void StaticOnIdle(wxIdleEvent&) { g_called.smethod = true; }
107
9b3ff3c0 108 void OnMyEvent(MyEvent&) { g_called.method = true; }
f3ff831f
VZ
109 void OnEvent(wxEvent&) { g_called.method = true; }
110 void OnAnotherEvent(AnotherEvent&);
111 void OnIdle(wxIdleEvent&) { g_called.method = true; }
112};
b2238cc3 113
f3ff831f
VZ
114// we can also handle events in classes not deriving from wxEvtHandler
115struct MySink
116{
117 void OnMyEvent(MyEvent&) { g_called.method = true; }
a01ada05 118 void OnEvent(wxEvent&) { g_called.method = true; }
f3ff831f
VZ
119 void OnIdle(wxIdleEvent&) { g_called.method = true; }
120};
b2238cc3 121
f3ff831f
VZ
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()
b2238cc3
VZ
133};
134
f3ff831f
VZ
135BEGIN_EVENT_TABLE(MyClassWithEventTable, wxEvtHandler)
136 EVT_IDLE(MyClassWithEventTable::OnIdle)
137
a01ada05 138 EVT_MYEVENT(MyClassWithEventTable::OnMyEvent)
890d70eb 139#ifdef wxHAS_EVENT_BIND
a01ada05 140 EVT_MYEVENT(MyClassWithEventTable::OnEvent)
bb87b19b 141#endif
a01ada05 142
f3ff831f 143 // this shouldn't compile:
a01ada05 144 //EVT_MYEVENT(MyClassWithEventTable::OnIdle)
f3ff831f
VZ
145 //EVT_IDLE(MyClassWithEventTable::OnAnotherEvent)
146END_EVENT_TABLE()
147
9b3ff3c0
VZ
148} // anonymous namespace
149
f3ff831f
VZ
150
151// --------------------------------------------------------------------------
152// test class
153// --------------------------------------------------------------------------
154
155class EvtHandlerTestCase : public CppUnit::TestCase
b2238cc3 156{
f3ff831f
VZ
157public:
158 EvtHandlerTestCase() {}
159
160private:
161 CPPUNIT_TEST_SUITE( EvtHandlerTestCase );
162 CPPUNIT_TEST( BuiltinConnect );
163 CPPUNIT_TEST( LegacyConnect );
75b2220e
VZ
164 CPPUNIT_TEST( DisconnectWildcard );
165 CPPUNIT_TEST( AutoDisconnect );
890d70eb 166#ifdef wxHAS_EVENT_BIND
5293e4b7
VZ
167 CPPUNIT_TEST( BindFunction );
168 CPPUNIT_TEST( BindStaticMethod );
169 CPPUNIT_TEST( BindFunctor );
170 CPPUNIT_TEST( BindMethod );
171 CPPUNIT_TEST( BindMethodUsingBaseEvent );
890d70eb 172 CPPUNIT_TEST( BindFunctionUsingBaseEvent );
5293e4b7
VZ
173 CPPUNIT_TEST( BindNonHandler );
174 CPPUNIT_TEST( InvalidBind );
890d70eb 175#endif // wxHAS_EVENT_BIND
f3ff831f
VZ
176 CPPUNIT_TEST_SUITE_END();
177
178 void BuiltinConnect();
179 void LegacyConnect();
75b2220e
VZ
180 void DisconnectWildcard();
181 void AutoDisconnect();
890d70eb 182#ifdef wxHAS_EVENT_BIND
5293e4b7
VZ
183 void BindFunction();
184 void BindStaticMethod();
185 void BindFunctor();
186 void BindMethod();
187 void BindMethodUsingBaseEvent();
890d70eb 188 void BindFunctionUsingBaseEvent();
5293e4b7
VZ
189 void BindNonHandler();
190 void InvalidBind();
890d70eb 191#endif // wxHAS_EVENT_BIND
f3ff831f 192
b2238cc3 193
f3ff831f
VZ
194 // these member variables exceptionally don't use "m_" prefix because
195 // they're used so many times
b2238cc3 196 MyHandler handler;
9b3ff3c0 197 MyEvent e;
b2238cc3 198
f3ff831f
VZ
199 DECLARE_NO_COPY_CLASS(EvtHandlerTestCase)
200};
b2238cc3 201
f3ff831f
VZ
202// register in the unnamed registry so that these tests are run by default
203CPPUNIT_TEST_SUITE_REGISTRATION( EvtHandlerTestCase );
204
e3778b4d 205// also include in its own registry so that these tests can be run alone
f3ff831f
VZ
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);
b2238cc3 215
a01ada05
VZ
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
890d70eb 221#ifdef wxHAS_EVENT_BIND
5293e4b7
VZ
222 handler.Bind(wxEVT_IDLE, GlobalOnIdle);
223 handler.Unbind(wxEVT_IDLE, GlobalOnIdle);
b2238cc3 224
f3ff831f 225 IdleFunctor f;
5293e4b7
VZ
226 handler.Bind(wxEVT_IDLE, f);
227 handler.Unbind(wxEVT_IDLE, f);
b2238cc3 228
5293e4b7
VZ
229 handler.Bind(wxEVT_IDLE, &MyHandler::OnIdle, &handler);
230 handler.Unbind(wxEVT_IDLE, &MyHandler::OnIdle, &handler);
f3ff831f 231
5293e4b7
VZ
232 handler.Bind(wxEVT_IDLE, &MyHandler::StaticOnIdle);
233 handler.Unbind(wxEVT_IDLE, &MyHandler::StaticOnIdle);
890d70eb 234#endif // wxHAS_EVENT_BIND
f3ff831f
VZ
235}
236
237void EvtHandlerTestCase::LegacyConnect()
238{
a01ada05
VZ
239 handler.Connect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
240 handler.Connect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
241 handler.Connect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
b2238cc3 242
a01ada05
VZ
243 handler.Disconnect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
244 handler.Disconnect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
245 handler.Disconnect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
b2238cc3 246
f3ff831f 247
a01ada05
VZ
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 );
f3ff831f 251
a01ada05
VZ
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 );
f3ff831f 255}
b2238cc3 256
75b2220e
VZ
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
890d70eb 282#ifdef wxHAS_EVENT_BIND
f3ff831f 283
5293e4b7 284void EvtHandlerTestCase::BindFunction()
f3ff831f
VZ
285{
286 // function tests
5293e4b7 287 handler.Bind( MyEventType, GlobalOnMyEvent );
f3ff831f
VZ
288 g_called.Reset();
289 handler.ProcessEvent(e);
290 CPPUNIT_ASSERT( g_called.function );
5293e4b7 291 handler.Unbind( MyEventType, GlobalOnMyEvent );
f3ff831f
VZ
292 g_called.Reset();
293 handler.ProcessEvent(e);
294 CPPUNIT_ASSERT( !g_called.function ); // check that it was disconnected
295
5293e4b7
VZ
296 handler.Bind( MyEventType, GlobalOnMyEvent, 0 );
297 handler.Unbind( MyEventType, GlobalOnMyEvent, 0 );
f3ff831f 298
5293e4b7
VZ
299 handler.Bind( MyEventType, GlobalOnMyEvent, 0, 0 );
300 handler.Unbind( MyEventType, GlobalOnMyEvent, 0, 0 );
f3ff831f
VZ
301}
302
5293e4b7 303void EvtHandlerTestCase::BindStaticMethod()
f3ff831f
VZ
304{
305 // static method tests (this is same as functions but still test it just in
306 // case we hit some strange compiler bugs)
5293e4b7 307 handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent );
9b3ff3c0
VZ
308 g_called.Reset();
309 handler.ProcessEvent(e);
310 CPPUNIT_ASSERT( g_called.smethod );
5293e4b7 311 handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent );
9b3ff3c0
VZ
312 g_called.Reset();
313 handler.ProcessEvent(e);
f3ff831f 314 CPPUNIT_ASSERT( !g_called.smethod );
b2238cc3 315
5293e4b7
VZ
316 handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent, 0 );
317 handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent, 0 );
b2238cc3 318
5293e4b7
VZ
319 handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent, 0, 0 );
320 handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent, 0, 0 );
f3ff831f 321}
b2238cc3 322
5293e4b7 323void EvtHandlerTestCase::BindFunctor()
f3ff831f
VZ
324{
325 // generalized functor tests
326 MyFunctor functor;
b2238cc3 327
5293e4b7 328 handler.Bind( MyEventType, functor );
f3ff831f
VZ
329 g_called.Reset();
330 handler.ProcessEvent(e);
331 CPPUNIT_ASSERT( g_called.functor );
5293e4b7 332 handler.Unbind( MyEventType, functor );
f3ff831f
VZ
333 g_called.Reset();
334 handler.ProcessEvent(e);
335 CPPUNIT_ASSERT( !g_called.functor );
b2238cc3 336
5293e4b7
VZ
337 handler.Bind( MyEventType, functor, 0 );
338 handler.Unbind( MyEventType, functor, 0 );
f3ff831f 339
5293e4b7
VZ
340 handler.Bind( MyEventType, functor, 0, 0 );
341 handler.Unbind( MyEventType, functor, 0, 0 );
ca6911c3 342
09be3364
VZ
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;
ca6911c3 347 handler.Bind( MyEventType, MyFunctor() );
09be3364 348 CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func ));
ca6911c3
VZ
349
350 handler.Bind( MyEventType, MyFunctor(), 0 );
09be3364 351 CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func, 0 ));
ca6911c3
VZ
352
353 handler.Bind( MyEventType, MyFunctor(), 0, 0 );
09be3364 354 CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func, 0, 0 ));
f3ff831f 355}
b2238cc3 356
5293e4b7 357void EvtHandlerTestCase::BindMethod()
f3ff831f
VZ
358{
359 // class method tests
5293e4b7 360 handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler );
a01ada05
VZ
361 g_called.Reset();
362 handler.ProcessEvent(e);
363 CPPUNIT_ASSERT( g_called.method );
5293e4b7 364 handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler );
a01ada05
VZ
365 g_called.Reset();
366 handler.ProcessEvent(e);
367 CPPUNIT_ASSERT( !g_called.method );
368
5293e4b7
VZ
369 handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler, 0 );
370 handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler, 0 );
a01ada05 371
5293e4b7
VZ
372 handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler, 0, 0 );
373 handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler, 0, 0 );
a01ada05
VZ
374}
375
5293e4b7 376void EvtHandlerTestCase::BindMethodUsingBaseEvent()
a01ada05
VZ
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
5293e4b7 381 handler.Bind( MyEventType, &MyHandler::OnEvent, &handler );
f3ff831f
VZ
382 g_called.Reset();
383 handler.ProcessEvent(e);
384 CPPUNIT_ASSERT( g_called.method );
5293e4b7 385 handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler );
f3ff831f
VZ
386 g_called.Reset();
387 handler.ProcessEvent(e);
388 CPPUNIT_ASSERT( !g_called.method );
b2238cc3 389
5293e4b7
VZ
390 handler.Bind( MyEventType, &MyHandler::OnEvent, &handler, 0 );
391 handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler, 0 );
b2238cc3 392
5293e4b7
VZ
393 handler.Bind( MyEventType, &MyHandler::OnEvent, &handler, 0, 0 );
394 handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler, 0, 0 );
f3ff831f 395}
b2238cc3 396
f3ff831f 397
890d70eb
VZ
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
5293e4b7 421void EvtHandlerTestCase::BindNonHandler()
f3ff831f
VZ
422{
423 // class method tests for class not derived from wxEvtHandler
424 MySink sink;
b2238cc3 425
5293e4b7 426 handler.Bind( MyEventType, &MySink::OnMyEvent, &sink );
f3ff831f
VZ
427 g_called.Reset();
428 handler.ProcessEvent(e);
429 CPPUNIT_ASSERT( g_called.method );
5293e4b7 430 handler.Unbind( MyEventType, &MySink::OnMyEvent, &sink );
f3ff831f
VZ
431 g_called.Reset();
432 handler.ProcessEvent(e);
433 CPPUNIT_ASSERT( !g_called.method );
434}
b2238cc3 435
5293e4b7 436void EvtHandlerTestCase::InvalidBind()
f3ff831f 437{
9b3ff3c0
VZ
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
5293e4b7 441
449cb073
VZ
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
48c56e04
VZ
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
449cb073
VZ
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
b2238cc3
VZ
476}
477
890d70eb 478#endif // wxHAS_EVENT_BIND