1 // Copyright 2013 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 "ui/views/test/widget_test.h"
6
7 #include "base/rand_util.h"
8 #include "base/test/bind.h"
9 #include "build/build_config.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 #include "ui/gfx/native_widget_types.h"
12 #include "ui/views/test/native_widget_factory.h"
13 #include "ui/views/widget/root_view.h"
14
15 namespace views {
16 namespace test {
17
18 namespace {
19
ShuffledChildren(View * view)20 View::Views ShuffledChildren(View* view) {
21 View::Views children(view->children());
22 base::RandomShuffle(children.begin(), children.end());
23 return children;
24 }
25
AnyViewMatchingPredicate(View * view,const ViewPredicate & predicate)26 View* AnyViewMatchingPredicate(View* view, const ViewPredicate& predicate) {
27 if (predicate.Run(view))
28 return view;
29 // Note that we randomize the order of the children, to avoid this function
30 // always choosing the same View to return out of a set of possible Views.
31 // If we didn't do this, client code could accidentally depend on a specific
32 // search order.
33 for (auto* child : ShuffledChildren(view)) {
34 auto* found = AnyViewMatchingPredicate(child, predicate);
35 if (found)
36 return found;
37 }
38 return nullptr;
39 }
40
41 } // namespace
42
AnyViewMatchingPredicate(Widget * widget,const ViewPredicate & predicate)43 View* AnyViewMatchingPredicate(Widget* widget, const ViewPredicate& predicate) {
44 return AnyViewMatchingPredicate(widget->GetRootView(), predicate);
45 }
46
AnyViewWithClassName(Widget * widget,const std::string & classname)47 View* AnyViewWithClassName(Widget* widget, const std::string& classname) {
48 return AnyViewMatchingPredicate(widget, [&](const View* view) {
49 return view->GetClassName() == classname;
50 });
51 }
52
53 WidgetTest::WidgetTest() = default;
54
WidgetTest(std::unique_ptr<base::test::TaskEnvironment> task_environment)55 WidgetTest::WidgetTest(
56 std::unique_ptr<base::test::TaskEnvironment> task_environment)
57 : ViewsTestBase(std::move(task_environment)) {}
58
59 WidgetTest::~WidgetTest() = default;
60
CreateTopLevelPlatformWidget()61 Widget* WidgetTest::CreateTopLevelPlatformWidget() {
62 Widget* widget = new Widget;
63 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
64 params.native_widget =
65 CreatePlatformNativeWidgetImpl(widget, kStubCapture, nullptr);
66 widget->Init(std::move(params));
67 return widget;
68 }
69
CreateTopLevelFramelessPlatformWidget()70 Widget* WidgetTest::CreateTopLevelFramelessPlatformWidget() {
71 Widget* widget = new Widget;
72 Widget::InitParams params =
73 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
74 params.native_widget =
75 CreatePlatformNativeWidgetImpl(widget, kStubCapture, nullptr);
76 widget->Init(std::move(params));
77 return widget;
78 }
79
CreateChildPlatformWidget(gfx::NativeView parent_native_view)80 Widget* WidgetTest::CreateChildPlatformWidget(
81 gfx::NativeView parent_native_view) {
82 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_CONTROL);
83 params.parent = parent_native_view;
84 Widget* child = new Widget;
85 params.native_widget =
86 CreatePlatformNativeWidgetImpl(child, kStubCapture, nullptr);
87 child->Init(std::move(params));
88 child->SetContentsView(std::make_unique<View>());
89 return child;
90 }
91
CreateTopLevelNativeWidget()92 Widget* WidgetTest::CreateTopLevelNativeWidget() {
93 Widget* toplevel = new Widget;
94 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
95 toplevel->Init(std::move(params));
96 return toplevel;
97 }
98
CreateChildNativeWidgetWithParent(Widget * parent)99 Widget* WidgetTest::CreateChildNativeWidgetWithParent(Widget* parent) {
100 Widget* child = new Widget;
101 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_CONTROL);
102 params.parent = parent->GetNativeView();
103 child->Init(std::move(params));
104 child->SetContentsView(std::make_unique<View>());
105 return child;
106 }
107
GetMousePressedHandler(internal::RootView * root_view)108 View* WidgetTest::GetMousePressedHandler(internal::RootView* root_view) {
109 return root_view->mouse_pressed_handler_;
110 }
111
GetMouseMoveHandler(internal::RootView * root_view)112 View* WidgetTest::GetMouseMoveHandler(internal::RootView* root_view) {
113 return root_view->mouse_move_handler_;
114 }
115
GetGestureHandler(internal::RootView * root_view)116 View* WidgetTest::GetGestureHandler(internal::RootView* root_view) {
117 return root_view->gesture_handler_;
118 }
119
120 DesktopWidgetTest::DesktopWidgetTest() = default;
121 DesktopWidgetTest::~DesktopWidgetTest() = default;
122
SetUp()123 void DesktopWidgetTest::SetUp() {
124 set_native_widget_type(NativeWidgetType::kDesktop);
125 WidgetTest::SetUp();
126 }
127
128 DesktopWidgetTestInteractive::DesktopWidgetTestInteractive() = default;
129 DesktopWidgetTestInteractive::~DesktopWidgetTestInteractive() = default;
130
SetUp()131 void DesktopWidgetTestInteractive::SetUp() {
132 SetUpForInteractiveTests();
133 DesktopWidgetTest::SetUp();
134 }
135
TestDesktopWidgetDelegate()136 TestDesktopWidgetDelegate::TestDesktopWidgetDelegate()
137 : TestDesktopWidgetDelegate(nullptr) {}
138
TestDesktopWidgetDelegate(Widget * widget)139 TestDesktopWidgetDelegate::TestDesktopWidgetDelegate(Widget* widget)
140 : widget_(widget ? widget : new Widget) {
141 SetFocusTraversesOut(true);
142 }
143
~TestDesktopWidgetDelegate()144 TestDesktopWidgetDelegate::~TestDesktopWidgetDelegate() {
145 if (widget_)
146 widget_->CloseNow();
147 EXPECT_FALSE(widget_);
148 }
149
InitWidget(Widget::InitParams init_params)150 void TestDesktopWidgetDelegate::InitWidget(Widget::InitParams init_params) {
151 init_params.delegate = this;
152 init_params.bounds = initial_bounds_;
153 widget_->Init(std::move(init_params));
154 }
155
WindowClosing()156 void TestDesktopWidgetDelegate::WindowClosing() {
157 window_closing_count_++;
158 widget_ = nullptr;
159 }
160
GetWidget()161 Widget* TestDesktopWidgetDelegate::GetWidget() {
162 return widget_;
163 }
164
GetWidget() const165 const Widget* TestDesktopWidgetDelegate::GetWidget() const {
166 return widget_;
167 }
168
GetContentsView()169 View* TestDesktopWidgetDelegate::GetContentsView() {
170 return contents_view_ ? contents_view_ : WidgetDelegate::GetContentsView();
171 }
172
OnCloseRequested(Widget::ClosedReason close_reason)173 bool TestDesktopWidgetDelegate::OnCloseRequested(
174 Widget::ClosedReason close_reason) {
175 last_closed_reason_ = close_reason;
176 return can_close_;
177 }
178
TestInitialFocusWidgetDelegate(gfx::NativeWindow context)179 TestInitialFocusWidgetDelegate::TestInitialFocusWidgetDelegate(
180 gfx::NativeWindow context)
181 : view_(new View) {
182 view_->SetFocusBehavior(View::FocusBehavior::ALWAYS);
183
184 Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
185 params.context = context;
186 params.delegate = this;
187 GetWidget()->Init(std::move(params));
188 GetWidget()->GetContentsView()->AddChildView(view_);
189 }
190
191 TestInitialFocusWidgetDelegate::~TestInitialFocusWidgetDelegate() = default;
192
GetInitiallyFocusedView()193 View* TestInitialFocusWidgetDelegate::GetInitiallyFocusedView() {
194 return view_;
195 }
196
WidgetActivationWaiter(Widget * widget,bool active)197 WidgetActivationWaiter::WidgetActivationWaiter(Widget* widget, bool active)
198 : observed_(false), active_(active) {
199 if (active == widget->IsActive()) {
200 observed_ = true;
201 return;
202 }
203 widget->AddObserver(this);
204 }
205
206 WidgetActivationWaiter::~WidgetActivationWaiter() = default;
207
Wait()208 void WidgetActivationWaiter::Wait() {
209 if (!observed_)
210 run_loop_.Run();
211 }
212
OnWidgetActivationChanged(Widget * widget,bool active)213 void WidgetActivationWaiter::OnWidgetActivationChanged(Widget* widget,
214 bool active) {
215 if (active_ != active)
216 return;
217
218 observed_ = true;
219 widget->RemoveObserver(this);
220 if (run_loop_.running())
221 run_loop_.Quit();
222 }
223
WidgetClosingObserver(Widget * widget)224 WidgetClosingObserver::WidgetClosingObserver(Widget* widget) : widget_(widget) {
225 widget_->AddObserver(this);
226 }
227
~WidgetClosingObserver()228 WidgetClosingObserver::~WidgetClosingObserver() {
229 if (widget_)
230 widget_->RemoveObserver(this);
231 }
232
Wait()233 void WidgetClosingObserver::Wait() {
234 if (widget_)
235 run_loop_.Run();
236 }
237
OnWidgetClosing(Widget * widget)238 void WidgetClosingObserver::OnWidgetClosing(Widget* widget) {
239 DCHECK_EQ(widget_, widget);
240 widget_->RemoveObserver(this);
241 widget_ = nullptr;
242 if (run_loop_.running())
243 run_loop_.Quit();
244 }
245
WidgetDestroyedWaiter(Widget * widget)246 WidgetDestroyedWaiter::WidgetDestroyedWaiter(Widget* widget) {
247 widget->AddObserver(this);
248 }
249
Wait()250 void WidgetDestroyedWaiter::Wait() {
251 run_loop_.Run();
252 }
253
OnWidgetDestroyed(Widget * widget)254 void WidgetDestroyedWaiter::OnWidgetDestroyed(Widget* widget) {
255 widget->RemoveObserver(this);
256 run_loop_.Quit();
257 }
258
WidgetVisibleWaiter(Widget * widget)259 WidgetVisibleWaiter::WidgetVisibleWaiter(Widget* widget) : widget_(widget) {}
260 WidgetVisibleWaiter::~WidgetVisibleWaiter() = default;
261
Wait()262 void WidgetVisibleWaiter::Wait() {
263 if (!widget_->IsVisible()) {
264 widget_observer_.Add(widget_);
265 run_loop_.Run();
266 }
267 }
268
OnWidgetVisibilityChanged(Widget * widget,bool visible)269 void WidgetVisibleWaiter::OnWidgetVisibilityChanged(Widget* widget,
270 bool visible) {
271 DCHECK_EQ(widget_, widget);
272 if (visible) {
273 widget_observer_.Remove(widget);
274 run_loop_.Quit();
275 }
276 }
277
OnWidgetDestroying(Widget * widget)278 void WidgetVisibleWaiter::OnWidgetDestroying(Widget* widget) {
279 DCHECK_EQ(widget_, widget);
280 ADD_FAILURE() << "Widget destroying before it became visible!";
281 // Even though the test failed, be polite and remove the observer so we
282 // don't crash with a UAF in the destructor.
283 widget_observer_.Remove(widget);
284 }
285
286 } // namespace test
287 } // namespace views
288