1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/menu/menu.cpp
3 // Purpose: wxMenu unit test
4 // Author: wxWidgets team
6 // Copyright: (c) 2010 wxWidgets team
7 ///////////////////////////////////////////////////////////////////////////////
9 // ----------------------------------------------------------------------------
11 // ----------------------------------------------------------------------------
24 #include "wx/uiaction.h"
28 // ----------------------------------------------------------------------------
30 // ----------------------------------------------------------------------------
37 MenuTestCase_Foo
= 10000,
42 void PopulateMenu(wxMenu
* menu
, const wxString
& name
, size_t& itemcount
)
44 // Start at item 1 to make it human-readable ;)
45 for (int n
=1; n
<6; ++n
, ++itemcount
)
47 wxString label
= name
; label
<< n
;
48 menu
->Append(MenuTestCase_First
+ itemcount
, label
, label
+ " help string");
52 void RecursivelyCountMenuItems(const wxMenu
* menu
, size_t& count
)
54 CPPUNIT_ASSERT( menu
);
56 count
+= menu
->GetMenuItemCount();
57 for (size_t n
=0; n
< menu
->GetMenuItemCount(); ++n
)
59 wxMenuItem
* item
= menu
->FindItemByPosition(n
);
60 if (item
->IsSubMenu())
62 RecursivelyCountMenuItems(item
->GetSubMenu(), count
);
70 // ----------------------------------------------------------------------------
72 // ----------------------------------------------------------------------------
74 class MenuTestCase
: public CppUnit::TestCase
79 virtual void setUp() { CreateFrame(); }
80 virtual void tearDown() { m_frame
->Destroy(); }
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();
107 // Holds the number of menuitems contained in all the menus
110 // Store here the id of a known submenu item, to be searched for later
113 // and a sub-submenu item
114 int m_subsubmenuItemId
;
116 wxArrayString m_menuLabels
;
118 // The menu containing the item with MenuTestCase_Bar id.
119 wxMenu
* m_menuWithBar
;
121 DECLARE_NO_COPY_CLASS(MenuTestCase
)
124 // register in the unnamed registry so that these tests are run by default
125 CPPUNIT_TEST_SUITE_REGISTRATION( MenuTestCase
);
127 // also include in its own registry so that these tests can be run alone
128 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( MenuTestCase
, "MenuTestCase" );
130 void MenuTestCase::CreateFrame()
132 m_frame
= new wxFrame(NULL
, wxID_ANY
, "test frame");
134 wxMenu
*fileMenu
= new wxMenu
;
135 wxMenu
*helpMenu
= new wxMenu
;
136 wxMenu
*subMenu
= new wxMenu
;
137 wxMenu
*subsubMenu
= new wxMenu
;
139 size_t itemcount
= 0;
141 PopulateMenu(subsubMenu
, "Subsubmenu item ", itemcount
);
143 // Store one of its IDs for later
144 m_subsubmenuItemId
= MenuTestCase_First
+ itemcount
- 2;
146 PopulateMenu(subMenu
, "Submenu item ", itemcount
);
148 // Store one of its IDs for later
149 m_submenuItemId
= MenuTestCase_First
+ itemcount
- 2;
151 subMenu
->AppendSubMenu(subsubMenu
, "Subsubmen&u", "Test a subsubmenu");
153 // Check GetTitle() returns the correct string _before_ appending to the bar
154 fileMenu
->SetTitle("&Foo\tCtrl-F");
155 CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", fileMenu
->GetTitle() );
157 PopulateMenu(fileMenu
, "Filemenu item ", itemcount
);
159 fileMenu
->Append(MenuTestCase_Foo
, "&Foo\tCtrl-F", "Test item to be found");
162 PopulateMenu(helpMenu
, "Helpmenu item ", itemcount
);
163 helpMenu
->Append(MenuTestCase_Bar
, "Bar\tF1");
164 m_menuWithBar
= helpMenu
;
165 helpMenu
->AppendSubMenu(subMenu
, "Sub&menu", "Test a submenu");
167 // +2 for "Foo" and "Bar", +2 for the 2 submenus
168 m_itemCount
= itemcount
+ 4;
170 // Use an arraystring here, to help with future tests
171 m_menuLabels
.Add("&File");
172 m_menuLabels
.Add("&Help");
174 wxMenuBar
*menuBar
= new wxMenuBar();
175 menuBar
->Append(fileMenu
, m_menuLabels
[0]);
176 menuBar
->Append(helpMenu
, m_menuLabels
[1]);
177 m_frame
->SetMenuBar(menuBar
);
180 void MenuTestCase::FindInMenubar()
182 wxMenuBar
* bar
= m_frame
->GetMenuBar();
185 CPPUNIT_ASSERT( bar
->FindMenu("File") != wxNOT_FOUND
);
186 CPPUNIT_ASSERT( bar
->FindMenu("&File") != wxNOT_FOUND
);
187 CPPUNIT_ASSERT( bar
->FindMenu("&Fail") == wxNOT_FOUND
);
189 // Find by menu name plus item name:
190 CPPUNIT_ASSERT( bar
->FindMenuItem("File", "Foo") != wxNOT_FOUND
);
191 CPPUNIT_ASSERT( bar
->FindMenuItem("&File", "&Foo") != wxNOT_FOUND
);
192 // and using the menu label
193 int index
= bar
->FindMenu("&File");
194 CPPUNIT_ASSERT( index
!= wxNOT_FOUND
);
195 wxString menulabel
= bar
->GetMenuLabel(index
);
196 CPPUNIT_ASSERT( bar
->FindMenuItem(menulabel
, "&Foo") != wxNOT_FOUND
);
198 wxString menutitle
= bar
->GetMenu(index
)->GetTitle();
199 CPPUNIT_ASSERT( bar
->FindMenuItem(menutitle
, "&Foo") != wxNOT_FOUND
);
202 for (size_t n
=0; n
< bar
->GetMenuCount(); ++n
)
204 CPPUNIT_ASSERT( bar
->GetMenu(n
) );
209 wxMenuItem
* item
= NULL
;
210 item
= bar
->FindItem(MenuTestCase_Foo
, &menu
);
211 CPPUNIT_ASSERT( item
);
212 CPPUNIT_ASSERT( menu
);
213 // Check that the correct menu was found
214 CPPUNIT_ASSERT( menu
->FindChildItem(MenuTestCase_Foo
) );
216 // Find submenu item:
217 item
= bar
->FindItem(m_submenuItemId
, &menu
);
218 CPPUNIT_ASSERT( item
);
219 CPPUNIT_ASSERT( menu
);
220 // and, for completeness, a subsubmenu one:
221 item
= bar
->FindItem(m_subsubmenuItemId
, &menu
);
222 CPPUNIT_ASSERT( item
);
223 CPPUNIT_ASSERT( menu
);
226 void MenuTestCase::FindInMenu()
228 wxMenuBar
* bar
= m_frame
->GetMenuBar();
231 wxMenu
* menuFind
= bar
->GetMenu(0);
232 CPPUNIT_ASSERT( menuFind
->FindItem("Foo") != wxNOT_FOUND
);
233 CPPUNIT_ASSERT( menuFind
->FindItem("&Foo") != wxNOT_FOUND
);
235 wxMenu
* menuHelp
= bar
->GetMenu(1);
236 CPPUNIT_ASSERT( menuHelp
->FindItem("Submenu") != wxNOT_FOUND
);
237 CPPUNIT_ASSERT( menuHelp
->FindItem("Sub&menu") != wxNOT_FOUND
);
241 for (n
=0; n
< menuHelp
->GetMenuItemCount(); ++n
)
243 CPPUNIT_ASSERT( menuHelp
->FindItemByPosition(n
) );
247 CPPUNIT_ASSERT( menuHelp
->FindItem(MenuTestCase_Bar
) );
248 CPPUNIT_ASSERT( menuHelp
->FindItem(MenuTestCase_Foo
) == NULL
);
250 for (n
=0; n
< menuHelp
->GetMenuItemCount(); ++n
)
253 wxMenuItem
* itemByPos
= menuHelp
->FindItemByPosition(n
);
254 CPPUNIT_ASSERT( itemByPos
);
255 wxMenuItem
* itemById
= menuHelp
->FindChildItem(itemByPos
->GetId(), &locatedAt
);
256 CPPUNIT_ASSERT_EQUAL( itemByPos
, itemById
);
257 CPPUNIT_ASSERT_EQUAL( locatedAt
, n
);
260 // Find submenu item:
261 for (n
=0; n
< menuHelp
->GetMenuItemCount(); ++n
)
263 wxMenuItem
* item
= menuHelp
->FindItemByPosition(n
);
264 if (item
->IsSubMenu())
267 wxMenuItem
* submenuItem
= menuHelp
->FindItem(m_submenuItemId
, &submenu
);
268 CPPUNIT_ASSERT( submenuItem
);
269 CPPUNIT_ASSERT( item
->GetSubMenu() == submenu
);
274 void MenuTestCase::EnableTop()
276 wxMenuBar
* const bar
= m_frame
->GetMenuBar();
277 CPPUNIT_ASSERT( bar
->IsEnabledTop(0) );
278 bar
->EnableTop( 0, false );
279 CPPUNIT_ASSERT( !bar
->IsEnabledTop(0) );
280 bar
->EnableTop( 0, true );
281 CPPUNIT_ASSERT( bar
->IsEnabledTop(0) );
284 void MenuTestCase::Count()
286 wxMenuBar
* bar
= m_frame
->GetMenuBar();
287 // I suppose you could call this "counting menubars" :)
288 CPPUNIT_ASSERT( bar
);
290 CPPUNIT_ASSERT_EQUAL( bar
->GetMenuCount(), 2 );
293 for (size_t n
=0; n
< bar
->GetMenuCount(); ++n
)
295 RecursivelyCountMenuItems(bar
->GetMenu(n
), count
);
297 CPPUNIT_ASSERT_EQUAL( count
, m_itemCount
);
300 void MenuTestCase::Labels()
302 wxMenuBar
* bar
= m_frame
->GetMenuBar();
303 CPPUNIT_ASSERT( bar
);
305 wxMenuItem
* itemFoo
= bar
->FindItem(MenuTestCase_Foo
, &filemenu
);
306 CPPUNIT_ASSERT( itemFoo
);
307 CPPUNIT_ASSERT( filemenu
);
309 // These return labels including mnemonics/accelerators:
312 CPPUNIT_ASSERT_EQUAL( "&File", bar
->GetMenuLabel(0) );
313 CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", bar
->GetLabel(MenuTestCase_Foo
) );
316 CPPUNIT_ASSERT_EQUAL( "&File", filemenu
->GetTitle() );
317 CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", filemenu
->GetLabel(MenuTestCase_Foo
) );
320 CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", itemFoo
->GetItemLabel() );
322 // These return labels stripped of mnemonics/accelerators:
325 CPPUNIT_ASSERT_EQUAL( "File", bar
->GetMenuLabelText(0) );
328 CPPUNIT_ASSERT_EQUAL( "Foo", filemenu
->GetLabelText(MenuTestCase_Foo
) );
331 CPPUNIT_ASSERT_EQUAL( "Foo", itemFoo
->GetItemLabelText() );
332 CPPUNIT_ASSERT_EQUAL( "Foo", wxMenuItem::GetLabelText("&Foo\tCtrl-F") );
335 void MenuTestCase::RadioItems()
337 wxMenuBar
* const bar
= m_frame
->GetMenuBar();
338 wxMenu
* const menu
= new wxMenu
;
339 bar
->Append(menu
, "&Radio");
341 // Adding consecutive radio items creates a radio group.
342 menu
->AppendRadioItem(MenuTestCase_First
, "Radio 0");
343 menu
->AppendRadioItem(MenuTestCase_First
+ 1, "Radio 1");
345 // First item of a radio group is checked by default.
346 CPPUNIT_ASSERT( menu
->IsChecked(MenuTestCase_First
) );
348 // Checking the second one make the first one unchecked however.
349 menu
->Check(MenuTestCase_First
+ 1, true);
350 CPPUNIT_ASSERT( !menu
->IsChecked(MenuTestCase_First
) );
351 CPPUNIT_ASSERT( menu
->IsChecked(MenuTestCase_First
+ 1) );
353 // Adding more radio items after a separator creates another radio group...
354 menu
->AppendSeparator();
355 menu
->AppendRadioItem(MenuTestCase_First
+ 2, "Radio 2");
356 menu
->AppendRadioItem(MenuTestCase_First
+ 3, "Radio 3");
357 menu
->AppendRadioItem(MenuTestCase_First
+ 4, "Radio 4");
359 // ... which is independent from the first one.
360 CPPUNIT_ASSERT( menu
->IsChecked(MenuTestCase_First
+ 2) );
362 menu
->Check(MenuTestCase_First
+ 3, true);
363 CPPUNIT_ASSERT( menu
->IsChecked(MenuTestCase_First
+ 3) );
364 CPPUNIT_ASSERT( !menu
->IsChecked(MenuTestCase_First
+ 2) );
365 CPPUNIT_ASSERT( menu
->IsChecked(MenuTestCase_First
+ 1) );
368 // Insert an item in the middle of an existing radio group.
369 menu
->InsertRadioItem(4, MenuTestCase_First
+ 5, "Radio 5");
370 CPPUNIT_ASSERT( menu
->IsChecked(MenuTestCase_First
+ 3) );
372 menu
->Check( MenuTestCase_First
+ 5, true );
373 CPPUNIT_ASSERT( !menu
->IsChecked(MenuTestCase_First
+ 3) );
376 // Prepend a couple of items before the first group.
377 menu
->PrependRadioItem(MenuTestCase_First
+ 6, "Radio 6");
378 menu
->PrependRadioItem(MenuTestCase_First
+ 7, "Radio 7");
379 menu
->Check(MenuTestCase_First
+ 7, true);
380 CPPUNIT_ASSERT( !menu
->IsChecked(MenuTestCase_First
+ 1) );
383 // Check that the last radio group still works as expected.
384 menu
->Check(MenuTestCase_First
+ 4, true);
385 CPPUNIT_ASSERT( !menu
->IsChecked(MenuTestCase_First
+ 5) );
388 void MenuTestCase::RemoveAdd()
390 wxMenuBar
* bar
= m_frame
->GetMenuBar();
392 wxMenu
* menu0
= bar
->GetMenu(0);
393 wxMenu
* menu1
= bar
->GetMenu(1);
394 wxMenuItem
* item
= new wxMenuItem(menu0
, MenuTestCase_Foo
+ 100, "t&ext\tCtrl-E");
395 menu0
->Insert(0, item
);
396 CPPUNIT_ASSERT( menu0
->FindItemByPosition(0) == item
);
398 CPPUNIT_ASSERT( menu0
->FindItemByPosition(0) != item
);
399 menu1
->Insert(0, item
);
400 CPPUNIT_ASSERT( menu1
->FindItemByPosition(0) == item
);
402 CPPUNIT_ASSERT( menu1
->FindItemByPosition(0) != item
);
403 menu0
->Insert(0, item
);
404 CPPUNIT_ASSERT( menu0
->FindItemByPosition(0) == item
);
408 void MenuTestCase::Events()
411 // FIXME: For some reason, we sporadically fail to get the event in
412 // buildbot slave builds even though the test always passes locally.
413 // There is undoubtedly something wrong here but without being able
414 // to debug it, I have no idea what is it, so let's just disable
415 // this test when running under buildbot to let the entire test
417 if ( IsAutomaticTest() )
421 #if wxUSE_UIACTIONSIMULATOR
422 class MenuEventHandler
: public wxEvtHandler
425 MenuEventHandler(wxWindow
* win
)
428 m_win
->Connect(wxEVT_MENU
,
429 wxCommandEventHandler(MenuEventHandler::OnMenu
),
437 virtual ~MenuEventHandler()
439 m_win
->Disconnect(wxEVT_MENU
,
440 wxCommandEventHandler(MenuEventHandler::OnMenu
),
447 const wxCommandEvent
& GetEvent()
449 CPPUNIT_ASSERT( m_gotEvent
);
457 void OnMenu(wxCommandEvent
& event
)
459 CPPUNIT_ASSERT( !m_gotEvent
);
462 m_event
= static_cast<wxCommandEvent
*>(event
.Clone());
466 wxWindow
* const m_win
;
467 wxCommandEvent
* m_event
;
471 MenuEventHandler
handler(m_frame
);
473 // Invoke the accelerator.
478 wxUIActionSimulator sim
;
483 const wxCommandEvent
& ev
= handler
.GetEvent();
484 CPPUNIT_ASSERT_EQUAL( static_cast<int>(MenuTestCase_Bar
), ev
.GetId() );
486 wxObject
* const src
= ev
.GetEventObject();
487 CPPUNIT_ASSERT( src
);
489 CPPUNIT_ASSERT_EQUAL( "wxMenu",
490 wxString(src
->GetClassInfo()->GetClassName()) );
491 CPPUNIT_ASSERT_EQUAL( static_cast<wxObject
*>(m_menuWithBar
),
493 #endif // wxUSE_UIACTIONSIMULATOR