| Index: ui/views/accessibility/native_view_accessibility_unittest.cc
|
| diff --git a/ui/views/accessibility/native_view_accessibility_unittest.cc b/ui/views/accessibility/native_view_accessibility_unittest.cc
|
| index 37435e205a1ebc3635ac2f8bc831bd657be62f4f..357377a253c888bf827988ac3255f9dc5c51abf4 100644
|
| --- a/ui/views/accessibility/native_view_accessibility_unittest.cc
|
| +++ b/ui/views/accessibility/native_view_accessibility_unittest.cc
|
| @@ -9,6 +9,7 @@
|
| #include "ui/views/controls/button/button.h"
|
| #include "ui/views/controls/label.h"
|
| #include "ui/views/test/views_test_base.h"
|
| +#include "ui/views/widget/widget.h"
|
|
|
| namespace views {
|
| namespace test {
|
| @@ -22,6 +23,20 @@ class TestButton : public Button {
|
| TestButton() : Button(NULL) {}
|
| };
|
|
|
| +// Helper to add new View with specific bounds and focusability to a parent.
|
| +View* AddNewChildWithBoundsAndFocusability(View& parent,
|
| + gfx::Rect bounds,
|
| + bool focusable) {
|
| + View* child = new View;
|
| + child->SetBounds(bounds.x(), bounds.y(), bounds.width(), bounds.height());
|
| + parent.AddChildView(child);
|
| + if (focusable)
|
| + child->SetFocusBehavior(ClientView::FocusBehavior::ACCESSIBLE_ONLY);
|
| + else
|
| + child->SetFocusBehavior(ClientView::FocusBehavior::NEVER);
|
| + return child;
|
| +}
|
| +
|
| } // namespace
|
|
|
| class NativeViewAccessibilityTest : public ViewsTestBase {
|
| @@ -31,40 +46,157 @@ class NativeViewAccessibilityTest : public ViewsTestBase {
|
|
|
| void SetUp() override {
|
| ViewsTestBase::SetUp();
|
| -
|
| - widget_ = new views::Widget;
|
| - views::Widget::InitParams params =
|
| - CreateParams(views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
|
| - params.bounds = gfx::Rect(0, 0, 200, 200);
|
| + widget_ = new Widget;
|
| + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
|
| + params.bounds = gfx::Rect(200, 50);
|
| widget_->Init(params);
|
|
|
| - button_ = new TestButton();
|
| - button_->SetSize(gfx::Size(20, 20));
|
| - button_accessibility_ = NativeViewAccessibility::Create(button_);
|
| + button_ = new TestButton;
|
| + button_accessibility_ = button_->GetNativeViewAccessibility();
|
|
|
| - label_ = new Label();
|
| + label_ = new Label;
|
| button_->AddChildView(label_);
|
| - label_accessibility_ = NativeViewAccessibility::Create(label_);
|
| + label_accessibility_ = label_->GetNativeViewAccessibility();
|
|
|
| - widget_->SetContentsView(button_);
|
| + // Make sure both views start off as non-leaf accessibility elements.
|
| + button_->SetFocusBehavior(ClientView::FocusBehavior::ACCESSIBLE_ONLY);
|
| + label_->SetFocusBehavior(ClientView::FocusBehavior::ACCESSIBLE_ONLY);
|
| + button_->SetSize(gfx::Size(200, 50));
|
| + label_->SetSize(gfx::Size(200, 50));
|
| +
|
| + widget_->GetContentsView()->AddChildView(button_);
|
| + widget_->Show();
|
| }
|
|
|
| void TearDown() override {
|
| - if (!widget_->IsClosed())
|
| - widget_->Close();
|
| - button_accessibility_->Destroy();
|
| - button_accessibility_ = NULL;
|
| - label_accessibility_->Destroy();
|
| - label_accessibility_ = NULL;
|
| + // Closing the Widget deletes child Views and their NativeViewAccessibility.
|
| + widget_->Close();
|
| + button_accessibility_ = nullptr;
|
| + label_accessibility_ = nullptr;
|
| ViewsTestBase::TearDown();
|
| }
|
|
|
| protected:
|
| - views::Widget* widget_;
|
| + Widget* widget_ = nullptr;
|
| TestButton* button_;
|
| NativeViewAccessibility* button_accessibility_;
|
| Label* label_;
|
| NativeViewAccessibility* label_accessibility_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(NativeViewAccessibilityTest);
|
| +};
|
| +
|
| +// Separate test class for a complicated test case for ignored accessibility
|
| +// elements.
|
| +class NativeViewAccessibilityIgnoredElementsTest : public ViewsTestBase {
|
| + public:
|
| + NativeViewAccessibilityIgnoredElementsTest() {}
|
| + ~NativeViewAccessibilityIgnoredElementsTest() override {}
|
| +
|
| + void SetUp() override {
|
| + ViewsTestBase::SetUp();
|
| + // Set up an accessibility tree like so (X should be ignored). So a Views
|
| + // hierarchy as shown on the left should expose the accessibility tree in
|
| + // the middle, and respond to hit tests as shown on the right.
|
| + //
|
| + // A A
|
| + // / \ / | \ +++---+---+---++---+---+---+++
|
| + // B X1 B F E ||| C | F | B || F | A | E |||
|
| + // / | \ / | \ / \ +++---+---+---++---+---+---+++
|
| + // C D X2 X3 X4 E C D
|
| + // | |
|
| + // X5 F
|
| + //
|
| + // Note: For hit tests, the parent's bounds will be divided equally amongst
|
| + // its children (including ignored elements). This means all Views belonging
|
| + // on the same level of the Views hierarchy will be the same size.
|
| + a_ = new View;
|
| + a_->SetSize(gfx::Size(400, 20));
|
| + a_->SetFocusBehavior(ClientView::FocusBehavior::ACCESSIBLE_ONLY);
|
| +
|
| + // Create Views in the left subtree from root |a_|.
|
| + gfx::Rect new_bounds(0, 0, a_->width() / 2, a_->height());
|
| + b_ = AddNewChildWithBoundsAndFocusability(*a_, new_bounds, true);
|
| + // |a_| has 6 leaves, so divvy up space equally between them for hit tests.
|
| + new_bounds = gfx::Rect(0, 0, a_->width() / 6, a_->height());
|
| + c_ = AddNewChildWithBoundsAndFocusability(*b_, new_bounds, true);
|
| + x5_ = AddNewChildWithBoundsAndFocusability(*c_, new_bounds, false);
|
| + // Update the |new_bounds| origin to position leaves next to each other.
|
| + new_bounds.set_x(new_bounds.x() + a_->width() / 6);
|
| + d_ = AddNewChildWithBoundsAndFocusability(*b_, new_bounds, true);
|
| + new_bounds.set_x(new_bounds.x() + a_->width() / 6);
|
| + x2_ = AddNewChildWithBoundsAndFocusability(*b_, new_bounds, false);
|
| + new_bounds.set_x(new_bounds.x() + a_->width() / 6);
|
| +
|
| + // Create Views in the right subtree from root |a_|.
|
| + new_bounds.set_size(b_->size());
|
| + x1_ = AddNewChildWithBoundsAndFocusability(*a_, new_bounds, false);
|
| + new_bounds.set_origin(gfx::Point());
|
| + x3_ = AddNewChildWithBoundsAndFocusability(*x1_, new_bounds, false);
|
| + f_ = AddNewChildWithBoundsAndFocusability(*x3_, new_bounds, true);
|
| + new_bounds.set_x(new_bounds.x() + a_->width() / 6);
|
| + x4_ = AddNewChildWithBoundsAndFocusability(*x1_, new_bounds, false);
|
| + new_bounds.set_x(new_bounds.x() + a_->width() / 6);
|
| + e_ = AddNewChildWithBoundsAndFocusability(*x1_, new_bounds, true);
|
| +
|
| + // Populate NativeViewAccessibility instances for convenience.
|
| + a_ax_ = a_->GetNativeViewAccessibility();
|
| + b_ax_ = b_->GetNativeViewAccessibility();
|
| + c_ax_ = c_->GetNativeViewAccessibility();
|
| + d_ax_ = d_->GetNativeViewAccessibility();
|
| + e_ax_ = e_->GetNativeViewAccessibility();
|
| + f_ax_ = f_->GetNativeViewAccessibility();
|
| + x1_ax_ = x1_->GetNativeViewAccessibility();
|
| + x2_ax_ = x2_->GetNativeViewAccessibility();
|
| + x3_ax_ = x3_->GetNativeViewAccessibility();
|
| + x4_ax_ = x4_->GetNativeViewAccessibility();
|
| + x5_ax_ = x5_->GetNativeViewAccessibility();
|
| +
|
| + // Add everything to a new widget, needed for hit testing and parent tests.
|
| + widget_ = new Widget;
|
| + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
|
| + widget_->Init(params);
|
| + widget_->GetContentsView()->AddChildView(a_);
|
| + widget_->Show();
|
| + }
|
| +
|
| + void TearDown() override {
|
| + widget_->Close();
|
| + ViewsTestBase::TearDown();
|
| + }
|
| +
|
| + protected:
|
| + // Don't use std::unique_ptr for the following Views - everything will be
|
| + // inside a widget, which will handle their deletion.
|
| + View* a_;
|
| + View* b_;
|
| + View* c_;
|
| + View* d_;
|
| + View* e_;
|
| + View* f_;
|
| + View* x1_;
|
| + View* x2_;
|
| + View* x3_;
|
| + View* x4_;
|
| + View* x5_;
|
| +
|
| + // Destroyed when the View they are attached to is destroyed.
|
| + NativeViewAccessibility* a_ax_;
|
| + NativeViewAccessibility* b_ax_;
|
| + NativeViewAccessibility* c_ax_;
|
| + NativeViewAccessibility* d_ax_;
|
| + NativeViewAccessibility* e_ax_;
|
| + NativeViewAccessibility* f_ax_;
|
| + NativeViewAccessibility* x1_ax_;
|
| + NativeViewAccessibility* x2_ax_;
|
| + NativeViewAccessibility* x3_ax_;
|
| + NativeViewAccessibility* x4_ax_;
|
| + NativeViewAccessibility* x5_ax_;
|
| +
|
| + Widget* widget_ = nullptr;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(NativeViewAccessibilityIgnoredElementsTest);
|
| };
|
|
|
| TEST_F(NativeViewAccessibilityTest, RoleShouldMatch) {
|
| @@ -85,6 +217,139 @@ TEST_F(NativeViewAccessibilityTest, LabelIsChildOfButton) {
|
| button_accessibility_->ChildAtIndex(0));
|
| EXPECT_EQ(button_->GetNativeViewAccessible(),
|
| label_accessibility_->GetParent());
|
| +
|
| + // Indicate the button should be a leaf node by ignoring the label.
|
| + label_->SetFocusBehavior(ClientView::FocusBehavior::NEVER);
|
| + EXPECT_EQ(button_, label_->parent());
|
| + EXPECT_EQ(0, button_accessibility_->GetChildCount());
|
| + EXPECT_EQ(nullptr, button_accessibility_->ChildAtIndex(0));
|
| +
|
| + // Check this is still true even with a child inside the label.
|
| + View* label_child = AddNewChildWithBoundsAndFocusability(
|
| + *label_, label_->GetBoundsInScreen(), true);
|
| + EXPECT_EQ(1, button_accessibility_->GetChildCount());
|
| + EXPECT_EQ(label_child->GetNativeViewAccessible(),
|
| + button_accessibility_->ChildAtIndex(0));
|
| +
|
| + label_child->SetFocusBehavior(ClientView::FocusBehavior::NEVER);
|
| + EXPECT_EQ(0, button_accessibility_->GetChildCount());
|
| + EXPECT_EQ(nullptr, button_accessibility_->ChildAtIndex(0));
|
| +}
|
| +
|
| +TEST_F(NativeViewAccessibilityIgnoredElementsTest, GetChildCount) {
|
| + EXPECT_EQ(3, a_ax_->GetChildCount());
|
| + EXPECT_EQ(2, b_ax_->GetChildCount());
|
| + EXPECT_EQ(0, c_ax_->GetChildCount());
|
| + EXPECT_EQ(0, x5_ax_->GetChildCount());
|
| + EXPECT_EQ(0, d_ax_->GetChildCount());
|
| + EXPECT_EQ(0, x2_ax_->GetChildCount());
|
| + EXPECT_EQ(2, x1_ax_->GetChildCount());
|
| + EXPECT_EQ(1, x3_ax_->GetChildCount());
|
| + EXPECT_EQ(0, f_ax_->GetChildCount());
|
| + EXPECT_EQ(0, x4_ax_->GetChildCount());
|
| + EXPECT_EQ(0, e_ax_->GetChildCount());
|
| +}
|
| +
|
| +TEST_F(NativeViewAccessibilityIgnoredElementsTest, ChildAtIndex) {
|
| + EXPECT_EQ(b_->GetNativeViewAccessible(), a_ax_->ChildAtIndex(0));
|
| + EXPECT_EQ(f_->GetNativeViewAccessible(), a_ax_->ChildAtIndex(1));
|
| + EXPECT_EQ(e_->GetNativeViewAccessible(), a_ax_->ChildAtIndex(2));
|
| + EXPECT_EQ(nullptr, a_ax_->ChildAtIndex(3));
|
| +
|
| + EXPECT_EQ(c_->GetNativeViewAccessible(), b_ax_->ChildAtIndex(0));
|
| + EXPECT_EQ(d_->GetNativeViewAccessible(), b_ax_->ChildAtIndex(1));
|
| + EXPECT_EQ(nullptr, b_ax_->ChildAtIndex(2));
|
| +
|
| + EXPECT_EQ(f_->GetNativeViewAccessible(), x1_ax_->ChildAtIndex(0));
|
| + EXPECT_EQ(e_->GetNativeViewAccessible(), x1_ax_->ChildAtIndex(1));
|
| + EXPECT_EQ(nullptr, x1_ax_->ChildAtIndex(2));
|
| +
|
| + EXPECT_EQ(f_->GetNativeViewAccessible(), x3_ax_->ChildAtIndex(0));
|
| +
|
| + // Node with ignored children.
|
| + EXPECT_EQ(nullptr, c_ax_->ChildAtIndex(0));
|
| + // Node with 0 children.
|
| + EXPECT_EQ(nullptr, d_ax_->ChildAtIndex(0));
|
| + // Ignored node with 0 children.
|
| + EXPECT_EQ(nullptr, x2_ax_->ChildAtIndex(0));
|
| +}
|
| +
|
| +TEST_F(NativeViewAccessibilityIgnoredElementsTest, GetParent) {
|
| +#if defined(OS_MACOSX)
|
| + // Only Mac is set up to return the native view going up to the Widget-level.
|
| + EXPECT_EQ(widget_->GetNativeView(), a_ax_->GetParent());
|
| +#else
|
| + EXPECT_EQ(nullptr, a_ax_->GetParent());
|
| +#endif
|
| + EXPECT_EQ(a_->GetNativeViewAccessible(), b_ax_->GetParent());
|
| + EXPECT_EQ(b_->GetNativeViewAccessible(), c_ax_->GetParent());
|
| + EXPECT_EQ(c_->GetNativeViewAccessible(), x5_ax_->GetParent());
|
| + EXPECT_EQ(b_->GetNativeViewAccessible(), d_ax_->GetParent());
|
| + EXPECT_EQ(b_->GetNativeViewAccessible(), x2_ax_->GetParent());
|
| +
|
| + EXPECT_EQ(a_->GetNativeViewAccessible(), x1_ax_->GetParent());
|
| + EXPECT_EQ(a_->GetNativeViewAccessible(), x3_ax_->GetParent());
|
| + EXPECT_EQ(a_->GetNativeViewAccessible(), x4_ax_->GetParent());
|
| + EXPECT_EQ(a_->GetNativeViewAccessible(), e_ax_->GetParent());
|
| + EXPECT_EQ(a_->GetNativeViewAccessible(), f_ax_->GetParent());
|
| +}
|
| +
|
| +TEST_F(NativeViewAccessibilityIgnoredElementsTest, IsLeafElement) {
|
| + EXPECT_FALSE(a_ax_->IsLeafElement());
|
| + EXPECT_FALSE(b_ax_->IsLeafElement());
|
| + EXPECT_TRUE(c_ax_->IsLeafElement());
|
| + EXPECT_TRUE(d_ax_->IsLeafElement());
|
| + EXPECT_TRUE(e_ax_->IsLeafElement());
|
| + EXPECT_TRUE(f_ax_->IsLeafElement());
|
| + EXPECT_FALSE(x1_ax_->IsLeafElement());
|
| + EXPECT_TRUE(x2_ax_->IsLeafElement());
|
| + EXPECT_FALSE(x3_ax_->IsLeafElement());
|
| + EXPECT_TRUE(x4_ax_->IsLeafElement());
|
| + EXPECT_TRUE(x5_ax_->IsLeafElement());
|
| +}
|
| +
|
| +TEST_F(NativeViewAccessibilityIgnoredElementsTest, HitTestSync) {
|
| + // Move the hit point horizontally, incrementing by the leaf View width.
|
| + int min_width = a_->GetBoundsInScreen().width() / 6;
|
| + int curr_x = a_->GetBoundsInScreen().x() + min_width / 2;
|
| + const int y = a_->GetBoundsInScreen().CenterPoint().y();
|
| +
|
| + // HitTestSync isn't recursive, so manually do the recursion until arriving at
|
| + // the correct answer. I.e., the last NativeViewAccessible being tested for
|
| + // each |curr_x|, |y| pair below would be the correct return value if
|
| + // HitTestSync were recursive.
|
| + EXPECT_EQ(b_->GetNativeViewAccessible(), a_ax_->HitTestSync(curr_x, y));
|
| + EXPECT_EQ(c_->GetNativeViewAccessible(), b_ax_->HitTestSync(curr_x, y));
|
| + EXPECT_EQ(c_->GetNativeViewAccessible(), c_ax_->HitTestSync(curr_x, y));
|
| + curr_x += min_width;
|
| + EXPECT_EQ(b_->GetNativeViewAccessible(), a_ax_->HitTestSync(curr_x, y));
|
| + EXPECT_EQ(d_->GetNativeViewAccessible(), b_ax_->HitTestSync(curr_x, y));
|
| + curr_x += min_width;
|
| + EXPECT_EQ(b_->GetNativeViewAccessible(), a_ax_->HitTestSync(curr_x, y));
|
| + EXPECT_EQ(x2_->GetNativeViewAccessible(), b_ax_->HitTestSync(curr_x, y));
|
| + EXPECT_EQ(b_->GetNativeViewAccessible(), x2_ax_->HitTestSync(curr_x, y));
|
| + curr_x += min_width;
|
| + EXPECT_EQ(x1_->GetNativeViewAccessible(), a_ax_->HitTestSync(curr_x, y));
|
| + EXPECT_EQ(x3_->GetNativeViewAccessible(), x1_ax_->HitTestSync(curr_x, y));
|
| + EXPECT_EQ(f_->GetNativeViewAccessible(), x3_ax_->HitTestSync(curr_x, y));
|
| + curr_x += min_width;
|
| + EXPECT_EQ(x1_->GetNativeViewAccessible(), a_ax_->HitTestSync(curr_x, y));
|
| + EXPECT_EQ(x4_->GetNativeViewAccessible(), x1_ax_->HitTestSync(curr_x, y));
|
| + EXPECT_EQ(a_->GetNativeViewAccessible(), x4_ax_->HitTestSync(curr_x, y));
|
| + curr_x += min_width;
|
| + EXPECT_EQ(x1_->GetNativeViewAccessible(), a_ax_->HitTestSync(curr_x, y));
|
| + EXPECT_EQ(e_->GetNativeViewAccessible(), x1_ax_->HitTestSync(curr_x, y));
|
| +
|
| + // The Widget should be revealed if |e_| and |a_| are ignored.
|
| + a_->SetFocusBehavior(ClientView::FocusBehavior::NEVER);
|
| + e_->SetFocusBehavior(ClientView::FocusBehavior::NEVER);
|
| + EXPECT_EQ(x1_->GetNativeViewAccessible(), a_ax_->HitTestSync(curr_x, y));
|
| + EXPECT_EQ(e_->GetNativeViewAccessible(), x1_ax_->HitTestSync(curr_x, y));
|
| +#if defined(OS_MACOSX)
|
| + EXPECT_EQ(widget_->GetNativeView(), e_ax_->HitTestSync(curr_x, y));
|
| +#else
|
| + EXPECT_EQ(nullptr, e_ax_->HitTestSync(curr_x, y));
|
| +#endif
|
| }
|
|
|
| // Subclass of NativeViewAccessibility that destroys itself when its
|
|
|