OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/callback.h" | |
6 #include "base/strings/utf_string_conversions.h" | |
7 #include "chrome/test/base/interactive_test_utils.h" | |
8 #include "chrome/test/base/ui_test_utils.h" | |
9 #include "chrome/test/base/view_event_test_base.h" | |
10 #include "ui/base/test/ui_controls.h" | |
11 #include "ui/views/controls/button/menu_button.h" | |
12 #include "ui/views/controls/button/menu_button_listener.h" | |
13 #include "ui/views/controls/menu/menu_controller.h" | |
14 #include "ui/views/controls/menu/menu_item_view.h" | |
15 #include "ui/views/controls/menu/menu_runner.h" | |
16 #include "ui/views/controls/menu/submenu_view.h" | |
17 #include "ui/views/widget/root_view.h" | |
18 #include "ui/views/widget/widget.h" | |
19 | |
20 using base::ASCIIToUTF16; | |
21 | |
22 // This is a convenience base class for all tests to provide some | |
23 // common functionality. It sets up a MenuButton and a MenuItemView | |
24 // and clicks the MenuButton. | |
25 // | |
26 // Subclasses should implement: | |
27 // BuildMenu() populate the menu | |
28 // DoTestOnMessageLoop() initiate the test | |
29 // | |
30 // Subclasses can call: | |
31 // Click() to post a mouse click on a View | |
32 // | |
33 // Although it should be possible to post a menu multiple times, | |
34 // MenuItemView prevents repeated activation of a menu by clicks too | |
35 // close in time. | |
36 class MenuItemViewTestBase : public ViewEventTestBase, | |
37 public views::MenuButtonListener, | |
38 public views::MenuDelegate { | |
39 public: | |
40 MenuItemViewTestBase() | |
41 : ViewEventTestBase(), | |
42 button_(NULL), | |
43 menu_(NULL) { | |
44 } | |
45 | |
46 virtual ~MenuItemViewTestBase() { | |
47 } | |
48 | |
49 // ViewEventTestBase implementation. | |
50 | |
51 virtual void SetUp() OVERRIDE { | |
52 button_ = new views::MenuButton( | |
53 NULL, ASCIIToUTF16("Menu Test"), this, true); | |
54 menu_ = new views::MenuItemView(this); | |
55 BuildMenu(menu_); | |
56 menu_runner_.reset(new views::MenuRunner(menu_)); | |
57 | |
58 ViewEventTestBase::SetUp(); | |
59 } | |
60 | |
61 virtual void TearDown() OVERRIDE { | |
62 menu_runner_.reset(NULL); | |
63 menu_ = NULL; | |
64 ViewEventTestBase::TearDown(); | |
65 } | |
66 | |
67 virtual views::View* CreateContentsView() OVERRIDE { | |
68 return button_; | |
69 } | |
70 | |
71 virtual gfx::Size GetPreferredSize() OVERRIDE { | |
72 return button_->GetPreferredSize(); | |
73 } | |
74 | |
75 // views::MenuButtonListener implementation. | |
76 virtual void OnMenuButtonClicked(views::View* source, | |
77 const gfx::Point& point) OVERRIDE { | |
78 gfx::Point screen_location; | |
79 views::View::ConvertPointToScreen(source, &screen_location); | |
80 gfx::Rect bounds(screen_location, source->size()); | |
81 ignore_result(menu_runner_->RunMenuAt( | |
82 source->GetWidget(), | |
83 button_, | |
84 bounds, | |
85 views::MenuItemView::TOPLEFT, | |
86 ui::MENU_SOURCE_NONE, | |
87 views::MenuRunner::HAS_MNEMONICS)); | |
88 } | |
89 | |
90 protected: | |
91 // Generate a mouse click on the specified view and post a new task. | |
92 virtual void Click(views::View* view, const base::Closure& next) { | |
93 ui_test_utils::MoveMouseToCenterAndPress( | |
94 view, | |
95 ui_controls::LEFT, | |
96 ui_controls::DOWN | ui_controls::UP, | |
97 next); | |
98 } | |
99 | |
100 virtual void BuildMenu(views::MenuItemView* menu) { | |
101 } | |
102 | |
103 views::MenuButton* button_; | |
104 views::MenuItemView* menu_; | |
105 scoped_ptr<views::MenuRunner> menu_runner_; | |
106 }; | |
107 | |
108 // Simple test for clicking a menu item. This template class clicks on an | |
109 // item and checks that the returned id matches. The index of the item | |
110 // is the template argument. | |
111 template<int INDEX> | |
112 class MenuItemViewTestBasic : public MenuItemViewTestBase { | |
113 public: | |
114 MenuItemViewTestBasic() : | |
115 last_command_(0) { | |
116 } | |
117 | |
118 virtual ~MenuItemViewTestBasic() { | |
119 } | |
120 | |
121 // views::MenuDelegate implementation | |
122 virtual void ExecuteCommand(int id) OVERRIDE { | |
123 last_command_ = id; | |
124 } | |
125 | |
126 // MenuItemViewTestBase implementation | |
127 virtual void BuildMenu(views::MenuItemView* menu) OVERRIDE { | |
128 menu->AppendMenuItemWithLabel(1, ASCIIToUTF16("item 1")); | |
129 menu->AppendMenuItemWithLabel(2, ASCIIToUTF16("item 2")); | |
130 menu->AppendSeparator(); | |
131 menu->AppendMenuItemWithLabel(3, ASCIIToUTF16("item 3")); | |
132 } | |
133 | |
134 // ViewEventTestBase implementation | |
135 virtual void DoTestOnMessageLoop() OVERRIDE { | |
136 Click(button_, CreateEventTask(this, &MenuItemViewTestBasic::Step1)); | |
137 } | |
138 | |
139 // Click on item INDEX. | |
140 void Step1() { | |
141 ASSERT_TRUE(menu_); | |
142 | |
143 views::SubmenuView* submenu = menu_->GetSubmenu(); | |
144 ASSERT_TRUE(submenu); | |
145 ASSERT_TRUE(submenu->IsShowing()); | |
146 ASSERT_EQ(3, submenu->GetMenuItemCount()); | |
147 | |
148 // click an item and pass control to the next step | |
149 views::MenuItemView* item = submenu->GetMenuItemAt(INDEX); | |
150 ASSERT_TRUE(item); | |
151 Click(item, CreateEventTask(this, &MenuItemViewTestBasic::Step2)); | |
152 } | |
153 | |
154 // Check the clicked item and complete the test. | |
155 void Step2() { | |
156 ASSERT_FALSE(menu_->GetSubmenu()->IsShowing()); | |
157 ASSERT_EQ(INDEX + 1,last_command_); | |
158 Done(); | |
159 } | |
160 | |
161 private: | |
162 int last_command_; | |
163 }; | |
164 | |
165 // Click each item of a 3-item menu (with separator). | |
166 typedef MenuItemViewTestBasic<0> MenuItemViewTestBasic0; | |
167 typedef MenuItemViewTestBasic<1> MenuItemViewTestBasic1; | |
168 typedef MenuItemViewTestBasic<2> MenuItemViewTestBasic2; | |
169 VIEW_TEST(MenuItemViewTestBasic0, SelectItem0) | |
170 VIEW_TEST(MenuItemViewTestBasic1, SelectItem1) | |
171 VIEW_TEST(MenuItemViewTestBasic2, SelectItem2) | |
172 | |
173 // Test class for inserting a menu item while the menu is open. | |
174 template<int INSERT_INDEX, int SELECT_INDEX> | |
175 class MenuItemViewTestInsert : public MenuItemViewTestBase { | |
176 public: | |
177 MenuItemViewTestInsert() : | |
178 last_command_(0), | |
179 inserted_item_(NULL) { | |
180 } | |
181 | |
182 virtual ~MenuItemViewTestInsert() { | |
183 } | |
184 | |
185 // views::MenuDelegate implementation | |
186 virtual void ExecuteCommand(int id) OVERRIDE { | |
187 last_command_ = id; | |
188 } | |
189 | |
190 // MenuItemViewTestBase implementation | |
191 virtual void BuildMenu(views::MenuItemView* menu) OVERRIDE { | |
192 menu->AppendMenuItemWithLabel(1, ASCIIToUTF16("item 1")); | |
193 menu->AppendMenuItemWithLabel(2, ASCIIToUTF16("item 2")); | |
194 } | |
195 | |
196 // ViewEventTestBase implementation | |
197 virtual void DoTestOnMessageLoop() OVERRIDE { | |
198 Click(button_, CreateEventTask(this, &MenuItemViewTestInsert::Step1)); | |
199 } | |
200 | |
201 // Insert item at INSERT_INDEX and click item at SELECT_INDEX. | |
202 void Step1() { | |
203 ASSERT_TRUE(menu_); | |
204 | |
205 views::SubmenuView* submenu = menu_->GetSubmenu(); | |
206 ASSERT_TRUE(submenu); | |
207 ASSERT_TRUE(submenu->IsShowing()); | |
208 ASSERT_EQ(2, submenu->GetMenuItemCount()); | |
209 | |
210 inserted_item_ = menu_->AddMenuItemAt(INSERT_INDEX, | |
211 1000, | |
212 ASCIIToUTF16("inserted item"), | |
213 base::string16(), | |
214 base::string16(), | |
215 gfx::ImageSkia(), | |
216 views::MenuItemView::NORMAL, | |
217 ui::NORMAL_SEPARATOR); | |
218 ASSERT_TRUE(inserted_item_); | |
219 menu_->ChildrenChanged(); | |
220 | |
221 // click an item and pass control to the next step | |
222 views::MenuItemView* item = submenu->GetMenuItemAt(SELECT_INDEX); | |
223 ASSERT_TRUE(item); | |
224 Click(item, CreateEventTask(this, &MenuItemViewTestInsert::Step2)); | |
225 } | |
226 | |
227 // Check clicked item and complete test. | |
228 void Step2() { | |
229 ASSERT_TRUE(menu_); | |
230 | |
231 views::SubmenuView* submenu = menu_->GetSubmenu(); | |
232 ASSERT_TRUE(submenu); | |
233 ASSERT_FALSE(submenu->IsShowing()); | |
234 ASSERT_EQ(3, submenu->GetMenuItemCount()); | |
235 | |
236 if (SELECT_INDEX == INSERT_INDEX) | |
237 ASSERT_EQ(1000, last_command_); | |
238 else if (SELECT_INDEX < INSERT_INDEX) | |
239 ASSERT_EQ(SELECT_INDEX + 1, last_command_); | |
240 else | |
241 ASSERT_EQ(SELECT_INDEX, last_command_); | |
242 | |
243 Done(); | |
244 } | |
245 | |
246 private: | |
247 int last_command_; | |
248 views::MenuItemView* inserted_item_; | |
249 }; | |
250 | |
251 // MenuItemViewTestInsertXY inserts an item at index X and selects the | |
252 // item at index Y (after the insertion). The tests here cover | |
253 // inserting at the beginning, middle, and end, crossbarred with | |
254 // selecting the first and last item. | |
255 typedef MenuItemViewTestInsert<0,0> MenuItemViewTestInsert00; | |
256 typedef MenuItemViewTestInsert<0,2> MenuItemViewTestInsert02; | |
257 typedef MenuItemViewTestInsert<1,0> MenuItemViewTestInsert10; | |
258 typedef MenuItemViewTestInsert<1,2> MenuItemViewTestInsert12; | |
259 typedef MenuItemViewTestInsert<2,0> MenuItemViewTestInsert20; | |
260 typedef MenuItemViewTestInsert<2,2> MenuItemViewTestInsert22; | |
261 VIEW_TEST(MenuItemViewTestInsert00, InsertItem00) | |
262 VIEW_TEST(MenuItemViewTestInsert02, InsertItem02) | |
263 VIEW_TEST(MenuItemViewTestInsert10, InsertItem10) | |
264 VIEW_TEST(MenuItemViewTestInsert12, InsertItem12) | |
265 VIEW_TEST(MenuItemViewTestInsert20, InsertItem20) | |
266 VIEW_TEST(MenuItemViewTestInsert22, InsertItem22) | |
267 | |
268 // Test class for inserting a menu item while a submenu is open. | |
269 template<int INSERT_INDEX> | |
270 class MenuItemViewTestInsertWithSubmenu : public MenuItemViewTestBase { | |
271 public: | |
272 MenuItemViewTestInsertWithSubmenu() : | |
273 last_command_(0), | |
274 submenu_(NULL), | |
275 inserted_item_(NULL) { | |
276 } | |
277 | |
278 virtual ~MenuItemViewTestInsertWithSubmenu() { | |
279 } | |
280 | |
281 // views::MenuDelegate implementation | |
282 virtual void ExecuteCommand(int id) OVERRIDE { | |
283 last_command_ = id; | |
284 } | |
285 | |
286 // MenuItemViewTestBase implementation | |
287 virtual void BuildMenu(views::MenuItemView* menu) OVERRIDE { | |
288 submenu_ = menu->AppendSubMenu(1, ASCIIToUTF16("My Submenu")); | |
289 submenu_->AppendMenuItemWithLabel(101, ASCIIToUTF16("submenu item 1")); | |
290 submenu_->AppendMenuItemWithLabel(101, ASCIIToUTF16("submenu item 2")); | |
291 menu->AppendMenuItemWithLabel(2, ASCIIToUTF16("item 2")); | |
292 } | |
293 | |
294 // ViewEventTestBase implementation | |
295 virtual void DoTestOnMessageLoop() OVERRIDE { | |
296 Click(button_, | |
297 CreateEventTask(this, &MenuItemViewTestInsertWithSubmenu::Step1)); | |
298 } | |
299 | |
300 // Post submenu. | |
301 void Step1() { | |
302 Click(submenu_, | |
303 CreateEventTask(this, &MenuItemViewTestInsertWithSubmenu::Step2)); | |
304 } | |
305 | |
306 // Insert item at INSERT_INDEX. | |
307 void Step2() { | |
308 inserted_item_ = menu_->AddMenuItemAt(INSERT_INDEX, | |
309 1000, | |
310 ASCIIToUTF16("inserted item"), | |
311 base::string16(), | |
312 base::string16(), | |
313 gfx::ImageSkia(), | |
314 views::MenuItemView::NORMAL, | |
315 ui::NORMAL_SEPARATOR); | |
316 ASSERT_TRUE(inserted_item_); | |
317 menu_->ChildrenChanged(); | |
318 | |
319 Click(inserted_item_, | |
320 CreateEventTask(this, &MenuItemViewTestInsertWithSubmenu::Step3)); | |
321 } | |
322 | |
323 void Step3() { | |
324 Done(); | |
325 } | |
326 | |
327 private: | |
328 int last_command_; | |
329 views::MenuItemView* submenu_; | |
330 views::MenuItemView* inserted_item_; | |
331 }; | |
332 | |
333 // MenuItemViewTestInsertWithSubmenuX posts a menu and its submenu, | |
334 // then inserts an item in the top-level menu at X. | |
335 typedef MenuItemViewTestInsertWithSubmenu<0> MenuItemViewTestInsertWithSubmenu0; | |
336 typedef MenuItemViewTestInsertWithSubmenu<1> MenuItemViewTestInsertWithSubmenu1; | |
337 VIEW_TEST(MenuItemViewTestInsertWithSubmenu0, InsertItemWithSubmenu0) | |
338 VIEW_TEST(MenuItemViewTestInsertWithSubmenu1, InsertItemWithSubmenu1) | |
339 | |
340 // Test class for removing a menu item while the menu is open. | |
341 template<int REMOVE_INDEX, int SELECT_INDEX> | |
342 class MenuItemViewTestRemove : public MenuItemViewTestBase { | |
343 public: | |
344 MenuItemViewTestRemove() | |
345 : last_command_(0) { | |
346 } | |
347 | |
348 virtual ~MenuItemViewTestRemove() { | |
349 } | |
350 | |
351 // views::MenuDelegate implementation | |
352 virtual void ExecuteCommand(int id) OVERRIDE { | |
353 last_command_ = id; | |
354 } | |
355 | |
356 // MenuItemViewTestBase implementation | |
357 virtual void BuildMenu(views::MenuItemView* menu) OVERRIDE { | |
358 menu->AppendMenuItemWithLabel(1, ASCIIToUTF16("item 1")); | |
359 menu->AppendMenuItemWithLabel(2, ASCIIToUTF16("item 2")); | |
360 menu->AppendMenuItemWithLabel(3, ASCIIToUTF16("item 3")); | |
361 } | |
362 | |
363 // ViewEventTestBase implementation | |
364 virtual void DoTestOnMessageLoop() OVERRIDE { | |
365 Click(button_, CreateEventTask(this, &MenuItemViewTestRemove::Step1)); | |
366 } | |
367 | |
368 // Remove item at REMOVE_INDEX and click item at SELECT_INDEX. | |
369 void Step1() { | |
370 ASSERT_TRUE(menu_); | |
371 | |
372 views::SubmenuView* submenu = menu_->GetSubmenu(); | |
373 ASSERT_TRUE(submenu); | |
374 ASSERT_TRUE(submenu->IsShowing()); | |
375 ASSERT_EQ(3, submenu->GetMenuItemCount()); | |
376 | |
377 // remove | |
378 menu_->RemoveMenuItemAt(REMOVE_INDEX); | |
379 menu_->ChildrenChanged(); | |
380 | |
381 // click | |
382 views::MenuItemView* item = submenu->GetMenuItemAt(SELECT_INDEX); | |
383 ASSERT_TRUE(item); | |
384 Click(item, CreateEventTask(this, &MenuItemViewTestRemove::Step2)); | |
385 } | |
386 | |
387 // Check clicked item and complete test. | |
388 void Step2() { | |
389 ASSERT_TRUE(menu_); | |
390 | |
391 views::SubmenuView* submenu = menu_->GetSubmenu(); | |
392 ASSERT_TRUE(submenu); | |
393 ASSERT_FALSE(submenu->IsShowing()); | |
394 ASSERT_EQ(2, submenu->GetMenuItemCount()); | |
395 | |
396 if (SELECT_INDEX < REMOVE_INDEX) | |
397 ASSERT_EQ(SELECT_INDEX + 1, last_command_); | |
398 else | |
399 ASSERT_EQ(SELECT_INDEX + 2, last_command_); | |
400 | |
401 Done(); | |
402 } | |
403 | |
404 private: | |
405 int last_command_; | |
406 }; | |
407 | |
408 typedef MenuItemViewTestRemove<0,0> MenuItemViewTestRemove00; | |
409 typedef MenuItemViewTestRemove<0,1> MenuItemViewTestRemove01; | |
410 typedef MenuItemViewTestRemove<1,0> MenuItemViewTestRemove10; | |
411 typedef MenuItemViewTestRemove<1,1> MenuItemViewTestRemove11; | |
412 typedef MenuItemViewTestRemove<2,0> MenuItemViewTestRemove20; | |
413 typedef MenuItemViewTestRemove<2,1> MenuItemViewTestRemove21; | |
414 VIEW_TEST(MenuItemViewTestRemove00, RemoveItem00) | |
415 VIEW_TEST(MenuItemViewTestRemove01, RemoveItem01) | |
416 VIEW_TEST(MenuItemViewTestRemove10, RemoveItem10) | |
417 VIEW_TEST(MenuItemViewTestRemove11, RemoveItem11) | |
418 VIEW_TEST(MenuItemViewTestRemove20, RemoveItem20) | |
419 VIEW_TEST(MenuItemViewTestRemove21, RemoveItem21) | |
420 | |
421 // Test class for removing a menu item while a submenu is open. | |
422 template<int REMOVE_INDEX> | |
423 class MenuItemViewTestRemoveWithSubmenu : public MenuItemViewTestBase { | |
424 public: | |
425 MenuItemViewTestRemoveWithSubmenu() : | |
426 last_command_(0), | |
427 submenu_(NULL) { | |
428 } | |
429 | |
430 virtual ~MenuItemViewTestRemoveWithSubmenu() { | |
431 } | |
432 | |
433 // views::MenuDelegate implementation | |
434 virtual void ExecuteCommand(int id) OVERRIDE { | |
435 last_command_ = id; | |
436 } | |
437 | |
438 // MenuItemViewTestBase implementation | |
439 virtual void BuildMenu(views::MenuItemView* menu) OVERRIDE { | |
440 menu->AppendMenuItemWithLabel(1, ASCIIToUTF16("item 1")); | |
441 submenu_ = menu->AppendSubMenu(2, ASCIIToUTF16("My Submenu")); | |
442 submenu_->AppendMenuItemWithLabel(101, ASCIIToUTF16("submenu item 1")); | |
443 submenu_->AppendMenuItemWithLabel(102, ASCIIToUTF16("submenu item 2")); | |
444 } | |
445 | |
446 // ViewEventTestBase implementation | |
447 virtual void DoTestOnMessageLoop() OVERRIDE { | |
448 Click(button_, | |
449 CreateEventTask(this, &MenuItemViewTestRemoveWithSubmenu::Step1)); | |
450 } | |
451 | |
452 // Post submenu. | |
453 void Step1() { | |
454 ASSERT_TRUE(menu_); | |
455 | |
456 views::SubmenuView* submenu = menu_->GetSubmenu(); | |
457 ASSERT_TRUE(submenu); | |
458 ASSERT_TRUE(submenu->IsShowing()); | |
459 | |
460 Click(submenu_, | |
461 CreateEventTask(this, &MenuItemViewTestRemoveWithSubmenu::Step2)); | |
462 } | |
463 | |
464 // Remove item at REMOVE_INDEX and select it to exit the menu loop. | |
465 void Step2() { | |
466 ASSERT_TRUE(menu_); | |
467 | |
468 views::SubmenuView* submenu = menu_->GetSubmenu(); | |
469 ASSERT_TRUE(submenu); | |
470 ASSERT_TRUE(submenu->IsShowing()); | |
471 ASSERT_EQ(2, submenu->GetMenuItemCount()); | |
472 | |
473 // remove | |
474 menu_->RemoveMenuItemAt(REMOVE_INDEX); | |
475 menu_->ChildrenChanged(); | |
476 | |
477 // click | |
478 Click(button_, | |
479 CreateEventTask(this, &MenuItemViewTestRemoveWithSubmenu::Step3)); | |
480 } | |
481 | |
482 void Step3() { | |
483 ASSERT_TRUE(menu_); | |
484 | |
485 views::SubmenuView* submenu = menu_->GetSubmenu(); | |
486 ASSERT_TRUE(submenu); | |
487 ASSERT_FALSE(submenu->IsShowing()); | |
488 ASSERT_EQ(1, submenu->GetMenuItemCount()); | |
489 | |
490 Done(); | |
491 } | |
492 | |
493 private: | |
494 int last_command_; | |
495 views::MenuItemView* submenu_; | |
496 }; | |
497 | |
498 typedef MenuItemViewTestRemoveWithSubmenu<0> MenuItemViewTestRemoveWithSubmenu0; | |
499 typedef MenuItemViewTestRemoveWithSubmenu<1> MenuItemViewTestRemoveWithSubmenu1; | |
500 VIEW_TEST(MenuItemViewTestRemoveWithSubmenu0, RemoveItemWithSubmenu0) | |
501 VIEW_TEST(MenuItemViewTestRemoveWithSubmenu1, RemoveItemWithSubmenu1) | |
OLD | NEW |