blob: d3a340c312ba9caa8eaefa458da07b240c305897 [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/accessibility/platform/one_shot_accessibility_tree_search.h"
#include <memory>
#include "build/build_config.h"
#include "ui/accessibility/platform/browser_accessibility.h"
#include "ui/accessibility/platform/browser_accessibility_manager.h"
#if BUILDFLAG(IS_ANDROID)
#include "content/browser/accessibility/browser_accessibility_manager_android.h"
#elif OS_FUCHSIA
#include "ui/accessibility/platform/fuchsia/browser_accessibility_manager_fuchsia.h"
#endif
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/platform/test_ax_node_id_delegate.h"
namespace content {
namespace {
#if BUILDFLAG(IS_ANDROID)
class TestBrowserAccessibilityManager
: public BrowserAccessibilityManagerAndroid {
public:
explicit TestBrowserAccessibilityManager(
const ui::AXTreeUpdate& initial_tree,
ui::AXNodeIdDelegate& node_id_delegate)
: BrowserAccessibilityManagerAndroid(initial_tree,
nullptr,
node_id_delegate,
nullptr) {}
};
#elif OS_FUCHSIA
class TestBrowserAccessibilityManager
: public ui::BrowserAccessibilityManagerFuchsia {
public:
explicit TestBrowserAccessibilityManager(
const ui::AXTreeUpdate& initial_tree,
ui::AXNodeIdDelegate& node_id_delegate)
: BrowserAccessibilityManagerFuchsia(initial_tree,
node_id_delegate,
nullptr) {}
};
#else
class TestBrowserAccessibilityManager : public ui::BrowserAccessibilityManager {
public:
explicit TestBrowserAccessibilityManager(
const ui::AXTreeUpdate& initial_tree,
ui::AXNodeIdDelegate& node_id_delegate)
: BrowserAccessibilityManager(node_id_delegate, nullptr) {
Initialize(initial_tree);
}
};
#endif
} // namespace
class OneShotAccessibilityTreeSearchTest : public testing::Test {
public:
OneShotAccessibilityTreeSearchTest() = default;
OneShotAccessibilityTreeSearchTest(
const OneShotAccessibilityTreeSearchTest&) = delete;
OneShotAccessibilityTreeSearchTest& operator=(
const OneShotAccessibilityTreeSearchTest&) = delete;
~OneShotAccessibilityTreeSearchTest() override = default;
protected:
void SetUp() override;
BrowserTaskEnvironment task_environment_;
ui::TestAXNodeIdDelegate node_id_delegate_;
std::unique_ptr<ui::BrowserAccessibilityManager> tree_;
};
void OneShotAccessibilityTreeSearchTest::SetUp() {
ui::AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
root.SetName("Document");
root.relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
root.AddBoolAttribute(ax::mojom::BoolAttribute::kClipsChildren, true);
ui::AXNodeData heading;
heading.id = 2;
heading.role = ax::mojom::Role::kHeading;
heading.SetName("Heading");
heading.relative_bounds.bounds = gfx::RectF(0, 0, 800, 50);
ui::AXNodeData table;
table.id = 3;
table.role = ax::mojom::Role::kTable;
table.AddIntAttribute(ax::mojom::IntAttribute::kTableRowCount, 1);
table.AddIntAttribute(ax::mojom::IntAttribute::kTableColumnCount, 2);
ui::AXNodeData table_row;
table_row.id = 4;
table_row.role = ax::mojom::Role::kRow;
table_row.AddIntAttribute(ax::mojom::IntAttribute::kTableRowIndex, 0);
ui::AXNodeData table_column_header_1;
table_column_header_1.id = 5;
table_column_header_1.role = ax::mojom::Role::kColumnHeader;
table_column_header_1.SetName("Cell1");
table_column_header_1.AddIntAttribute(
ax::mojom::IntAttribute::kTableCellRowIndex, 0);
table_column_header_1.AddIntAttribute(
ax::mojom::IntAttribute::kTableCellColumnIndex, 0);
ui::AXNodeData table_column_header_2;
table_column_header_2.id = 6;
table_column_header_2.role = ax::mojom::Role::kColumnHeader;
table_column_header_2.SetName("Cell2");
table_column_header_2.AddIntAttribute(
ax::mojom::IntAttribute::kTableCellRowIndex, 0);
table_column_header_2.AddIntAttribute(
ax::mojom::IntAttribute::kTableCellColumnIndex, 1);
ui::AXNodeData list;
list.id = 7;
list.role = ax::mojom::Role::kList;
list.relative_bounds.bounds = gfx::RectF(0, 50, 500, 500);
ui::AXNodeData list_item_1;
list_item_1.id = 8;
list_item_1.role = ax::mojom::Role::kListItem;
list_item_1.SetName("Autobots");
list_item_1.relative_bounds.bounds = gfx::RectF(10, 10, 200, 30);
ui::AXNodeData list_item_2;
list_item_2.id = 9;
list_item_2.role = ax::mojom::Role::kListItem;
list_item_2.SetName("Decepticons");
list_item_2.relative_bounds.bounds = gfx::RectF(10, 40, 200, 60);
ui::AXNodeData footer;
footer.id = 10;
footer.role = ax::mojom::Role::kFooter;
footer.SetName("Footer");
footer.relative_bounds.bounds = gfx::RectF(0, 650, 100, 800);
table_row.child_ids = {table_column_header_1.id, table_column_header_2.id};
table.child_ids = {table_row.id};
list.child_ids = {list_item_1.id, list_item_2.id};
root.child_ids = {heading.id, table.id, list.id, footer.id};
tree_ = std::make_unique<TestBrowserAccessibilityManager>(
MakeAXTreeUpdateForTesting(root, heading, table, table_row,
table_column_header_1, table_column_header_2,
list, list_item_1, list_item_2, footer),
node_id_delegate_);
}
TEST_F(OneShotAccessibilityTreeSearchTest, GetAll) {
ui::OneShotAccessibilityTreeSearch search(
tree_->GetBrowserAccessibilityRoot());
#if BUILDFLAG(IS_MAC)
ASSERT_EQ(13U, search.CountMatches());
#else
ASSERT_EQ(10U, search.CountMatches());
#endif
}
TEST_F(OneShotAccessibilityTreeSearchTest, BackwardsWrapFromRoot) {
ui::OneShotAccessibilityTreeSearch search(
tree_->GetBrowserAccessibilityRoot());
search.SetDirection(ui::OneShotAccessibilityTreeSearch::BACKWARDS);
search.SetResultLimit(100);
search.SetCanWrapToLastElement(true);
#if BUILDFLAG(IS_MAC)
ASSERT_EQ(13U, search.CountMatches());
#else
ASSERT_EQ(10U, search.CountMatches());
#endif
EXPECT_EQ(1, search.GetMatchAtIndex(0)->GetId());
EXPECT_EQ(10, search.GetMatchAtIndex(1)->GetId());
EXPECT_EQ(9, search.GetMatchAtIndex(2)->GetId());
EXPECT_EQ(8, search.GetMatchAtIndex(3)->GetId());
EXPECT_EQ(7, search.GetMatchAtIndex(4)->GetId());
#if BUILDFLAG(IS_MAC)
EXPECT_EQ(-3, search.GetMatchAtIndex(5)->GetId());
EXPECT_EQ(-2, search.GetMatchAtIndex(6)->GetId());
EXPECT_EQ(-1, search.GetMatchAtIndex(7)->GetId());
EXPECT_EQ(6, search.GetMatchAtIndex(8)->GetId());
EXPECT_EQ(5, search.GetMatchAtIndex(9)->GetId());
EXPECT_EQ(4, search.GetMatchAtIndex(10)->GetId());
EXPECT_EQ(3, search.GetMatchAtIndex(11)->GetId());
EXPECT_EQ(2, search.GetMatchAtIndex(12)->GetId());
#else
EXPECT_EQ(6, search.GetMatchAtIndex(5)->GetId());
EXPECT_EQ(5, search.GetMatchAtIndex(6)->GetId());
EXPECT_EQ(4, search.GetMatchAtIndex(7)->GetId());
EXPECT_EQ(3, search.GetMatchAtIndex(8)->GetId());
EXPECT_EQ(2, search.GetMatchAtIndex(9)->GetId());
#endif
}
TEST_F(OneShotAccessibilityTreeSearchTest, NoCycle) {
// If you set a result limit of 1, you won't get the root node back as
// the first match.
ui::OneShotAccessibilityTreeSearch search(
tree_->GetBrowserAccessibilityRoot());
search.SetResultLimit(1);
ASSERT_EQ(1U, search.CountMatches());
EXPECT_NE(1, search.GetMatchAtIndex(0)->GetId());
}
TEST_F(OneShotAccessibilityTreeSearchTest, ForwardsWithStartNode) {
ui::OneShotAccessibilityTreeSearch search(
tree_->GetBrowserAccessibilityRoot());
search.SetStartNode(tree_->GetFromID(7));
ASSERT_EQ(3U, search.CountMatches());
EXPECT_EQ(8, search.GetMatchAtIndex(0)->GetId());
EXPECT_EQ(9, search.GetMatchAtIndex(1)->GetId());
EXPECT_EQ(10, search.GetMatchAtIndex(2)->GetId());
}
TEST_F(OneShotAccessibilityTreeSearchTest, BackwardsWithStartNode) {
ui::OneShotAccessibilityTreeSearch search(
tree_->GetBrowserAccessibilityRoot());
search.SetStartNode(tree_->GetFromID(4));
search.SetDirection(ui::OneShotAccessibilityTreeSearch::BACKWARDS);
ASSERT_EQ(3U, search.CountMatches());
EXPECT_EQ(3, search.GetMatchAtIndex(0)->GetId());
EXPECT_EQ(2, search.GetMatchAtIndex(1)->GetId());
EXPECT_EQ(1, search.GetMatchAtIndex(2)->GetId());
}
TEST_F(OneShotAccessibilityTreeSearchTest, BackwardsWithStartNodeForAndroid) {
ui::OneShotAccessibilityTreeSearch search(
tree_->GetBrowserAccessibilityRoot());
search.SetStartNode(tree_->GetFromID(4));
search.SetDirection(ui::OneShotAccessibilityTreeSearch::BACKWARDS);
search.SetResultLimit(3);
search.SetCanWrapToLastElement(true);
ASSERT_EQ(3U, search.CountMatches());
EXPECT_EQ(3, search.GetMatchAtIndex(0)->GetId());
EXPECT_EQ(2, search.GetMatchAtIndex(1)->GetId());
EXPECT_EQ(1, search.GetMatchAtIndex(2)->GetId());
}
TEST_F(OneShotAccessibilityTreeSearchTest, ForwardsWithStartNodeAndScope) {
ui::OneShotAccessibilityTreeSearch search(tree_->GetFromID(7));
search.SetStartNode(tree_->GetFromID(8));
ASSERT_EQ(2U, search.CountMatches());
EXPECT_EQ(9, search.GetMatchAtIndex(0)->GetId());
EXPECT_EQ(10, search.GetMatchAtIndex(1)->GetId());
}
TEST_F(OneShotAccessibilityTreeSearchTest, ResultLimitZero) {
ui::OneShotAccessibilityTreeSearch search(
tree_->GetBrowserAccessibilityRoot());
search.SetResultLimit(0);
ASSERT_EQ(0U, search.CountMatches());
}
TEST_F(OneShotAccessibilityTreeSearchTest, ResultLimitFive) {
ui::OneShotAccessibilityTreeSearch search(
tree_->GetBrowserAccessibilityRoot());
search.SetResultLimit(5);
ASSERT_EQ(5U, search.CountMatches());
}
TEST_F(OneShotAccessibilityTreeSearchTest, DescendantsOnlyOfRoot) {
ui::OneShotAccessibilityTreeSearch search(
tree_->GetBrowserAccessibilityRoot());
search.SetStartNode(tree_->GetFromID(1));
search.SetImmediateDescendantsOnly(true);
ASSERT_EQ(4U, search.CountMatches());
EXPECT_EQ(2, search.GetMatchAtIndex(0)->GetId());
EXPECT_EQ(3, search.GetMatchAtIndex(1)->GetId());
EXPECT_EQ(7, search.GetMatchAtIndex(2)->GetId());
EXPECT_EQ(10, search.GetMatchAtIndex(3)->GetId());
}
TEST_F(OneShotAccessibilityTreeSearchTest, DescendantsOnlyOfNode) {
ui::OneShotAccessibilityTreeSearch search(tree_->GetFromID(7));
search.SetImmediateDescendantsOnly(true);
ASSERT_EQ(2U, search.CountMatches());
EXPECT_EQ(8, search.GetMatchAtIndex(0)->GetId());
EXPECT_EQ(9, search.GetMatchAtIndex(1)->GetId());
}
TEST_F(OneShotAccessibilityTreeSearchTest, DescendantsOnlyOfNodeWithStartNode) {
ui::OneShotAccessibilityTreeSearch search(tree_->GetFromID(7));
search.SetStartNode(tree_->GetFromID(8));
search.SetImmediateDescendantsOnly(true);
ASSERT_EQ(1U, search.CountMatches());
EXPECT_EQ(9, search.GetMatchAtIndex(0)->GetId());
}
TEST_F(OneShotAccessibilityTreeSearchTest,
DescendantsOnlyOfNodeWithStartNodeBackwardsTableCell) {
ui::OneShotAccessibilityTreeSearch search(tree_->GetFromID(3));
search.SetStartNode(tree_->GetFromID(5));
search.SetDirection(ui::OneShotAccessibilityTreeSearch::BACKWARDS);
search.SetImmediateDescendantsOnly(true);
ASSERT_EQ(0U, search.CountMatches());
}
TEST_F(OneShotAccessibilityTreeSearchTest,
DescendantsOnlyOfNodeWithStartNodeBackwardsListItem) {
ui::OneShotAccessibilityTreeSearch search(tree_->GetFromID(7));
search.SetStartNode(tree_->GetFromID(9));
search.SetImmediateDescendantsOnly(true);
search.SetDirection(ui::OneShotAccessibilityTreeSearch::BACKWARDS);
ASSERT_EQ(1U, search.CountMatches());
EXPECT_EQ(8, search.GetMatchAtIndex(0)->GetId());
}
TEST_F(OneShotAccessibilityTreeSearchTest, OnscreenOnly) {
ui::OneShotAccessibilityTreeSearch search(
tree_->GetBrowserAccessibilityRoot());
search.SetOnscreenOnly(true);
ASSERT_EQ(7U, search.CountMatches());
EXPECT_EQ(1, search.GetMatchAtIndex(0)->GetId());
EXPECT_EQ(2, search.GetMatchAtIndex(1)->GetId());
EXPECT_EQ(3, search.GetMatchAtIndex(2)->GetId());
EXPECT_EQ(4, search.GetMatchAtIndex(3)->GetId());
EXPECT_EQ(7, search.GetMatchAtIndex(4)->GetId());
EXPECT_EQ(8, search.GetMatchAtIndex(5)->GetId());
EXPECT_EQ(9, search.GetMatchAtIndex(6)->GetId());
}
TEST_F(OneShotAccessibilityTreeSearchTest, CaseInsensitiveStringMatch) {
ui::OneShotAccessibilityTreeSearch search(
tree_->GetBrowserAccessibilityRoot());
search.SetSearchText("eCEptiCOn");
ASSERT_EQ(1U, search.CountMatches());
EXPECT_EQ(9, search.GetMatchAtIndex(0)->GetId());
}
TEST_F(OneShotAccessibilityTreeSearchTest, OnePredicateTableCell) {
ui::OneShotAccessibilityTreeSearch search(
tree_->GetBrowserAccessibilityRoot());
search.AddPredicate(
[](ui::BrowserAccessibility* start, ui::BrowserAccessibility* current) {
return current->GetRole() == ax::mojom::Role::kColumnHeader;
});
ASSERT_EQ(2U, search.CountMatches());
EXPECT_EQ(5, search.GetMatchAtIndex(0)->GetId());
EXPECT_EQ(6, search.GetMatchAtIndex(1)->GetId());
}
TEST_F(OneShotAccessibilityTreeSearchTest, OnePredicateListItem) {
ui::OneShotAccessibilityTreeSearch search(
tree_->GetBrowserAccessibilityRoot());
search.AddPredicate(
[](ui::BrowserAccessibility* start, ui::BrowserAccessibility* current) {
return current->GetRole() == ax::mojom::Role::kListItem;
});
ASSERT_EQ(2U, search.CountMatches());
EXPECT_EQ(8, search.GetMatchAtIndex(0)->GetId());
EXPECT_EQ(9, search.GetMatchAtIndex(1)->GetId());
}
TEST_F(OneShotAccessibilityTreeSearchTest, TwoPredicatesTableRowAndCell) {
ui::OneShotAccessibilityTreeSearch search(
tree_->GetBrowserAccessibilityRoot());
search.AddPredicate(
[](ui::BrowserAccessibility* start, ui::BrowserAccessibility* current) {
return (current->GetRole() == ax::mojom::Role::kRow);
});
search.AddPredicate(
[](ui::BrowserAccessibility* start, ui::BrowserAccessibility* current) {
return (current->GetRole() == ax::mojom::Role::kColumnHeader);
});
ASSERT_EQ(3U, search.CountMatches());
EXPECT_EQ(4, search.GetMatchAtIndex(0)->GetId());
EXPECT_EQ(5, search.GetMatchAtIndex(1)->GetId());
EXPECT_EQ(6, search.GetMatchAtIndex(2)->GetId());
}
TEST_F(OneShotAccessibilityTreeSearchTest, TwoPredicatesListItem) {
ui::OneShotAccessibilityTreeSearch search(
tree_->GetBrowserAccessibilityRoot());
search.AddPredicate(
[](ui::BrowserAccessibility* start, ui::BrowserAccessibility* current) {
return (current->GetRole() == ax::mojom::Role::kList);
});
search.AddPredicate(
[](ui::BrowserAccessibility* start, ui::BrowserAccessibility* current) {
return (current->GetRole() == ax::mojom::Role::kListItem);
});
ASSERT_EQ(3U, search.CountMatches());
EXPECT_EQ(7, search.GetMatchAtIndex(0)->GetId());
EXPECT_EQ(8, search.GetMatchAtIndex(1)->GetId());
EXPECT_EQ(9, search.GetMatchAtIndex(2)->GetId());
}
} // namespace content