| Index: ui/accessibility/platform/ax_platform_node_win_unittest.cc
|
| diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e6476816dfe1516f453dccd5eeb5d8c58a878fec
|
| --- /dev/null
|
| +++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
|
| @@ -0,0 +1,372 @@
|
| +// Copyright 2015 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 <atlbase.h>
|
| +#include <atlcom.h>
|
| +#include <oleacc.h>
|
| +
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/win/scoped_bstr.h"
|
| +#include "base/win/scoped_comptr.h"
|
| +#include "base/win/scoped_variant.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "third_party/iaccessible2/ia2_api_all.h"
|
| +#include "ui/accessibility/ax_node_data.h"
|
| +#include "ui/accessibility/platform/ax_platform_node.h"
|
| +#include "ui/accessibility/platform/test_ax_node_wrapper.h"
|
| +#include "ui/base/win/atl_module.h"
|
| +
|
| +using base::win::ScopedBstr;
|
| +using base::win::ScopedComPtr;
|
| +using base::win::ScopedVariant;
|
| +
|
| +namespace ui {
|
| +
|
| +namespace {
|
| +
|
| +// Most IAccessible functions require a VARIANT set to CHILDID_SELF as
|
| +// the first argument.
|
| +ScopedVariant SELF(CHILDID_SELF);
|
| +
|
| +} // namespace
|
| +
|
| +class AXPlatformNodeWinTest : public testing::Test {
|
| + public:
|
| + AXPlatformNodeWinTest() {}
|
| + virtual ~AXPlatformNodeWinTest() {}
|
| +
|
| + void SetUp() override {
|
| + win::CreateATLModuleIfNeeded();
|
| + }
|
| +
|
| + // Initialize given an AXTreeUpdate.
|
| + void Init(const AXTreeUpdate& initial_state) {
|
| + tree_.reset(new AXTree(initial_state));
|
| + }
|
| +
|
| + // Convenience functions to initialize directly from a few AXNodeDatas.
|
| + void Init(const AXNodeData& node1) {
|
| + AXTreeUpdate update;
|
| + update.nodes.push_back(node1);
|
| + Init(update);
|
| + }
|
| +
|
| + void Init(const AXNodeData& node1,
|
| + const AXNodeData& node2) {
|
| + AXTreeUpdate update;
|
| + update.nodes.push_back(node1);
|
| + update.nodes.push_back(node2);
|
| + Init(update);
|
| + }
|
| +
|
| + void Init(const AXNodeData& node1,
|
| + const AXNodeData& node2,
|
| + const AXNodeData& node3) {
|
| + AXTreeUpdate update;
|
| + update.nodes.push_back(node1);
|
| + update.nodes.push_back(node2);
|
| + update.nodes.push_back(node3);
|
| + Init(update);
|
| + }
|
| +
|
| + protected:
|
| + AXNode* GetRootNode() {
|
| + return tree_->root();
|
| + }
|
| +
|
| + ScopedComPtr<IAccessible> IAccessibleFromNode(AXNode* node) {
|
| + TestAXNodeWrapper* wrapper =
|
| + TestAXNodeWrapper::GetOrCreate(tree_.get(), node);
|
| + AXPlatformNode* ax_platform_node = wrapper->ax_platform_node();
|
| + IAccessible* iaccessible = ax_platform_node->GetNativeViewAccessible();
|
| + iaccessible->AddRef();
|
| + return ScopedComPtr<IAccessible>(iaccessible);
|
| + }
|
| +
|
| + ScopedComPtr<IAccessible> GetRootIAccessible() {
|
| + return IAccessibleFromNode(GetRootNode());
|
| + }
|
| +
|
| + ScopedComPtr<IAccessible2> ToIAccessible2(
|
| + ScopedComPtr<IAccessible> accessible) {
|
| + ScopedComPtr<IServiceProvider> service_provider;
|
| + service_provider.QueryFrom(accessible.get());
|
| + ScopedComPtr<IAccessible2> result;
|
| + CHECK(SUCCEEDED(
|
| + service_provider->QueryService(IID_IAccessible2, result.Receive())));
|
| + return result;
|
| + }
|
| +
|
| + scoped_ptr<AXTree> tree_;
|
| +};
|
| +
|
| +TEST_F(AXPlatformNodeWinTest, TestIAccessibleDetachedObject) {
|
| + AXNodeData root;
|
| + root.id = 1;
|
| + root.role = AX_ROLE_ROOT_WEB_AREA;
|
| + root.AddStringAttribute(AX_ATTR_NAME, "Name");
|
| + Init(root);
|
| +
|
| + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible());
|
| + ScopedBstr name;
|
| + ASSERT_EQ(S_OK, root_obj->get_accName(SELF, name.Receive()));
|
| + EXPECT_EQ(L"Name", base::string16(name));
|
| +
|
| + tree_.reset(new AXTree());
|
| + ScopedBstr name2;
|
| + ASSERT_EQ(E_FAIL, root_obj->get_accName(SELF, name2.Receive()));
|
| +}
|
| +
|
| +TEST_F(AXPlatformNodeWinTest, TestIAccessibleName) {
|
| + AXNodeData root;
|
| + root.id = 1;
|
| + root.role = AX_ROLE_ROOT_WEB_AREA;
|
| + root.AddStringAttribute(AX_ATTR_NAME, "Name");
|
| + Init(root);
|
| +
|
| + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible());
|
| + ScopedBstr name;
|
| + ASSERT_EQ(S_OK, root_obj->get_accName(SELF, name.Receive()));
|
| + EXPECT_EQ(L"Name", base::string16(name));
|
| +
|
| + ASSERT_EQ(E_INVALIDARG, root_obj->get_accName(SELF, nullptr));
|
| + ScopedVariant bad_id(999);
|
| + ScopedBstr name2;
|
| + ASSERT_EQ(E_INVALIDARG, root_obj->get_accName(bad_id, name2.Receive()));
|
| +}
|
| +
|
| +TEST_F(AXPlatformNodeWinTest, TestIAccessibleDescription) {
|
| + AXNodeData root;
|
| + root.id = 1;
|
| + root.role = AX_ROLE_ROOT_WEB_AREA;
|
| + root.AddStringAttribute(AX_ATTR_DESCRIPTION, "Description");
|
| + Init(root);
|
| +
|
| + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible());
|
| + ScopedBstr description;
|
| + ASSERT_EQ(S_OK, root_obj->get_accDescription(SELF, description.Receive()));
|
| + EXPECT_EQ(L"Description", base::string16(description));
|
| +
|
| + ASSERT_EQ(E_INVALIDARG, root_obj->get_accDescription(SELF, nullptr));
|
| + ScopedVariant bad_id(999);
|
| + ScopedBstr d2;
|
| + ASSERT_EQ(E_INVALIDARG, root_obj->get_accDescription(bad_id, d2.Receive()));
|
| +}
|
| +
|
| +TEST_F(AXPlatformNodeWinTest, TestIAccessibleHelp) {
|
| + AXNodeData root;
|
| + root.id = 1;
|
| + root.role = AX_ROLE_ROOT_WEB_AREA;
|
| + root.AddStringAttribute(AX_ATTR_HELP, "Help");
|
| + Init(root);
|
| +
|
| + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible());
|
| + ScopedBstr help;
|
| + ASSERT_EQ(S_OK, root_obj->get_accHelp(SELF, help.Receive()));
|
| + EXPECT_EQ(L"Help", base::string16(help));
|
| +
|
| + ASSERT_EQ(E_INVALIDARG, root_obj->get_accHelp(SELF, nullptr));
|
| + ScopedVariant bad_id(999);
|
| + ScopedBstr h2;
|
| + ASSERT_EQ(E_INVALIDARG, root_obj->get_accHelp(bad_id, h2.Receive()));
|
| +}
|
| +
|
| +TEST_F(AXPlatformNodeWinTest, TestIAccessibleValue) {
|
| + AXNodeData root;
|
| + root.id = 1;
|
| + root.role = AX_ROLE_ROOT_WEB_AREA;
|
| + root.AddStringAttribute(AX_ATTR_VALUE, "Value");
|
| + Init(root);
|
| +
|
| + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible());
|
| + ScopedBstr value;
|
| + ASSERT_EQ(S_OK, root_obj->get_accValue(SELF, value.Receive()));
|
| + EXPECT_EQ(L"Value", base::string16(value));
|
| +
|
| + ASSERT_EQ(E_INVALIDARG, root_obj->get_accValue(SELF, nullptr));
|
| + ScopedVariant bad_id(999);
|
| + ScopedBstr v2;
|
| + ASSERT_EQ(E_INVALIDARG, root_obj->get_accValue(bad_id, v2.Receive()));
|
| +}
|
| +
|
| +TEST_F(AXPlatformNodeWinTest, TestIAccessibleShortcut) {
|
| + AXNodeData root;
|
| + root.id = 1;
|
| + root.role = AX_ROLE_ROOT_WEB_AREA;
|
| + root.AddStringAttribute(AX_ATTR_SHORTCUT, "Shortcut");
|
| + Init(root);
|
| +
|
| + ScopedComPtr<IAccessible> root_obj(GetRootIAccessible());
|
| + ScopedBstr shortcut;
|
| + ASSERT_EQ(S_OK, root_obj->get_accKeyboardShortcut(
|
| + SELF, shortcut.Receive()));
|
| + EXPECT_EQ(L"Shortcut", base::string16(shortcut));
|
| +
|
| + ASSERT_EQ(E_INVALIDARG, root_obj->get_accKeyboardShortcut(SELF, nullptr));
|
| + ScopedVariant bad_id(999);
|
| + ScopedBstr k2;
|
| + ASSERT_EQ(E_INVALIDARG, root_obj->get_accKeyboardShortcut(
|
| + bad_id, k2.Receive()));
|
| +}
|
| +
|
| +TEST_F(AXPlatformNodeWinTest, TestIAccessibleRole) {
|
| + AXNodeData root;
|
| + root.id = 1;
|
| + root.role = AX_ROLE_ROOT_WEB_AREA;
|
| + root.child_ids.push_back(2);
|
| +
|
| + AXNodeData child;
|
| + child.id = 2;
|
| +
|
| + Init(root, child);
|
| + AXNode* child_node = GetRootNode()->children()[0];
|
| + ScopedComPtr<IAccessible> child_iaccessible(
|
| + IAccessibleFromNode(child_node));
|
| +
|
| + ScopedVariant role;
|
| +
|
| + child.role = AX_ROLE_ALERT;
|
| + child_node->SetData(child);
|
| + ASSERT_EQ(S_OK, child_iaccessible->get_accRole(SELF, role.Receive()));
|
| + EXPECT_EQ(ROLE_SYSTEM_ALERT, V_I4(&role));
|
| +
|
| + child.role = AX_ROLE_BUTTON;
|
| + child_node->SetData(child);
|
| + ASSERT_EQ(S_OK, child_iaccessible->get_accRole(SELF, role.Receive()));
|
| + EXPECT_EQ(ROLE_SYSTEM_PUSHBUTTON, V_I4(&role));
|
| +
|
| + child.role = AX_ROLE_POP_UP_BUTTON;
|
| + child_node->SetData(child);
|
| + ASSERT_EQ(S_OK, child_iaccessible->get_accRole(SELF, role.Receive()));
|
| + EXPECT_EQ(ROLE_SYSTEM_BUTTONMENU, V_I4(&role));
|
| +
|
| + ASSERT_EQ(E_INVALIDARG, child_iaccessible->get_accRole(SELF, nullptr));
|
| + ScopedVariant bad_id(999);
|
| + ASSERT_EQ(E_INVALIDARG, child_iaccessible->get_accRole(
|
| + bad_id, role.Receive()));
|
| +}
|
| +
|
| +TEST_F(AXPlatformNodeWinTest, TestIAccessibleLocation) {
|
| + AXNodeData root;
|
| + root.id = 1;
|
| + root.role = AX_ROLE_ROOT_WEB_AREA;
|
| + root.location = gfx::Rect(10, 40, 800, 600);
|
| + Init(root);
|
| +
|
| + TestAXNodeWrapper::SetGlobalCoordinateOffset(gfx::Vector2d(100, 200));
|
| +
|
| + LONG x_left, y_top, width, height;
|
| + ASSERT_EQ(S_OK, GetRootIAccessible()->accLocation(
|
| + &x_left, &y_top, &width, &height, SELF));
|
| + EXPECT_EQ(110, x_left);
|
| + EXPECT_EQ(240, y_top);
|
| + EXPECT_EQ(800, width);
|
| + EXPECT_EQ(600, height);
|
| +
|
| + ASSERT_EQ(E_INVALIDARG, GetRootIAccessible()->accLocation(
|
| + nullptr, &y_top, &width, &height, SELF));
|
| + ASSERT_EQ(E_INVALIDARG, GetRootIAccessible()->accLocation(
|
| + &x_left, nullptr, &width, &height, SELF));
|
| + ASSERT_EQ(E_INVALIDARG, GetRootIAccessible()->accLocation(
|
| + &x_left, &y_top, nullptr, &height, SELF));
|
| + ASSERT_EQ(E_INVALIDARG, GetRootIAccessible()->accLocation(
|
| + &x_left, &y_top, &width, nullptr, SELF));
|
| + ScopedVariant bad_id(999);
|
| + ASSERT_EQ(E_INVALIDARG, GetRootIAccessible()->accLocation(
|
| + &x_left, &y_top, &width, &height, bad_id));
|
| +}
|
| +
|
| +TEST_F(AXPlatformNodeWinTest, TestIAccessibleChildAndParent) {
|
| + AXNodeData root;
|
| + root.id = 1;
|
| + root.role = AX_ROLE_ROOT_WEB_AREA;
|
| + root.child_ids.push_back(2);
|
| + root.child_ids.push_back(3);
|
| +
|
| + AXNodeData button;
|
| + button.role = AX_ROLE_BUTTON;
|
| + button.id = 2;
|
| +
|
| + AXNodeData checkbox;
|
| + checkbox.role = AX_ROLE_CHECK_BOX;
|
| + checkbox.id = 3;
|
| +
|
| + Init(root, button, checkbox);
|
| + AXNode* button_node = GetRootNode()->children()[0];
|
| + AXNode* checkbox_node = GetRootNode()->children()[1];
|
| + ScopedComPtr<IAccessible> root_iaccessible(GetRootIAccessible());
|
| + ScopedComPtr<IAccessible> button_iaccessible(
|
| + IAccessibleFromNode(button_node));
|
| + ScopedComPtr<IAccessible> checkbox_iaccessible(
|
| + IAccessibleFromNode(checkbox_node));
|
| +
|
| + LONG child_count;
|
| + ASSERT_EQ(S_OK, root_iaccessible->get_accChildCount(&child_count));
|
| + ASSERT_EQ(2L, child_count);
|
| + ASSERT_EQ(S_OK, button_iaccessible->get_accChildCount(&child_count));
|
| + ASSERT_EQ(0L, child_count);
|
| + ASSERT_EQ(S_OK, checkbox_iaccessible->get_accChildCount(&child_count));
|
| + ASSERT_EQ(0L, child_count);
|
| +
|
| + {
|
| + ScopedComPtr<IDispatch> result;
|
| + ASSERT_EQ(S_OK, root_iaccessible->get_accChild(SELF, result.Receive()));
|
| + ASSERT_EQ(result.get(), root_iaccessible);
|
| + }
|
| +
|
| + {
|
| + ScopedComPtr<IDispatch> result;
|
| + ScopedVariant child1(1);
|
| + ASSERT_EQ(S_OK, root_iaccessible->get_accChild(child1, result.Receive()));
|
| + ASSERT_EQ(result.get(), button_iaccessible);
|
| + }
|
| +
|
| + {
|
| + ScopedComPtr<IDispatch> result;
|
| + ScopedVariant child2(2);
|
| + ASSERT_EQ(S_OK, root_iaccessible->get_accChild(child2, result.Receive()));
|
| + ASSERT_EQ(result.get(), checkbox_iaccessible);
|
| + }
|
| +
|
| + {
|
| + // Asking for child id 3 should fail.
|
| + ScopedComPtr<IDispatch> result;
|
| + ScopedVariant child3(3);
|
| + ASSERT_EQ(E_FAIL, root_iaccessible->get_accChild(child3, result.Receive()));
|
| + }
|
| +
|
| + // We should be able to ask for the button by its unique id too.
|
| + LONG button_unique_id;
|
| + ScopedComPtr<IAccessible2> button_iaccessible2 =
|
| + ToIAccessible2(button_iaccessible);
|
| + button_iaccessible2->get_uniqueID(&button_unique_id);
|
| + ASSERT_LT(button_unique_id, 0);
|
| + {
|
| + ScopedComPtr<IDispatch> result;
|
| + ScopedVariant button_id_variant(button_unique_id);
|
| + ASSERT_EQ(S_OK, root_iaccessible->get_accChild(button_id_variant,
|
| + result.Receive()));
|
| + ASSERT_EQ(result.get(), button_iaccessible);
|
| + }
|
| +
|
| + // Now check parents.
|
| + {
|
| + ScopedComPtr<IDispatch> result;
|
| + ASSERT_EQ(S_OK, button_iaccessible->get_accParent(result.Receive()));
|
| + ASSERT_EQ(result.get(), root_iaccessible);
|
| + }
|
| +
|
| + {
|
| + ScopedComPtr<IDispatch> result;
|
| + ASSERT_EQ(S_OK, checkbox_iaccessible->get_accParent(result.Receive()));
|
| + ASSERT_EQ(result.get(), root_iaccessible);
|
| + }
|
| +
|
| + {
|
| + ScopedComPtr<IDispatch> result;
|
| + ASSERT_EQ(S_FALSE, root_iaccessible->get_accParent(result.Receive()));
|
| + }
|
| +}
|
| +
|
| +} // namespace ui
|
|
|