blob: 0a88e411bc0efe11607b8cbbadcdaefd316b9975 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/accessibility/ax_virtual_view.h"
#include "base/memory/ptr_util.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/accessibility/view_ax_platform_node_delegate.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
namespace views {
namespace test {
namespace {
class TestButton : public Button {
public:
TestButton() : Button(NULL) {}
~TestButton() override = default;
private:
DISALLOW_COPY_AND_ASSIGN(TestButton);
};
} // namespace
class AXVirtualViewTest : public ViewsTestBase {
public:
AXVirtualViewTest() = default;
~AXVirtualViewTest() override = default;
void SetUp() override {
ViewsTestBase::SetUp();
widget_ = new Widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.bounds = gfx::Rect(0, 0, 200, 200);
widget_->Init(params);
button_ = new TestButton;
button_->SetSize(gfx::Size(20, 20));
widget_->GetContentsView()->AddChildView(button_);
virtual_label_ = new AXVirtualView;
virtual_label_->GetCustomData().role = ax::mojom::Role::kStaticText;
virtual_label_->GetCustomData().SetName("Label");
button_->GetViewAccessibility().AddVirtualChildView(
base::WrapUnique(virtual_label_));
widget_->Show();
}
void TearDown() override {
if (!widget_->IsClosed())
widget_->Close();
ViewsTestBase::TearDown();
}
ViewAXPlatformNodeDelegate* GetButtonAccessibility() {
return static_cast<ViewAXPlatformNodeDelegate*>(
&button_->GetViewAccessibility());
}
protected:
Widget* widget_;
Button* button_;
// Weak, |button_| owns this.
AXVirtualView* virtual_label_;
private:
DISALLOW_COPY_AND_ASSIGN(AXVirtualViewTest);
};
TEST_F(AXVirtualViewTest, AccessibilityRoleAndName) {
EXPECT_EQ(ax::mojom::Role::kButton, GetButtonAccessibility()->GetData().role);
EXPECT_EQ(ax::mojom::Role::kStaticText, virtual_label_->GetData().role);
EXPECT_EQ("Label", virtual_label_->GetData().GetStringAttribute(
ax::mojom::StringAttribute::kName));
}
// The focusable state of a virtual view should not depend on the focusable
// state of the real view ancestor, however the enabled state should.
TEST_F(AXVirtualViewTest, FocusableAndEnabledState) {
virtual_label_->GetCustomData().AddState(ax::mojom::State::kFocusable);
EXPECT_TRUE(GetButtonAccessibility()->GetData().HasState(
ax::mojom::State::kFocusable));
EXPECT_TRUE(virtual_label_->GetData().HasState(ax::mojom::State::kFocusable));
EXPECT_EQ(ax::mojom::Restriction::kNone,
GetButtonAccessibility()->GetData().GetRestriction());
EXPECT_EQ(ax::mojom::Restriction::kNone,
virtual_label_->GetData().GetRestriction());
button_->SetFocusBehavior(View::FocusBehavior::NEVER);
EXPECT_FALSE(GetButtonAccessibility()->GetData().HasState(
ax::mojom::State::kFocusable));
EXPECT_TRUE(virtual_label_->GetData().HasState(ax::mojom::State::kFocusable));
EXPECT_EQ(ax::mojom::Restriction::kNone,
GetButtonAccessibility()->GetData().GetRestriction());
EXPECT_EQ(ax::mojom::Restriction::kNone,
virtual_label_->GetData().GetRestriction());
button_->SetEnabled(false);
EXPECT_FALSE(GetButtonAccessibility()->GetData().HasState(
ax::mojom::State::kFocusable));
EXPECT_TRUE(virtual_label_->GetData().HasState(ax::mojom::State::kFocusable));
EXPECT_EQ(ax::mojom::Restriction::kDisabled,
GetButtonAccessibility()->GetData().GetRestriction());
EXPECT_EQ(ax::mojom::Restriction::kDisabled,
virtual_label_->GetData().GetRestriction());
button_->SetEnabled(true);
button_->SetFocusBehavior(View::FocusBehavior::ALWAYS);
virtual_label_->GetCustomData().RemoveState(ax::mojom::State::kFocusable);
EXPECT_TRUE(GetButtonAccessibility()->GetData().HasState(
ax::mojom::State::kFocusable));
EXPECT_FALSE(
virtual_label_->GetData().HasState(ax::mojom::State::kFocusable));
EXPECT_EQ(ax::mojom::Restriction::kNone,
GetButtonAccessibility()->GetData().GetRestriction());
EXPECT_EQ(ax::mojom::Restriction::kNone,
virtual_label_->GetData().GetRestriction());
}
TEST_F(AXVirtualViewTest, VirtualLabelIsChildOfButton) {
EXPECT_EQ(1, GetButtonAccessibility()->GetChildCount());
EXPECT_EQ(0, virtual_label_->GetChildCount());
ASSERT_NE(nullptr, virtual_label_->GetParent());
EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_label_->GetParent());
ASSERT_NE(nullptr, GetButtonAccessibility()->ChildAtIndex(0));
EXPECT_EQ(virtual_label_->GetNativeObject(),
GetButtonAccessibility()->ChildAtIndex(0));
}
TEST_F(AXVirtualViewTest, AddingAndRemovingVirtualChildren) {
ASSERT_EQ(0, virtual_label_->GetChildCount());
AXVirtualView* virtual_child_1 = new AXVirtualView;
virtual_label_->AddChildView(base::WrapUnique(virtual_child_1));
EXPECT_EQ(1, virtual_label_->GetChildCount());
ASSERT_NE(nullptr, virtual_child_1->GetParent());
EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_1->GetParent());
ASSERT_NE(nullptr, virtual_label_->ChildAtIndex(0));
EXPECT_EQ(virtual_child_1->GetNativeObject(),
virtual_label_->ChildAtIndex(0));
AXVirtualView* virtual_child_2 = new AXVirtualView;
virtual_label_->AddChildView(base::WrapUnique(virtual_child_2));
EXPECT_EQ(2, virtual_label_->GetChildCount());
ASSERT_NE(nullptr, virtual_child_2->GetParent());
EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_2->GetParent());
ASSERT_NE(nullptr, virtual_label_->ChildAtIndex(1));
EXPECT_EQ(virtual_child_2->GetNativeObject(),
virtual_label_->ChildAtIndex(1));
AXVirtualView* virtual_child_3 = new AXVirtualView;
virtual_child_2->AddChildView(base::WrapUnique(virtual_child_3));
EXPECT_EQ(2, virtual_label_->GetChildCount());
EXPECT_EQ(0, virtual_child_1->GetChildCount());
EXPECT_EQ(1, virtual_child_2->GetChildCount());
ASSERT_NE(nullptr, virtual_child_3->GetParent());
EXPECT_EQ(virtual_child_2->GetNativeObject(), virtual_child_3->GetParent());
ASSERT_NE(nullptr, virtual_child_2->ChildAtIndex(0));
EXPECT_EQ(virtual_child_3->GetNativeObject(),
virtual_child_2->ChildAtIndex(0));
virtual_child_2->RemoveChildView(virtual_child_3);
EXPECT_EQ(0, virtual_child_2->GetChildCount());
EXPECT_EQ(2, virtual_label_->GetChildCount());
virtual_label_->RemoveAllChildViews();
EXPECT_EQ(0, virtual_label_->GetChildCount());
}
TEST_F(AXVirtualViewTest, ReorderingVirtualChildren) {
ASSERT_EQ(0, virtual_label_->GetChildCount());
AXVirtualView* virtual_child_1 = new AXVirtualView;
virtual_label_->AddChildView(base::WrapUnique(virtual_child_1));
ASSERT_EQ(1, virtual_label_->GetChildCount());
AXVirtualView* virtual_child_2 = new AXVirtualView;
virtual_label_->AddChildView(base::WrapUnique(virtual_child_2));
ASSERT_EQ(2, virtual_label_->GetChildCount());
virtual_label_->ReorderChildView(virtual_child_1, -1);
ASSERT_EQ(2, virtual_label_->GetChildCount());
EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_2->GetParent());
ASSERT_NE(nullptr, virtual_label_->ChildAtIndex(0));
EXPECT_EQ(virtual_child_2->GetNativeObject(),
virtual_label_->ChildAtIndex(0));
ASSERT_NE(nullptr, virtual_label_->ChildAtIndex(1));
EXPECT_EQ(virtual_child_1->GetNativeObject(),
virtual_label_->ChildAtIndex(1));
virtual_label_->ReorderChildView(virtual_child_1, 0);
ASSERT_EQ(2, virtual_label_->GetChildCount());
EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_1->GetParent());
ASSERT_NE(nullptr, virtual_label_->ChildAtIndex(0));
EXPECT_EQ(virtual_child_1->GetNativeObject(),
virtual_label_->ChildAtIndex(0));
ASSERT_NE(nullptr, virtual_label_->ChildAtIndex(1));
EXPECT_EQ(virtual_child_2->GetNativeObject(),
virtual_label_->ChildAtIndex(1));
virtual_label_->RemoveAllChildViews();
ASSERT_EQ(0, virtual_label_->GetChildCount());
}
TEST_F(AXVirtualViewTest, ContainsVirtualChild) {
ASSERT_EQ(0, virtual_label_->GetChildCount());
AXVirtualView* virtual_child_1 = new AXVirtualView;
virtual_label_->AddChildView(base::WrapUnique(virtual_child_1));
ASSERT_EQ(1, virtual_label_->GetChildCount());
AXVirtualView* virtual_child_2 = new AXVirtualView;
virtual_label_->AddChildView(base::WrapUnique(virtual_child_2));
ASSERT_EQ(2, virtual_label_->GetChildCount());
AXVirtualView* virtual_child_3 = new AXVirtualView;
virtual_child_2->AddChildView(base::WrapUnique(virtual_child_3));
ASSERT_EQ(1, virtual_child_2->GetChildCount());
EXPECT_TRUE(button_->GetViewAccessibility().Contains(virtual_label_));
EXPECT_TRUE(virtual_label_->Contains(virtual_label_));
EXPECT_TRUE(virtual_label_->Contains(virtual_child_1));
EXPECT_TRUE(virtual_label_->Contains(virtual_child_2));
EXPECT_TRUE(virtual_label_->Contains(virtual_child_3));
EXPECT_TRUE(virtual_child_2->Contains(virtual_child_2));
EXPECT_TRUE(virtual_child_2->Contains(virtual_child_3));
EXPECT_FALSE(virtual_child_1->Contains(virtual_label_));
EXPECT_FALSE(virtual_child_2->Contains(virtual_label_));
EXPECT_FALSE(virtual_child_3->Contains(virtual_child_2));
virtual_label_->RemoveAllChildViews();
ASSERT_EQ(0, virtual_label_->GetChildCount());
}
TEST_F(AXVirtualViewTest, GetIndexOfVirtualChild) {
ASSERT_EQ(0, virtual_label_->GetChildCount());
AXVirtualView* virtual_child_1 = new AXVirtualView;
virtual_label_->AddChildView(base::WrapUnique(virtual_child_1));
ASSERT_EQ(1, virtual_label_->GetChildCount());
AXVirtualView* virtual_child_2 = new AXVirtualView;
virtual_label_->AddChildView(base::WrapUnique(virtual_child_2));
ASSERT_EQ(2, virtual_label_->GetChildCount());
AXVirtualView* virtual_child_3 = new AXVirtualView;
virtual_child_2->AddChildView(base::WrapUnique(virtual_child_3));
ASSERT_EQ(1, virtual_child_2->GetChildCount());
EXPECT_EQ(-1, virtual_label_->GetIndexOf(virtual_label_));
EXPECT_EQ(0, virtual_label_->GetIndexOf(virtual_child_1));
EXPECT_EQ(1, virtual_label_->GetIndexOf(virtual_child_2));
EXPECT_EQ(-1, virtual_label_->GetIndexOf(virtual_child_3));
EXPECT_EQ(0, virtual_child_2->GetIndexOf(virtual_child_3));
virtual_label_->RemoveAllChildViews();
ASSERT_EQ(0, virtual_label_->GetChildCount());
}
// Verify that virtual views with invisible ancestors inherit the
// ax::mojom::State::kInvisible state.
TEST_F(AXVirtualViewTest, InvisibleVirtualViews) {
EXPECT_TRUE(widget_->IsVisible());
EXPECT_FALSE(GetButtonAccessibility()->GetData().HasState(
ax::mojom::State::kInvisible));
EXPECT_FALSE(
virtual_label_->GetData().HasState(ax::mojom::State::kInvisible));
button_->SetVisible(false);
EXPECT_TRUE(GetButtonAccessibility()->GetData().HasState(
ax::mojom::State::kInvisible));
EXPECT_TRUE(virtual_label_->GetData().HasState(ax::mojom::State::kInvisible));
button_->SetVisible(true);
}
TEST_F(AXVirtualViewTest, OverrideFocus) {
ViewAccessibility& button_accessibility = button_->GetViewAccessibility();
ASSERT_NE(nullptr, button_accessibility.GetNativeObject());
ASSERT_NE(nullptr, virtual_label_->GetNativeObject());
EXPECT_EQ(button_accessibility.GetNativeObject(),
button_accessibility.GetFocusedDescendant());
button_accessibility.OverrideFocus(virtual_label_);
EXPECT_EQ(virtual_label_->GetNativeObject(),
button_accessibility.GetFocusedDescendant());
button_accessibility.OverrideFocus(nullptr);
EXPECT_EQ(button_accessibility.GetNativeObject(),
button_accessibility.GetFocusedDescendant());
ASSERT_EQ(0, virtual_label_->GetChildCount());
AXVirtualView* virtual_child_1 = new AXVirtualView;
virtual_label_->AddChildView(base::WrapUnique(virtual_child_1));
ASSERT_EQ(1, virtual_label_->GetChildCount());
AXVirtualView* virtual_child_2 = new AXVirtualView;
virtual_label_->AddChildView(base::WrapUnique(virtual_child_2));
ASSERT_EQ(2, virtual_label_->GetChildCount());
button_accessibility.OverrideFocus(virtual_child_1);
EXPECT_EQ(virtual_child_1->GetNativeObject(),
button_accessibility.GetFocusedDescendant());
AXVirtualView* virtual_child_3 = new AXVirtualView;
virtual_child_2->AddChildView(base::WrapUnique(virtual_child_3));
ASSERT_EQ(1, virtual_child_2->GetChildCount());
EXPECT_EQ(virtual_child_1->GetNativeObject(),
button_accessibility.GetFocusedDescendant());
button_accessibility.OverrideFocus(virtual_child_3);
EXPECT_EQ(virtual_child_3->GetNativeObject(),
button_accessibility.GetFocusedDescendant());
// Test that calling GetFocus() from any object in the tree will return the
// same result.
EXPECT_EQ(virtual_child_3->GetNativeObject(), virtual_label_->GetFocus());
EXPECT_EQ(virtual_child_3->GetNativeObject(), virtual_child_1->GetFocus());
EXPECT_EQ(virtual_child_3->GetNativeObject(), virtual_child_2->GetFocus());
EXPECT_EQ(virtual_child_3->GetNativeObject(), virtual_child_3->GetFocus());
virtual_label_->RemoveChildView(virtual_child_2);
ASSERT_EQ(1, virtual_label_->GetChildCount());
EXPECT_EQ(button_accessibility.GetNativeObject(),
button_accessibility.GetFocusedDescendant());
EXPECT_EQ(button_accessibility.GetNativeObject(), virtual_label_->GetFocus());
EXPECT_EQ(button_accessibility.GetNativeObject(),
virtual_child_1->GetFocus());
button_accessibility.OverrideFocus(virtual_child_1);
EXPECT_EQ(virtual_child_1->GetNativeObject(),
button_accessibility.GetFocusedDescendant());
virtual_label_->RemoveAllChildViews();
ASSERT_EQ(0, virtual_label_->GetChildCount());
EXPECT_EQ(button_accessibility.GetNativeObject(),
button_accessibility.GetFocusedDescendant());
}
} // namespace test
} // namespace views