Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(33)

Side by Side Diff: ui/views/controls/menu/menu_controller_unittest.cc

Issue 1138523006: Enable keyboard accelerators while a menu is open (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Handling oshima's comments Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/controls/menu/menu_controller.h" 5 #include "ui/views/controls/menu/menu_controller.h"
6 6
7 #include "base/run_loop.h"
8 #include "base/strings/utf_string_conversions.h" 7 #include "base/strings/utf_string_conversions.h"
9 #include "ui/aura/scoped_window_targeter.h" 8 #include "ui/aura/scoped_window_targeter.h"
10 #include "ui/aura/window.h" 9 #include "ui/aura/window.h"
11 #include "ui/events/event_handler.h" 10 #include "ui/events/event_handler.h"
12 #include "ui/events/null_event_targeter.h" 11 #include "ui/events/null_event_targeter.h"
13 #include "ui/events/platform/platform_event_source.h" 12 #include "ui/events/test/event_generator.h"
14 #include "ui/views/controls/menu/menu_item_view.h" 13 #include "ui/views/controls/menu/menu_item_view.h"
15 #include "ui/views/controls/menu/submenu_view.h" 14 #include "ui/views/controls/menu/submenu_view.h"
16 #include "ui/views/test/views_test_base.h" 15 #include "ui/views/test/views_test_base.h"
17 #include "ui/wm/public/dispatcher_client.h"
18 16
19 #if defined(OS_WIN) 17 #if defined(USE_X11)
20 #include "base/message_loop/message_pump_dispatcher.h"
21 #elif defined(USE_X11)
22 #include <X11/Xlib.h> 18 #include <X11/Xlib.h>
23 #undef Bool 19 #undef Bool
24 #undef None 20 #undef None
25 #include "ui/events/devices/x11/device_data_manager_x11.h" 21 #include "ui/events/devices/x11/device_data_manager_x11.h"
26 #include "ui/events/test/events_test_utils_x11.h" 22 #include "ui/events/test/events_test_utils_x11.h"
27 #elif defined(USE_OZONE)
28 #include "ui/events/event.h"
29 #endif 23 #endif
30 24
31 namespace views { 25 namespace views {
32 26
33 namespace { 27 namespace {
34 28
35 class TestMenuItemView : public MenuItemView { 29 class TestMenuItemView : public MenuItemView {
36 public: 30 public:
37 TestMenuItemView() : MenuItemView(nullptr) {} 31 TestMenuItemView() : MenuItemView(nullptr) {}
38 ~TestMenuItemView() override {} 32 ~TestMenuItemView() override {}
39 33
40 private: 34 private:
41 DISALLOW_COPY_AND_ASSIGN(TestMenuItemView); 35 DISALLOW_COPY_AND_ASSIGN(TestMenuItemView);
42 }; 36 };
43 37
44 class TestPlatformEventSource : public ui::PlatformEventSource {
45 public:
46 TestPlatformEventSource() {
47 #if defined(USE_X11)
48 ui::DeviceDataManagerX11::CreateInstance();
49 #endif
50 }
51 ~TestPlatformEventSource() override {}
52
53 uint32_t Dispatch(const ui::PlatformEvent& event) {
54 return DispatchEvent(event);
55 }
56
57 private:
58 DISALLOW_COPY_AND_ASSIGN(TestPlatformEventSource);
59 };
60
61 class TestDispatcherClient : public aura::client::DispatcherClient {
62 public:
63 TestDispatcherClient() : dispatcher_(nullptr) {}
64 ~TestDispatcherClient() override {}
65
66 base::MessagePumpDispatcher* dispatcher() {
67 return dispatcher_;
68 }
69
70 // aura::client::DispatcherClient:
71 void PrepareNestedLoopClosures(base::MessagePumpDispatcher* dispatcher,
72 base::Closure* run_closure,
73 base::Closure* quit_closure) override {
74 scoped_ptr<base::RunLoop> run_loop(new base::RunLoop());
75 *quit_closure = run_loop->QuitClosure();
76 *run_closure = base::Bind(&TestDispatcherClient::RunNestedDispatcher,
77 base::Unretained(this),
78 base::Passed(&run_loop),
79 dispatcher);
80 }
81
82 private:
83 void RunNestedDispatcher(scoped_ptr<base::RunLoop> run_loop,
84 base::MessagePumpDispatcher* dispatcher) {
85 base::AutoReset<base::MessagePumpDispatcher*> reset_dispatcher(&dispatcher_,
86 dispatcher);
87 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
88 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
89 run_loop->Run();
90 }
91
92 base::MessagePumpDispatcher* dispatcher_;
93
94 DISALLOW_COPY_AND_ASSIGN(TestDispatcherClient);
95 };
96
97 } // namespace
98
99 class MenuControllerTest : public ViewsTestBase {
100 public:
101 MenuControllerTest() : controller_(nullptr) {}
102 ~MenuControllerTest() override { ResetMenuController(); }
103
104 // Dispatches |count| number of items, each in a separate iteration of the
105 // message-loop, by posting a task.
106 void Step3_DispatchEvents(int count) {
107 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
108 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
109 controller_->exit_type_ = MenuController::EXIT_ALL;
110
111 DispatchEvent();
112 if (count) {
113 base::MessageLoop::current()->PostTask(
114 FROM_HERE,
115 base::Bind(&MenuControllerTest::Step3_DispatchEvents,
116 base::Unretained(this),
117 count - 1));
118 } else {
119 EXPECT_TRUE(run_loop_->running());
120 run_loop_->Quit();
121 }
122 }
123
124 // Runs a nested message-loop that does not involve the menu itself.
125 void Step2_RunNestedLoop() {
126 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
127 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
128 base::MessageLoop::current()->PostTask(
129 FROM_HERE,
130 base::Bind(&MenuControllerTest::Step3_DispatchEvents,
131 base::Unretained(this),
132 3));
133 run_loop_.reset(new base::RunLoop());
134 run_loop_->Run();
135 }
136
137 void Step1_RunMenu() {
138 base::MessageLoop::current()->PostTask(
139 FROM_HERE,
140 base::Bind(&MenuControllerTest::Step2_RunNestedLoop,
141 base::Unretained(this)));
142 scoped_ptr<Widget> owner(CreateOwnerWidget());
143 RunMenu(owner.get());
144 }
145
146 scoped_ptr<Widget> CreateOwnerWidget() {
147 scoped_ptr<Widget> widget(new Widget);
148 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
149 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
150 widget->Init(params);
151 widget->Show();
152
153 aura::client::SetDispatcherClient(
154 widget->GetNativeWindow()->GetRootWindow(), &dispatcher_client_);
155 return widget.Pass();
156 }
157
158 const MenuItemView* pending_state_item() const {
159 return controller_->pending_state_.item;
160 }
161
162 void SetPendingStateItem(MenuItemView* item) {
163 controller_->pending_state_.item = item;
164 }
165
166 void ResetSelection() {
167 controller_->SetSelection(nullptr,
168 MenuController::SELECTION_EXIT |
169 MenuController::SELECTION_UPDATE_IMMEDIATELY);
170 }
171
172 void IncrementSelection(int delta) {
173 controller_->IncrementSelection(delta);
174 }
175
176 MenuItemView* FindFirstSelectableMenuItem(MenuItemView* parent) {
177 return controller_->FindFirstSelectableMenuItem(parent);
178 }
179
180 MenuItemView* FindNextSelectableMenuItem(MenuItemView* parent,
181 int index,
182 int delta) {
183 return controller_->FindNextSelectableMenuItem(parent, index, delta);
184 }
185 void SetupMenu(views::Widget* owner, views::MenuItemView* item) {
186 ResetMenuController();
187 controller_ = new MenuController(nullptr, true, nullptr);
188 controller_->owner_ = owner;
189 controller_->showing_ = true;
190 controller_->SetSelection(item,
191 MenuController::SELECTION_UPDATE_IMMEDIATELY);
192 }
193
194 void RunMenu(views::Widget* owner) {
195 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView);
196 SetupMenu(owner, menu_item.get());
197 controller_->RunMessageLoop(false);
198 }
199
200 #if defined(USE_X11)
201 void DispatchEscapeAndExpect(MenuController::ExitType exit_type) {
202 ui::ScopedXI2Event key_event;
203 key_event.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, 0);
204 event_source_.Dispatch(key_event);
205 EXPECT_EQ(exit_type, controller_->exit_type());
206 controller_->exit_type_ = MenuController::EXIT_ALL;
207 DispatchEvent();
208 }
209
210 void DispatchTouch(int evtype, int id) {
211 ui::ScopedXI2Event touch_event;
212 std::vector<ui::Valuator> valuators;
213 touch_event.InitTouchEvent(1, evtype, id, gfx::Point(10, 10), valuators);
214 event_source_.Dispatch(touch_event);
215 DispatchEvent();
216 }
217 #endif
218
219 void DispatchEvent() {
220 #if defined(USE_X11)
221 XEvent xevent;
222 memset(&xevent, 0, sizeof(xevent));
223 event_source_.Dispatch(&xevent);
224 #elif defined(OS_WIN)
225 MSG msg;
226 memset(&msg, 0, sizeof(MSG));
227 dispatcher_client_.dispatcher()->Dispatch(msg);
228 #elif defined(USE_OZONE)
229 ui::KeyEvent event(' ', ui::VKEY_SPACE, ui::EF_NONE);
230 event_source_.Dispatch(&event);
231 #else
232 #error Unsupported platform
233 #endif
234 }
235
236 private:
237 void ResetMenuController() {
238 if (controller_) {
239 // These properties are faked by RunMenu for the purposes of testing and
240 // need to be undone before we call the destructor.
241 controller_->owner_ = nullptr;
242 controller_->showing_ = false;
243 delete controller_;
244 controller_ = nullptr;
245 }
246 }
247
248 // A weak pointer to the MenuController owned by this class.
249 MenuController* controller_;
250 scoped_ptr<base::RunLoop> run_loop_;
251 TestPlatformEventSource event_source_;
252 TestDispatcherClient dispatcher_client_;
253
254 DISALLOW_COPY_AND_ASSIGN(MenuControllerTest);
255 };
256
257 TEST_F(MenuControllerTest, Basic) {
258 base::MessageLoop::ScopedNestableTaskAllower allow_nested(
259 base::MessageLoop::current());
260 message_loop()->PostTask(
261 FROM_HERE,
262 base::Bind(&MenuControllerTest::Step1_RunMenu, base::Unretained(this)));
263 }
264
265 #if defined(OS_LINUX) && defined(USE_X11)
266 // Tests that an event targeter which blocks events will be honored by the menu
267 // event dispatcher.
268 TEST_F(MenuControllerTest, EventTargeter) {
269 {
270 // Verify that the menu handles the escape key under normal circumstances.
271 scoped_ptr<Widget> owner(CreateOwnerWidget());
272 message_loop()->PostTask(
273 FROM_HERE,
274 base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
275 base::Unretained(this),
276 MenuController::EXIT_OUTERMOST));
277 RunMenu(owner.get());
278 }
279
280 {
281 // With the NULL targeter instantiated and assigned we expect the menu to
282 // not handle the key event.
283 scoped_ptr<Widget> owner(CreateOwnerWidget());
284 aura::ScopedWindowTargeter scoped_targeter(
285 owner->GetNativeWindow()->GetRootWindow(),
286 scoped_ptr<ui::EventTargeter>(new ui::NullEventTargeter));
287 message_loop()->PostTask(
288 FROM_HERE,
289 base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
290 base::Unretained(this),
291 MenuController::EXIT_NONE));
292 RunMenu(owner.get());
293 }
294 }
295 #endif
296
297 #if defined(USE_X11)
298
299 class TestEventHandler : public ui::EventHandler { 38 class TestEventHandler : public ui::EventHandler {
300 public: 39 public:
301 TestEventHandler() : outstanding_touches_(0) {} 40 TestEventHandler() : outstanding_touches_(0) {}
302 41
303 void OnTouchEvent(ui::TouchEvent* event) override { 42 void OnTouchEvent(ui::TouchEvent* event) override {
304 switch(event->type()) { 43 switch(event->type()) {
305 case ui::ET_TOUCH_PRESSED: 44 case ui::ET_TOUCH_PRESSED:
306 outstanding_touches_++; 45 outstanding_touches_++;
307 break; 46 break;
308 case ui::ET_TOUCH_RELEASED: 47 case ui::ET_TOUCH_RELEASED:
309 case ui::ET_TOUCH_CANCELLED: 48 case ui::ET_TOUCH_CANCELLED:
310 outstanding_touches_--; 49 outstanding_touches_--;
311 break; 50 break;
312 default: 51 default:
313 break; 52 break;
314 } 53 }
315 } 54 }
316 55
317 int outstanding_touches() const { return outstanding_touches_; } 56 int outstanding_touches() const { return outstanding_touches_; }
318 57
319 private: 58 private:
320 int outstanding_touches_; 59 int outstanding_touches_;
321 }; 60 };
322 61
62 } // namespace
63
64 // This a deleter to enable us to use a scoped_ptr of a MenuController, since
65 // otherwise MenuController's destructor is private and cannot be called by the
66 // scoped_ptr's DefaulDeleter.
67 class MenuControllerTestDeleter {
68 public:
69 void operator()(MenuController* ptr) const {
70 DCHECK(ptr);
71 // Must clear the following value before deleting the MenuController, or
72 // otherwise the destructor will crash on a DCHECK();
73 ptr->showing_ = false;
74 delete ptr;
75 }
76 };
77
78 class MenuControllerTest : public ViewsTestBase {
79 public:
80 MenuControllerTest() : menu_controller_(nullptr, contoller_deleter_) {
81 }
82
83 ~MenuControllerTest() override {}
84
85 void SetUp() override {
86 ViewsTestBase::SetUp();
87 Init();
88 }
89
90 void ReleaseTouchId(int id) {
91 event_generator_->ReleaseTouchId(id);
92 }
93
94 void PressKey(ui::KeyboardCode key_code) {
95 event_generator_->PressKey(key_code, 0);
96 }
97
98 void TestEventTargeter() {
99 // With the |ui::NullEventTargeter| instantiated and assigned we expect the
100 // menu to not handle the key event.
101 scoped_ptr<aura::ScopedWindowTargeter> scoped_targeter(
102 new aura::ScopedWindowTargeter(
103 owner()->GetNativeWindow()->GetRootWindow(),
104 scoped_ptr<ui::EventTargeter>(new ui::NullEventTargeter)));
105 event_generator_->PressKey(ui::VKEY_ESCAPE, 0);
106 EXPECT_EQ(MenuController::EXIT_NONE, menu_exit_type());
107
108 // Now remove the targeter an expect to exit the menu normally.
109 scoped_targeter.reset();
110 event_generator_->PressKey(ui::VKEY_ESCAPE, 0);
111 EXPECT_EQ(MenuController::EXIT_OUTERMOST, menu_exit_type());
112 }
113
114 protected:
115 void SetPendingStateItem(MenuItemView* item) {
116 menu_controller_->pending_state_.item = item;
117 }
118
119 void ResetSelection() {
120 menu_controller_->SetSelection(
121 nullptr,
122 MenuController::SELECTION_EXIT |
123 MenuController::SELECTION_UPDATE_IMMEDIATELY);
124 }
125
126 void IncrementSelection(int delta) {
127 menu_controller_->IncrementSelection(delta);
128 }
129
130 MenuItemView* FindFirstSelectableMenuItem(MenuItemView* parent) {
131 return menu_controller_->FindFirstSelectableMenuItem(parent);
132 }
133
134 MenuItemView* FindNextSelectableMenuItem(MenuItemView* parent,
135 int index,
136 int delta) {
137
138 return menu_controller_->FindNextSelectableMenuItem(parent, index, delta);
139 }
140
141 void RunMenu() {
142 menu_controller_->RunMessageLoop(false);
143 }
144
145 Widget* owner() { return owner_.get(); }
146 ui::test::EventGenerator* event_generator() { return event_generator_.get(); }
147 TestMenuItemView* menu_item() { return menu_item_.get(); }
148 MenuController* menu_controller() { return menu_controller_.get(); }
149 const MenuItemView* pending_state_item() const {
150 return menu_controller_->pending_state_.item;
151 }
152 const MenuController::ExitType menu_exit_type() const {
153 return menu_controller_->exit_type_;
154 }
155
156 private:
157 void Init() {
158 owner_.reset(new Widget);
159 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
160 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
161 owner_->Init(params);
162 event_generator_.reset(new ui::test::EventGenerator(
163 owner_->GetNativeWindow()->GetRootWindow(), owner_->GetNativeWindow()));
164 owner_->Show();
165
166 SetupMenuItem();
167
168 SetupMenuController();
169 }
170
171 void SetupMenuItem() {
172 menu_item_.reset(new TestMenuItemView);
173 menu_item_->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One"));
174 menu_item_->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two"));
175 menu_item_->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three"));
176 menu_item_->AppendMenuItemWithLabel(4, base::ASCIIToUTF16("Four"));
177 }
178
179 void SetupMenuController() {
180 menu_controller_.reset(new MenuController(nullptr, true, nullptr));
181 menu_controller_->owner_ = owner_.get();
182 menu_controller_->showing_ = true;
183 menu_controller_->SetSelection(
184 menu_item_.get(), MenuController::SELECTION_UPDATE_IMMEDIATELY);
185 }
186
187 scoped_ptr<Widget> owner_;
188 scoped_ptr<ui::test::EventGenerator> event_generator_;
189 scoped_ptr<TestMenuItemView> menu_item_;
190 MenuControllerTestDeleter contoller_deleter_;
191 scoped_ptr<MenuController, MenuControllerTestDeleter> menu_controller_;
192
193 DISALLOW_COPY_AND_ASSIGN(MenuControllerTest);
194 };
195
196 // Tests that an event targeter which blocks events will be honored by the menu
197 // event dispatcher.
198 TEST_F(MenuControllerTest, EventTargeter) {
199 base::MessageLoopForUI::current()->PostTask(
200 FROM_HERE,
201 base::Bind(&MenuControllerTest::TestEventTargeter,
202 base::Unretained(this)));
203 RunMenu();
204 }
205
206 #if defined(USE_X11)
207
323 // Tests that touch event ids are released correctly. See 208 // Tests that touch event ids are released correctly. See
324 // crbug.com/439051 for details. When the ids aren't managed 209 // crbug.com/439051 for details. When the ids aren't managed
325 // correctly, we get stuck down touches. 210 // correctly, we get stuck down touches.
326 TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) { 211 TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) {
327 scoped_ptr<Widget> owner(CreateOwnerWidget());
328 TestEventHandler test_event_handler; 212 TestEventHandler test_event_handler;
329 owner->GetNativeWindow()->GetRootWindow()->AddPreTargetHandler( 213 owner()->GetNativeWindow()->GetRootWindow()->AddPreTargetHandler(
330 &test_event_handler); 214 &test_event_handler);
331 215
332 std::vector<int> devices; 216 std::vector<int> devices;
333 devices.push_back(1); 217 devices.push_back(1);
334 ui::SetUpTouchDevicesForTest(devices); 218 ui::SetUpTouchDevicesForTest(devices);
335 219
336 DispatchTouch(XI_TouchBegin, 0); 220 event_generator()->PressTouchId(0);
337 DispatchTouch(XI_TouchBegin, 1); 221 event_generator()->PressTouchId(1);
338 DispatchTouch(XI_TouchEnd, 0); 222 event_generator()->ReleaseTouchId(0);
339 223
340 message_loop()->PostTask(FROM_HERE, 224 base::MessageLoopForUI::current()->PostTask(
341 base::Bind(&MenuControllerTest::DispatchTouch,
342 base::Unretained(this), XI_TouchEnd, 1));
343
344 message_loop()->PostTask(
345 FROM_HERE, 225 FROM_HERE,
346 base::Bind(&MenuControllerTest::DispatchEscapeAndExpect, 226 base::Bind(&MenuControllerTest::ReleaseTouchId,
347 base::Unretained(this), MenuController::EXIT_OUTERMOST)); 227 base::Unretained(this),
348 228 1));
349 RunMenu(owner.get()); 229
230 base::MessageLoopForUI::current()->PostTask(
231 FROM_HERE,
232 base::Bind(&MenuControllerTest::PressKey,
233 base::Unretained(this),
234 ui::VKEY_ESCAPE));
235
236 RunMenu();
237
238 EXPECT_EQ(MenuController::EXIT_OUTERMOST, menu_exit_type());
350 EXPECT_EQ(0, test_event_handler.outstanding_touches()); 239 EXPECT_EQ(0, test_event_handler.outstanding_touches());
351 240
352 owner->GetNativeWindow()->GetRootWindow()->RemovePreTargetHandler( 241 owner()->GetNativeWindow()->GetRootWindow()->RemovePreTargetHandler(
353 &test_event_handler); 242 &test_event_handler);
354 } 243 }
355 #endif // defined(USE_X11) 244
245 #endif // defined(USE_X11)
356 246
357 TEST_F(MenuControllerTest, FirstSelectedItem) { 247 TEST_F(MenuControllerTest, FirstSelectedItem) {
358 scoped_ptr<Widget> owner(CreateOwnerWidget()); 248 // disabling all items but "Two".
359 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView); 249 menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false);
360 menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One")); 250 menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
361 menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two")); 251 menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
362 // Disabling the item "One" gets it skipped when a menu is first opened. 252
363 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false); 253 // "Two" should be the first selectable item.
364 254 MenuItemView* first_selectable = FindFirstSelectableMenuItem(menu_item());
365 SetupMenu(owner.get(), menu_item.get());
366
367 // First selectable item should be item "Two".
368 MenuItemView* first_selectable = FindFirstSelectableMenuItem(menu_item.get());
369 EXPECT_EQ(2, first_selectable->GetCommand()); 255 EXPECT_EQ(2, first_selectable->GetCommand());
370 256
371 // There should be no next or previous selectable item since there is only a 257 // There should be no next or previous selectable item since there is only a
372 // single enabled item in the menu. 258 // single enabled item in the menu.
373 SetPendingStateItem(first_selectable); 259 SetPendingStateItem(first_selectable);
374 EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item.get(), 1, 1)); 260 EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item(), 1, 1));
375 EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item.get(), 1, -1)); 261 EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item(), 1, -1));
376 262
377 // Clear references in menu controller to the menu item that is going away. 263 // Clear references in menu controller to the menu item that is going away.
378 ResetSelection(); 264 ResetSelection();
379 } 265 }
380 266
381 TEST_F(MenuControllerTest, NextSelectedItem) { 267 TEST_F(MenuControllerTest, NextSelectedItem) {
382 scoped_ptr<Widget> owner(CreateOwnerWidget());
383 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView);
384 menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One"));
385 menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two"));
386 menu_item->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three"));
387 menu_item->AppendMenuItemWithLabel(4, base::ASCIIToUTF16("Four"));
388 // Disabling the item "Three" gets it skipped when using keyboard to navigate. 268 // Disabling the item "Three" gets it skipped when using keyboard to navigate.
389 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); 269 menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
390
391 SetupMenu(owner.get(), menu_item.get());
392 270
393 // Fake initial hot selection. 271 // Fake initial hot selection.
394 SetPendingStateItem(menu_item->GetSubmenu()->GetMenuItemAt(0)); 272 SetPendingStateItem(menu_item()->GetSubmenu()->GetMenuItemAt(0));
395 EXPECT_EQ(1, pending_state_item()->GetCommand()); 273 EXPECT_EQ(1, pending_state_item()->GetCommand());
396 274
397 // Move down in the menu. 275 // Move down in the menu.
398 // Select next item. 276 // Select next item.
399 IncrementSelection(1); 277 IncrementSelection(1);
400 EXPECT_EQ(2, pending_state_item()->GetCommand()); 278 EXPECT_EQ(2, pending_state_item()->GetCommand());
401 279
402 // Skip disabled item. 280 // Skip disabled item.
403 IncrementSelection(1); 281 IncrementSelection(1);
404 EXPECT_EQ(4, pending_state_item()->GetCommand()); 282 EXPECT_EQ(4, pending_state_item()->GetCommand());
(...skipping 13 matching lines...) Expand all
418 296
419 // Select previous item. 297 // Select previous item.
420 IncrementSelection(-1); 298 IncrementSelection(-1);
421 EXPECT_EQ(1, pending_state_item()->GetCommand()); 299 EXPECT_EQ(1, pending_state_item()->GetCommand());
422 300
423 // Clear references in menu controller to the menu item that is going away. 301 // Clear references in menu controller to the menu item that is going away.
424 ResetSelection(); 302 ResetSelection();
425 } 303 }
426 304
427 } // namespace views 305 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698