blob: ac7518e5d31f290695fcd61e4b60dfdbeb1f6a3e [file] [log] [blame]
// Copyright 2019 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/accessibility/platform/ax_platform_node_win_unittest.h"
#include "ui/accessibility/platform/ax_fragment_root_win.h"
#include "ui/accessibility/platform/ax_platform_node_textchildprovider_win.h"
#include "ui/accessibility/platform/ax_platform_node_textprovider_win.h"
#include "ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h"
using Microsoft::WRL::ComPtr;
namespace ui {
class AXPlatformNodeTextChildProviderTest : public ui::AXPlatformNodeWinTest {
protected:
// Construct an accessibility tree for testing ITextChildProvider resolution
// from various positions in the tree. The following tree configuration
// is constructed:
//
// root_______________
// | |
// nontext____ text
// | | |
// nontext text text
void SetUp() override {
ui::AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
ui::AXNodeData nontext_child_of_root;
nontext_child_of_root.id = 2;
nontext_child_of_root.role = ax::mojom::Role::kGroup;
root.child_ids.push_back(nontext_child_of_root.id);
ui::AXNodeData text_child_of_root;
text_child_of_root.id = 3;
text_child_of_root.role = ax::mojom::Role::kStaticText;
root.child_ids.push_back(text_child_of_root.id);
ui::AXNodeData nontext_child_of_nontext;
nontext_child_of_nontext.id = 4;
nontext_child_of_nontext.role = ax::mojom::Role::kGroup;
nontext_child_of_root.child_ids.push_back(nontext_child_of_nontext.id);
ui::AXNodeData text_child_of_nontext;
text_child_of_nontext.id = 5;
text_child_of_nontext.role = ax::mojom::Role::kStaticText;
nontext_child_of_root.child_ids.push_back(text_child_of_nontext.id);
ui::AXNodeData text_child_of_text;
text_child_of_text.id = 6;
text_child_of_text.role = ax::mojom::Role::kStaticText;
text_child_of_root.child_ids.push_back(text_child_of_text.id);
ui::AXTreeUpdate update;
ui::AXTreeData tree_data;
tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
update.tree_data = tree_data;
update.has_tree_data = true;
update.root_id = root.id;
update.nodes.push_back(root);
update.nodes.push_back(nontext_child_of_root);
update.nodes.push_back(text_child_of_root);
update.nodes.push_back(nontext_child_of_nontext);
update.nodes.push_back(text_child_of_nontext);
update.nodes.push_back(text_child_of_text);
Init(update);
AXNode* root_node = GetRootNode();
AXNodePosition::SetTree(tree_.get());
AXTreeManagerMap::GetInstance().AddTreeManager(update.tree_data.tree_id,
this);
AXNode* nontext_child_of_root_node = root_node->children()[0];
AXNode* text_child_of_root_node = root_node->children()[1];
AXNode* nontext_child_of_nontext_node =
nontext_child_of_root_node->children()[0];
AXNode* text_child_of_nontext_node =
nontext_child_of_root_node->children()[1];
AXNode* text_child_of_text_node = text_child_of_root_node->children()[0];
InitITextChildProvider(root_node, root_provider_raw_,
root_text_child_provider_);
InitITextChildProvider(nontext_child_of_root_node,
nontext_child_of_root_provider_raw_,
nontext_child_of_root_text_child_provider_);
InitITextChildProvider(text_child_of_root_node,
text_child_of_root_text_provider_raw_,
text_child_of_root_text_child_provider_);
InitITextChildProvider(nontext_child_of_nontext_node,
nontext_child_of_nontext_text_provider_raw_,
nontext_child_of_nontext_text_child_provider_);
InitITextChildProvider(text_child_of_nontext_node,
text_child_of_nontext_text_provider_raw_,
text_child_of_nontext_text_child_provider_);
InitITextChildProvider(text_child_of_text_node,
text_child_of_text_text_provider_raw_,
text_child_of_text_text_child_provider_);
}
void TearDown() override { AXNodePosition::SetTree(nullptr); }
void InitITextChildProvider(
AXNode* node,
ComPtr<IRawElementProviderSimple>& raw_element_provider,
ComPtr<ITextChildProvider>& text_child_provider) {
raw_element_provider =
QueryInterfaceFromNode<IRawElementProviderSimple>(node);
EXPECT_HRESULT_SUCCEEDED(raw_element_provider->GetPatternProvider(
UIA_TextChildPatternId, &text_child_provider));
// If the element does not support ITextChildProvider, create one anyways
// for testing purposes.
if (!text_child_provider) {
ui::AXPlatformNodeWin* platform_node =
(ui::AXPlatformNodeWin*)raw_element_provider.Get();
ComPtr<ITextChildProvider> new_child_provider =
ui::AXPlatformNodeTextChildProviderWin::Create(platform_node);
new_child_provider->QueryInterface(IID_PPV_ARGS(&text_child_provider));
}
}
ComPtr<IRawElementProviderSimple> root_provider_raw_;
ComPtr<IRawElementProviderSimple> nontext_child_of_root_provider_raw_;
ComPtr<IRawElementProviderSimple> text_child_of_root_text_provider_raw_;
ComPtr<IRawElementProviderSimple> nontext_child_of_nontext_text_provider_raw_;
ComPtr<IRawElementProviderSimple> text_child_of_nontext_text_provider_raw_;
ComPtr<IRawElementProviderSimple> text_child_of_text_text_provider_raw_;
ComPtr<ITextChildProvider> root_text_child_provider_;
ComPtr<ITextChildProvider> nontext_child_of_root_text_child_provider_;
ComPtr<ITextChildProvider> text_child_of_root_text_child_provider_;
ComPtr<ITextChildProvider> nontext_child_of_nontext_text_child_provider_;
ComPtr<ITextChildProvider> text_child_of_nontext_text_child_provider_;
ComPtr<ITextChildProvider> text_child_of_text_text_child_provider_;
};
// ITextChildProvider::TextContainer Tests
//
// For each possible position in the tree verify:
// 1) A text container can/cannot be retrieved if an ancestor does/doesn't
// support the UIA Text control pattern.
// 2) Any retrieved text container is the nearest ancestor text container.
// 3) A Text control can in fact be retrieved from any retrieved text
// container.
TEST_F(AXPlatformNodeTextChildProviderTest,
TestITextChildProviderTextContainerFromRoot) {
CComPtr<IRawElementProviderSimple> text_container;
ASSERT_HRESULT_SUCCEEDED(
root_text_child_provider_->get_TextContainer(&text_container));
ASSERT_EQ(nullptr, text_container);
}
TEST_F(AXPlatformNodeTextChildProviderTest,
TestITextChildProviderTextContainerFromNontextChildOfRoot) {
CComPtr<IRawElementProviderSimple> text_container;
ASSERT_HRESULT_SUCCEEDED(
nontext_child_of_root_text_child_provider_->get_TextContainer(
&text_container));
ASSERT_NE(nullptr, text_container);
ASSERT_EQ(root_provider_raw_.Get(), text_container);
CComPtr<ITextProvider> text_container_text_provider;
text_container->GetPatternProvider(
UIA_TextPatternId,
reinterpret_cast<IUnknown**>(&text_container_text_provider));
ASSERT_NE(nullptr, text_container_text_provider);
}
TEST_F(AXPlatformNodeTextChildProviderTest,
TestITextChildProviderTextContainerFromTextChildOfRoot) {
CComPtr<IRawElementProviderSimple> text_container;
ASSERT_HRESULT_SUCCEEDED(
text_child_of_root_text_child_provider_->get_TextContainer(
&text_container));
ASSERT_NE(nullptr, text_container);
ASSERT_EQ(root_provider_raw_.Get(), text_container);
CComPtr<ITextProvider> text_container_text_provider;
text_container->GetPatternProvider(
UIA_TextPatternId,
reinterpret_cast<IUnknown**>(&text_container_text_provider));
ASSERT_NE(nullptr, text_container_text_provider);
}
TEST_F(AXPlatformNodeTextChildProviderTest,
TestITextChildProviderTextContainerFromNontextChildOfNontext) {
CComPtr<IRawElementProviderSimple> text_container;
ASSERT_HRESULT_SUCCEEDED(
nontext_child_of_nontext_text_child_provider_->get_TextContainer(
&text_container));
ASSERT_NE(nullptr, text_container);
ASSERT_EQ(root_provider_raw_.Get(), text_container);
CComPtr<ITextProvider> text_container_text_provider;
text_container->GetPatternProvider(
UIA_TextPatternId,
reinterpret_cast<IUnknown**>(&text_container_text_provider));
ASSERT_NE(nullptr, text_container_text_provider);
}
TEST_F(AXPlatformNodeTextChildProviderTest,
TestITextChildProviderTextContainerFromTextChildOfNontext) {
CComPtr<IRawElementProviderSimple> text_container;
ASSERT_HRESULT_SUCCEEDED(
text_child_of_nontext_text_child_provider_->get_TextContainer(
&text_container));
ASSERT_NE(nullptr, text_container);
ASSERT_EQ(root_provider_raw_.Get(), text_container);
CComPtr<ITextProvider> text_container_text_provider;
text_container->GetPatternProvider(
UIA_TextPatternId,
reinterpret_cast<IUnknown**>(&text_container_text_provider));
ASSERT_NE(nullptr, text_container_text_provider);
}
TEST_F(AXPlatformNodeTextChildProviderTest,
TestITextChildProviderTextContainerFromTextChildOfText) {
CComPtr<IRawElementProviderSimple> text_container;
ASSERT_HRESULT_SUCCEEDED(
text_child_of_text_text_child_provider_->get_TextContainer(
&text_container));
ASSERT_NE(nullptr, text_container);
ASSERT_EQ(text_child_of_root_text_provider_raw_.Get(), text_container);
CComPtr<ITextProvider> text_container_text_provider;
text_container->GetPatternProvider(
UIA_TextPatternId,
reinterpret_cast<IUnknown**>(&text_container_text_provider));
ASSERT_NE(nullptr, text_container_text_provider);
}
// ITextChildProvider::TextRange Tests
//
// For each possible position in the tree verify:
// 1) A text range can/cannot be retrieved if an ancestor does/doesn't
// support the UIA Text control pattern.
// 2) Any retrieved text range encloses the child element.
TEST_F(AXPlatformNodeTextChildProviderTest,
TestITextChildProviderTextRangeFromRoot) {
CComPtr<ITextRangeProvider> text_range_provider;
ASSERT_HRESULT_SUCCEEDED(
root_text_child_provider_->get_TextRange(&text_range_provider));
ASSERT_EQ(nullptr, text_range_provider);
}
TEST_F(AXPlatformNodeTextChildProviderTest,
TestITextChildProviderTextRangeFromNontextChildOfRoot) {
CComPtr<ITextRangeProvider> text_range_provider;
ASSERT_HRESULT_SUCCEEDED(
nontext_child_of_root_text_child_provider_->get_TextRange(
&text_range_provider));
ASSERT_NE(nullptr, text_range_provider);
CComPtr<IRawElementProviderSimple> enclosing_element;
text_range_provider->GetEnclosingElement(&enclosing_element);
ASSERT_EQ(nontext_child_of_nontext_text_provider_raw_.Get(),
enclosing_element);
}
TEST_F(AXPlatformNodeTextChildProviderTest,
TestITextChildProviderTextRangeFromTextChildOfRoot) {
CComPtr<ITextRangeProvider> text_range_provider;
ASSERT_HRESULT_SUCCEEDED(
text_child_of_root_text_child_provider_->get_TextRange(
&text_range_provider));
ASSERT_NE(nullptr, text_range_provider);
CComPtr<IRawElementProviderSimple> enclosing_element;
text_range_provider->GetEnclosingElement(&enclosing_element);
ASSERT_EQ(text_child_of_text_text_provider_raw_.Get(), enclosing_element);
}
TEST_F(AXPlatformNodeTextChildProviderTest,
TestITextChildProviderTextRangeFromNontextChildOfNontext) {
CComPtr<ITextRangeProvider> text_range_provider;
ASSERT_HRESULT_SUCCEEDED(
nontext_child_of_nontext_text_child_provider_->get_TextRange(
&text_range_provider));
ASSERT_NE(nullptr, text_range_provider);
CComPtr<IRawElementProviderSimple> enclosing_element;
text_range_provider->GetEnclosingElement(&enclosing_element);
ASSERT_EQ(nontext_child_of_nontext_text_provider_raw_.Get(),
enclosing_element);
}
TEST_F(AXPlatformNodeTextChildProviderTest,
TestITextChildProviderTextRangeFromTextChildOfNontext) {
CComPtr<ITextRangeProvider> text_range_provider;
ASSERT_HRESULT_SUCCEEDED(
text_child_of_nontext_text_child_provider_->get_TextRange(
&text_range_provider));
ASSERT_NE(nullptr, text_range_provider);
CComPtr<IRawElementProviderSimple> enclosing_element;
text_range_provider->GetEnclosingElement(&enclosing_element);
ASSERT_EQ(text_child_of_nontext_text_provider_raw_.Get(), enclosing_element);
}
TEST_F(AXPlatformNodeTextChildProviderTest,
TestITextChildProviderTextRangeFromTextChildOfText) {
CComPtr<ITextRangeProvider> text_range_provider;
ASSERT_HRESULT_SUCCEEDED(
text_child_of_text_text_child_provider_->get_TextRange(
&text_range_provider));
ASSERT_NE(nullptr, text_range_provider);
CComPtr<IRawElementProviderSimple> enclosing_element;
text_range_provider->GetEnclosingElement(&enclosing_element);
ASSERT_EQ(text_child_of_text_text_provider_raw_.Get(), enclosing_element);
}
// ITextChildProvider Tests - Inactive AX Tree
//
// Test that both ITextChildProvider::GetTextContainer and
// ITextChildProvider::GetTextContainer fail under an inactive AX tree.
TEST_F(AXPlatformNodeTextChildProviderTest,
TestITextChildProviderInactiveAccessibilityTree) {
tree_.reset();
// Test that GetTextContainer fails under an inactive tree.
CComPtr<IRawElementProviderSimple> text_container;
HRESULT hr = nontext_child_of_root_text_child_provider_->get_TextContainer(
&text_container);
ASSERT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE), hr);
// Test that GetTextRange fails under an inactive tree.
CComPtr<ITextRangeProvider> text_range_provider;
hr = nontext_child_of_root_text_child_provider_->get_TextRange(
&text_range_provider);
ASSERT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE), hr);
}
} // namespace ui