evthandler.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  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. // headers
  10. // ----------------------------------------------------------------------------
  11. #include "testprec.h"
  12. #ifdef __BORLANDC__
  13. #pragma hdrstop
  14. #endif
  15. #include "wx/event.h"
  16. // ----------------------------------------------------------------------------
  17. // test events and their handlers
  18. // ----------------------------------------------------------------------------
  19. const wxEventType LegacyEventType = wxNewEventType();
  20. class MyEvent;
  21. wxDEFINE_EVENT(MyEventType, MyEvent);
  22. class MyEvent : public wxEvent
  23. {
  24. public:
  25. MyEvent() : wxEvent(0, MyEventType) { }
  26. virtual wxEvent *Clone() const { return new MyEvent; }
  27. };
  28. typedef void (wxEvtHandler::*MyEventFunction)(MyEvent&);
  29. #ifndef wxHAS_EVENT_BIND
  30. #define MyEventHandler(func) wxEVENT_HANDLER_CAST(MyEventFunction, func)
  31. #else
  32. #define MyEventHandler(func) &func
  33. #endif
  34. #define EVT_MYEVENT(func) \
  35. wx__DECLARE_EVT0(MyEventType, MyEventHandler(func))
  36. class AnotherEvent : public wxEvent
  37. {
  38. };
  39. namespace
  40. {
  41. struct Called
  42. {
  43. Called() { Reset(); }
  44. void Reset()
  45. {
  46. function =
  47. functor =
  48. method =
  49. smethod = false;
  50. }
  51. bool function,
  52. functor,
  53. method,
  54. smethod;
  55. } g_called;
  56. void GlobalOnMyEvent(MyEvent&)
  57. {
  58. g_called.function = true;
  59. }
  60. void GlobalOnEvent(wxEvent&)
  61. {
  62. g_called.function = true;
  63. }
  64. #ifdef TEST_INVALID_BIND_GLOBAL
  65. void GlobalOnAnotherEvent(AnotherEvent&);
  66. #endif
  67. void GlobalOnIdle(wxIdleEvent&)
  68. {
  69. g_called.function = true;
  70. }
  71. struct MyFunctor
  72. {
  73. void operator()(MyEvent &) { g_called.functor = true; }
  74. };
  75. struct IdleFunctor
  76. {
  77. void operator()(wxIdleEvent &) { g_called.functor = true; }
  78. };
  79. class MyHandler : public wxEvtHandler
  80. {
  81. public:
  82. static void StaticOnMyEvent(MyEvent &) { g_called.smethod = true; }
  83. static void StaticOnAnotherEvent(AnotherEvent &);
  84. static void StaticOnIdle(wxIdleEvent&) { g_called.smethod = true; }
  85. void OnMyEvent(MyEvent&) { g_called.method = true; }
  86. void OnEvent(wxEvent&) { g_called.method = true; }
  87. void OnAnotherEvent(AnotherEvent&);
  88. void OnIdle(wxIdleEvent&) { g_called.method = true; }
  89. };
  90. // we can also handle events in classes not deriving from wxEvtHandler
  91. struct MySink
  92. {
  93. void OnMyEvent(MyEvent&) { g_called.method = true; }
  94. void OnEvent(wxEvent&) { g_called.method = true; }
  95. void OnIdle(wxIdleEvent&) { g_called.method = true; }
  96. };
  97. // also test event table compilation
  98. class MyClassWithEventTable : public wxEvtHandler
  99. {
  100. public:
  101. void OnMyEvent(MyEvent&) { g_called.method = true; }
  102. void OnEvent(wxEvent&) { g_called.method = true; }
  103. void OnAnotherEvent(AnotherEvent&);
  104. void OnIdle(wxIdleEvent&) { g_called.method = true; }
  105. private:
  106. DECLARE_EVENT_TABLE()
  107. };
  108. BEGIN_EVENT_TABLE(MyClassWithEventTable, wxEvtHandler)
  109. EVT_IDLE(MyClassWithEventTable::OnIdle)
  110. EVT_MYEVENT(MyClassWithEventTable::OnMyEvent)
  111. #ifdef wxHAS_EVENT_BIND
  112. EVT_MYEVENT(MyClassWithEventTable::OnEvent)
  113. #endif
  114. // this shouldn't compile:
  115. //EVT_MYEVENT(MyClassWithEventTable::OnIdle)
  116. //EVT_IDLE(MyClassWithEventTable::OnAnotherEvent)
  117. END_EVENT_TABLE()
  118. } // anonymous namespace
  119. // --------------------------------------------------------------------------
  120. // test class
  121. // --------------------------------------------------------------------------
  122. class EvtHandlerTestCase : public CppUnit::TestCase
  123. {
  124. public:
  125. EvtHandlerTestCase() {}
  126. private:
  127. CPPUNIT_TEST_SUITE( EvtHandlerTestCase );
  128. CPPUNIT_TEST( BuiltinConnect );
  129. CPPUNIT_TEST( LegacyConnect );
  130. CPPUNIT_TEST( DisconnectWildcard );
  131. CPPUNIT_TEST( AutoDisconnect );
  132. #ifdef wxHAS_EVENT_BIND
  133. CPPUNIT_TEST( BindFunction );
  134. CPPUNIT_TEST( BindStaticMethod );
  135. CPPUNIT_TEST( BindFunctor );
  136. CPPUNIT_TEST( BindMethod );
  137. CPPUNIT_TEST( BindMethodUsingBaseEvent );
  138. CPPUNIT_TEST( BindFunctionUsingBaseEvent );
  139. CPPUNIT_TEST( BindNonHandler );
  140. CPPUNIT_TEST( InvalidBind );
  141. #endif // wxHAS_EVENT_BIND
  142. CPPUNIT_TEST_SUITE_END();
  143. void BuiltinConnect();
  144. void LegacyConnect();
  145. void DisconnectWildcard();
  146. void AutoDisconnect();
  147. #ifdef wxHAS_EVENT_BIND
  148. void BindFunction();
  149. void BindStaticMethod();
  150. void BindFunctor();
  151. void BindMethod();
  152. void BindMethodUsingBaseEvent();
  153. void BindFunctionUsingBaseEvent();
  154. void BindNonHandler();
  155. void InvalidBind();
  156. #endif // wxHAS_EVENT_BIND
  157. // these member variables exceptionally don't use "m_" prefix because
  158. // they're used so many times
  159. MyHandler handler;
  160. MyEvent e;
  161. DECLARE_NO_COPY_CLASS(EvtHandlerTestCase)
  162. };
  163. // register in the unnamed registry so that these tests are run by default
  164. CPPUNIT_TEST_SUITE_REGISTRATION( EvtHandlerTestCase );
  165. // also include in its own registry so that these tests can be run alone
  166. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtHandlerTestCase, "EvtHandlerTestCase" );
  167. void EvtHandlerTestCase::BuiltinConnect()
  168. {
  169. handler.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle));
  170. handler.Disconnect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle));
  171. handler.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &handler);
  172. handler.Disconnect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &handler);
  173. // using casts like this is even uglier than using wxIdleEventHandler but
  174. // it should still continue to work for compatibility
  175. handler.Connect(wxEVT_IDLE, (wxObjectEventFunction)(wxEventFunction)&MyHandler::OnIdle);
  176. handler.Disconnect(wxEVT_IDLE, (wxObjectEventFunction)(wxEventFunction)&MyHandler::OnIdle);
  177. #ifdef wxHAS_EVENT_BIND
  178. handler.Bind(wxEVT_IDLE, GlobalOnIdle);
  179. handler.Unbind(wxEVT_IDLE, GlobalOnIdle);
  180. IdleFunctor f;
  181. handler.Bind(wxEVT_IDLE, f);
  182. handler.Unbind(wxEVT_IDLE, f);
  183. handler.Bind(wxEVT_IDLE, &MyHandler::OnIdle, &handler);
  184. handler.Unbind(wxEVT_IDLE, &MyHandler::OnIdle, &handler);
  185. handler.Bind(wxEVT_IDLE, &MyHandler::StaticOnIdle);
  186. handler.Unbind(wxEVT_IDLE, &MyHandler::StaticOnIdle);
  187. #endif // wxHAS_EVENT_BIND
  188. }
  189. void EvtHandlerTestCase::LegacyConnect()
  190. {
  191. handler.Connect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
  192. handler.Connect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
  193. handler.Connect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
  194. handler.Disconnect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
  195. handler.Disconnect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
  196. handler.Disconnect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent );
  197. handler.Connect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
  198. handler.Connect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
  199. handler.Connect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
  200. handler.Disconnect( LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
  201. handler.Disconnect( 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
  202. handler.Disconnect( 0, 0, LegacyEventType, (wxObjectEventFunction)&MyHandler::OnEvent, NULL, &handler );
  203. }
  204. void EvtHandlerTestCase::DisconnectWildcard()
  205. {
  206. // should be able to disconnect a different handler using "wildcard search"
  207. MyHandler sink;
  208. wxEvtHandler source;
  209. source.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &sink);
  210. CPPUNIT_ASSERT(source.Disconnect(wxID_ANY, wxEVT_IDLE));
  211. // destruction of source and sink here should properly clean up the
  212. // wxEventConnectionRef without crashing
  213. }
  214. void EvtHandlerTestCase::AutoDisconnect()
  215. {
  216. wxEvtHandler source;
  217. {
  218. MyHandler sink;
  219. source.Connect(wxEVT_IDLE, wxIdleEventHandler(MyHandler::OnIdle), NULL, &sink);
  220. // mismatched event type, so nothing should be disconnected
  221. CPPUNIT_ASSERT(!source.Disconnect(wxEVT_THREAD, wxIdleEventHandler(MyHandler::OnIdle), NULL, &sink));
  222. }
  223. // destruction of sink should have automatically disconnected it, so
  224. // there should be nothing to disconnect anymore
  225. CPPUNIT_ASSERT(!source.Disconnect(wxID_ANY, wxEVT_IDLE));
  226. }
  227. #ifdef wxHAS_EVENT_BIND
  228. void EvtHandlerTestCase::BindFunction()
  229. {
  230. // function tests
  231. handler.Bind( MyEventType, GlobalOnMyEvent );
  232. g_called.Reset();
  233. handler.ProcessEvent(e);
  234. CPPUNIT_ASSERT( g_called.function );
  235. handler.Unbind( MyEventType, GlobalOnMyEvent );
  236. g_called.Reset();
  237. handler.ProcessEvent(e);
  238. CPPUNIT_ASSERT( !g_called.function ); // check that it was disconnected
  239. handler.Bind( MyEventType, GlobalOnMyEvent, 0 );
  240. handler.Unbind( MyEventType, GlobalOnMyEvent, 0 );
  241. handler.Bind( MyEventType, GlobalOnMyEvent, 0, 0 );
  242. handler.Unbind( MyEventType, GlobalOnMyEvent, 0, 0 );
  243. }
  244. void EvtHandlerTestCase::BindStaticMethod()
  245. {
  246. // static method tests (this is same as functions but still test it just in
  247. // case we hit some strange compiler bugs)
  248. handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent );
  249. g_called.Reset();
  250. handler.ProcessEvent(e);
  251. CPPUNIT_ASSERT( g_called.smethod );
  252. handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent );
  253. g_called.Reset();
  254. handler.ProcessEvent(e);
  255. CPPUNIT_ASSERT( !g_called.smethod );
  256. handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent, 0 );
  257. handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent, 0 );
  258. handler.Bind( MyEventType, &MyHandler::StaticOnMyEvent, 0, 0 );
  259. handler.Unbind( MyEventType, &MyHandler::StaticOnMyEvent, 0, 0 );
  260. }
  261. void EvtHandlerTestCase::BindFunctor()
  262. {
  263. // generalized functor tests
  264. MyFunctor functor;
  265. handler.Bind( MyEventType, functor );
  266. g_called.Reset();
  267. handler.ProcessEvent(e);
  268. CPPUNIT_ASSERT( g_called.functor );
  269. handler.Unbind( MyEventType, functor );
  270. g_called.Reset();
  271. handler.ProcessEvent(e);
  272. CPPUNIT_ASSERT( !g_called.functor );
  273. handler.Bind( MyEventType, functor, 0 );
  274. handler.Unbind( MyEventType, functor, 0 );
  275. handler.Bind( MyEventType, functor, 0, 0 );
  276. handler.Unbind( MyEventType, functor, 0, 0 );
  277. // test that a temporary functor is working as well and also test that
  278. // unbinding a different (though equal) instance of the same functor does
  279. // not work
  280. MyFunctor func;
  281. handler.Bind( MyEventType, MyFunctor() );
  282. CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func ));
  283. handler.Bind( MyEventType, MyFunctor(), 0 );
  284. CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func, 0 ));
  285. handler.Bind( MyEventType, MyFunctor(), 0, 0 );
  286. CPPUNIT_ASSERT( !handler.Unbind( MyEventType, func, 0, 0 ));
  287. }
  288. void EvtHandlerTestCase::BindMethod()
  289. {
  290. // class method tests
  291. handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler );
  292. g_called.Reset();
  293. handler.ProcessEvent(e);
  294. CPPUNIT_ASSERT( g_called.method );
  295. handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler );
  296. g_called.Reset();
  297. handler.ProcessEvent(e);
  298. CPPUNIT_ASSERT( !g_called.method );
  299. handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler, 0 );
  300. handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler, 0 );
  301. handler.Bind( MyEventType, &MyHandler::OnMyEvent, &handler, 0, 0 );
  302. handler.Unbind( MyEventType, &MyHandler::OnMyEvent, &handler, 0, 0 );
  303. }
  304. void EvtHandlerTestCase::BindMethodUsingBaseEvent()
  305. {
  306. // test connecting a method taking just wxEvent and not MyEvent: this
  307. // should work too if we don't need any MyEvent-specific information in the
  308. // handler
  309. handler.Bind( MyEventType, &MyHandler::OnEvent, &handler );
  310. g_called.Reset();
  311. handler.ProcessEvent(e);
  312. CPPUNIT_ASSERT( g_called.method );
  313. handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler );
  314. g_called.Reset();
  315. handler.ProcessEvent(e);
  316. CPPUNIT_ASSERT( !g_called.method );
  317. handler.Bind( MyEventType, &MyHandler::OnEvent, &handler, 0 );
  318. handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler, 0 );
  319. handler.Bind( MyEventType, &MyHandler::OnEvent, &handler, 0, 0 );
  320. handler.Unbind( MyEventType, &MyHandler::OnEvent, &handler, 0, 0 );
  321. }
  322. void EvtHandlerTestCase::BindFunctionUsingBaseEvent()
  323. {
  324. // test connecting a function taking just wxEvent and not MyEvent: this
  325. // should work too if we don't need any MyEvent-specific information in the
  326. // handler
  327. handler.Bind( MyEventType, GlobalOnEvent );
  328. g_called.Reset();
  329. handler.ProcessEvent(e);
  330. CPPUNIT_ASSERT( g_called.function );
  331. handler.Unbind( MyEventType, GlobalOnEvent );
  332. g_called.Reset();
  333. handler.ProcessEvent(e);
  334. CPPUNIT_ASSERT( !g_called.function );
  335. handler.Bind( MyEventType, GlobalOnEvent, 0 );
  336. handler.Unbind( MyEventType, GlobalOnEvent, 0 );
  337. handler.Bind( MyEventType, GlobalOnEvent, 0, 0 );
  338. handler.Unbind( MyEventType, GlobalOnEvent, 0, 0 );
  339. }
  340. void EvtHandlerTestCase::BindNonHandler()
  341. {
  342. // class method tests for class not derived from wxEvtHandler
  343. MySink sink;
  344. handler.Bind( MyEventType, &MySink::OnMyEvent, &sink );
  345. g_called.Reset();
  346. handler.ProcessEvent(e);
  347. CPPUNIT_ASSERT( g_called.method );
  348. handler.Unbind( MyEventType, &MySink::OnMyEvent, &sink );
  349. g_called.Reset();
  350. handler.ProcessEvent(e);
  351. CPPUNIT_ASSERT( !g_called.method );
  352. }
  353. void EvtHandlerTestCase::InvalidBind()
  354. {
  355. // these calls shouldn't compile but we unfortunately can't check this
  356. // automatically, you need to uncomment them manually and test that
  357. // compilation does indeed fail
  358. // connecting a handler with incompatible signature shouldn't work
  359. #ifdef TEST_INVALID_BIND_GLOBAL
  360. handler.Bind(MyEventType, GlobalOnAnotherEvent);
  361. #endif
  362. #ifdef TEST_INVALID_BIND_STATIC
  363. handler.Bind(MyEventType, &MyHandler::StaticOnAnotherEvent);
  364. #endif
  365. #ifdef TEST_INVALID_BIND_METHOD
  366. handler.Bind(MyEventType, &MyHandler::OnAnotherEvent, &handler);
  367. #endif
  368. #ifdef TEST_INVALID_BIND_FUNCTOR
  369. IdleFunctor f;
  370. handler.Bind(MyEventType, f);
  371. #endif
  372. // the handler can't be omitted when calling Bind()
  373. #ifdef TEST_INVALID_BIND_NO_HANDLER
  374. handler.Bind(MyEventType, &MyHandler::OnMyEvent);
  375. #endif
  376. // calling a derived class method with a base class pointer must not work
  377. #ifdef TEST_INVALID_BIND_DERIVED
  378. struct C1 : wxEvtHandler { };
  379. struct C2 : wxEvtHandler { void OnWhatever(wxEvent&); };
  380. C1 c1;
  381. c1.Bind(&C2::OnWhatever);
  382. #endif
  383. // using object pointer incompatible with the method must not work
  384. #ifdef TEST_INVALID_BIND_WRONG_CLASS
  385. MySink mySink;
  386. MyHandler myHandler;
  387. myHandler.Bind(MyEventType, &MyHandler::OnMyEvent, &mySink);
  388. #endif
  389. }
  390. #endif // wxHAS_EVENT_BIND