Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ui / accessibility / platform / ax_platform_node_win_unittest.cc
blob8c441400a2616b37f8747fbb9b3d0104fb90732b
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <atlbase.h>
6 #include <atlcom.h>
7 #include <oleacc.h>
9 #include "base/memory/scoped_ptr.h"
10 #include "base/win/scoped_bstr.h"
11 #include "base/win/scoped_comptr.h"
12 #include "base/win/scoped_variant.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/iaccessible2/ia2_api_all.h"
15 #include "ui/accessibility/ax_node_data.h"
16 #include "ui/accessibility/platform/ax_platform_node.h"
17 #include "ui/accessibility/platform/test_ax_node_wrapper.h"
18 #include "ui/base/win/atl_module.h"
20 using base::win::ScopedBstr;
21 using base::win::ScopedComPtr;
22 using base::win::ScopedVariant;
24 namespace ui {
26 namespace {
28 // Most IAccessible functions require a VARIANT set to CHILDID_SELF as
29 // the first argument.
30 ScopedVariant SELF(CHILDID_SELF);
32 } // namespace
34 class AXPlatformNodeWinTest : public testing::Test {
35 public:
36 AXPlatformNodeWinTest() {}
37 ~AXPlatformNodeWinTest() override {}
39 void SetUp() override {
40 win::CreateATLModuleIfNeeded();
43 // Initialize given an AXTreeUpdate.
44 void Init(const AXTreeUpdate<AXNodeData>& initial_state) {
45 tree_.reset(new AXTree(initial_state));
48 // Convenience functions to initialize directly from a few AXNodeDatas.
49 void Init(const AXNodeData& node1) {
50 AXTreeUpdate<AXNodeData> update;
51 update.nodes.push_back(node1);
52 Init(update);
55 void Init(const AXNodeData& node1,
56 const AXNodeData& node2) {
57 AXTreeUpdate<AXNodeData> update;
58 update.nodes.push_back(node1);
59 update.nodes.push_back(node2);
60 Init(update);
63 void Init(const AXNodeData& node1,
64 const AXNodeData& node2,
65 const AXNodeData& node3) {
66 AXTreeUpdate<AXNodeData> update;
67 update.nodes.push_back(node1);
68 update.nodes.push_back(node2);
69 update.nodes.push_back(node3);
70 Init(update);
73 protected:
74 AXNode* GetRootNode() {
75 return tree_->root();
78 ScopedComPtr<IAccessible> IAccessibleFromNode(AXNode* node) {
79 TestAXNodeWrapper* wrapper =
80 TestAXNodeWrapper::GetOrCreate(tree_.get(), node);
81 AXPlatformNode* ax_platform_node = wrapper->ax_platform_node();
82 IAccessible* iaccessible = ax_platform_node->GetNativeViewAccessible();
83 iaccessible->AddRef();
84 return ScopedComPtr<IAccessible>(iaccessible);
87 ScopedComPtr<IAccessible> GetRootIAccessible() {
88 return IAccessibleFromNode(GetRootNode());
91 ScopedComPtr<IAccessible2> ToIAccessible2(
92 ScopedComPtr<IAccessible> accessible) {
93 ScopedComPtr<IServiceProvider> service_provider;
94 service_provider.QueryFrom(accessible.get());
95 ScopedComPtr<IAccessible2> result;
96 CHECK(SUCCEEDED(
97 service_provider->QueryService(IID_IAccessible2, result.Receive())));
98 return result;
101 scoped_ptr<AXTree> tree_;
104 TEST_F(AXPlatformNodeWinTest, TestIAccessibleDetachedObject) {
105 AXNodeData root;
106 root.id = 1;
107 root.role = AX_ROLE_ROOT_WEB_AREA;
108 root.AddStringAttribute(AX_ATTR_NAME, "Name");
109 Init(root);
111 ScopedComPtr<IAccessible> root_obj(GetRootIAccessible());
112 ScopedBstr name;
113 ASSERT_EQ(S_OK, root_obj->get_accName(SELF, name.Receive()));
114 EXPECT_EQ(L"Name", base::string16(name));
116 tree_.reset(new AXTree());
117 ScopedBstr name2;
118 ASSERT_EQ(E_FAIL, root_obj->get_accName(SELF, name2.Receive()));
121 TEST_F(AXPlatformNodeWinTest, TestIAccessibleName) {
122 AXNodeData root;
123 root.id = 1;
124 root.role = AX_ROLE_ROOT_WEB_AREA;
125 root.AddStringAttribute(AX_ATTR_NAME, "Name");
126 Init(root);
128 ScopedComPtr<IAccessible> root_obj(GetRootIAccessible());
129 ScopedBstr name;
130 ASSERT_EQ(S_OK, root_obj->get_accName(SELF, name.Receive()));
131 EXPECT_EQ(L"Name", base::string16(name));
133 ASSERT_EQ(E_INVALIDARG, root_obj->get_accName(SELF, nullptr));
134 ScopedVariant bad_id(999);
135 ScopedBstr name2;
136 ASSERT_EQ(E_INVALIDARG, root_obj->get_accName(bad_id, name2.Receive()));
139 TEST_F(AXPlatformNodeWinTest, TestIAccessibleDescription) {
140 AXNodeData root;
141 root.id = 1;
142 root.role = AX_ROLE_ROOT_WEB_AREA;
143 root.AddStringAttribute(AX_ATTR_DESCRIPTION, "Description");
144 Init(root);
146 ScopedComPtr<IAccessible> root_obj(GetRootIAccessible());
147 ScopedBstr description;
148 ASSERT_EQ(S_OK, root_obj->get_accDescription(SELF, description.Receive()));
149 EXPECT_EQ(L"Description", base::string16(description));
151 ASSERT_EQ(E_INVALIDARG, root_obj->get_accDescription(SELF, nullptr));
152 ScopedVariant bad_id(999);
153 ScopedBstr d2;
154 ASSERT_EQ(E_INVALIDARG, root_obj->get_accDescription(bad_id, d2.Receive()));
157 TEST_F(AXPlatformNodeWinTest, TestIAccessibleHelp) {
158 AXNodeData root;
159 root.id = 1;
160 root.role = AX_ROLE_ROOT_WEB_AREA;
161 root.AddStringAttribute(AX_ATTR_HELP, "Help");
162 Init(root);
164 ScopedComPtr<IAccessible> root_obj(GetRootIAccessible());
165 ScopedBstr help;
166 ASSERT_EQ(S_OK, root_obj->get_accHelp(SELF, help.Receive()));
167 EXPECT_EQ(L"Help", base::string16(help));
169 ASSERT_EQ(E_INVALIDARG, root_obj->get_accHelp(SELF, nullptr));
170 ScopedVariant bad_id(999);
171 ScopedBstr h2;
172 ASSERT_EQ(E_INVALIDARG, root_obj->get_accHelp(bad_id, h2.Receive()));
175 TEST_F(AXPlatformNodeWinTest, TestIAccessibleValue) {
176 AXNodeData root;
177 root.id = 1;
178 root.role = AX_ROLE_ROOT_WEB_AREA;
179 root.AddStringAttribute(AX_ATTR_VALUE, "Value");
180 Init(root);
182 ScopedComPtr<IAccessible> root_obj(GetRootIAccessible());
183 ScopedBstr value;
184 ASSERT_EQ(S_OK, root_obj->get_accValue(SELF, value.Receive()));
185 EXPECT_EQ(L"Value", base::string16(value));
187 ASSERT_EQ(E_INVALIDARG, root_obj->get_accValue(SELF, nullptr));
188 ScopedVariant bad_id(999);
189 ScopedBstr v2;
190 ASSERT_EQ(E_INVALIDARG, root_obj->get_accValue(bad_id, v2.Receive()));
193 TEST_F(AXPlatformNodeWinTest, TestIAccessibleShortcut) {
194 AXNodeData root;
195 root.id = 1;
196 root.role = AX_ROLE_ROOT_WEB_AREA;
197 root.AddStringAttribute(AX_ATTR_SHORTCUT, "Shortcut");
198 Init(root);
200 ScopedComPtr<IAccessible> root_obj(GetRootIAccessible());
201 ScopedBstr shortcut;
202 ASSERT_EQ(S_OK, root_obj->get_accKeyboardShortcut(
203 SELF, shortcut.Receive()));
204 EXPECT_EQ(L"Shortcut", base::string16(shortcut));
206 ASSERT_EQ(E_INVALIDARG, root_obj->get_accKeyboardShortcut(SELF, nullptr));
207 ScopedVariant bad_id(999);
208 ScopedBstr k2;
209 ASSERT_EQ(E_INVALIDARG, root_obj->get_accKeyboardShortcut(
210 bad_id, k2.Receive()));
213 TEST_F(AXPlatformNodeWinTest, TestIAccessibleRole) {
214 AXNodeData root;
215 root.id = 1;
216 root.role = AX_ROLE_ROOT_WEB_AREA;
217 root.child_ids.push_back(2);
219 AXNodeData child;
220 child.id = 2;
222 Init(root, child);
223 AXNode* child_node = GetRootNode()->children()[0];
224 ScopedComPtr<IAccessible> child_iaccessible(
225 IAccessibleFromNode(child_node));
227 ScopedVariant role;
229 child.role = AX_ROLE_ALERT;
230 child_node->SetData(child);
231 ASSERT_EQ(S_OK, child_iaccessible->get_accRole(SELF, role.Receive()));
232 EXPECT_EQ(ROLE_SYSTEM_ALERT, V_I4(role.ptr()));
234 child.role = AX_ROLE_BUTTON;
235 child_node->SetData(child);
236 ASSERT_EQ(S_OK, child_iaccessible->get_accRole(SELF, role.Receive()));
237 EXPECT_EQ(ROLE_SYSTEM_PUSHBUTTON, V_I4(role.ptr()));
239 child.role = AX_ROLE_POP_UP_BUTTON;
240 child_node->SetData(child);
241 ASSERT_EQ(S_OK, child_iaccessible->get_accRole(SELF, role.Receive()));
242 EXPECT_EQ(ROLE_SYSTEM_BUTTONMENU, V_I4(role.ptr()));
244 ASSERT_EQ(E_INVALIDARG, child_iaccessible->get_accRole(SELF, nullptr));
245 ScopedVariant bad_id(999);
246 ASSERT_EQ(E_INVALIDARG, child_iaccessible->get_accRole(
247 bad_id, role.Receive()));
250 TEST_F(AXPlatformNodeWinTest, TestIAccessibleLocation) {
251 AXNodeData root;
252 root.id = 1;
253 root.role = AX_ROLE_ROOT_WEB_AREA;
254 root.location = gfx::Rect(10, 40, 800, 600);
255 Init(root);
257 TestAXNodeWrapper::SetGlobalCoordinateOffset(gfx::Vector2d(100, 200));
259 LONG x_left, y_top, width, height;
260 ASSERT_EQ(S_OK, GetRootIAccessible()->accLocation(
261 &x_left, &y_top, &width, &height, SELF));
262 EXPECT_EQ(110, x_left);
263 EXPECT_EQ(240, y_top);
264 EXPECT_EQ(800, width);
265 EXPECT_EQ(600, height);
267 ASSERT_EQ(E_INVALIDARG, GetRootIAccessible()->accLocation(
268 nullptr, &y_top, &width, &height, SELF));
269 ASSERT_EQ(E_INVALIDARG, GetRootIAccessible()->accLocation(
270 &x_left, nullptr, &width, &height, SELF));
271 ASSERT_EQ(E_INVALIDARG, GetRootIAccessible()->accLocation(
272 &x_left, &y_top, nullptr, &height, SELF));
273 ASSERT_EQ(E_INVALIDARG, GetRootIAccessible()->accLocation(
274 &x_left, &y_top, &width, nullptr, SELF));
275 ScopedVariant bad_id(999);
276 ASSERT_EQ(E_INVALIDARG, GetRootIAccessible()->accLocation(
277 &x_left, &y_top, &width, &height, bad_id));
280 TEST_F(AXPlatformNodeWinTest, TestIAccessibleChildAndParent) {
281 AXNodeData root;
282 root.id = 1;
283 root.role = AX_ROLE_ROOT_WEB_AREA;
284 root.child_ids.push_back(2);
285 root.child_ids.push_back(3);
287 AXNodeData button;
288 button.role = AX_ROLE_BUTTON;
289 button.id = 2;
291 AXNodeData checkbox;
292 checkbox.role = AX_ROLE_CHECK_BOX;
293 checkbox.id = 3;
295 Init(root, button, checkbox);
296 AXNode* button_node = GetRootNode()->children()[0];
297 AXNode* checkbox_node = GetRootNode()->children()[1];
298 ScopedComPtr<IAccessible> root_iaccessible(GetRootIAccessible());
299 ScopedComPtr<IAccessible> button_iaccessible(
300 IAccessibleFromNode(button_node));
301 ScopedComPtr<IAccessible> checkbox_iaccessible(
302 IAccessibleFromNode(checkbox_node));
304 LONG child_count;
305 ASSERT_EQ(S_OK, root_iaccessible->get_accChildCount(&child_count));
306 ASSERT_EQ(2L, child_count);
307 ASSERT_EQ(S_OK, button_iaccessible->get_accChildCount(&child_count));
308 ASSERT_EQ(0L, child_count);
309 ASSERT_EQ(S_OK, checkbox_iaccessible->get_accChildCount(&child_count));
310 ASSERT_EQ(0L, child_count);
313 ScopedComPtr<IDispatch> result;
314 ASSERT_EQ(S_OK, root_iaccessible->get_accChild(SELF, result.Receive()));
315 ASSERT_EQ(result.get(), root_iaccessible);
319 ScopedComPtr<IDispatch> result;
320 ScopedVariant child1(1);
321 ASSERT_EQ(S_OK, root_iaccessible->get_accChild(child1, result.Receive()));
322 ASSERT_EQ(result.get(), button_iaccessible);
326 ScopedComPtr<IDispatch> result;
327 ScopedVariant child2(2);
328 ASSERT_EQ(S_OK, root_iaccessible->get_accChild(child2, result.Receive()));
329 ASSERT_EQ(result.get(), checkbox_iaccessible);
333 // Asking for child id 3 should fail.
334 ScopedComPtr<IDispatch> result;
335 ScopedVariant child3(3);
336 ASSERT_EQ(E_FAIL, root_iaccessible->get_accChild(child3, result.Receive()));
339 // We should be able to ask for the button by its unique id too.
340 LONG button_unique_id;
341 ScopedComPtr<IAccessible2> button_iaccessible2 =
342 ToIAccessible2(button_iaccessible);
343 button_iaccessible2->get_uniqueID(&button_unique_id);
344 ASSERT_LT(button_unique_id, 0);
346 ScopedComPtr<IDispatch> result;
347 ScopedVariant button_id_variant(button_unique_id);
348 ASSERT_EQ(S_OK, root_iaccessible->get_accChild(button_id_variant,
349 result.Receive()));
350 ASSERT_EQ(result.get(), button_iaccessible);
353 // Now check parents.
355 ScopedComPtr<IDispatch> result;
356 ASSERT_EQ(S_OK, button_iaccessible->get_accParent(result.Receive()));
357 ASSERT_EQ(result.get(), root_iaccessible);
361 ScopedComPtr<IDispatch> result;
362 ASSERT_EQ(S_OK, checkbox_iaccessible->get_accParent(result.Receive()));
363 ASSERT_EQ(result.get(), root_iaccessible);
367 ScopedComPtr<IDispatch> result;
368 ASSERT_EQ(S_FALSE, root_iaccessible->get_accParent(result.Receive()));
372 TEST_F(AXPlatformNodeWinTest, TestIAccessible2IndexInParent) {
373 AXNodeData root;
374 root.id = 1;
375 root.role = AX_ROLE_ROOT_WEB_AREA;
376 root.child_ids.push_back(2);
377 root.child_ids.push_back(3);
379 AXNodeData left;
380 left.id = 2;
382 AXNodeData right;
383 right.id = 3;
385 Init(root, left, right);
386 ScopedComPtr<IAccessible> root_iaccessible(GetRootIAccessible());
387 ScopedComPtr<IAccessible2> root_iaccessible2 =
388 ToIAccessible2(root_iaccessible);
389 ScopedComPtr<IAccessible> left_iaccessible(
390 IAccessibleFromNode(GetRootNode()->children()[0]));
391 ScopedComPtr<IAccessible2> left_iaccessible2 =
392 ToIAccessible2(left_iaccessible);
393 ScopedComPtr<IAccessible> right_iaccessible(
394 IAccessibleFromNode(GetRootNode()->children()[1]));
395 ScopedComPtr<IAccessible2> right_iaccessible2 =
396 ToIAccessible2(right_iaccessible);
398 LONG index;
399 ASSERT_EQ(E_FAIL, root_iaccessible2->get_indexInParent(&index));
401 ASSERT_EQ(S_OK, left_iaccessible2->get_indexInParent(&index));
402 EXPECT_EQ(0, index);
404 ASSERT_EQ(S_OK, right_iaccessible2->get_indexInParent(&index));
405 EXPECT_EQ(1, index);
408 } // namespace ui