Drive: Add BatchableRequest subclass.
[chromium-blink-merge.git] / ui / views / controls / native / native_view_host_unittest.cc
blobbed30576b8c191f0778abde3c0335d7859944acf
1 // Copyright (c) 2012 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.
5 #include "ui/views/controls/native/native_view_host.h"
7 #include "base/basictypes.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "ui/aura/window.h"
10 #include "ui/views/controls/native/native_view_host_test_base.h"
11 #include "ui/views/test/views_test_base.h"
12 #include "ui/views/widget/widget.h"
14 namespace views {
16 class NativeViewHostTest : public test::NativeViewHostTestBase {
17 public:
18 NativeViewHostTest() {
21 void SetUp() override {
22 ViewsTestBase::SetUp();
23 CreateTopLevel();
26 private:
27 DISALLOW_COPY_AND_ASSIGN(NativeViewHostTest);
30 namespace {
32 // View implementation used by NativeViewHierarchyChanged to count number of
33 // times NativeViewHierarchyChanged() is invoked.
34 class NativeViewHierarchyChangedTestView : public View {
35 public:
36 NativeViewHierarchyChangedTestView() : notification_count_(0) {
39 void ResetCount() {
40 notification_count_ = 0;
43 int notification_count() const { return notification_count_; }
45 // Overriden from View:
46 void NativeViewHierarchyChanged() override {
47 ++notification_count_;
48 View::NativeViewHierarchyChanged();
51 private:
52 int notification_count_;
54 DISALLOW_COPY_AND_ASSIGN(NativeViewHierarchyChangedTestView);
57 aura::Window* GetNativeParent(aura::Window* window) {
58 return window->parent();
61 class ViewHierarchyChangedTestHost : public NativeViewHost {
62 public:
63 ViewHierarchyChangedTestHost()
64 : num_parent_changes_(0) {
67 void ResetParentChanges() {
68 num_parent_changes_ = 0;
71 int num_parent_changes() const {
72 return num_parent_changes_;
75 // Overriden from NativeViewHost:
76 void ViewHierarchyChanged(
77 const ViewHierarchyChangedDetails& details) override {
78 gfx::NativeView parent_before = native_view() ?
79 GetNativeParent(native_view()) : NULL;
80 NativeViewHost::ViewHierarchyChanged(details);
81 gfx::NativeView parent_after = native_view() ?
82 GetNativeParent(native_view()) : NULL;
83 if (parent_before != parent_after)
84 ++num_parent_changes_;
87 private:
88 int num_parent_changes_;
90 DISALLOW_COPY_AND_ASSIGN(ViewHierarchyChangedTestHost);
93 } // namespace
95 // Verifies NativeViewHierarchyChanged is sent.
96 TEST_F(NativeViewHostTest, NativeViewHierarchyChanged) {
97 // Create a child widget.
98 NativeViewHierarchyChangedTestView* test_view =
99 new NativeViewHierarchyChangedTestView;
100 NativeViewHost* host = new NativeViewHost;
101 scoped_ptr<Widget> child(CreateChildForHost(toplevel()->GetNativeView(),
102 toplevel()->GetRootView(),
103 test_view,
104 host));
105 #if defined(USE_AURA)
106 // Two notifications are generated from inserting the native view into the
107 // clipping window and then inserting the clipping window into the root
108 // window.
109 EXPECT_EQ(2, test_view->notification_count());
110 #else
111 EXPECT_EQ(0, test_view->notification_count());
112 #endif
113 test_view->ResetCount();
115 // Detaching should send a NativeViewHierarchyChanged() notification and
116 // change the parent.
117 host->Detach();
118 #if defined(USE_AURA)
119 // Two notifications are generated from removing the native view from the
120 // clipping window and then reparenting it to the root window.
121 EXPECT_EQ(2, test_view->notification_count());
122 #else
123 EXPECT_EQ(1, test_view->notification_count());
124 #endif
125 EXPECT_NE(toplevel()->GetNativeView(),
126 GetNativeParent(child->GetNativeView()));
127 test_view->ResetCount();
129 // Attaching should send a NativeViewHierarchyChanged() notification and
130 // reset the parent.
131 host->Attach(child->GetNativeView());
132 #if defined(USE_AURA)
133 // There is a clipping window inserted above the native view that needs to be
134 // accounted for when looking at the relationship between the native views.
135 EXPECT_EQ(2, test_view->notification_count());
136 EXPECT_EQ(toplevel()->GetNativeView(),
137 GetNativeParent(GetNativeParent(child->GetNativeView())));
138 #else
139 EXPECT_EQ(1, test_view->notification_count());
140 EXPECT_EQ(toplevel()->GetNativeView(),
141 GetNativeParent(child->GetNativeView()));
142 #endif
145 // Verifies ViewHierarchyChanged handles NativeViewHost remove, add and move
146 // (reparent) operations with correct parent changes.
147 // This exercises the non-recursive code paths in
148 // View::PropagateRemoveNotifications() and View::PropagateAddNotifications().
149 TEST_F(NativeViewHostTest, ViewHierarchyChangedForHost) {
150 // Original tree:
151 // toplevel
152 // +-- host0 (NativeViewHost)
153 // +-- child0 (Widget, attached to host0)
154 // +-- test_host (ViewHierarchyChangedTestHost)
155 // +-- test_child (Widget, attached to test_host)
156 // +-- host1 (NativeViewHost)
157 // +-- child1 (Widget, attached to host1)
159 // Add two children widgets attached to a NativeViewHost, and a test
160 // grandchild as child widget of host0.
161 NativeViewHost* host0 = new NativeViewHost;
162 scoped_ptr<Widget> child0(CreateChildForHost(toplevel()->GetNativeView(),
163 toplevel()->GetRootView(),
164 new View,
165 host0));
166 NativeViewHost* host1 = new NativeViewHost;
167 scoped_ptr<Widget> child1(CreateChildForHost(toplevel()->GetNativeView(),
168 toplevel()->GetRootView(),
169 new View,
170 host1));
171 ViewHierarchyChangedTestHost* test_host = new ViewHierarchyChangedTestHost;
172 scoped_ptr<Widget> test_child(CreateChildForHost(host0->native_view(),
173 host0,
174 new View,
175 test_host));
177 // Remove test_host from host0, expect 1 parent change.
178 test_host->ResetParentChanges();
179 EXPECT_EQ(0, test_host->num_parent_changes());
180 host0->RemoveChildView(test_host);
181 EXPECT_EQ(1, test_host->num_parent_changes());
183 // Add test_host back to host0, expect 1 parent change.
184 test_host->ResetParentChanges();
185 EXPECT_EQ(0, test_host->num_parent_changes());
186 host0->AddChildView(test_host);
187 EXPECT_EQ(1, test_host->num_parent_changes());
189 // Reparent test_host to host1, expect no parent change because the old and
190 // new parents, host0 and host1, belong to the same toplevel widget.
191 test_host->ResetParentChanges();
192 EXPECT_EQ(0, test_host->num_parent_changes());
193 host1->AddChildView(test_host);
194 EXPECT_EQ(0, test_host->num_parent_changes());
196 // Reparent test_host to contents view of child0, expect 2 parent changes
197 // because the old parent belongs to the toplevel widget whereas the new
198 // parent belongs to the child0.
199 test_host->ResetParentChanges();
200 EXPECT_EQ(0, test_host->num_parent_changes());
201 child0->GetContentsView()->AddChildView(test_host);
202 EXPECT_EQ(2, test_host->num_parent_changes());
205 // Verifies ViewHierarchyChanged handles NativeViewHost's parent remove, add and
206 // move (reparent) operations with correct parent changes.
207 // This exercises the recursive code paths in
208 // View::PropagateRemoveNotifications() and View::PropagateAddNotifications().
209 TEST_F(NativeViewHostTest, ViewHierarchyChangedForHostParent) {
210 // Original tree:
211 // toplevel
212 // +-- view0 (View)
213 // +-- host0 (NativeViewHierarchyChangedTestHost)
214 // +-- child0 (Widget, attached to host0)
215 // +-- view1 (View)
216 // +-- host1 (NativeViewHierarchyChangedTestHost)
217 // +-- child1 (Widget, attached to host1)
219 // Add two children views.
220 View* view0 = new View;
221 toplevel()->GetRootView()->AddChildView(view0);
222 View* view1 = new View;
223 toplevel()->GetRootView()->AddChildView(view1);
225 // To each child view, add a child widget.
226 ViewHierarchyChangedTestHost* host0 = new ViewHierarchyChangedTestHost;
227 scoped_ptr<Widget> child0(CreateChildForHost(toplevel()->GetNativeView(),
228 view0,
229 new View,
230 host0));
231 ViewHierarchyChangedTestHost* host1 = new ViewHierarchyChangedTestHost;
232 scoped_ptr<Widget> child1(CreateChildForHost(toplevel()->GetNativeView(),
233 view1,
234 new View,
235 host1));
237 // Remove view0 from top level, expect 1 parent change.
238 host0->ResetParentChanges();
239 EXPECT_EQ(0, host0->num_parent_changes());
240 toplevel()->GetRootView()->RemoveChildView(view0);
241 EXPECT_EQ(1, host0->num_parent_changes());
243 // Add view0 back to top level, expect 1 parent change.
244 host0->ResetParentChanges();
245 EXPECT_EQ(0, host0->num_parent_changes());
246 toplevel()->GetRootView()->AddChildView(view0);
247 EXPECT_EQ(1, host0->num_parent_changes());
249 // Reparent view0 to view1, expect no parent change because the old and new
250 // parents of both view0 and view1 belong to the same toplevel widget.
251 host0->ResetParentChanges();
252 host1->ResetParentChanges();
253 EXPECT_EQ(0, host0->num_parent_changes());
254 EXPECT_EQ(0, host1->num_parent_changes());
255 view1->AddChildView(view0);
256 EXPECT_EQ(0, host0->num_parent_changes());
257 EXPECT_EQ(0, host1->num_parent_changes());
259 // Restore original view hierarchy by adding back view0 to top level.
260 // Then, reparent view1 to contents view of child0.
261 // Expect 2 parent changes because the old parent belongs to the toplevel
262 // widget whereas the new parent belongs to the 1st child widget.
263 toplevel()->GetRootView()->AddChildView(view0);
264 host0->ResetParentChanges();
265 host1->ResetParentChanges();
266 EXPECT_EQ(0, host0->num_parent_changes());
267 EXPECT_EQ(0, host1->num_parent_changes());
268 child0->GetContentsView()->AddChildView(view1);
269 EXPECT_EQ(0, host0->num_parent_changes());
270 EXPECT_EQ(2, host1->num_parent_changes());
273 } // namespace views