OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include <atlbase.h> | |
6 #include <atlcom.h> | |
7 #include <oleacc.h> | |
8 | |
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" | |
19 | |
20 using base::win::ScopedBstr; | |
21 using base::win::ScopedComPtr; | |
22 using base::win::ScopedVariant; | |
23 | |
24 namespace ui { | |
25 | |
26 namespace { | |
27 | |
28 // Most IAccessible functions require a VARIANT set to CHILDID_SELF as | |
29 // the first argument. | |
30 ScopedVariant SELF(CHILDID_SELF); | |
31 | |
32 } // namespace | |
33 | |
34 class AXPlatformNodeWinTest : public testing::Test { | |
35 public: | |
36 AXPlatformNodeWinTest() {} | |
37 virtual ~AXPlatformNodeWinTest() {} | |
38 | |
39 void SetUp() override { | |
40 win::CreateATLModuleIfNeeded(); | |
41 } | |
42 | |
43 // Initialize given an AXTreeUpdate. | |
44 void Init(const AXTreeUpdate& initial_state) { | |
45 tree_.reset(new AXTree(initial_state)); | |
46 } | |
47 | |
48 // Convenience functions to initialize directly from a few AXNodeDatas. | |
49 void Init(const AXNodeData& node1) { | |
50 AXTreeUpdate update; | |
51 update.nodes.push_back(node1); | |
52 Init(update); | |
53 } | |
54 | |
55 void Init(const AXNodeData& node1, | |
56 const AXNodeData& node2) { | |
57 AXTreeUpdate update; | |
58 update.nodes.push_back(node1); | |
59 update.nodes.push_back(node2); | |
60 Init(update); | |
61 } | |
62 | |
63 void Init(const AXNodeData& node1, | |
64 const AXNodeData& node2, | |
65 const AXNodeData& node3) { | |
66 AXTreeUpdate update; | |
67 update.nodes.push_back(node1); | |
68 update.nodes.push_back(node2); | |
69 update.nodes.push_back(node3); | |
70 Init(update); | |
71 } | |
72 | |
73 protected: | |
74 AXNode* GetRootNode() { | |
75 return tree_->root(); | |
76 } | |
77 | |
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); | |
85 } | |
86 | |
87 ScopedComPtr<IAccessible> GetRootIAccessible() { | |
88 return IAccessibleFromNode(GetRootNode()); | |
89 } | |
90 | |
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; | |
99 } | |
100 | |
101 scoped_ptr<AXTree> tree_; | |
102 }; | |
103 | |
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); | |
110 | |
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)); | |
115 | |
116 tree_.reset(new AXTree()); | |
117 ScopedBstr name2; | |
118 ASSERT_EQ(E_FAIL, root_obj->get_accName(SELF, name2.Receive())); | |
119 } | |
120 | |
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); | |
127 | |
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)); | |
132 | |
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())); | |
137 } | |
138 | |
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); | |
145 | |
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)); | |
150 | |
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())); | |
155 } | |
156 | |
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); | |
163 | |
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)); | |
168 | |
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())); | |
173 } | |
174 | |
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); | |
181 | |
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)); | |
186 | |
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())); | |
191 } | |
192 | |
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); | |
199 | |
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)); | |
205 | |
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())); | |
211 } | |
212 | |
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); | |
218 | |
219 AXNodeData child; | |
220 child.id = 2; | |
221 | |
222 Init(root, child); | |
223 AXNode* child_node = GetRootNode()->children()[0]; | |
224 ScopedComPtr<IAccessible> child_iaccessible( | |
225 IAccessibleFromNode(child_node)); | |
226 | |
227 ScopedVariant role; | |
228 | |
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)); | |
233 | |
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)); | |
238 | |
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)); | |
243 | |
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())); | |
248 } | |
249 | |
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); | |
256 | |
257 TestAXNodeWrapper::SetGlobalCoordinateOffset(gfx::Vector2d(100, 200)); | |
258 | |
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); | |
266 | |
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)); | |
278 } | |
279 | |
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); | |
286 | |
287 AXNodeData button; | |
288 button.role = AX_ROLE_BUTTON; | |
289 button.id = 2; | |
290 | |
291 AXNodeData checkbox; | |
292 checkbox.role = AX_ROLE_CHECK_BOX; | |
293 checkbox.id = 3; | |
294 | |
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)); | |
303 | |
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); | |
311 | |
312 { | |
313 ScopedComPtr<IDispatch> result; | |
314 ASSERT_EQ(S_OK, root_iaccessible->get_accChild(SELF, result.Receive())); | |
315 ASSERT_EQ(result.get(), root_iaccessible); | |
316 } | |
317 | |
318 { | |
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); | |
323 } | |
324 | |
325 { | |
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); | |
330 } | |
331 | |
332 { | |
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())); | |
337 } | |
338 | |
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); | |
345 { | |
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); | |
351 } | |
352 | |
353 // Now check parents. | |
354 { | |
355 ScopedComPtr<IDispatch> result; | |
356 ASSERT_EQ(S_OK, button_iaccessible->get_accParent(result.Receive())); | |
357 ASSERT_EQ(result.get(), root_iaccessible); | |
358 } | |
359 | |
360 { | |
361 ScopedComPtr<IDispatch> result; | |
362 ASSERT_EQ(S_OK, checkbox_iaccessible->get_accParent(result.Receive())); | |
363 ASSERT_EQ(result.get(), root_iaccessible); | |
364 } | |
365 | |
366 { | |
367 ScopedComPtr<IDispatch> result; | |
368 ASSERT_EQ(S_FALSE, root_iaccessible->get_accParent(result.Receive())); | |
369 } | |
370 } | |
371 | |
372 } // namespace ui | |
OLD | NEW |