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

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

Issue 286933007: Reland "Only dispatch menu events if they have a valid target. (https://codereview.chromium.org/284… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merge Created 6 years, 7 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 | Annotate | Revision Log
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" 7 #include "base/run_loop.h"
8 #include "ui/aura/scoped_window_targeter.h"
8 #include "ui/aura/window.h" 9 #include "ui/aura/window.h"
10 #include "ui/events/event_targeter.h"
9 #include "ui/events/platform/platform_event_source.h" 11 #include "ui/events/platform/platform_event_source.h"
12 #include "ui/views/controls/menu/menu_item_view.h"
10 #include "ui/views/test/views_test_base.h" 13 #include "ui/views/test/views_test_base.h"
11 #include "ui/wm/public/dispatcher_client.h" 14 #include "ui/wm/public/dispatcher_client.h"
12 15
13 #if defined(OS_WIN) 16 #if defined(OS_WIN)
14 #include "base/message_loop/message_pump_dispatcher.h" 17 #include "base/message_loop/message_pump_dispatcher.h"
15 #elif defined(USE_X11) 18 #elif defined(USE_X11)
16 #include <X11/Xlib.h> 19 #include <X11/Xlib.h>
17 #undef Bool 20 #undef Bool
18 #undef None 21 #undef None
22 #include "ui/events/test/events_test_utils_x11.h"
19 #elif defined(USE_OZONE) 23 #elif defined(USE_OZONE)
20 #include "ui/events/event.h" 24 #include "ui/events/event.h"
21 #endif 25 #endif
22 26
23 namespace views { 27 namespace views {
24 28
25 namespace { 29 namespace {
26 30
31 class TestMenuItemView : public MenuItemView {
32 public:
33 TestMenuItemView() : MenuItemView(NULL) {}
34 virtual ~TestMenuItemView() {}
35
36 private:
37 DISALLOW_COPY_AND_ASSIGN(TestMenuItemView);
38 };
39
27 class TestPlatformEventSource : public ui::PlatformEventSource { 40 class TestPlatformEventSource : public ui::PlatformEventSource {
28 public: 41 public:
29 TestPlatformEventSource() {} 42 TestPlatformEventSource() {}
30 virtual ~TestPlatformEventSource() {} 43 virtual ~TestPlatformEventSource() {}
31 44
32 uint32_t Dispatch(const ui::PlatformEvent& event) { 45 uint32_t Dispatch(const ui::PlatformEvent& event) {
33 return DispatchEvent(event); 46 return DispatchEvent(event);
34 } 47 }
35 48
36 private: 49 private:
37 DISALLOW_COPY_AND_ASSIGN(TestPlatformEventSource); 50 DISALLOW_COPY_AND_ASSIGN(TestPlatformEventSource);
38 }; 51 };
39 52
53 class TestNullTargeter : public ui::EventTargeter {
54 public:
55 TestNullTargeter() {}
56 virtual ~TestNullTargeter() {}
57
58 virtual ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
59 ui::Event* event) OVERRIDE {
60 return NULL;
61 }
62
63 private:
64 DISALLOW_COPY_AND_ASSIGN(TestNullTargeter);
65 };
66
40 class TestDispatcherClient : public aura::client::DispatcherClient { 67 class TestDispatcherClient : public aura::client::DispatcherClient {
41 public: 68 public:
42 TestDispatcherClient() : dispatcher_(NULL) {} 69 TestDispatcherClient() : dispatcher_(NULL) {}
43 virtual ~TestDispatcherClient() {} 70 virtual ~TestDispatcherClient() {}
44 71
45 base::MessagePumpDispatcher* dispatcher() { 72 base::MessagePumpDispatcher* dispatcher() {
46 return dispatcher_; 73 return dispatcher_;
47 } 74 }
48 75
49 // aura::client::DispatcherClient: 76 // aura::client::DispatcherClient:
(...skipping 15 matching lines...) Expand all
65 base::Closure quit_callback_; 92 base::Closure quit_callback_;
66 93
67 DISALLOW_COPY_AND_ASSIGN(TestDispatcherClient); 94 DISALLOW_COPY_AND_ASSIGN(TestDispatcherClient);
68 }; 95 };
69 96
70 } // namespace 97 } // namespace
71 98
72 class MenuControllerTest : public ViewsTestBase { 99 class MenuControllerTest : public ViewsTestBase {
73 public: 100 public:
74 MenuControllerTest() : controller_(NULL) {} 101 MenuControllerTest() : controller_(NULL) {}
75 virtual ~MenuControllerTest() {} 102 virtual ~MenuControllerTest() {
103 ResetMenuController();
104 }
76 105
77 // Dispatches |count| number of items, each in a separate iteration of the 106 // Dispatches |count| number of items, each in a separate iteration of the
78 // message-loop, by posting a task. 107 // message-loop, by posting a task.
79 void Step3_DispatchEvents(int count) { 108 void Step3_DispatchEvents(int count) {
80 base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); 109 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
81 base::MessageLoop::ScopedNestableTaskAllower allow(loop); 110 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
82 controller_->exit_type_ = MenuController::EXIT_ALL; 111 controller_->exit_type_ = MenuController::EXIT_ALL;
83 112
84 #if defined(USE_X11) 113 DispatchEvent();
85 XEvent xevent;
86 memset(&xevent, 0, sizeof(xevent));
87 event_source_.Dispatch(&xevent);
88 #elif defined(OS_WIN)
89 MSG msg;
90 memset(&msg, 0, sizeof(MSG));
91 dispatcher_client_.dispatcher()->Dispatch(msg);
92 #elif defined(USE_OZONE)
93 ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, 0, true);
94 dispatcher_client_.dispatcher()->Dispatch(&event);
95 #else
96 #error Unsupported platform
97 #endif
98
99 if (count) { 114 if (count) {
100 base::MessageLoop::current()->PostTask( 115 base::MessageLoop::current()->PostTask(
101 FROM_HERE, 116 FROM_HERE,
102 base::Bind(&MenuControllerTest::Step3_DispatchEvents, 117 base::Bind(&MenuControllerTest::Step3_DispatchEvents,
103 base::Unretained(this), 118 base::Unretained(this),
104 count - 1)); 119 count - 1));
105 } else { 120 } else {
106 EXPECT_TRUE(run_loop_->running()); 121 EXPECT_TRUE(run_loop_->running());
107 run_loop_->Quit(); 122 run_loop_->Quit();
108 } 123 }
109 } 124 }
110 125
111 // Runs a nested message-loop that does not involve the menu itself. 126 // Runs a nested message-loop that does not involve the menu itself.
112 void Step2_RunNestedLoop() { 127 void Step2_RunNestedLoop() {
113 base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); 128 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
114 base::MessageLoop::ScopedNestableTaskAllower allow(loop); 129 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
115 base::MessageLoop::current()->PostTask( 130 base::MessageLoop::current()->PostTask(
116 FROM_HERE, 131 FROM_HERE,
117 base::Bind(&MenuControllerTest::Step3_DispatchEvents, 132 base::Bind(&MenuControllerTest::Step3_DispatchEvents,
118 base::Unretained(this), 133 base::Unretained(this),
119 3)); 134 3));
120 run_loop_.reset(new base::RunLoop()); 135 run_loop_.reset(new base::RunLoop());
121 run_loop_->Run(); 136 run_loop_->Run();
122 } 137 }
123 138
124 void Step1_RunMenu() { 139 void Step1_RunMenu() {
125 Widget widget;
126 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
127 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
128 widget.Init(params);
129 widget.Show();
130
131 aura::client::SetDispatcherClient(widget.GetNativeWindow()->GetRootWindow(),
132 &dispatcher_client_);
133
134 controller_ = new MenuController(NULL, true, NULL);
135 controller_->owner_ = &widget;
136 base::MessageLoop::current()->PostTask( 140 base::MessageLoop::current()->PostTask(
137 FROM_HERE, 141 FROM_HERE,
138 base::Bind(&MenuControllerTest::Step2_RunNestedLoop, 142 base::Bind(&MenuControllerTest::Step2_RunNestedLoop,
139 base::Unretained(this))); 143 base::Unretained(this)));
144 scoped_ptr<Widget> owner(CreateOwnerWidget());
145 RunMenu(owner.get());
146 }
147
148 scoped_ptr<Widget> CreateOwnerWidget() {
149 scoped_ptr<Widget> widget(new Widget);
150 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
151 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
152 widget->Init(params);
153 widget->Show();
154
155 aura::client::SetDispatcherClient(
156 widget->GetNativeWindow()->GetRootWindow(), &dispatcher_client_);
157 return widget.Pass();
158 }
159
160 void RunMenu(views::Widget* owner) {
161 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView);
162 ResetMenuController();
163 controller_ = new MenuController(NULL, true, NULL);
164 controller_->owner_ = owner;
165 controller_->showing_ = true;
166 controller_->SetSelection(menu_item.get(),
167 MenuController::SELECTION_UPDATE_IMMEDIATELY);
140 controller_->RunMessageLoop(false); 168 controller_->RunMessageLoop(false);
141 } 169 }
142 170
171 #if defined(USE_X11)
172 void DispatchEscapeAndExpect(MenuController::ExitType exit_type) {
173 ui::ScopedXI2Event key_event;
174 key_event.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, 0);
175 event_source_.Dispatch(key_event);
176 EXPECT_EQ(exit_type, controller_->exit_type());
177 controller_->exit_type_ = MenuController::EXIT_ALL;
178 DispatchEvent();
179 }
180 #endif
181
182 void DispatchEvent() {
183 #if defined(USE_X11)
184 XEvent xevent;
185 memset(&xevent, 0, sizeof(xevent));
186 event_source_.Dispatch(&xevent);
187 #elif defined(OS_WIN)
188 MSG msg;
189 memset(&msg, 0, sizeof(MSG));
190 dispatcher_client_.dispatcher()->Dispatch(msg);
191 #elif defined(USE_OZONE)
192 ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, 0, true);
193 dispatcher_client_.dispatcher()->Dispatch(&event);
194 #else
195 #error Unsupported platform
196 #endif
197 }
198
143 private: 199 private:
200 void ResetMenuController() {
201 if (controller_) {
202 // These properties are faked by RunMenu for the purposes of testing and
203 // need to be undone before we call the destructor.
204 controller_->owner_ = NULL;
205 controller_->showing_ = false;
206 delete controller_;
207 controller_ = NULL;
208 }
209 }
210
211 // A weak pointer to the MenuController owned by this class.
144 MenuController* controller_; 212 MenuController* controller_;
145 scoped_ptr<base::RunLoop> run_loop_; 213 scoped_ptr<base::RunLoop> run_loop_;
146 TestPlatformEventSource event_source_; 214 TestPlatformEventSource event_source_;
147 TestDispatcherClient dispatcher_client_; 215 TestDispatcherClient dispatcher_client_;
148 216
149 DISALLOW_COPY_AND_ASSIGN(MenuControllerTest); 217 DISALLOW_COPY_AND_ASSIGN(MenuControllerTest);
150 }; 218 };
151 219
152 TEST_F(MenuControllerTest, Basic) { 220 TEST_F(MenuControllerTest, Basic) {
153 base::MessageLoop::ScopedNestableTaskAllower allow_nested( 221 base::MessageLoop::ScopedNestableTaskAllower allow_nested(
154 base::MessageLoop::current()); 222 base::MessageLoop::current());
155 message_loop()->PostTask( 223 message_loop()->PostTask(
156 FROM_HERE, 224 FROM_HERE,
157 base::Bind(&MenuControllerTest::Step1_RunMenu, base::Unretained(this))); 225 base::Bind(&MenuControllerTest::Step1_RunMenu, base::Unretained(this)));
158 } 226 }
159 227
228 #if defined(OS_LINUX) && defined(USE_X11)
229 // Tests that an event targeter which blocks events will be honored by the menu
230 // event dispatcher.
231 TEST_F(MenuControllerTest, EventTargeter) {
232 {
233 // Verify that the menu handles the escape key under normal circumstances.
234 scoped_ptr<Widget> owner(CreateOwnerWidget());
235 message_loop()->PostTask(
236 FROM_HERE,
237 base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
238 base::Unretained(this),
239 MenuController::EXIT_OUTERMOST));
240 RunMenu(owner.get());
241 }
242
243 {
244 // With the NULL targeter instantiated and assigned we expect the menu to
245 // not handle the key event.
246 scoped_ptr<Widget> owner(CreateOwnerWidget());
247 aura::ScopedWindowTargeter scoped_targeter(
248 owner->GetNativeWindow()->GetRootWindow(),
249 scoped_ptr<ui::EventTargeter>(new TestNullTargeter));
250 message_loop()->PostTask(
251 FROM_HERE,
252 base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
253 base::Unretained(this),
254 MenuController::EXIT_NONE));
255 RunMenu(owner.get());
256 }
257 }
258 #endif
259
160 } // namespace views 260 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/menu/menu_controller.h ('k') | ui/views/controls/menu/menu_event_dispatcher_linux.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698