OLD | NEW |
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 "base/memory/ptr_util.h" | 5 #include "base/memory/ptr_util.h" |
6 #include "base/strings/utf_string_conversions.h" | 6 #include "base/strings/utf_string_conversions.h" |
7 #include "ui/accessibility/ax_node_data.h" | 7 #include "ui/accessibility/ax_node_data.h" |
8 #include "ui/gfx/geometry/rect_conversions.h" | 8 #include "ui/gfx/geometry/rect_conversions.h" |
9 #include "ui/views/accessibility/ax_aura_obj_cache.h" | 9 #include "ui/views/accessibility/ax_aura_obj_cache.h" |
10 #include "ui/views/accessibility/ax_aura_obj_wrapper.h" | 10 #include "ui/views/accessibility/ax_aura_obj_wrapper.h" |
11 #include "ui/views/accessibility/ax_widget_obj_wrapper.h" | 11 #include "ui/views/accessibility/ax_widget_obj_wrapper.h" |
12 #include "ui/views/accessibility/native_view_accessibility_base.h" | 12 #include "ui/views/accessibility/native_view_accessibility_base.h" |
13 #include "ui/views/controls/button/button.h" | 13 #include "ui/views/controls/button/button.h" |
14 #include "ui/views/controls/label.h" | 14 #include "ui/views/controls/label.h" |
15 #include "ui/views/test/views_test_base.h" | 15 #include "ui/views/test/views_test_base.h" |
| 16 #include "ui/views/widget/widget.h" |
16 | 17 |
17 namespace views { | 18 namespace views { |
18 namespace test { | 19 namespace test { |
19 | 20 |
20 class NativeViewAccessibilityTest; | |
21 | |
22 namespace { | 21 namespace { |
23 | 22 |
24 class TestButton : public Button { | 23 class TestButton : public Button { |
25 public: | 24 public: |
26 TestButton() : Button(NULL) {} | 25 TestButton() : Button(NULL) {} |
27 }; | 26 }; |
28 | 27 |
| 28 // Adds a View with given bounds and focusability to a parent. |
| 29 View* AddNewChildWithBoundsAndFocusability(View* parent, |
| 30 const gfx::Rect& bounds, |
| 31 bool focusable) { |
| 32 View* child = new View; |
| 33 child->SetBoundsRect(bounds); |
| 34 parent->AddChildView(child); |
| 35 child->SetFocusBehavior(focusable ? ClientView::FocusBehavior::ACCESSIBLE_ONLY |
| 36 : ClientView::FocusBehavior::NEVER); |
| 37 return child; |
| 38 } |
| 39 |
29 } // namespace | 40 } // namespace |
30 | 41 |
31 class NativeViewAccessibilityTest : public ViewsTestBase { | 42 class NativeViewAccessibilityTest : public ViewsTestBase { |
32 public: | 43 public: |
33 NativeViewAccessibilityTest() {} | 44 NativeViewAccessibilityTest() {} |
34 ~NativeViewAccessibilityTest() override {} | 45 ~NativeViewAccessibilityTest() override {} |
35 | 46 |
36 void SetUp() override { | 47 void SetUp() override { |
37 ViewsTestBase::SetUp(); | 48 ViewsTestBase::SetUp(); |
38 | 49 |
39 widget_ = new views::Widget; | 50 widget_ = new Widget; |
40 views::Widget::InitParams params = | 51 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); |
41 CreateParams(views::Widget::InitParams::TYPE_WINDOW); | |
42 params.bounds = gfx::Rect(0, 0, 200, 200); | 52 params.bounds = gfx::Rect(0, 0, 200, 200); |
43 widget_->Init(params); | 53 widget_->Init(params); |
44 | 54 |
45 button_ = new TestButton(); | 55 button_ = new TestButton(); |
46 button_->SetSize(gfx::Size(20, 20)); | 56 button_->SetSize(gfx::Size(20, 20)); |
47 button_accessibility_ = NativeViewAccessibility::Create(button_); | 57 button_accessibility_ = NativeViewAccessibility::Create(button_); |
48 | 58 |
49 label_ = new Label(); | 59 label_ = new Label(); |
50 button_->AddChildView(label_); | 60 button_->AddChildView(label_); |
51 label_accessibility_ = NativeViewAccessibility::Create(label_); | 61 label_accessibility_ = NativeViewAccessibility::Create(label_); |
(...skipping 19 matching lines...) Expand all Loading... |
71 } | 81 } |
72 | 82 |
73 bool SetFocused(NativeViewAccessibilityBase* view_accessibility, | 83 bool SetFocused(NativeViewAccessibilityBase* view_accessibility, |
74 bool focused) { | 84 bool focused) { |
75 ui::AXActionData data; | 85 ui::AXActionData data; |
76 data.action = focused ? ui::AX_ACTION_FOCUS : ui::AX_ACTION_BLUR; | 86 data.action = focused ? ui::AX_ACTION_FOCUS : ui::AX_ACTION_BLUR; |
77 return view_accessibility->AccessibilityPerformAction(data); | 87 return view_accessibility->AccessibilityPerformAction(data); |
78 } | 88 } |
79 | 89 |
80 protected: | 90 protected: |
81 views::Widget* widget_; | 91 Widget* widget_; |
82 TestButton* button_; | 92 TestButton* button_; |
83 std::unique_ptr<NativeViewAccessibility> button_accessibility_; | 93 std::unique_ptr<NativeViewAccessibility> button_accessibility_; |
84 Label* label_; | 94 Label* label_; |
85 std::unique_ptr<NativeViewAccessibility> label_accessibility_; | 95 std::unique_ptr<NativeViewAccessibility> label_accessibility_; |
| 96 |
| 97 DISALLOW_COPY_AND_ASSIGN(NativeViewAccessibilityTest); |
86 }; | 98 }; |
87 | 99 |
88 TEST_F(NativeViewAccessibilityTest, RoleShouldMatch) { | 100 TEST_F(NativeViewAccessibilityTest, RoleShouldMatch) { |
89 EXPECT_EQ(ui::AX_ROLE_BUTTON, button_accessibility()->GetData().role); | 101 EXPECT_EQ(ui::AX_ROLE_BUTTON, button_accessibility()->GetData().role); |
| 102 // Since the label is a subview of |button_|, and the button is keyboard |
| 103 // focusable, the label is assumed to form part of the button and not have a |
| 104 // role of its own. |
| 105 EXPECT_EQ(ui::AX_ROLE_IGNORED, label_accessibility()->GetData().role); |
| 106 // This will happen for all potentially keyboard-focusable Views with |
| 107 // non-keyboard-focusable children, so if we make the button unfocusable, the |
| 108 // label will be allowed to have its own role again. |
| 109 button_->SetFocusBehavior(View::FocusBehavior::NEVER); |
90 EXPECT_EQ(ui::AX_ROLE_STATIC_TEXT, label_accessibility()->GetData().role); | 110 EXPECT_EQ(ui::AX_ROLE_STATIC_TEXT, label_accessibility()->GetData().role); |
91 } | 111 } |
92 | 112 |
93 TEST_F(NativeViewAccessibilityTest, BoundsShouldMatch) { | 113 TEST_F(NativeViewAccessibilityTest, BoundsShouldMatch) { |
94 gfx::Rect bounds = | 114 gfx::Rect bounds = |
95 gfx::ToEnclosingRect(button_accessibility()->GetData().location); | 115 gfx::ToEnclosingRect(button_accessibility()->GetData().location); |
96 gfx::Rect screen_bounds = button_accessibility()->GetScreenBoundsRect(); | 116 gfx::Rect screen_bounds = button_accessibility()->GetScreenBoundsRect(); |
97 | 117 |
98 EXPECT_EQ(button_->GetBoundsInScreen(), bounds); | 118 EXPECT_EQ(button_->GetBoundsInScreen(), bounds); |
99 EXPECT_EQ(screen_bounds, bounds); | 119 EXPECT_EQ(screen_bounds, bounds); |
100 } | 120 } |
101 | 121 |
102 TEST_F(NativeViewAccessibilityTest, LabelIsChildOfButton) { | 122 TEST_F(NativeViewAccessibilityTest, LabelIsChildOfButton) { |
| 123 EXPECT_EQ(0, button_accessibility()->GetChildCount()); |
| 124 EXPECT_EQ(nullptr, button_accessibility()->ChildAtIndex(0)); |
| 125 EXPECT_EQ(button_->GetNativeViewAccessible(), |
| 126 label_accessibility()->GetParent()); |
| 127 |
| 128 // If |button_| is no longer focusable, |label_| should show up again. |
| 129 button_->SetFocusBehavior(View::FocusBehavior::NEVER); |
103 EXPECT_EQ(1, button_accessibility()->GetChildCount()); | 130 EXPECT_EQ(1, button_accessibility()->GetChildCount()); |
104 EXPECT_EQ(label_->GetNativeViewAccessible(), | 131 EXPECT_EQ(label_->GetNativeViewAccessible(), |
105 button_accessibility()->ChildAtIndex(0)); | 132 button_accessibility()->ChildAtIndex(0)); |
106 EXPECT_EQ(button_->GetNativeViewAccessible(), | 133 EXPECT_EQ(button_->GetNativeViewAccessible(), |
107 label_accessibility()->GetParent()); | 134 label_accessibility()->GetParent()); |
108 } | 135 } |
109 | 136 |
110 // Verify Views with invisible ancestors have AX_STATE_INVISIBLE. | 137 // Verify Views with invisible ancestors have AX_STATE_INVISIBLE. |
111 TEST_F(NativeViewAccessibilityTest, InvisibleViews) { | 138 TEST_F(NativeViewAccessibilityTest, InvisibleViews) { |
112 EXPECT_TRUE(widget_->IsVisible()); | 139 EXPECT_TRUE(widget_->IsVisible()); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 bool is_destroying_parent_widget = (parent_widget_ == widget); | 178 bool is_destroying_parent_widget = (parent_widget_ == widget); |
152 NativeViewAccessibilityBase::OnWidgetDestroying(widget); | 179 NativeViewAccessibilityBase::OnWidgetDestroying(widget); |
153 if (is_destroying_parent_widget) | 180 if (is_destroying_parent_widget) |
154 delete this; | 181 delete this; |
155 } | 182 } |
156 }; | 183 }; |
157 | 184 |
158 TEST_F(NativeViewAccessibilityTest, CrashOnWidgetDestroyed) { | 185 TEST_F(NativeViewAccessibilityTest, CrashOnWidgetDestroyed) { |
159 std::unique_ptr<Widget> parent_widget(new Widget); | 186 std::unique_ptr<Widget> parent_widget(new Widget); |
160 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); | 187 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); |
161 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 188 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
162 params.bounds = gfx::Rect(50, 50, 650, 650); | 189 params.bounds = gfx::Rect(50, 50, 650, 650); |
163 parent_widget->Init(params); | 190 parent_widget->Init(params); |
164 | 191 |
165 std::unique_ptr<Widget> child_widget(new Widget); | 192 std::unique_ptr<Widget> child_widget(new Widget); |
166 child_widget->Init(params); | 193 child_widget->Init(params); |
167 | 194 |
168 // Make sure that deleting the parent widget can't cause a crash | 195 // Make sure that deleting the parent widget can't cause a crash |
169 // due to NativeViewAccessibility not unregistering itself as a | 196 // due to NativeViewAccessibility not unregistering itself as a |
170 // WidgetObserver. Note that TestNativeViewAccessibility is a subclass | 197 // WidgetObserver. Note that TestNativeViewAccessibility is a subclass |
171 // defined above that destroys itself when its parent widget is destroyed. | 198 // defined above that destroys itself when its parent widget is destroyed. |
(...skipping 10 matching lines...) Expand all Loading... |
182 ~DerivedTestView() override {} | 209 ~DerivedTestView() override {} |
183 | 210 |
184 void OnBlur() override { SetVisible(false); } | 211 void OnBlur() override { SetVisible(false); } |
185 }; | 212 }; |
186 | 213 |
187 class AxTestViewsDelegate : public TestViewsDelegate { | 214 class AxTestViewsDelegate : public TestViewsDelegate { |
188 public: | 215 public: |
189 AxTestViewsDelegate() {} | 216 AxTestViewsDelegate() {} |
190 ~AxTestViewsDelegate() override {} | 217 ~AxTestViewsDelegate() override {} |
191 | 218 |
192 void NotifyAccessibilityEvent(views::View* view, | 219 void NotifyAccessibilityEvent(View* view, ui::AXEvent event_type) override { |
193 ui::AXEvent event_type) override { | |
194 AXAuraObjCache* ax = AXAuraObjCache::GetInstance(); | 220 AXAuraObjCache* ax = AXAuraObjCache::GetInstance(); |
195 std::vector<AXAuraObjWrapper*> out_children; | 221 std::vector<AXAuraObjWrapper*> out_children; |
196 AXAuraObjWrapper* ax_obj = ax->GetOrCreate(view->GetWidget()); | 222 AXAuraObjWrapper* ax_obj = ax->GetOrCreate(view->GetWidget()); |
197 ax_obj->GetChildren(&out_children); | 223 ax_obj->GetChildren(&out_children); |
198 } | 224 } |
199 | 225 |
200 private: | 226 private: |
201 DISALLOW_COPY_AND_ASSIGN(AxTestViewsDelegate); | 227 DISALLOW_COPY_AND_ASSIGN(AxTestViewsDelegate); |
202 }; | 228 }; |
203 | 229 |
204 class AXViewTest : public ViewsTestBase { | 230 class AXViewTest : public ViewsTestBase { |
205 public: | 231 public: |
206 AXViewTest() {} | 232 AXViewTest() {} |
207 ~AXViewTest() override {} | 233 ~AXViewTest() override {} |
208 void SetUp() override { | 234 void SetUp() override { |
209 std::unique_ptr<TestViewsDelegate> views_delegate( | 235 std::unique_ptr<TestViewsDelegate> views_delegate( |
210 new AxTestViewsDelegate()); | 236 new AxTestViewsDelegate()); |
211 set_views_delegate(std::move(views_delegate)); | 237 set_views_delegate(std::move(views_delegate)); |
212 views::ViewsTestBase::SetUp(); | 238 ViewsTestBase::SetUp(); |
213 } | 239 } |
214 }; | 240 }; |
215 | 241 |
216 // Check if the destruction of the widget ends successfully if |view|'s | 242 // Check if the destruction of the widget ends successfully if |view|'s |
217 // visibility changed during destruction. | 243 // visibility changed during destruction. |
218 TEST_F(AXViewTest, LayoutCalledInvalidateRootView) { | 244 TEST_F(AXViewTest, LayoutCalledInvalidateRootView) { |
219 std::unique_ptr<Widget> widget(new Widget); | 245 std::unique_ptr<Widget> widget(new Widget); |
220 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); | 246 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); |
221 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 247 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
222 widget->Init(params); | 248 widget->Init(params); |
223 widget->Show(); | 249 widget->Show(); |
224 | 250 |
225 View* root = widget->GetRootView(); | 251 View* root = widget->GetRootView(); |
226 DerivedTestView* parent = new DerivedTestView(); | 252 DerivedTestView* parent = new DerivedTestView(); |
227 DerivedTestView* child = new DerivedTestView(); | 253 DerivedTestView* child = new DerivedTestView(); |
228 root->AddChildView(parent); | 254 root->AddChildView(parent); |
229 parent->AddChildView(child); | 255 parent->AddChildView(child); |
230 child->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); | 256 child->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); |
231 parent->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); | 257 parent->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); |
232 root->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); | 258 root->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); |
233 parent->RequestFocus(); | 259 parent->RequestFocus(); |
234 // During the destruction of parent, OnBlur will be called and change the | 260 // During the destruction of parent, OnBlur will be called and change the |
235 // visibility to false. | 261 // visibility to false. |
236 parent->SetVisible(true); | 262 parent->SetVisible(true); |
237 AXAuraObjCache* ax = AXAuraObjCache::GetInstance(); | 263 AXAuraObjCache* ax = AXAuraObjCache::GetInstance(); |
238 ax->GetOrCreate(widget.get()); | 264 ax->GetOrCreate(widget.get()); |
239 } | 265 } |
240 #endif | 266 #endif |
241 | 267 |
| 268 // Separate test class for a complicated test case for ignored accessibility |
| 269 // elements which are excluded from the accessibility tree. |
| 270 class NativeViewAccessibilityBaseIgnoredElementsTest : public ViewsTestBase { |
| 271 public: |
| 272 NativeViewAccessibilityBaseIgnoredElementsTest() { |
| 273 a_root_ = new View; |
| 274 NativeViewAccessibilityBase::GetForView(a_root_); |
| 275 } |
| 276 |
| 277 void SetUp() override { |
| 278 ViewsTestBase::SetUp(); |
| 279 // Set up an accessibility tree where X-nodes should be ignored. A Views |
| 280 // hierarchy as shown on the left should expose the accessibility tree in |
| 281 // the middle, and respond to hit tests as shown on the right. This test |
| 282 // is here for completeness (in practice, it's unlikely a keyboard-focusable |
| 283 // View will be needed as a descendant of another keyboard-focusable View). |
| 284 // |
| 285 // A A |
| 286 // / \ / | \ +++---+---+---++---+---+---+++ |
| 287 // B X1 B F E ||| C | D | B || F | A | E ||| |
| 288 // / | \ / | \ / \ +++---+---+---++---+---+---+++ |
| 289 // C D X2 X3 X4 E C D |
| 290 // | | |
| 291 // X5 F |
| 292 // |
| 293 // Note: For hit tests, the parent's bounds will be divided equally amongst |
| 294 // its children (including ignored elements). This means all Views belonging |
| 295 // on the same level of the Views hierarchy will be the same size. |
| 296 a_root_ = new View; |
| 297 a_root_->SetSize(gfx::Size(400, 20)); |
| 298 a_root_->SetFocusBehavior(View::FocusBehavior::ACCESSIBLE_ONLY); |
| 299 |
| 300 // Create Views in the left subtree from |a_root_|. |
| 301 gfx::Rect new_bounds(0, 0, a_root_->width() / 2, a_root_->height()); |
| 302 View* b = AddNewChildWithBoundsAndFocusability(a_root_, new_bounds, true); |
| 303 // |a_root_| has 6 leaves, so divvy up space equally between them for hit |
| 304 // tests. |
| 305 new_bounds = gfx::Rect(0, 0, a_root_->width() / 6, a_root_->height()); |
| 306 View* c = AddNewChildWithBoundsAndFocusability(b, new_bounds, true); |
| 307 View* x5 = AddNewChildWithBoundsAndFocusability(c, new_bounds, false); |
| 308 // Update the |new_bounds| origin to position leaves next to each other. |
| 309 new_bounds.set_x(new_bounds.x() + a_root_->width() / 6); |
| 310 View* d = AddNewChildWithBoundsAndFocusability(b, new_bounds, true); |
| 311 new_bounds.set_x(new_bounds.x() + a_root_->width() / 6); |
| 312 View* x2 = AddNewChildWithBoundsAndFocusability(b, new_bounds, false); |
| 313 new_bounds.set_x(new_bounds.x() + a_root_->width() / 6); |
| 314 |
| 315 // Create Views in the right subtree from root |a_root_|. |
| 316 new_bounds.set_size(b->size()); |
| 317 View* x1 = AddNewChildWithBoundsAndFocusability(a_root_, new_bounds, false); |
| 318 new_bounds.set_origin(gfx::Point()); |
| 319 View* x3 = AddNewChildWithBoundsAndFocusability(x1, new_bounds, false); |
| 320 View* f = AddNewChildWithBoundsAndFocusability(x3, new_bounds, true); |
| 321 new_bounds.set_x(new_bounds.x() + a_root_->width() / 6); |
| 322 View* x4 = AddNewChildWithBoundsAndFocusability(x1, new_bounds, false); |
| 323 new_bounds.set_x(new_bounds.x() + a_root_->width() / 6); |
| 324 View* e = AddNewChildWithBoundsAndFocusability(x1, new_bounds, true); |
| 325 |
| 326 // Populate NPlatformativeViewAccessibility instances for convenience. |
| 327 a_root_nva_ = NativeViewAccessibilityBase::GetForView(a_root_); |
| 328 b_nva_ = NativeViewAccessibilityBase::GetForView(b); |
| 329 c_b_nva_ = NativeViewAccessibilityBase::GetForView(c); |
| 330 d_b_nva_ = NativeViewAccessibilityBase::GetForView(d); |
| 331 e_x1_nva_ = NativeViewAccessibilityBase::GetForView(e); |
| 332 f_x3_x1_nva_ = NativeViewAccessibilityBase::GetForView(f); |
| 333 x1_nva_ = NativeViewAccessibilityBase::GetForView(x1); |
| 334 x2_b_nva_ = NativeViewAccessibilityBase::GetForView(x2); |
| 335 x3_x1_nva_ = NativeViewAccessibilityBase::GetForView(x3); |
| 336 x4_x1_nva_ = NativeViewAccessibilityBase::GetForView(x4); |
| 337 x5_c_b_nva_ = NativeViewAccessibilityBase::GetForView(x5); |
| 338 |
| 339 // Add everything to a new widget, needed for hit testing and parent tests. |
| 340 widget_ = new Widget; |
| 341 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); |
| 342 widget_->Init(params); |
| 343 widget_->GetContentsView()->AddChildView(a_root_); |
| 344 widget_->Show(); |
| 345 } |
| 346 |
| 347 void TearDown() override { |
| 348 widget_->Close(); |
| 349 ViewsTestBase::TearDown(); |
| 350 } |
| 351 |
| 352 protected: |
| 353 // Owned by |widget_|. |
| 354 View* a_root_; |
| 355 |
| 356 // Owned by their respective View, which are owned by |widget_|. |
| 357 // The following NativeViewAccessibilityBase objects are named after their |
| 358 // corresponding node as shown in the diagrams in SetUp(), then a list of |
| 359 // their ancestors (minus the root), separated by underscores. |
| 360 NativeViewAccessibilityBase* a_root_nva_; |
| 361 NativeViewAccessibilityBase* b_nva_; |
| 362 NativeViewAccessibilityBase* c_b_nva_; |
| 363 NativeViewAccessibilityBase* d_b_nva_; |
| 364 NativeViewAccessibilityBase* e_x1_nva_; |
| 365 NativeViewAccessibilityBase* f_x3_x1_nva_; |
| 366 NativeViewAccessibilityBase* x1_nva_; |
| 367 NativeViewAccessibilityBase* x2_b_nva_; |
| 368 NativeViewAccessibilityBase* x3_x1_nva_; |
| 369 NativeViewAccessibilityBase* x4_x1_nva_; |
| 370 NativeViewAccessibilityBase* x5_c_b_nva_; |
| 371 |
| 372 Widget* widget_ = nullptr; |
| 373 |
| 374 private: |
| 375 DISALLOW_COPY_AND_ASSIGN(NativeViewAccessibilityBaseIgnoredElementsTest); |
| 376 }; |
| 377 |
| 378 // Check the number of a11y children returned accounts for ignored elements. |
| 379 TEST_F(NativeViewAccessibilityBaseIgnoredElementsTest, GetChildCount) { |
| 380 EXPECT_EQ(3, a_root_nva_->GetChildCount()); |
| 381 EXPECT_EQ(2, b_nva_->GetChildCount()); |
| 382 // Leaf elements will return 0. |
| 383 EXPECT_EQ(0, c_b_nva_->GetChildCount()); |
| 384 EXPECT_EQ(0, x5_c_b_nva_->GetChildCount()); |
| 385 EXPECT_EQ(0, d_b_nva_->GetChildCount()); |
| 386 EXPECT_EQ(0, x2_b_nva_->GetChildCount()); |
| 387 EXPECT_EQ(2, x1_nva_->GetChildCount()); |
| 388 EXPECT_EQ(1, x3_x1_nva_->GetChildCount()); |
| 389 EXPECT_EQ(0, f_x3_x1_nva_->GetChildCount()); |
| 390 EXPECT_EQ(0, x4_x1_nva_->GetChildCount()); |
| 391 EXPECT_EQ(0, e_x1_nva_->GetChildCount()); |
| 392 } |
| 393 |
| 394 // Make sure the correct a11y child element is returned at its corresponding |
| 395 // index. Unignored children with ignored parents should move up in the tree. |
| 396 TEST_F(NativeViewAccessibilityBaseIgnoredElementsTest, ChildAtIndex) { |
| 397 EXPECT_EQ(b_nva_->GetNativeObject(), a_root_nva_->ChildAtIndex(0)); |
| 398 EXPECT_EQ(f_x3_x1_nva_->GetNativeObject(), a_root_nva_->ChildAtIndex(1)); |
| 399 EXPECT_EQ(e_x1_nva_->GetNativeObject(), a_root_nva_->ChildAtIndex(2)); |
| 400 EXPECT_EQ(nullptr, a_root_nva_->ChildAtIndex(3)); |
| 401 |
| 402 EXPECT_EQ(c_b_nva_->GetNativeObject(), b_nva_->ChildAtIndex(0)); |
| 403 EXPECT_EQ(d_b_nva_->GetNativeObject(), b_nva_->ChildAtIndex(1)); |
| 404 EXPECT_EQ(nullptr, b_nva_->ChildAtIndex(2)); |
| 405 |
| 406 EXPECT_EQ(f_x3_x1_nva_->GetNativeObject(), x1_nva_->ChildAtIndex(0)); |
| 407 EXPECT_EQ(e_x1_nva_->GetNativeObject(), x1_nva_->ChildAtIndex(1)); |
| 408 EXPECT_EQ(nullptr, x1_nva_->ChildAtIndex(2)); |
| 409 |
| 410 EXPECT_EQ(f_x3_x1_nva_->GetNativeObject(), x3_x1_nva_->ChildAtIndex(0)); |
| 411 |
| 412 // Node with ignored children. |
| 413 EXPECT_EQ(nullptr, c_b_nva_->ChildAtIndex(0)); |
| 414 // Node with 0 children. |
| 415 EXPECT_EQ(nullptr, d_b_nva_->ChildAtIndex(0)); |
| 416 // Ignored node with 0 children. |
| 417 EXPECT_EQ(nullptr, x2_b_nva_->ChildAtIndex(0)); |
| 418 } |
| 419 |
| 420 // Check the a11y parents returned correspond to their unignored children. |
| 421 TEST_F(NativeViewAccessibilityBaseIgnoredElementsTest, GetParent) { |
| 422 EXPECT_EQ(a_root_->parent()->GetNativeViewAccessible(), |
| 423 a_root_nva_->GetParent()); |
| 424 EXPECT_EQ(a_root_->GetNativeViewAccessible(), b_nva_->GetParent()); |
| 425 EXPECT_EQ(b_nva_->GetNativeObject(), c_b_nva_->GetParent()); |
| 426 EXPECT_EQ(c_b_nva_->GetNativeObject(), x5_c_b_nva_->GetParent()); |
| 427 EXPECT_EQ(b_nva_->GetNativeObject(), d_b_nva_->GetParent()); |
| 428 EXPECT_EQ(b_nva_->GetNativeObject(), x2_b_nva_->GetParent()); |
| 429 EXPECT_EQ(a_root_->GetNativeViewAccessible(), x1_nva_->GetParent()); |
| 430 |
| 431 // Skips X1. |
| 432 EXPECT_EQ(a_root_->GetNativeViewAccessible(), x3_x1_nva_->GetParent()); |
| 433 EXPECT_EQ(a_root_->GetNativeViewAccessible(), x4_x1_nva_->GetParent()); |
| 434 EXPECT_EQ(a_root_->GetNativeViewAccessible(), e_x1_nva_->GetParent()); |
| 435 |
| 436 // Skips X3 and X1. |
| 437 EXPECT_EQ(a_root_->GetNativeViewAccessible(), f_x3_x1_nva_->GetParent()); |
| 438 } |
| 439 |
| 440 // Test that a11y hit tests work correctly with ignored elements. A hit on a |
| 441 // ignored element should return its first unignored ancestor. |
| 442 TEST_F(NativeViewAccessibilityBaseIgnoredElementsTest, HitTestSync) { |
| 443 // Move the hit point horizontally, incrementing by the leaf View width. |
| 444 const int min_width = a_root_->GetBoundsInScreen().width() / 6; |
| 445 int curr_x = a_root_->GetBoundsInScreen().x() + min_width / 2; |
| 446 const int y = a_root_->GetBoundsInScreen().CenterPoint().y(); |
| 447 |
| 448 // HitTestSync isn't recursive, so manually do the recursion until arriving at |
| 449 // the correct answer. I.e., the last NativeViewAccessible being tested for |
| 450 // each |curr_x|, |y| pair below would be the correct return value if |
| 451 // HitTestSync were recursive. |
| 452 EXPECT_EQ(b_nva_->GetNativeObject(), a_root_nva_->HitTestSync(curr_x, y)); |
| 453 EXPECT_EQ(c_b_nva_->GetNativeObject(), b_nva_->HitTestSync(curr_x, y)); |
| 454 EXPECT_EQ(c_b_nva_->GetNativeObject(), c_b_nva_->HitTestSync(curr_x, y)); |
| 455 curr_x += min_width; |
| 456 EXPECT_EQ(b_nva_->GetNativeObject(), a_root_nva_->HitTestSync(curr_x, y)); |
| 457 EXPECT_EQ(d_b_nva_->GetNativeObject(), b_nva_->HitTestSync(curr_x, y)); |
| 458 curr_x += min_width; |
| 459 EXPECT_EQ(b_nva_->GetNativeObject(), a_root_nva_->HitTestSync(curr_x, y)); |
| 460 EXPECT_EQ(b_nva_->GetNativeObject(), b_nva_->HitTestSync(curr_x, y)); |
| 461 curr_x += min_width; |
| 462 EXPECT_EQ(x1_nva_->GetNativeObject(), a_root_nva_->HitTestSync(curr_x, y)); |
| 463 EXPECT_EQ(x3_x1_nva_->GetNativeObject(), x1_nva_->HitTestSync(curr_x, y)); |
| 464 EXPECT_EQ(f_x3_x1_nva_->GetNativeObject(), |
| 465 x3_x1_nva_->HitTestSync(curr_x, y)); |
| 466 curr_x += min_width; |
| 467 EXPECT_EQ(x1_nva_->GetNativeObject(), a_root_nva_->HitTestSync(curr_x, y)); |
| 468 EXPECT_EQ(a_root_nva_->GetNativeObject(), x1_nva_->HitTestSync(curr_x, y)); |
| 469 curr_x += min_width; |
| 470 EXPECT_EQ(x1_nva_->GetNativeObject(), a_root_nva_->HitTestSync(curr_x, y)); |
| 471 EXPECT_EQ(e_x1_nva_->GetNativeObject(), x1_nva_->HitTestSync(curr_x, y)); |
| 472 } |
| 473 |
242 } // namespace test | 474 } // namespace test |
243 } // namespace views | 475 } // namespace views |
OLD | NEW |