]> git.saurik.com Git - wxWidgets.git/blob - tests/menu/menu.cpp
Crash fix for inserting text into a buffer without an associated control
[wxWidgets.git] / tests / menu / menu.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/menu/menu.cpp
3 // Purpose: wxMenu unit test
4 // Author: wxWidgets team
5 // Created: 2010-11-10
6 // Copyright: (c) 2010 wxWidgets team
7 ///////////////////////////////////////////////////////////////////////////////
8
9 // ----------------------------------------------------------------------------
10 // headers
11 // ----------------------------------------------------------------------------
12
13 #include "testprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WX_PRECOMP
20 #include "wx/wx.h"
21 #endif // WX_PRECOMP
22
23 #include "wx/menu.h"
24 #include "wx/uiaction.h"
25
26 #include <stdarg.h>
27
28 // ----------------------------------------------------------------------------
29 // helper
30 // ----------------------------------------------------------------------------
31
32 namespace
33 {
34
35 enum
36 {
37 MenuTestCase_Foo = 10000,
38 MenuTestCase_Bar,
39 MenuTestCase_First
40 };
41
42 void PopulateMenu(wxMenu* menu, const wxString& name, size_t& itemcount)
43 {
44 // Start at item 1 to make it human-readable ;)
45 for (int n=1; n<6; ++n, ++itemcount)
46 {
47 wxString label = name; label << n;
48 menu->Append(MenuTestCase_First + itemcount, label, label + " help string");
49 }
50 }
51
52 void RecursivelyCountMenuItems(const wxMenu* menu, size_t& count)
53 {
54 CPPUNIT_ASSERT( menu );
55
56 count += menu->GetMenuItemCount();
57 for (size_t n=0; n < menu->GetMenuItemCount(); ++n)
58 {
59 wxMenuItem* item = menu->FindItemByPosition(n);
60 if (item->IsSubMenu())
61 {
62 RecursivelyCountMenuItems(item->GetSubMenu(), count);
63 }
64 }
65 }
66
67 } // anon namespace
68
69
70 // ----------------------------------------------------------------------------
71 // test class
72 // ----------------------------------------------------------------------------
73
74 class MenuTestCase : public CppUnit::TestCase
75 {
76 public:
77 MenuTestCase() {}
78
79 virtual void setUp() { CreateFrame(); }
80 virtual void tearDown() { m_frame->Destroy(); }
81
82 private:
83 CPPUNIT_TEST_SUITE( MenuTestCase );
84 CPPUNIT_TEST( FindInMenubar );
85 CPPUNIT_TEST( FindInMenu );
86 CPPUNIT_TEST( EnableTop );
87 CPPUNIT_TEST( Count );
88 CPPUNIT_TEST( Labels );
89 CPPUNIT_TEST( RadioItems );
90 CPPUNIT_TEST( RemoveAdd );
91 WXUISIM_TEST( Events );
92 CPPUNIT_TEST_SUITE_END();
93
94 void CreateFrame();
95
96 void FindInMenubar();
97 void FindInMenu();
98 void EnableTop();
99 void Count();
100 void Labels();
101 void RadioItems();
102 void RemoveAdd();
103 void Events();
104
105 wxFrame* m_frame;
106
107 // Holds the number of menuitems contained in all the menus
108 size_t m_itemCount;
109
110 // Store here the id of a known submenu item, to be searched for later
111 int m_submenuItemId;
112
113 // and a sub-submenu item
114 int m_subsubmenuItemId;
115
116 wxArrayString m_menuLabels;
117
118 // The menu containing the item with MenuTestCase_Bar id.
119 wxMenu* m_menuWithBar;
120
121 DECLARE_NO_COPY_CLASS(MenuTestCase)
122 };
123
124 // register in the unnamed registry so that these tests are run by default
125 CPPUNIT_TEST_SUITE_REGISTRATION( MenuTestCase );
126
127 // also include in its own registry so that these tests can be run alone
128 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( MenuTestCase, "MenuTestCase" );
129
130 void MenuTestCase::CreateFrame()
131 {
132 m_frame = new wxFrame(NULL, wxID_ANY, "test frame");
133
134 wxMenu *fileMenu = new wxMenu;
135 wxMenu *helpMenu = new wxMenu;
136 wxMenu *subMenu = new wxMenu;
137 wxMenu *subsubMenu = new wxMenu;
138
139 size_t itemcount = 0;
140
141 PopulateMenu(subsubMenu, "Subsubmenu item ", itemcount);
142
143 // Store one of its IDs for later
144 m_subsubmenuItemId = MenuTestCase_First + itemcount - 2;
145
146 PopulateMenu(subMenu, "Submenu item ", itemcount);
147
148 // Store one of its IDs for later
149 m_submenuItemId = MenuTestCase_First + itemcount - 2;
150
151 subMenu->AppendSubMenu(subsubMenu, "Subsubmen&u", "Test a subsubmenu");
152
153 PopulateMenu(fileMenu, "Filemenu item ", itemcount);
154
155 fileMenu->Append(MenuTestCase_Foo, "&Foo\tCtrl-F", "Test item to be found");
156
157
158 PopulateMenu(helpMenu, "Helpmenu item ", itemcount);
159 helpMenu->Append(MenuTestCase_Bar, "Bar\tF1");
160 m_menuWithBar = helpMenu;
161 helpMenu->AppendSubMenu(subMenu, "Sub&menu", "Test a submenu");
162
163 // +2 for "Foo" and "Bar", +2 for the 2 submenus
164 m_itemCount = itemcount + 4;
165
166 // Use an arraystring here, to help with future tests
167 m_menuLabels.Add("&File");
168 m_menuLabels.Add("&Help");
169
170 wxMenuBar *menuBar = new wxMenuBar();
171 menuBar->Append(fileMenu, m_menuLabels[0]);
172 menuBar->Append(helpMenu, m_menuLabels[1]);
173 m_frame->SetMenuBar(menuBar);
174 }
175
176 void MenuTestCase::FindInMenubar()
177 {
178 wxMenuBar* bar = m_frame->GetMenuBar();
179
180 // Find by name:
181 CPPUNIT_ASSERT( bar->FindMenu("File") != wxNOT_FOUND );
182 CPPUNIT_ASSERT( bar->FindMenu("&File") != wxNOT_FOUND );
183 CPPUNIT_ASSERT( bar->FindMenu("&Fail") == wxNOT_FOUND );
184
185 // Find by menu name plus item name:
186 CPPUNIT_ASSERT( bar->FindMenuItem("File", "Foo") != wxNOT_FOUND );
187 CPPUNIT_ASSERT( bar->FindMenuItem("&File", "&Foo") != wxNOT_FOUND );
188 // and using the menu label
189 int index = bar->FindMenu("&File");
190 CPPUNIT_ASSERT( index != wxNOT_FOUND );
191 wxString menulabel = bar->GetMenuLabel(index);
192 CPPUNIT_ASSERT( bar->FindMenuItem(menulabel, "&Foo") != wxNOT_FOUND );
193 // and title
194 wxString menutitle = bar->GetMenu(index)->GetTitle();
195 CPPUNIT_ASSERT( bar->FindMenuItem(menutitle, "&Foo") != wxNOT_FOUND );
196
197 // Find by position:
198 for (size_t n=0; n < bar->GetMenuCount(); ++n)
199 {
200 CPPUNIT_ASSERT( bar->GetMenu(n) );
201 }
202
203 // Find by id:
204 wxMenu* menu = NULL;
205 wxMenuItem* item = NULL;
206 item = bar->FindItem(MenuTestCase_Foo, &menu);
207 CPPUNIT_ASSERT( item );
208 CPPUNIT_ASSERT( menu );
209 // Check that the correct menu was found
210 CPPUNIT_ASSERT( menu->FindChildItem(MenuTestCase_Foo) );
211
212 // Find submenu item:
213 item = bar->FindItem(m_submenuItemId, &menu);
214 CPPUNIT_ASSERT( item );
215 CPPUNIT_ASSERT( menu );
216 // and, for completeness, a subsubmenu one:
217 item = bar->FindItem(m_subsubmenuItemId, &menu);
218 CPPUNIT_ASSERT( item );
219 CPPUNIT_ASSERT( menu );
220 }
221
222 void MenuTestCase::FindInMenu()
223 {
224 wxMenuBar* bar = m_frame->GetMenuBar();
225
226 // Find by name:
227 wxMenu* menuFind = bar->GetMenu(0);
228 CPPUNIT_ASSERT( menuFind->FindItem("Foo") != wxNOT_FOUND );
229 CPPUNIT_ASSERT( menuFind->FindItem("&Foo") != wxNOT_FOUND );
230 // and for submenus
231 wxMenu* menuHelp = bar->GetMenu(1);
232 CPPUNIT_ASSERT( menuHelp->FindItem("Submenu") != wxNOT_FOUND );
233 CPPUNIT_ASSERT( menuHelp->FindItem("Sub&menu") != wxNOT_FOUND );
234
235 // Find by position:
236 size_t n;
237 for (n=0; n < menuHelp->GetMenuItemCount(); ++n)
238 {
239 CPPUNIT_ASSERT( menuHelp->FindItemByPosition(n) );
240 }
241
242 // Find by id:
243 CPPUNIT_ASSERT( menuHelp->FindItem(MenuTestCase_Bar) );
244 CPPUNIT_ASSERT( menuHelp->FindItem(MenuTestCase_Foo) == NULL );
245
246 for (n=0; n < menuHelp->GetMenuItemCount(); ++n)
247 {
248 size_t locatedAt;
249 wxMenuItem* itemByPos = menuHelp->FindItemByPosition(n);
250 CPPUNIT_ASSERT( itemByPos );
251 wxMenuItem* itemById = menuHelp->FindChildItem(itemByPos->GetId(), &locatedAt);
252 CPPUNIT_ASSERT_EQUAL( itemByPos, itemById );
253 CPPUNIT_ASSERT_EQUAL( locatedAt, n );
254 }
255
256 // Find submenu item:
257 for (n=0; n < menuHelp->GetMenuItemCount(); ++n)
258 {
259 wxMenuItem* item = menuHelp->FindItemByPosition(n);
260 if (item->IsSubMenu())
261 {
262 wxMenu* submenu;
263 wxMenuItem* submenuItem = menuHelp->FindItem(m_submenuItemId, &submenu);
264 CPPUNIT_ASSERT( submenuItem );
265 CPPUNIT_ASSERT( item->GetSubMenu() == submenu );
266 }
267 }
268 }
269
270 void MenuTestCase::EnableTop()
271 {
272 wxMenuBar* const bar = m_frame->GetMenuBar();
273 CPPUNIT_ASSERT( bar->IsEnabledTop(0) );
274 bar->EnableTop( 0, false );
275 CPPUNIT_ASSERT( !bar->IsEnabledTop(0) );
276 bar->EnableTop( 0, true );
277 CPPUNIT_ASSERT( bar->IsEnabledTop(0) );
278 }
279
280 void MenuTestCase::Count()
281 {
282 wxMenuBar* bar = m_frame->GetMenuBar();
283 // I suppose you could call this "counting menubars" :)
284 CPPUNIT_ASSERT( bar );
285
286 CPPUNIT_ASSERT_EQUAL( bar->GetMenuCount(), 2 );
287
288 size_t count = 0;
289 for (size_t n=0; n < bar->GetMenuCount(); ++n)
290 {
291 RecursivelyCountMenuItems(bar->GetMenu(n), count);
292 }
293 CPPUNIT_ASSERT_EQUAL( count, m_itemCount );
294 }
295
296 void MenuTestCase::Labels()
297 {
298 wxMenuBar* bar = m_frame->GetMenuBar();
299 CPPUNIT_ASSERT( bar );
300 wxMenu* filemenu;
301 wxMenuItem* itemFoo = bar->FindItem(MenuTestCase_Foo, &filemenu);
302 CPPUNIT_ASSERT( itemFoo );
303 CPPUNIT_ASSERT( filemenu );
304
305 // These return labels including mnemonics/accelerators:
306
307 // wxMenuBar
308 CPPUNIT_ASSERT_EQUAL( "&File", bar->GetMenuLabel(0) );
309 CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", bar->GetLabel(MenuTestCase_Foo) );
310
311 // wxMenu
312 CPPUNIT_ASSERT_EQUAL( "&File", filemenu->GetTitle() );
313 CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", filemenu->GetLabel(MenuTestCase_Foo) );
314
315 // wxMenuItem
316 CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", itemFoo->GetItemLabel() );
317
318 // These return labels stripped of mnemonics/accelerators:
319
320 // wxMenuBar
321 CPPUNIT_ASSERT_EQUAL( "File", bar->GetMenuLabelText(0) );
322
323 // wxMenu
324 CPPUNIT_ASSERT_EQUAL( "Foo", filemenu->GetLabelText(MenuTestCase_Foo) );
325
326 // wxMenuItem
327 CPPUNIT_ASSERT_EQUAL( "Foo", itemFoo->GetItemLabelText() );
328 CPPUNIT_ASSERT_EQUAL( "Foo", wxMenuItem::GetLabelText("&Foo\tCtrl-F") );
329 }
330
331 void MenuTestCase::RadioItems()
332 {
333 wxMenuBar * const bar = m_frame->GetMenuBar();
334 wxMenu * const menu = new wxMenu;
335 bar->Append(menu, "&Radio");
336
337 // Adding consecutive radio items creates a radio group.
338 menu->AppendRadioItem(MenuTestCase_First, "Radio 0");
339 menu->AppendRadioItem(MenuTestCase_First + 1, "Radio 1");
340
341 // First item of a radio group is checked by default.
342 CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First) );
343
344 // Checking the second one make the first one unchecked however.
345 menu->Check(MenuTestCase_First + 1, true);
346 CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First) );
347 CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 1) );
348
349 // Adding more radio items after a separator creates another radio group...
350 menu->AppendSeparator();
351 menu->AppendRadioItem(MenuTestCase_First + 2, "Radio 2");
352 menu->AppendRadioItem(MenuTestCase_First + 3, "Radio 3");
353 menu->AppendRadioItem(MenuTestCase_First + 4, "Radio 4");
354
355 // ... which is independent from the first one.
356 CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 2) );
357
358 menu->Check(MenuTestCase_First + 3, true);
359 CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 3) );
360 CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 2) );
361 CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 1) );
362
363
364 // Insert an item in the middle of an existing radio group.
365 menu->InsertRadioItem(4, MenuTestCase_First + 5, "Radio 5");
366 CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 3) );
367
368 menu->Check( MenuTestCase_First + 5, true );
369 CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 3) );
370
371
372 // Prepend a couple of items before the first group.
373 menu->PrependRadioItem(MenuTestCase_First + 6, "Radio 6");
374 menu->PrependRadioItem(MenuTestCase_First + 7, "Radio 7");
375 menu->Check(MenuTestCase_First + 7, true);
376 CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 1) );
377
378
379 // Check that the last radio group still works as expected.
380 menu->Check(MenuTestCase_First + 4, true);
381 CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 5) );
382 }
383
384 void MenuTestCase::RemoveAdd()
385 {
386 wxMenuBar* bar = m_frame->GetMenuBar();
387
388 wxMenu* menu0 = bar->GetMenu(0);
389 wxMenu* menu1 = bar->GetMenu(1);
390 wxMenuItem* item = new wxMenuItem(menu0, MenuTestCase_Foo + 100, "t&ext\tCtrl-E");
391 menu0->Insert(0, item);
392 CPPUNIT_ASSERT( menu0->FindItemByPosition(0) == item );
393 menu0->Remove(item);
394 CPPUNIT_ASSERT( menu0->FindItemByPosition(0) != item );
395 menu1->Insert(0, item);
396 CPPUNIT_ASSERT( menu1->FindItemByPosition(0) == item );
397 menu1->Remove(item);
398 CPPUNIT_ASSERT( menu1->FindItemByPosition(0) != item );
399 menu0->Insert(0, item);
400 CPPUNIT_ASSERT( menu0->FindItemByPosition(0) == item );
401 menu0->Delete(item);
402 }
403
404 void MenuTestCase::Events()
405 {
406 #ifdef __WXGTK__
407 // FIXME: For some reason, we sporadically fail to get the event in
408 // buildbot slave builds even though the test always passes locally.
409 // There is undoubtedly something wrong here but without being able
410 // to debug it, I have no idea what is it, so let's just disable
411 // this test when running under buildbot to let the entire test
412 // suite pass.
413 if ( IsAutomaticTest() )
414 return;
415 #endif // __WXGTK__
416
417 #if wxUSE_UIACTIONSIMULATOR
418 class MenuEventHandler : public wxEvtHandler
419 {
420 public:
421 MenuEventHandler(wxWindow* win)
422 : m_win(win)
423 {
424 m_win->Connect(wxEVT_MENU,
425 wxCommandEventHandler(MenuEventHandler::OnMenu),
426 NULL,
427 this);
428
429 m_gotEvent = false;
430 m_event = NULL;
431 }
432
433 virtual ~MenuEventHandler()
434 {
435 m_win->Disconnect(wxEVT_MENU,
436 wxCommandEventHandler(MenuEventHandler::OnMenu),
437 NULL,
438 this);
439
440 delete m_event;
441 }
442
443 const wxCommandEvent& GetEvent()
444 {
445 CPPUNIT_ASSERT( m_gotEvent );
446
447 m_gotEvent = false;
448
449 return *m_event;
450 }
451
452 private:
453 void OnMenu(wxCommandEvent& event)
454 {
455 CPPUNIT_ASSERT( !m_gotEvent );
456
457 delete m_event;
458 m_event = static_cast<wxCommandEvent*>(event.Clone());
459 m_gotEvent = true;
460 }
461
462 wxWindow* const m_win;
463 wxCommandEvent* m_event;
464 bool m_gotEvent;
465 };
466
467 MenuEventHandler handler(m_frame);
468
469 // Invoke the accelerator.
470 m_frame->Show();
471 m_frame->SetFocus();
472 wxYield();
473
474 wxUIActionSimulator sim;
475 sim.KeyDown(WXK_F1);
476 sim.KeyUp(WXK_F1);
477 wxYield();
478
479 const wxCommandEvent& ev = handler.GetEvent();
480 CPPUNIT_ASSERT_EQUAL( static_cast<int>(MenuTestCase_Bar), ev.GetId() );
481
482 wxObject* const src = ev.GetEventObject();
483 CPPUNIT_ASSERT( src );
484
485 CPPUNIT_ASSERT_EQUAL( "wxMenu",
486 wxString(src->GetClassInfo()->GetClassName()) );
487 CPPUNIT_ASSERT_EQUAL( static_cast<wxObject*>(m_menuWithBar),
488 src );
489 #endif // wxUSE_UIACTIONSIMULATOR
490 }