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

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: Reset menu controller between tests and on subsequent calls to RunMenu. 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 #endif 23 #endif
20 24
21 namespace views { 25 namespace views {
22 26
23 namespace { 27 namespace {
24 28
29 class TestMenuItemView : public MenuItemView {
30 public:
31 TestMenuItemView() : MenuItemView(NULL) {}
32 virtual ~TestMenuItemView() {}
33
34 private:
35 DISALLOW_COPY_AND_ASSIGN(TestMenuItemView);
36 };
37
25 class TestPlatformEventSource : public ui::PlatformEventSource { 38 class TestPlatformEventSource : public ui::PlatformEventSource {
26 public: 39 public:
27 TestPlatformEventSource() {} 40 TestPlatformEventSource() {}
28 virtual ~TestPlatformEventSource() {} 41 virtual ~TestPlatformEventSource() {}
29 42
30 uint32_t Dispatch(const ui::PlatformEvent& event) { 43 uint32_t Dispatch(const ui::PlatformEvent& event) {
31 return DispatchEvent(event); 44 return DispatchEvent(event);
32 } 45 }
33 46
34 private: 47 private:
35 DISALLOW_COPY_AND_ASSIGN(TestPlatformEventSource); 48 DISALLOW_COPY_AND_ASSIGN(TestPlatformEventSource);
36 }; 49 };
37 50
51 class TestNullTargeter : public ui::EventTargeter {
52 public:
53 TestNullTargeter() {}
54 virtual ~TestNullTargeter() {}
55
56 virtual ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
57 ui::Event* event) OVERRIDE {
58 return NULL;
59 }
60
61 private:
62 DISALLOW_COPY_AND_ASSIGN(TestNullTargeter);
63 };
64
38 class TestDispatcherClient : public aura::client::DispatcherClient { 65 class TestDispatcherClient : public aura::client::DispatcherClient {
39 public: 66 public:
40 TestDispatcherClient() : dispatcher_(NULL) {} 67 TestDispatcherClient() : dispatcher_(NULL) {}
41 virtual ~TestDispatcherClient() {} 68 virtual ~TestDispatcherClient() {}
42 69
43 base::MessagePumpDispatcher* dispatcher() { 70 base::MessagePumpDispatcher* dispatcher() {
44 return dispatcher_; 71 return dispatcher_;
45 } 72 }
46 73
47 // aura::client::DispatcherClient: 74 // aura::client::DispatcherClient:
(...skipping 15 matching lines...) Expand all
63 base::Closure quit_callback_; 90 base::Closure quit_callback_;
64 91
65 DISALLOW_COPY_AND_ASSIGN(TestDispatcherClient); 92 DISALLOW_COPY_AND_ASSIGN(TestDispatcherClient);
66 }; 93 };
67 94
68 } // namespace 95 } // namespace
69 96
70 class MenuControllerTest : public ViewsTestBase { 97 class MenuControllerTest : public ViewsTestBase {
71 public: 98 public:
72 MenuControllerTest() : controller_(NULL) {} 99 MenuControllerTest() : controller_(NULL) {}
73 virtual ~MenuControllerTest() {} 100 virtual ~MenuControllerTest() {
101 ResetMenuController();
102 }
74 103
75 // Dispatches |count| number of items, each in a separate iteration of the 104 // Dispatches |count| number of items, each in a separate iteration of the
76 // message-loop, by posting a task. 105 // message-loop, by posting a task.
77 void Step3_DispatchEvents(int count) { 106 void Step3_DispatchEvents(int count) {
78 base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); 107 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
79 base::MessageLoop::ScopedNestableTaskAllower allow(loop); 108 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
80 controller_->exit_type_ = MenuController::EXIT_ALL; 109 controller_->exit_type_ = MenuController::EXIT_ALL;
81 110
82 #if defined(USE_X11) 111 DispatchEvent();
83 XEvent xevent;
84 memset(&xevent, 0, sizeof(xevent));
85 event_source_.Dispatch(&xevent);
86 #else
87 MSG msg;
88 memset(&msg, 0, sizeof(MSG));
89 dispatcher_client_.dispatcher()->Dispatch(msg);
90 #endif
91
92 if (count) { 112 if (count) {
93 base::MessageLoop::current()->PostTask( 113 base::MessageLoop::current()->PostTask(
94 FROM_HERE, 114 FROM_HERE,
95 base::Bind(&MenuControllerTest::Step3_DispatchEvents, 115 base::Bind(&MenuControllerTest::Step3_DispatchEvents,
96 base::Unretained(this), 116 base::Unretained(this),
97 count - 1)); 117 count - 1));
98 } else { 118 } else {
99 EXPECT_TRUE(run_loop_->running()); 119 EXPECT_TRUE(run_loop_->running());
100 run_loop_->Quit(); 120 run_loop_->Quit();
101 } 121 }
102 } 122 }
103 123
104 // Runs a nested message-loop that does not involve the menu itself. 124 // Runs a nested message-loop that does not involve the menu itself.
105 void Step2_RunNestedLoop() { 125 void Step2_RunNestedLoop() {
106 base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); 126 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
107 base::MessageLoop::ScopedNestableTaskAllower allow(loop); 127 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
108 base::MessageLoop::current()->PostTask( 128 base::MessageLoop::current()->PostTask(
109 FROM_HERE, 129 FROM_HERE,
110 base::Bind(&MenuControllerTest::Step3_DispatchEvents, 130 base::Bind(&MenuControllerTest::Step3_DispatchEvents,
111 base::Unretained(this), 131 base::Unretained(this),
112 3)); 132 3));
113 run_loop_.reset(new base::RunLoop()); 133 run_loop_.reset(new base::RunLoop());
114 run_loop_->Run(); 134 run_loop_->Run();
115 } 135 }
116 136
117 void Step1_RunMenu() { 137 void Step1_RunMenu() {
118 Widget widget;
119 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
120 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
121 widget.Init(params);
122 widget.Show();
123
124 aura::client::SetDispatcherClient(widget.GetNativeWindow()->GetRootWindow(),
125 &dispatcher_client_);
126
127 controller_ = new MenuController(NULL, true, NULL);
128 controller_->owner_ = &widget;
129 base::MessageLoop::current()->PostTask( 138 base::MessageLoop::current()->PostTask(
130 FROM_HERE, 139 FROM_HERE,
131 base::Bind(&MenuControllerTest::Step2_RunNestedLoop, 140 base::Bind(&MenuControllerTest::Step2_RunNestedLoop,
132 base::Unretained(this))); 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 void RunMenu(views::Widget* owner) {
159 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView);
160 ResetMenuController();
161 controller_ = new MenuController(NULL, true, NULL);
162 controller_->owner_ = owner;
163 controller_->showing_ = true;
164 controller_->SetSelection(menu_item.get(),
165 MenuController::SELECTION_UPDATE_IMMEDIATELY);
133 controller_->RunMessageLoop(false); 166 controller_->RunMessageLoop(false);
134 } 167 }
135 168
169 #if defined(USE_X11)
170 void DispatchEscapeAndExpect(MenuController::ExitType exit_type) {
171 ui::ScopedXI2Event key_event;
172 key_event.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, 0);
173 event_source_.Dispatch(key_event);
174 EXPECT_EQ(exit_type, controller_->exit_type());
175 controller_->exit_type_ = MenuController::EXIT_ALL;
176 DispatchEvent();
177 }
178 #endif
179
180 void DispatchEvent() {
181 #if defined(USE_X11)
182 XEvent xevent;
183 memset(&xevent, 0, sizeof(xevent));
184 event_source_.Dispatch(&xevent);
185 #else
186 MSG msg;
187 memset(&msg, 0, sizeof(MSG));
188 dispatcher_client_.dispatcher()->Dispatch(msg);
189 #endif
190 }
191
136 private: 192 private:
193 void ResetMenuController() {
194 if (controller_) {
195 // These properties are faked by RunMenu for the purposes of testing and
196 // need to be undone before we call the destructor.
197 controller_->owner_ = NULL;
198 controller_->showing_ = false;
199 delete controller_;
200 controller_ = NULL;
201 }
202 }
203
204 // A weak pointer to the MenuController owned by this class.
137 MenuController* controller_; 205 MenuController* controller_;
sadrul 2014/05/20 19:55:45 Does it make sense to just have this as scoped_ptr
flackr 2014/05/20 20:33:41 It will fail to destruct unless we reset the owner
138 scoped_ptr<base::RunLoop> run_loop_; 206 scoped_ptr<base::RunLoop> run_loop_;
139 TestPlatformEventSource event_source_; 207 TestPlatformEventSource event_source_;
140 TestDispatcherClient dispatcher_client_; 208 TestDispatcherClient dispatcher_client_;
141 209
142 DISALLOW_COPY_AND_ASSIGN(MenuControllerTest); 210 DISALLOW_COPY_AND_ASSIGN(MenuControllerTest);
143 }; 211 };
144 212
145 TEST_F(MenuControllerTest, Basic) { 213 TEST_F(MenuControllerTest, Basic) {
146 base::MessageLoop::ScopedNestableTaskAllower allow_nested( 214 base::MessageLoop::ScopedNestableTaskAllower allow_nested(
147 base::MessageLoop::current()); 215 base::MessageLoop::current());
148 message_loop()->PostTask( 216 message_loop()->PostTask(
149 FROM_HERE, 217 FROM_HERE,
150 base::Bind(&MenuControllerTest::Step1_RunMenu, base::Unretained(this))); 218 base::Bind(&MenuControllerTest::Step1_RunMenu, base::Unretained(this)));
151 } 219 }
152 220
221 #if defined(OS_LINUX) && defined(USE_X11)
222 // Tests that an event targeter which blocks events will be honored by the menu
223 // event dispatcher.
224 TEST_F(MenuControllerTest, EventTargeter) {
225 {
226 // Verify that the menu handles the escape key under normal circumstances.
227 scoped_ptr<Widget> owner(CreateOwnerWidget());
228 message_loop()->PostTask(
229 FROM_HERE,
230 base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
231 base::Unretained(this),
232 MenuController::EXIT_OUTERMOST));
233 RunMenu(owner.get());
234 }
235
236 {
237 // With the NULL targeter instantiated and assigned we expect the menu to
238 // not handle the key event.
239 scoped_ptr<Widget> owner(CreateOwnerWidget());
240 aura::ScopedWindowTargeter scoped_targeter(
241 owner->GetNativeWindow()->GetRootWindow(),
242 scoped_ptr<ui::EventTargeter>(new TestNullTargeter));
243 message_loop()->PostTask(
244 FROM_HERE,
245 base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
246 base::Unretained(this),
247 MenuController::EXIT_NONE));
248 RunMenu(owner.get());
249 }
250 }
251 #endif
252
153 } // namespace views 253 } // 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