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 |