// Copyright 2019 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/ax_fragment_root_win.h"
#include <UIAutomationClient.h>
#include <UIAutomationCoreApi.h>
#include "base/auto_reset.h"
#include "base/win/scoped_safearray.h"
#include "base/win/scoped_variant.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/platform/ax_platform_node_win.h"
#include "ui/accessibility/platform/ax_platform_node_win_unittest.h"
#include "ui/accessibility/platform/test_ax_node_wrapper.h"
#include "ui/accessibility/platform/uia_registrar_win.h"
using base::win::ScopedVariant;
using Microsoft::WRL::ComPtr;
namespace ui {
#define EXPECT_UIA_BSTR_EQ(node, property_id, expected) \
{ \
ScopedVariant expectedVariant(expected); \
ASSERT_EQ(VT_BSTR, expectedVariant.type()); \
ASSERT_NE(nullptr, expectedVariant.ptr()->bstrVal); \
ScopedVariant actual; \
ASSERT_HRESULT_SUCCEEDED( \
node->GetPropertyValue(property_id, actual.Receive())); \
ASSERT_EQ(VT_BSTR, actual.type()); \
ASSERT_NE(nullptr, actual.ptr()->bstrVal); \
EXPECT_STREQ(expectedVariant.ptr()->bstrVal, actual.ptr()->bstrVal); \
}
class AXFragmentRootTest : public AXPlatformNodeWinTest {
public:
AXFragmentRootTest() = default;
~AXFragmentRootTest() override = default;
AXFragmentRootTest(const AXFragmentRootTest&) = delete;
AXFragmentRootTest& operator=(const AXFragmentRootTest&) = delete;
};
TEST_F(AXFragmentRootTest, UIAFindItemByPropertyUniqueId) {
AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
root.SetName("root");
root.child_ids = {2, 3};
AXNodeData text1;
text1.id = 2;
text1.role = ax::mojom::Role::kStaticText;
text1.SetName("text1");
AXNodeData button;
button.id = 3;
button.role = ax::mojom::Role::kButton;
button.SetName("button");
button.child_ids = {4};
AXNodeData text2;
text2.id = 4;
text2.role = ax::mojom::Role::kStaticText;
text2.SetName("text2");
Init(root, text1, button, text2);
InitFragmentRoot();
ComPtr<IRawElementProviderSimple> root_raw_element_provider_simple;
ax_fragment_root_->GetNativeViewAccessible()->QueryInterface(
IID_PPV_ARGS(&root_raw_element_provider_simple));
ComPtr<IRawElementProviderSimple> text1_raw_element_provider_simple =
GetIRawElementProviderSimpleFromChildIndex(0);
ComPtr<IRawElementProviderSimple> button_raw_element_provider_simple =
GetIRawElementProviderSimpleFromChildIndex(1);
AXNode* text1_node = GetRoot()->children()[0];
AXNode* button_node = GetRoot()->children()[1];
ComPtr<IItemContainerProvider> item_container_provider;
EXPECT_HRESULT_SUCCEEDED(root_raw_element_provider_simple->GetPatternProvider(
UIA_ItemContainerPatternId, &item_container_provider));
ASSERT_NE(nullptr, item_container_provider.Get());
ScopedVariant unique_id_variant;
int32_t unique_id;
ComPtr<IRawElementProviderSimple> result;
// When |start_after_element| is an invalid element, we should fail at finding
// the item.
{
unique_id = AXPlatformNodeFromNode(GetRoot())->GetUniqueId();
unique_id_variant.Set(
SysAllocString(base::NumberToWString(-unique_id).c_str()));
ComPtr<IRawElementProviderSimple> invalid_element_provider_simple;
EXPECT_HRESULT_SUCCEEDED(
MockIRawElementProviderSimple::CreateMockIRawElementProviderSimple(
&invalid_element_provider_simple));
EXPECT_HRESULT_FAILED(item_container_provider->FindItemByProperty(
invalid_element_provider_simple.Get(),
UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
result.Reset();
unique_id_variant.Release();
}
// Fetch the AxUniqueId of "root", and verify we can retrieve its
// corresponding IRawElementProviderSimple through FindItemByProperty().
{
unique_id = AXPlatformNodeFromNode(GetRoot())->GetUniqueId();
unique_id_variant.Set(
SysAllocString(base::NumberToWString(-unique_id).c_str()));
// When |start_after_element| of FindItemByProperty() is nullptr, we should
// be able to find "text1".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
nullptr, UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"root");
result.Reset();
// When |start_after_element| of FindItemByProperty() is "text1", there
// should be no element found, since "text1" comes after the element we are
// looking for.
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
text1_raw_element_provider_simple.Get(),
UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_EQ(nullptr, result.Get());
result.Reset();
// When |start_after_element| of FindItemByProperty() is "button", there
// should be no element found, since "button" comes after the element we are
// looking for.
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
button_raw_element_provider_simple.Get(),
UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_EQ(nullptr, result.Get());
result.Reset();
unique_id_variant.Release();
}
// Fetch the AxUniqueId of "text1", and verify if we can retrieve its
// corresponding IRawElementProviderSimple through FindItemByProperty().
{
unique_id = AXPlatformNodeFromNode(text1_node)->GetUniqueId();
unique_id_variant.Set(
SysAllocString(base::NumberToWString(-unique_id).c_str()));
// When |start_after_element| of FindItemByProperty() is nullptr, we should
// be able to find "text1".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
nullptr, UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"text1");
result.Reset();
// When |start_after_element| of FindItemByProperty() is "text1", there
// should be no element found, since "text1" equals the element we are
// looking for.
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
text1_raw_element_provider_simple.Get(),
UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_EQ(nullptr, result.Get());
result.Reset();
// When |start_after_element| of FindItemByProperty() is "button", there
// should be no element found, since "button" comes after the element we are
// looking for.
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
button_raw_element_provider_simple.Get(),
UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_EQ(nullptr, result.Get());
result.Reset();
unique_id_variant.Release();
}
// Fetch the AxUniqueId of "button", and verify we can retrieve its
// corresponding IRawElementProviderSimple through FindItemByProperty().
{
unique_id = AXPlatformNodeFromNode(button_node)->GetUniqueId();
unique_id_variant.Set(
SysAllocString(base::NumberToWString(-unique_id).c_str()));
// When |start_after_element| of FindItemByProperty() is nullptr, we should
// be able to find "button".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
nullptr, UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"button");
result.Reset();
// When |start_after_element| of FindItemByProperty() is "text1", we should
// be able to find "button".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
text1_raw_element_provider_simple.Get(),
UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"button");
result.Reset();
// When |start_after_element| of FindItemByProperty() is "button", there
// should be no element found, since "button" equals the element we are
// looking for.
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
button_raw_element_provider_simple.Get(),
UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_EQ(nullptr, result.Get());
result.Reset();
unique_id_variant.Release();
}
// Fetch the AxUniqueId of "text2", and verify we can retrieve its
// corresponding IRawElementProviderSimple through FindItemByProperty().
{
unique_id =
AXPlatformNodeFromNode(button_node->children()[0])->GetUniqueId();
unique_id_variant.Set(
SysAllocString(base::NumberToWString(-unique_id).c_str()));
// When |start_after_element| of FindItemByProperty() is nullptr, we should
// be able to find "text2".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
nullptr, UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"text2");
// When |start_after_element| of FindItemByProperty() is root, we should
// be able to find "text2".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
root_raw_element_provider_simple.Get(),
UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"text2");
// When |start_after_element| of FindItemByProperty() is "text1", we should
// be able to find "text2".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
text1_raw_element_provider_simple.Get(),
UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"text2");
// When |start_after_element| of FindItemByProperty() is "button", we should
// be able to find "text2".
EXPECT_HRESULT_SUCCEEDED(item_container_provider->FindItemByProperty(
button_raw_element_provider_simple.Get(),
UiaRegistrarWin::GetInstance().GetUniqueIdPropertyId(),
unique_id_variant, &result));
EXPECT_UIA_BSTR_EQ(result, UIA_NamePropertyId, L"text2");
}
}
TEST_F(AXFragmentRootTest, TestUIAGetFragmentRoot) {
AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
Init(root);
InitFragmentRoot();
ComPtr<IRawElementProviderFragmentRoot> expected_fragment_root =
GetFragmentRoot();
ComPtr<IRawElementProviderFragment> fragment_provider;
expected_fragment_root.As(&fragment_provider);
ComPtr<IRawElementProviderFragmentRoot> actual_fragment_root;
EXPECT_HRESULT_SUCCEEDED(
fragment_provider->get_FragmentRoot(&actual_fragment_root));
EXPECT_EQ(expected_fragment_root.Get(), actual_fragment_root.Get());
}
TEST_F(AXFragmentRootTest, TestUIAElementProviderFromPoint) {
AXNodeData root_data;
root_data.id = 1;
root_data.relative_bounds.bounds = gfx::RectF(0, 0, 80, 80);
AXNodeData element1_data;
element1_data.id = 2;
element1_data.relative_bounds.bounds = gfx::RectF(0, 0, 50, 50);
root_data.child_ids.push_back(element1_data.id);
AXNodeData element2_data;
element2_data.id = 3;
element2_data.relative_bounds.bounds = gfx::RectF(0, 50, 30, 30);
root_data.child_ids.push_back(element2_data.id);
Init(root_data, element1_data, element2_data);
InitFragmentRoot();
AXNode* root_node = GetRoot();
AXNode* element1_node = root_node->children()[0];
AXNode* element2_node = root_node->children()[1];
ComPtr<IRawElementProviderFragmentRoot> fragment_root_prov(GetFragmentRoot());
ComPtr<IRawElementProviderFragment> root_provider(
GetRootIRawElementProviderFragment());
ComPtr<IRawElementProviderFragment> element1_provider =
QueryInterfaceFromNode<IRawElementProviderFragment>(element1_node);
ComPtr<IRawElementProviderFragment> element2_provider =
QueryInterfaceFromNode<IRawElementProviderFragment>(element2_node);
ComPtr<IRawElementProviderFragment> provider_from_point;
EXPECT_HRESULT_SUCCEEDED(fragment_root_prov->ElementProviderFromPoint(
23, 31, &provider_from_point));
EXPECT_EQ(element1_provider.Get(), provider_from_point.Get());
EXPECT_HRESULT_SUCCEEDED(fragment_root_prov->ElementProviderFromPoint(
23, 67, &provider_from_point));
EXPECT_EQ(element2_provider.Get(), provider_from_point.Get());
EXPECT_HRESULT_SUCCEEDED(fragment_root_prov->ElementProviderFromPoint(
47, 67, &provider_from_point));
EXPECT_EQ(root_provider.Get(), provider_from_point.Get());
// This is on node 1 with scale factor of 1.5.
std::unique_ptr<base::AutoReset<float>> scale_factor_reset =
TestAXNodeWrapper::SetScaleFactor(1.5);
EXPECT_HRESULT_SUCCEEDED(fragment_root_prov->ElementProviderFromPoint(
60, 60, &provider_from_point));
EXPECT_EQ(element1_provider.Get(), provider_from_point.Get());
}
TEST_F(AXFragmentRootTest, TestUIAGetFocus) {
AXNodeData root_data;
root_data.id = 1;
AXNodeData element1_data;
element1_data.id = 2;
root_data.child_ids.push_back(element1_data.id);
AXNodeData element2_data;
element2_data.id = 3;
root_data.child_ids.push_back(element2_data.id);
Init(root_data, element1_data, element2_data);
InitFragmentRoot();
AXNode* root_node = GetRoot();
AXNode* element1_node = root_node->children()[0];
AXNode* element2_node = root_node->children()[1];
ComPtr<IRawElementProviderFragmentRoot> fragment_root_prov(GetFragmentRoot());
ComPtr<IRawElementProviderFragment> root_provider(
GetRootIRawElementProviderFragment());
ComPtr<IRawElementProviderFragment> element1_provider =
QueryInterfaceFromNode<IRawElementProviderFragment>(element1_node);
ComPtr<IRawElementProviderFragment> element2_provider =
QueryInterfaceFromNode<IRawElementProviderFragment>(element2_node);
ComPtr<IRawElementProviderFragment> focused_fragment;
EXPECT_HRESULT_SUCCEEDED(root_provider->SetFocus());
EXPECT_HRESULT_SUCCEEDED(fragment_root_prov->GetFocus(&focused_fragment));
EXPECT_EQ(root_provider.Get(), focused_fragment.Get());
EXPECT_HRESULT_SUCCEEDED(element1_provider->SetFocus());
EXPECT_HRESULT_SUCCEEDED(fragment_root_prov->GetFocus(&focused_fragment));
EXPECT_EQ(element1_provider.Get(), focused_fragment.Get());
EXPECT_HRESULT_SUCCEEDED(element2_provider->SetFocus());
EXPECT_HRESULT_SUCCEEDED(fragment_root_prov->GetFocus(&focused_fragment));
EXPECT_EQ(element2_provider.Get(), focused_fragment.Get());
}
TEST_F(AXFragmentRootTest, TestUIAErrorHandling) {
AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
Init(root);
InitFragmentRoot();
ComPtr<IRawElementProviderSimple> simple_provider =
GetRootIRawElementProviderSimple();
ComPtr<IRawElementProviderFragment> fragment_provider =
GetRootIRawElementProviderFragment();
ComPtr<IRawElementProviderFragmentRoot> fragment_root_provider =
GetFragmentRoot();
SetTree(std::make_unique<AXTree>());
ax_fragment_root_.reset(nullptr);
ComPtr<IRawElementProviderSimple> returned_simple_provider;
ComPtr<IRawElementProviderFragment> returned_fragment_provider;
ComPtr<IRawElementProviderFragmentRoot> returned_fragment_root_provider;
base::win::ScopedSafearray returned_runtime_id;
EXPECT_EQ(
static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
simple_provider->get_HostRawElementProvider(&returned_simple_provider));
EXPECT_EQ(
static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
fragment_provider->get_FragmentRoot(&returned_fragment_root_provider));
EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
fragment_provider->GetRuntimeId(returned_runtime_id.Receive()));
EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
fragment_root_provider->ElementProviderFromPoint(
67, 23, &returned_fragment_provider));
EXPECT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE),
fragment_root_provider->GetFocus(&returned_fragment_provider));
}
TEST_F(AXFragmentRootTest, TestGetChildCount) {
AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
Init(root);
InitFragmentRoot();
AXPlatformNodeDelegate* fragment_root = ax_fragment_root_.get();
EXPECT_EQ(1u, fragment_root->GetChildCount());
test_fragment_root_delegate_->child_ = nullptr;
EXPECT_EQ(0u, fragment_root->GetChildCount());
}
TEST_F(AXFragmentRootTest, TestChildAtIndex) {
AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
Init(root);
InitFragmentRoot();
gfx::NativeViewAccessible native_view_accessible =
AXPlatformNodeFromNode(GetRoot())->GetNativeViewAccessible();
AXPlatformNodeDelegate* fragment_root = ax_fragment_root_.get();
EXPECT_EQ(native_view_accessible, fragment_root->ChildAtIndex(0));
EXPECT_EQ(nullptr, fragment_root->ChildAtIndex(1));
test_fragment_root_delegate_->child_ = nullptr;
EXPECT_EQ(nullptr, fragment_root->ChildAtIndex(0));
}
TEST_F(AXFragmentRootTest, TestGetParent) {
AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
Init(root);
InitFragmentRoot();
AXPlatformNodeDelegate* fragment_root = ax_fragment_root_.get();
EXPECT_EQ(nullptr, fragment_root->GetParent());
gfx::NativeViewAccessible native_view_accessible =
AXPlatformNodeFromNode(GetRoot())->GetNativeViewAccessible();
test_fragment_root_delegate_->parent_ = native_view_accessible;
EXPECT_EQ(native_view_accessible, fragment_root->GetParent());
}
TEST_F(AXFragmentRootTest, TestGetPropertyValue) {
AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
Init(root);
InitFragmentRoot();
ComPtr<IRawElementProviderSimple> root_provider;
ax_fragment_root_->GetNativeViewAccessible()->QueryInterface(
IID_PPV_ARGS(&root_provider));
// IsControlElement and IsContentElement should follow the setting on the
// fragment root delegate.
test_fragment_root_delegate_->is_control_element_ = true;
ScopedVariant result;
EXPECT_HRESULT_SUCCEEDED(root_provider->GetPropertyValue(
UIA_IsControlElementPropertyId, result.Receive()));
EXPECT_EQ(result.type(), VT_BOOL);
EXPECT_EQ(result.ptr()->boolVal, VARIANT_TRUE);
EXPECT_HRESULT_SUCCEEDED(root_provider->GetPropertyValue(
UIA_IsContentElementPropertyId, result.Receive()));
EXPECT_EQ(result.type(), VT_BOOL);
EXPECT_EQ(result.ptr()->boolVal, VARIANT_TRUE);
test_fragment_root_delegate_->is_control_element_ = false;
EXPECT_HRESULT_SUCCEEDED(root_provider->GetPropertyValue(
UIA_IsControlElementPropertyId, result.Receive()));
EXPECT_EQ(result.type(), VT_BOOL);
EXPECT_EQ(result.ptr()->boolVal, VARIANT_FALSE);
EXPECT_HRESULT_SUCCEEDED(root_provider->GetPropertyValue(
UIA_IsContentElementPropertyId, result.Receive()));
EXPECT_EQ(result.type(), VT_BOOL);
EXPECT_EQ(result.ptr()->boolVal, VARIANT_FALSE);
// Other properties should return VT_EMPTY.
EXPECT_HRESULT_SUCCEEDED(root_provider->GetPropertyValue(
UIA_ControlTypePropertyId, result.Receive()));
EXPECT_EQ(result.type(), VT_EMPTY);
}
TEST_F(AXFragmentRootTest, TestUIAMultipleFragmentRoots) {
// Consider the following platform-neutral tree:
//
// N1
// _____/ \_____
// / \
// N2---N3---N4---N5
// / \ / \
// N6---N7 N8---N9
//
// N3 and N5 are nodes for which we need a fragment root. This will correspond
// to the following tree in UIA:
//
// U1
// _____/ \_____
// / \
// U2---R3---U4---R5
// | |
// U3 U5
// / \ / \
// U6---U7 U8---U9
AXNodeData top_fragment_root_n1;
top_fragment_root_n1.id = 1;
AXNodeData sibling_n2;
sibling_n2.id = 2;
AXNodeData child_fragment_root_n3;
child_fragment_root_n3.id = 3;
AXNodeData sibling_n6;
sibling_n6.id = 6;
AXNodeData sibling_n7;
sibling_n7.id = 7;
child_fragment_root_n3.child_ids = {6, 7};
AXNodeData sibling_n4;
sibling_n4.id = 4;
AXNodeData child_fragment_root_n5;
child_fragment_root_n5.id = 5;
AXNodeData sibling_n8;
sibling_n8.id = 8;
AXNodeData sibling_n9;
sibling_n9.id = 9;
child_fragment_root_n5.child_ids = {8, 9};
top_fragment_root_n1.child_ids = {2, 3, 4, 5};
AXTreeUpdate update;
update.has_tree_data = true;
update.root_id = top_fragment_root_n1.id;
update.nodes = {top_fragment_root_n1,
sibling_n2,
child_fragment_root_n3,
sibling_n6,
sibling_n7,
sibling_n4,
child_fragment_root_n5,
sibling_n8,
sibling_n9};
update.tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
Init(update);
InitFragmentRoot();
AXNode* root_node = GetRoot();
// Set up other fragment roots
AXNode* child_fragment_root_n3_node = root_node->children()[1];
std::unique_ptr<TestFragmentRootDelegate> n3_fragment_root_delegate =
std::make_unique<TestFragmentRootDelegate>();
std::unique_ptr<AXFragmentRootWin> n3_fragment_root(InitNodeAsFragmentRoot(
child_fragment_root_n3_node, n3_fragment_root_delegate.get()));
AXNode* child_fragment_root_n5_node = root_node->children()[3];
std::unique_ptr<TestFragmentRootDelegate> n5_fragment_root_delegate =
std::make_unique<TestFragmentRootDelegate>();
std::unique_ptr<AXFragmentRootWin> n5_fragment_root(InitNodeAsFragmentRoot(
child_fragment_root_n5_node, n5_fragment_root_delegate.get()));
// Test navigation from root fragment
ComPtr<IRawElementProviderFragmentRoot> root_fragment_root =
GetFragmentRoot();
ComPtr<IRawElementProviderFragment> root_fragment;
root_fragment_root.As(&root_fragment);
ComPtr<IRawElementProviderFragment> test_fragment;
EXPECT_HRESULT_SUCCEEDED(
root_fragment->Navigate(NavigateDirection_Parent, &test_fragment));
EXPECT_EQ(nullptr, test_fragment.Get());
EXPECT_HRESULT_SUCCEEDED(
root_fragment->Navigate(NavigateDirection_NextSibling, &test_fragment));
EXPECT_EQ(nullptr, test_fragment.Get());
EXPECT_HRESULT_SUCCEEDED(root_fragment->Navigate(
NavigateDirection_PreviousSibling, &test_fragment));
EXPECT_EQ(nullptr, test_fragment.Get());
EXPECT_HRESULT_SUCCEEDED(
root_fragment->Navigate(NavigateDirection_FirstChild, &test_fragment));
ComPtr<IUnknown> root_child_unknown = test_fragment_root_delegate_->child_;
ComPtr<IRawElementProviderFragment> root_child_fragment;
root_child_unknown.As(&root_child_fragment);
EXPECT_EQ(root_child_fragment.Get(), test_fragment.Get());
EXPECT_HRESULT_SUCCEEDED(
root_fragment->Navigate(NavigateDirection_LastChild, &test_fragment));
EXPECT_EQ(root_child_fragment.Get(), test_fragment.Get());
// Test navigation from first child root (R3)
ComPtr<IRawElementProviderFragmentRoot> n3_fragment_root_provider;
n3_fragment_root->GetNativeViewAccessible()->QueryInterface(
IID_PPV_ARGS(&n3_fragment_root_provider));
ComPtr<IRawElementProviderFragment> n3_fragment;
n3_fragment_root_provider.As(&n3_fragment);
EXPECT_HRESULT_SUCCEEDED(
n3_fragment->Navigate(NavigateDirection_Parent, &test_fragment));
EXPECT_EQ(root_child_fragment.Get(), test_fragment.Get());
AXNode* sibling_n2_node = root_node->children()[0];
EXPECT_HRESULT_SUCCEEDED(
n3_fragment->Navigate(NavigateDirection_PreviousSibling, &test_fragment));
EXPECT_EQ(IRawElementProviderFragmentFromNode(sibling_n2_node).Get(),
test_fragment.Get());
AXNode* sibling_n4_node = root_node->children()[2];
EXPECT_HRESULT_SUCCEEDED(
n3_fragment->Navigate(NavigateDirection_NextSibling, &test_fragment));
EXPECT_EQ(IRawElementProviderFragmentFromNode(sibling_n4_node).Get(),
test_fragment.Get());
EXPECT_HRESULT_SUCCEEDED(
n3_fragment->Navigate(NavigateDirection_FirstChild, &test_fragment));
EXPECT_EQ(
IRawElementProviderFragmentFromNode(child_fragment_root_n3_node).Get(),
test_fragment.Get());
EXPECT_HRESULT_SUCCEEDED(
n3_fragment->Navigate(NavigateDirection_LastChild, &test_fragment));
EXPECT_EQ(
IRawElementProviderFragmentFromNode(child_fragment_root_n3_node).Get(),
test_fragment.Get());
// Test navigation from second child root (R5)
ComPtr<IRawElementProviderFragmentRoot> n5_fragment_root_provider;
n5_fragment_root->GetNativeViewAccessible()->QueryInterface(
IID_PPV_ARGS(&n5_fragment_root_provider));
ComPtr<IRawElementProviderFragment> n5_fragment;
n5_fragment_root_provider.As(&n5_fragment);
EXPECT_HRESULT_SUCCEEDED(
n5_fragment->Navigate(NavigateDirection_Parent, &test_fragment));
EXPECT_EQ(root_child_fragment.Get(), test_fragment.Get());
EXPECT_HRESULT_SUCCEEDED(
n5_fragment->Navigate(NavigateDirection_NextSibling, &test_fragment));
EXPECT_EQ(nullptr, test_fragment.Get());
EXPECT_HRESULT_SUCCEEDED(
n5_fragment->Navigate(NavigateDirection_PreviousSibling, &test_fragment));
EXPECT_EQ(IRawElementProviderFragmentFromNode(sibling_n4_node).Get(),
test_fragment.Get());
EXPECT_HRESULT_SUCCEEDED(
n5_fragment->Navigate(NavigateDirection_FirstChild, &test_fragment));
EXPECT_EQ(
IRawElementProviderFragmentFromNode(child_fragment_root_n5_node).Get(),
test_fragment.Get());
EXPECT_HRESULT_SUCCEEDED(
n5_fragment->Navigate(NavigateDirection_LastChild, &test_fragment));
EXPECT_EQ(
IRawElementProviderFragmentFromNode(child_fragment_root_n5_node).Get(),
test_fragment.Get());
}
TEST_F(AXFragmentRootTest, TestFragmentRootMap) {
AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
Init(root);
// There should be nothing in the map before we create a fragment root.
// Call GetForAcceleratedWidget() first to ensure that querying for a
// fragment root doesn't inadvertently create an empty entry in the map
// (https://crbug.com/1071185).
EXPECT_EQ(nullptr, AXFragmentRootWin::GetForAcceleratedWidget(
gfx::kMockAcceleratedWidget));
EXPECT_EQ(nullptr, AXFragmentRootWin::GetFragmentRootParentOf(
GetRootIAccessible().Get()));
// After initializing a fragment root, we should be able to retrieve it using
// its accelerated widget, or as the parent of its child.
InitFragmentRoot();
EXPECT_EQ(ax_fragment_root_.get(), AXFragmentRootWin::GetForAcceleratedWidget(
gfx::kMockAcceleratedWidget));
EXPECT_EQ(ax_fragment_root_.get(), AXFragmentRootWin::GetFragmentRootParentOf(
GetRootIAccessible().Get()));
// After deleting a fragment root, it should no longer be reachable from the
// map.
ax_fragment_root_.reset();
EXPECT_EQ(nullptr, AXFragmentRootWin::GetForAcceleratedWidget(
gfx::kMockAcceleratedWidget));
EXPECT_EQ(nullptr, AXFragmentRootWin::GetFragmentRootParentOf(
GetRootIAccessible().Get()));
}
} // namespace ui