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