1 // Copyright (c) 2012 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 "base/memory/scoped_ptr.h"
6 #include "base/strings/utf_string_conversions.h"
7 #include "base/win/scoped_bstr.h"
8 #include "base/win/scoped_comptr.h"
9 #include "base/win/scoped_variant.h"
10 #include "content/browser/accessibility/browser_accessibility_manager.h"
11 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
12 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
13 #include "content/browser/accessibility/browser_accessibility_win.h"
14 #include "content/browser/renderer_host/legacy_render_widget_host_win.h"
15 #include "content/common/accessibility_messages.h"
16 #include "content/public/test/test_browser_thread_bundle.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "ui/base/win/atl_module.h"
24 // CountedBrowserAccessibility ------------------------------------------------
26 // Subclass of BrowserAccessibilityWin that counts the number of instances.
27 class CountedBrowserAccessibility
: public BrowserAccessibilityWin
{
29 CountedBrowserAccessibility();
30 ~CountedBrowserAccessibility() override
;
32 static void reset() { num_instances_
= 0; }
33 static int num_instances() { return num_instances_
; }
36 static int num_instances_
;
38 DISALLOW_COPY_AND_ASSIGN(CountedBrowserAccessibility
);
42 int CountedBrowserAccessibility::num_instances_
= 0;
44 CountedBrowserAccessibility::CountedBrowserAccessibility() {
48 CountedBrowserAccessibility::~CountedBrowserAccessibility() {
53 // CountedBrowserAccessibilityFactory -----------------------------------------
55 // Factory that creates a CountedBrowserAccessibility.
56 class CountedBrowserAccessibilityFactory
: public BrowserAccessibilityFactory
{
58 CountedBrowserAccessibilityFactory();
61 ~CountedBrowserAccessibilityFactory() override
;
63 BrowserAccessibility
* Create() override
;
65 DISALLOW_COPY_AND_ASSIGN(CountedBrowserAccessibilityFactory
);
68 CountedBrowserAccessibilityFactory::CountedBrowserAccessibilityFactory() {
71 CountedBrowserAccessibilityFactory::~CountedBrowserAccessibilityFactory() {
74 BrowserAccessibility
* CountedBrowserAccessibilityFactory::Create() {
75 CComObject
<CountedBrowserAccessibility
>* instance
;
76 HRESULT hr
= CComObject
<CountedBrowserAccessibility
>::CreateInstance(
78 DCHECK(SUCCEEDED(hr
));
86 // BrowserAccessibilityTest ---------------------------------------------------
88 class BrowserAccessibilityTest
: public testing::Test
{
90 BrowserAccessibilityTest();
91 ~BrowserAccessibilityTest() override
;
94 void SetUp() override
;
96 content::TestBrowserThreadBundle thread_bundle_
;
98 DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityTest
);
101 BrowserAccessibilityTest::BrowserAccessibilityTest() {
104 BrowserAccessibilityTest::~BrowserAccessibilityTest() {
107 void BrowserAccessibilityTest::SetUp() {
108 ui::win::CreateATLModuleIfNeeded();
112 // Actual tests ---------------------------------------------------------------
114 // Test that BrowserAccessibilityManager correctly releases the tree of
115 // BrowserAccessibility instances upon delete.
116 TEST_F(BrowserAccessibilityTest
, TestNoLeaks
) {
117 // Create ui::AXNodeData objects for a simple document tree,
118 // representing the accessibility information used to initialize
119 // BrowserAccessibilityManager.
120 ui::AXNodeData button
;
122 button
.SetName("Button");
123 button
.role
= ui::AX_ROLE_BUTTON
;
126 ui::AXNodeData checkbox
;
128 checkbox
.SetName("Checkbox");
129 checkbox
.role
= ui::AX_ROLE_CHECK_BOX
;
134 root
.SetName("Document");
135 root
.role
= ui::AX_ROLE_ROOT_WEB_AREA
;
137 root
.child_ids
.push_back(2);
138 root
.child_ids
.push_back(3);
140 // Construct a BrowserAccessibilityManager with this
141 // ui::AXNodeData tree and a factory for an instance-counting
142 // BrowserAccessibility, and ensure that exactly 3 instances were
143 // created. Note that the manager takes ownership of the factory.
144 CountedBrowserAccessibility::reset();
145 scoped_ptr
<BrowserAccessibilityManager
> manager(
146 BrowserAccessibilityManager::Create(
147 MakeAXTreeUpdate(root
, button
, checkbox
),
148 NULL
, new CountedBrowserAccessibilityFactory()));
149 ASSERT_EQ(3, CountedBrowserAccessibility::num_instances());
151 // Delete the manager and test that all 3 instances are deleted.
153 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
155 // Construct a manager again, and this time use the IAccessible interface
156 // to get new references to two of the three nodes in the tree.
157 manager
.reset(BrowserAccessibilityManager::Create(
158 MakeAXTreeUpdate(root
, button
, checkbox
),
159 NULL
, new CountedBrowserAccessibilityFactory()));
160 ASSERT_EQ(3, CountedBrowserAccessibility::num_instances());
161 IAccessible
* root_accessible
=
162 manager
->GetRoot()->ToBrowserAccessibilityWin();
163 IDispatch
* root_iaccessible
= NULL
;
164 IDispatch
* child1_iaccessible
= NULL
;
165 base::win::ScopedVariant
childid_self(CHILDID_SELF
);
166 HRESULT hr
= root_accessible
->get_accChild(childid_self
, &root_iaccessible
);
168 base::win::ScopedVariant
one(1);
169 hr
= root_accessible
->get_accChild(one
, &child1_iaccessible
);
172 // Now delete the manager, and only one of the three nodes in the tree
173 // should be released.
175 ASSERT_EQ(2, CountedBrowserAccessibility::num_instances());
177 // Release each of our references and make sure that each one results in
178 // the instance being deleted as its reference count hits zero.
179 root_iaccessible
->Release();
180 ASSERT_EQ(1, CountedBrowserAccessibility::num_instances());
181 child1_iaccessible
->Release();
182 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
185 TEST_F(BrowserAccessibilityTest
, TestChildrenChange
) {
186 // Create ui::AXNodeData objects for a simple document tree,
187 // representing the accessibility information used to initialize
188 // BrowserAccessibilityManager.
191 text
.role
= ui::AX_ROLE_STATIC_TEXT
;
192 text
.SetName("old text");
197 root
.SetName("Document");
198 root
.role
= ui::AX_ROLE_ROOT_WEB_AREA
;
200 root
.child_ids
.push_back(2);
202 // Construct a BrowserAccessibilityManager with this
203 // ui::AXNodeData tree and a factory for an instance-counting
204 // BrowserAccessibility.
205 CountedBrowserAccessibility::reset();
206 scoped_ptr
<BrowserAccessibilityManager
> manager(
207 BrowserAccessibilityManager::Create(
208 MakeAXTreeUpdate(root
, text
),
209 NULL
, new CountedBrowserAccessibilityFactory()));
211 // Query for the text IAccessible and verify that it returns "old text" as its
213 base::win::ScopedVariant
one(1);
214 base::win::ScopedComPtr
<IDispatch
> text_dispatch
;
215 HRESULT hr
= manager
->GetRoot()->ToBrowserAccessibilityWin()->get_accChild(
216 one
, text_dispatch
.Receive());
219 base::win::ScopedComPtr
<IAccessible
> text_accessible
;
220 hr
= text_dispatch
.QueryInterface(text_accessible
.Receive());
223 base::win::ScopedVariant
childid_self(CHILDID_SELF
);
224 base::win::ScopedBstr name
;
225 hr
= text_accessible
->get_accName(childid_self
, name
.Receive());
227 EXPECT_EQ(L
"old text", base::string16(name
));
230 text_dispatch
.Release();
231 text_accessible
.Release();
233 // Notify the BrowserAccessibilityManager that the text child has changed.
234 AXContentNodeData text2
;
236 text2
.role
= ui::AX_ROLE_STATIC_TEXT
;
237 text2
.SetName("new text");
238 text2
.SetName("old text");
239 AXEventNotificationDetails param
;
240 param
.event_type
= ui::AX_EVENT_CHILDREN_CHANGED
;
241 param
.update
.nodes
.push_back(text2
);
243 std::vector
<AXEventNotificationDetails
> events
;
244 events
.push_back(param
);
245 manager
->OnAccessibilityEvents(events
);
247 // Query for the text IAccessible and verify that it now returns "new text"
249 hr
= manager
->GetRoot()->ToBrowserAccessibilityWin()->get_accChild(
250 one
, text_dispatch
.Receive());
253 hr
= text_dispatch
.QueryInterface(text_accessible
.Receive());
256 hr
= text_accessible
->get_accName(childid_self
, name
.Receive());
258 EXPECT_EQ(L
"new text", base::string16(name
));
260 text_dispatch
.Release();
261 text_accessible
.Release();
263 // Delete the manager and test that all BrowserAccessibility instances are
266 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
269 TEST_F(BrowserAccessibilityTest
, TestChildrenChangeNoLeaks
) {
270 // Create ui::AXNodeData objects for a simple document tree,
271 // representing the accessibility information used to initialize
272 // BrowserAccessibilityManager.
275 div
.role
= ui::AX_ROLE_GROUP
;
278 ui::AXNodeData text3
;
280 text3
.role
= ui::AX_ROLE_STATIC_TEXT
;
283 ui::AXNodeData text4
;
285 text4
.role
= ui::AX_ROLE_STATIC_TEXT
;
288 div
.child_ids
.push_back(3);
289 div
.child_ids
.push_back(4);
293 root
.role
= ui::AX_ROLE_ROOT_WEB_AREA
;
295 root
.child_ids
.push_back(2);
297 // Construct a BrowserAccessibilityManager with this
298 // ui::AXNodeData tree and a factory for an instance-counting
299 // BrowserAccessibility and ensure that exactly 4 instances were
300 // created. Note that the manager takes ownership of the factory.
301 CountedBrowserAccessibility::reset();
302 scoped_ptr
<BrowserAccessibilityManager
> manager(
303 BrowserAccessibilityManager::Create(
304 MakeAXTreeUpdate(root
, div
, text3
, text4
),
305 NULL
, new CountedBrowserAccessibilityFactory()));
306 ASSERT_EQ(4, CountedBrowserAccessibility::num_instances());
308 // Notify the BrowserAccessibilityManager that the div node and its children
309 // were removed and ensure that only one BrowserAccessibility instance exists.
310 root
.child_ids
.clear();
311 AXEventNotificationDetails param
;
312 param
.event_type
= ui::AX_EVENT_CHILDREN_CHANGED
;
313 param
.update
.nodes
.push_back(root
);
315 std::vector
<AXEventNotificationDetails
> events
;
316 events
.push_back(param
);
317 manager
->OnAccessibilityEvents(events
);
318 ASSERT_EQ(1, CountedBrowserAccessibility::num_instances());
320 // Delete the manager and test that all BrowserAccessibility instances are
323 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
326 TEST_F(BrowserAccessibilityTest
, TestTextBoundaries
) {
327 std::string line1
= "One two three.";
328 std::string line2
= "Four five six.";
329 std::string text_value
= line1
+ '\n' + line2
;
333 root
.role
= ui::AX_ROLE_ROOT_WEB_AREA
;
334 root
.child_ids
.push_back(2);
336 ui::AXNodeData text_field
;
338 text_field
.role
= ui::AX_ROLE_TEXT_FIELD
;
339 text_field
.AddStringAttribute(ui::AX_ATTR_VALUE
, text_value
);
340 std::vector
<int32
> line_start_offsets
;
341 line_start_offsets
.push_back(15);
342 text_field
.AddIntListAttribute(
343 ui::AX_ATTR_LINE_BREAKS
, line_start_offsets
);
344 text_field
.child_ids
.push_back(3);
345 text_field
.child_ids
.push_back(5);
346 text_field
.child_ids
.push_back(6);
348 ui::AXNodeData static_text1
;
350 static_text1
.role
= ui::AX_ROLE_STATIC_TEXT
;
351 static_text1
.AddStringAttribute(ui::AX_ATTR_VALUE
, line1
);
352 static_text1
.child_ids
.push_back(4);
354 ui::AXNodeData inline_box1
;
356 inline_box1
.role
= ui::AX_ROLE_INLINE_TEXT_BOX
;
357 inline_box1
.AddStringAttribute(ui::AX_ATTR_VALUE
, line1
);
358 std::vector
<int32
> word_start_offsets1
;
359 word_start_offsets1
.push_back(0);
360 word_start_offsets1
.push_back(4);
361 word_start_offsets1
.push_back(8);
362 inline_box1
.AddIntListAttribute(
363 ui::AX_ATTR_WORD_STARTS
, word_start_offsets1
);
365 ui::AXNodeData line_break
;
367 line_break
.role
= ui::AX_ROLE_LINE_BREAK
;
368 line_break
.AddStringAttribute(ui::AX_ATTR_VALUE
, "\n");
370 ui::AXNodeData static_text2
;
372 static_text2
.role
= ui::AX_ROLE_STATIC_TEXT
;
373 static_text2
.AddStringAttribute(ui::AX_ATTR_VALUE
, line2
);
374 static_text2
.child_ids
.push_back(7);
376 ui::AXNodeData inline_box2
;
378 inline_box2
.role
= ui::AX_ROLE_INLINE_TEXT_BOX
;
379 inline_box2
.AddStringAttribute(ui::AX_ATTR_VALUE
, line2
);
380 std::vector
<int32
> word_start_offsets2
;
381 word_start_offsets2
.push_back(0);
382 word_start_offsets2
.push_back(5);
383 word_start_offsets2
.push_back(10);
384 inline_box2
.AddIntListAttribute(
385 ui::AX_ATTR_WORD_STARTS
, word_start_offsets2
);
387 CountedBrowserAccessibility::reset();
388 scoped_ptr
<BrowserAccessibilityManager
> manager(
389 BrowserAccessibilityManager::Create(
390 MakeAXTreeUpdate(root
, text_field
, static_text1
, inline_box1
,
391 line_break
, static_text2
, inline_box2
),
392 nullptr, new CountedBrowserAccessibilityFactory()));
393 ASSERT_EQ(7, CountedBrowserAccessibility::num_instances());
395 BrowserAccessibilityWin
* root_obj
=
396 manager
->GetRoot()->ToBrowserAccessibilityWin();
397 ASSERT_NE(nullptr, root_obj
);
398 ASSERT_EQ(1, root_obj
->PlatformChildCount());
400 BrowserAccessibilityWin
* text_field_obj
=
401 root_obj
->PlatformGetChild(0)->ToBrowserAccessibilityWin();
402 ASSERT_NE(nullptr, text_field_obj
);
405 EXPECT_EQ(S_OK
, text_field_obj
->get_nCharacters(&text_len
));
407 base::win::ScopedBstr text
;
408 EXPECT_EQ(S_OK
, text_field_obj
->get_text(0, text_len
, text
.Receive()));
409 EXPECT_EQ(text_value
, base::UTF16ToUTF8(base::string16(text
)));
412 EXPECT_EQ(S_OK
, text_field_obj
->get_text(0, 4, text
.Receive()));
413 EXPECT_STREQ(L
"One ", text
);
418 EXPECT_EQ(S_OK
, text_field_obj
->get_textAtOffset(
419 1, IA2_TEXT_BOUNDARY_CHAR
, &start
, &end
, text
.Receive()));
422 EXPECT_STREQ(L
"n", text
);
425 EXPECT_EQ(S_FALSE
, text_field_obj
->get_textAtOffset(
426 text_len
, IA2_TEXT_BOUNDARY_CHAR
, &start
, &end
, text
.Receive()));
429 EXPECT_EQ(nullptr, text
);
432 EXPECT_EQ(S_FALSE
, text_field_obj
->get_textAtOffset(
433 text_len
, IA2_TEXT_BOUNDARY_WORD
, &start
, &end
, text
.Receive()));
436 EXPECT_EQ(nullptr, text
);
439 EXPECT_EQ(S_OK
, text_field_obj
->get_textAtOffset(
440 1, IA2_TEXT_BOUNDARY_WORD
, &start
, &end
, text
.Receive()));
443 EXPECT_STREQ(L
"One ", text
);
446 EXPECT_EQ(S_OK
, text_field_obj
->get_textAtOffset(
447 6, IA2_TEXT_BOUNDARY_WORD
, &start
, &end
, text
.Receive()));
450 EXPECT_STREQ(L
"two ", text
);
453 EXPECT_EQ(S_OK
, text_field_obj
->get_textAtOffset(
454 text_len
- 1, IA2_TEXT_BOUNDARY_WORD
, &start
, &end
, text
.Receive()));
455 EXPECT_EQ(25, start
);
457 EXPECT_STREQ(L
"six.", text
);
460 EXPECT_EQ(S_OK
, text_field_obj
->get_textAtOffset(
461 1, IA2_TEXT_BOUNDARY_LINE
, &start
, &end
, text
.Receive()));
464 EXPECT_STREQ(L
"One two three.\n", text
);
467 EXPECT_EQ(S_OK
, text_field_obj
->get_textAtOffset(
468 text_len
, IA2_TEXT_BOUNDARY_LINE
, &start
, &end
, text
.Receive()));
469 EXPECT_EQ(15, start
);
470 EXPECT_EQ(text_len
, end
);
471 EXPECT_STREQ(L
"Four five six.", text
);
474 EXPECT_EQ(S_OK
, text_field_obj
->get_text(
475 0, IA2_TEXT_OFFSET_LENGTH
, text
.Receive()));
476 EXPECT_EQ(text_value
, base::UTF16ToUTF8(base::string16(text
)));
478 // Delete the manager and test that all BrowserAccessibility instances are
481 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
484 TEST_F(BrowserAccessibilityTest
, TestSimpleHypertext
) {
485 const std::string text1_name
= "One two three.";
486 const std::string text2_name
= " Four five six.";
488 ui::AXNodeData text1
;
490 text1
.role
= ui::AX_ROLE_STATIC_TEXT
;
491 text1
.state
= 1 << ui::AX_STATE_READ_ONLY
;
492 text1
.SetName(text1_name
);
494 ui::AXNodeData text2
;
496 text2
.role
= ui::AX_ROLE_STATIC_TEXT
;
497 text2
.state
= 1 << ui::AX_STATE_READ_ONLY
;
498 text2
.SetName(text2_name
);
502 root
.role
= ui::AX_ROLE_ROOT_WEB_AREA
;
503 root
.state
= 1 << ui::AX_STATE_READ_ONLY
;
504 root
.child_ids
.push_back(11);
505 root
.child_ids
.push_back(12);
507 CountedBrowserAccessibility::reset();
508 scoped_ptr
<BrowserAccessibilityManager
> manager(
509 BrowserAccessibilityManager::Create(
510 MakeAXTreeUpdate(root
, text1
, text2
),
511 NULL
, new CountedBrowserAccessibilityFactory()));
512 ASSERT_EQ(3, CountedBrowserAccessibility::num_instances());
514 BrowserAccessibilityWin
* root_obj
=
515 manager
->GetRoot()->ToBrowserAccessibilityWin();
518 ASSERT_EQ(S_OK
, root_obj
->get_nCharacters(&text_len
));
520 base::win::ScopedBstr text
;
521 ASSERT_EQ(S_OK
, root_obj
->get_text(0, text_len
, text
.Receive()));
522 EXPECT_EQ(text1_name
+ text2_name
, base::UTF16ToUTF8(base::string16(text
)));
524 long hyperlink_count
;
525 ASSERT_EQ(S_OK
, root_obj
->get_nHyperlinks(&hyperlink_count
));
526 EXPECT_EQ(0, hyperlink_count
);
528 base::win::ScopedComPtr
<IAccessibleHyperlink
> hyperlink
;
529 EXPECT_EQ(E_INVALIDARG
, root_obj
->get_hyperlink(-1, hyperlink
.Receive()));
530 EXPECT_EQ(E_INVALIDARG
, root_obj
->get_hyperlink(0, hyperlink
.Receive()));
531 EXPECT_EQ(E_INVALIDARG
, root_obj
->get_hyperlink(28, hyperlink
.Receive()));
532 EXPECT_EQ(E_INVALIDARG
, root_obj
->get_hyperlink(29, hyperlink
.Receive()));
534 long hyperlink_index
;
535 EXPECT_EQ(E_FAIL
, root_obj
->get_hyperlinkIndex(0, &hyperlink_index
));
536 EXPECT_EQ(-1, hyperlink_index
);
537 EXPECT_EQ(E_FAIL
, root_obj
->get_hyperlinkIndex(28, &hyperlink_index
));
538 EXPECT_EQ(-1, hyperlink_index
);
539 EXPECT_EQ(E_INVALIDARG
, root_obj
->get_hyperlinkIndex(-1, &hyperlink_index
));
540 EXPECT_EQ(-1, hyperlink_index
);
541 EXPECT_EQ(E_INVALIDARG
, root_obj
->get_hyperlinkIndex(29, &hyperlink_index
));
542 EXPECT_EQ(-1, hyperlink_index
);
544 // Delete the manager and test that all BrowserAccessibility instances are
547 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
550 TEST_F(BrowserAccessibilityTest
, TestComplexHypertext
) {
551 const std::string text1_name
= "One two three.";
552 const std::string text2_name
= " Four five six.";
553 const std::string button1_text_name
= "red";
554 const std::string link1_text_name
= "blue";
556 ui::AXNodeData text1
;
558 text1
.role
= ui::AX_ROLE_STATIC_TEXT
;
559 text1
.state
= 1 << ui::AX_STATE_READ_ONLY
;
560 text1
.SetName(text1_name
);
562 ui::AXNodeData text2
;
564 text2
.role
= ui::AX_ROLE_STATIC_TEXT
;
565 text2
.state
= 1 << ui::AX_STATE_READ_ONLY
;
566 text2
.SetName(text2_name
);
568 ui::AXNodeData button1
, button1_text
;
570 button1_text
.id
= 15;
571 button1_text
.SetName(button1_text_name
);
572 button1
.role
= ui::AX_ROLE_BUTTON
;
573 button1_text
.role
= ui::AX_ROLE_STATIC_TEXT
;
574 button1
.state
= 1 << ui::AX_STATE_READ_ONLY
;
575 button1_text
.state
= 1 << ui::AX_STATE_READ_ONLY
;
576 button1
.child_ids
.push_back(15);
578 ui::AXNodeData link1
, link1_text
;
581 link1_text
.SetName(link1_text_name
);
582 link1
.role
= ui::AX_ROLE_LINK
;
583 link1_text
.role
= ui::AX_ROLE_STATIC_TEXT
;
584 link1
.state
= 1 << ui::AX_STATE_READ_ONLY
;
585 link1_text
.state
= 1 << ui::AX_STATE_READ_ONLY
;
586 link1
.child_ids
.push_back(16);
590 root
.role
= ui::AX_ROLE_ROOT_WEB_AREA
;
591 root
.state
= 1 << ui::AX_STATE_READ_ONLY
;
592 root
.child_ids
.push_back(11);
593 root
.child_ids
.push_back(13);
594 root
.child_ids
.push_back(12);
595 root
.child_ids
.push_back(14);
597 CountedBrowserAccessibility::reset();
598 scoped_ptr
<BrowserAccessibilityManager
> manager(
599 BrowserAccessibilityManager::Create(
600 MakeAXTreeUpdate(root
,
601 text1
, button1
, button1_text
,
602 text2
, link1
, link1_text
),
603 NULL
, new CountedBrowserAccessibilityFactory()));
604 ASSERT_EQ(7, CountedBrowserAccessibility::num_instances());
606 BrowserAccessibilityWin
* root_obj
=
607 manager
->GetRoot()->ToBrowserAccessibilityWin();
610 ASSERT_EQ(S_OK
, root_obj
->get_nCharacters(&text_len
));
612 base::win::ScopedBstr text
;
613 ASSERT_EQ(S_OK
, root_obj
->get_text(0, text_len
, text
.Receive()));
614 const std::string embed
= base::UTF16ToUTF8(
615 base::string16(1, BrowserAccessibilityWin::kEmbeddedCharacter
));
616 EXPECT_EQ(text1_name
+ embed
+ text2_name
+ embed
,
617 base::UTF16ToUTF8(base::string16(text
)));
620 long hyperlink_count
;
621 ASSERT_EQ(S_OK
, root_obj
->get_nHyperlinks(&hyperlink_count
));
622 EXPECT_EQ(2, hyperlink_count
);
624 base::win::ScopedComPtr
<IAccessibleHyperlink
> hyperlink
;
625 base::win::ScopedComPtr
<IAccessibleText
> hypertext
;
626 EXPECT_EQ(E_INVALIDARG
, root_obj
->get_hyperlink(-1, hyperlink
.Receive()));
627 EXPECT_EQ(E_INVALIDARG
, root_obj
->get_hyperlink(2, hyperlink
.Receive()));
628 EXPECT_EQ(E_INVALIDARG
, root_obj
->get_hyperlink(28, hyperlink
.Receive()));
630 EXPECT_EQ(S_OK
, root_obj
->get_hyperlink(0, hyperlink
.Receive()));
632 hyperlink
.QueryInterface
<IAccessibleText
>(hypertext
.Receive()));
633 EXPECT_EQ(S_OK
, hypertext
->get_text(0, 3, text
.Receive()));
634 EXPECT_STREQ(button1_text_name
.c_str(),
635 base::UTF16ToUTF8(base::string16(text
)).c_str());
640 EXPECT_EQ(S_OK
, root_obj
->get_hyperlink(1, hyperlink
.Receive()));
642 hyperlink
.QueryInterface
<IAccessibleText
>(hypertext
.Receive()));
643 EXPECT_EQ(S_OK
, hypertext
->get_text(0, 4, text
.Receive()));
644 EXPECT_STREQ(link1_text_name
.c_str(),
645 base::UTF16ToUTF8(base::string16(text
)).c_str());
650 long hyperlink_index
;
651 EXPECT_EQ(E_FAIL
, root_obj
->get_hyperlinkIndex(0, &hyperlink_index
));
652 EXPECT_EQ(-1, hyperlink_index
);
653 EXPECT_EQ(E_FAIL
, root_obj
->get_hyperlinkIndex(28, &hyperlink_index
));
654 EXPECT_EQ(-1, hyperlink_index
);
655 EXPECT_EQ(S_OK
, root_obj
->get_hyperlinkIndex(14, &hyperlink_index
));
656 EXPECT_EQ(0, hyperlink_index
);
657 EXPECT_EQ(S_OK
, root_obj
->get_hyperlinkIndex(30, &hyperlink_index
));
658 EXPECT_EQ(1, hyperlink_index
);
660 // Delete the manager and test that all BrowserAccessibility instances are
663 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
666 TEST_F(BrowserAccessibilityTest
, TestCreateEmptyDocument
) {
667 // Try creating an empty document with busy state. Readonly is
668 // set automatically.
669 CountedBrowserAccessibility::reset();
670 const int32 busy_state
= 1 << ui::AX_STATE_BUSY
;
671 const int32 readonly_state
= 1 << ui::AX_STATE_READ_ONLY
;
672 const int32 enabled_state
= 1 << ui::AX_STATE_ENABLED
;
673 scoped_ptr
<BrowserAccessibilityManager
> manager(
674 new BrowserAccessibilityManagerWin(
675 BrowserAccessibilityManagerWin::GetEmptyDocument(),
677 new CountedBrowserAccessibilityFactory()));
679 // Verify the root is as we expect by default.
680 BrowserAccessibility
* root
= manager
->GetRoot();
681 EXPECT_EQ(0, root
->GetId());
682 EXPECT_EQ(ui::AX_ROLE_ROOT_WEB_AREA
, root
->GetRole());
683 EXPECT_EQ(busy_state
| readonly_state
| enabled_state
, root
->GetState());
685 // Tree with a child textfield.
686 ui::AXNodeData tree1_1
;
688 tree1_1
.role
= ui::AX_ROLE_ROOT_WEB_AREA
;
689 tree1_1
.child_ids
.push_back(2);
691 ui::AXNodeData tree1_2
;
693 tree1_2
.role
= ui::AX_ROLE_TEXT_FIELD
;
695 // Process a load complete.
696 std::vector
<AXEventNotificationDetails
> params
;
697 params
.push_back(AXEventNotificationDetails());
698 AXEventNotificationDetails
* msg
= ¶ms
[0];
699 msg
->event_type
= ui::AX_EVENT_LOAD_COMPLETE
;
700 msg
->update
.nodes
.push_back(tree1_1
);
701 msg
->update
.nodes
.push_back(tree1_2
);
702 msg
->id
= tree1_1
.id
;
703 manager
->OnAccessibilityEvents(params
);
705 // Save for later comparison.
706 BrowserAccessibility
* acc1_2
= manager
->GetFromID(2);
708 // Verify the root has changed.
709 EXPECT_NE(root
, manager
->GetRoot());
711 // And the proper child remains.
712 EXPECT_EQ(ui::AX_ROLE_TEXT_FIELD
, acc1_2
->GetRole());
713 EXPECT_EQ(2, acc1_2
->GetId());
715 // Tree with a child button.
716 ui::AXNodeData tree2_1
;
718 tree2_1
.role
= ui::AX_ROLE_ROOT_WEB_AREA
;
719 tree2_1
.child_ids
.push_back(3);
721 ui::AXNodeData tree2_2
;
723 tree2_2
.role
= ui::AX_ROLE_BUTTON
;
725 msg
->update
.nodes
.clear();
726 msg
->update
.nodes
.push_back(tree2_1
);
727 msg
->update
.nodes
.push_back(tree2_2
);
728 msg
->id
= tree2_1
.id
;
730 // Fire another load complete.
731 manager
->OnAccessibilityEvents(params
);
733 BrowserAccessibility
* acc2_2
= manager
->GetFromID(3);
735 // Verify the root has changed.
736 EXPECT_NE(root
, manager
->GetRoot());
738 // And the new child exists.
739 EXPECT_EQ(ui::AX_ROLE_BUTTON
, acc2_2
->GetRole());
740 EXPECT_EQ(3, acc2_2
->GetId());
742 // Ensure we properly cleaned up.
744 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
747 // This is a regression test for a bug where the initial empty document
748 // loaded by a BrowserAccessibilityManagerWin couldn't be looked up by
749 // its UniqueIDWin, because the AX Tree was loaded in
750 // BrowserAccessibilityManager code before BrowserAccessibilityManagerWin
752 TEST_F(BrowserAccessibilityTest
, EmptyDocHasUniqueIdWin
) {
753 scoped_ptr
<BrowserAccessibilityManagerWin
> manager(
754 new BrowserAccessibilityManagerWin(
755 BrowserAccessibilityManagerWin::GetEmptyDocument(),
757 new CountedBrowserAccessibilityFactory()));
759 // Verify the root is as we expect by default.
760 BrowserAccessibility
* root
= manager
->GetRoot();
761 EXPECT_EQ(0, root
->GetId());
762 EXPECT_EQ(ui::AX_ROLE_ROOT_WEB_AREA
, root
->GetRole());
763 EXPECT_EQ(1 << ui::AX_STATE_BUSY
|
764 1 << ui::AX_STATE_READ_ONLY
|
765 1 << ui::AX_STATE_ENABLED
,
768 LONG unique_id_win
= root
->ToBrowserAccessibilityWin()->unique_id_win();
769 ASSERT_EQ(root
, manager
->GetFromUniqueIdWin(unique_id_win
));
772 TEST_F(BrowserAccessibilityTest
, TestIA2Attributes
) {
773 ui::AXNodeData checkbox
;
775 checkbox
.SetName("Checkbox");
776 checkbox
.role
= ui::AX_ROLE_CHECK_BOX
;
777 checkbox
.state
= 1 << ui::AX_STATE_CHECKED
;
781 root
.SetName("Document");
782 root
.role
= ui::AX_ROLE_ROOT_WEB_AREA
;
783 root
.state
= (1 << ui::AX_STATE_READ_ONLY
) | (1 << ui::AX_STATE_FOCUSABLE
);
784 root
.child_ids
.push_back(2);
786 CountedBrowserAccessibility::reset();
787 scoped_ptr
<BrowserAccessibilityManager
> manager(
788 BrowserAccessibilityManager::Create(
789 MakeAXTreeUpdate(root
, checkbox
),
790 nullptr, new CountedBrowserAccessibilityFactory()));
791 ASSERT_EQ(2, CountedBrowserAccessibility::num_instances());
793 ASSERT_NE(nullptr, manager
->GetRoot());
794 BrowserAccessibilityWin
* root_accessible
=
795 manager
->GetRoot()->ToBrowserAccessibilityWin();
796 ASSERT_NE(nullptr, root_accessible
);
797 ASSERT_EQ(1, root_accessible
->PlatformChildCount());
798 BrowserAccessibilityWin
* checkbox_accessible
=
799 root_accessible
->PlatformGetChild(0)->ToBrowserAccessibilityWin();
800 ASSERT_NE(nullptr, checkbox_accessible
);
802 base::win::ScopedBstr attributes
;
803 HRESULT hr
= checkbox_accessible
->get_attributes(attributes
.Receive());
805 EXPECT_NE(nullptr, static_cast<BSTR
>(attributes
));
806 std::wstring
attributes_str(attributes
, attributes
.Length());
807 EXPECT_EQ(L
"checkable:true;", attributes_str
);
810 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
814 * Ensures that ui::AX_ATTR_TEXT_SEL_START/END attributes are correctly used to
815 * determine caret position and text selection in simple form fields.
817 TEST_F(BrowserAccessibilityTest
, TestCaretAndSelectionInSimpleFields
) {
820 root
.role
= ui::AX_ROLE_ROOT_WEB_AREA
;
821 root
.state
= (1 << ui::AX_STATE_READ_ONLY
) | (1 << ui::AX_STATE_FOCUSABLE
);
823 ui::AXNodeData combo_box
;
825 combo_box
.role
= ui::AX_ROLE_COMBO_BOX
;
826 combo_box
.state
= (1 << ui::AX_STATE_EDITABLE
) |
827 (1 << ui::AX_STATE_FOCUSABLE
) | (1 << ui::AX_STATE_FOCUSED
);
828 combo_box
.SetValue("Test1");
829 // Place the caret between 't' and 'e'.
830 combo_box
.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START
, 1);
831 combo_box
.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END
, 1);
833 ui::AXNodeData text_field
;
835 text_field
.role
= ui::AX_ROLE_TEXT_FIELD
;
836 text_field
.state
= (1 << ui::AX_STATE_EDITABLE
) |
837 (1 << ui::AX_STATE_FOCUSABLE
);
838 text_field
.SetValue("Test2");
839 // Select the letter 'e'.
840 text_field
.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START
, 1);
841 text_field
.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END
, 2);
843 root
.child_ids
.push_back(2);
844 root
.child_ids
.push_back(3);
846 CountedBrowserAccessibility::reset();
847 scoped_ptr
<BrowserAccessibilityManager
> manager(
848 BrowserAccessibilityManager::Create(
849 MakeAXTreeUpdate(root
, combo_box
, text_field
),
850 nullptr, new CountedBrowserAccessibilityFactory()));
851 ASSERT_EQ(3, CountedBrowserAccessibility::num_instances());
853 ASSERT_NE(nullptr, manager
->GetRoot());
854 BrowserAccessibilityWin
* root_accessible
=
855 manager
->GetRoot()->ToBrowserAccessibilityWin();
856 ASSERT_NE(nullptr, root_accessible
);
857 ASSERT_EQ(2, root_accessible
->PlatformChildCount());
859 BrowserAccessibilityWin
* combo_box_accessible
=
860 root_accessible
->PlatformGetChild(0)->ToBrowserAccessibilityWin();
861 ASSERT_NE(nullptr, combo_box_accessible
);
862 manager
->SetFocus(combo_box_accessible
, false /* notify */);
863 ASSERT_EQ(combo_box_accessible
,
864 manager
->GetFocus(root_accessible
)->ToBrowserAccessibilityWin());
865 BrowserAccessibilityWin
* text_field_accessible
=
866 root_accessible
->PlatformGetChild(1)->ToBrowserAccessibilityWin();
867 ASSERT_NE(nullptr, text_field_accessible
);
869 // -2 is never a valid offset.
870 LONG caret_offset
= -2;
871 LONG n_selections
= -2;
872 LONG selection_start
= -2;
873 LONG selection_end
= -2;
875 // Test get_caretOffset.
876 HRESULT hr
= combo_box_accessible
->get_caretOffset(&caret_offset
);;
878 EXPECT_EQ(1L, caret_offset
);
879 // The caret should be at the start of the selection.
880 hr
= text_field_accessible
->get_caretOffset(&caret_offset
);;
882 EXPECT_EQ(1L, caret_offset
);
884 // Move the focus to the text field.
885 combo_box
.state
&= ~(1 << ui::AX_STATE_FOCUSED
);
886 text_field
.state
|= 1 << ui::AX_STATE_FOCUSED
;
887 manager
->SetFocus(text_field_accessible
, false /* notify */);
888 ASSERT_EQ(text_field_accessible
,
889 manager
->GetFocus(root_accessible
)->ToBrowserAccessibilityWin());
891 // The caret should not have moved.
892 hr
= text_field_accessible
->get_caretOffset(&caret_offset
);;
894 EXPECT_EQ(1L, caret_offset
);
896 // Test get_nSelections.
897 hr
= combo_box_accessible
->get_nSelections(&n_selections
);;
899 EXPECT_EQ(0L, n_selections
);
900 hr
= text_field_accessible
->get_nSelections(&n_selections
);;
902 EXPECT_EQ(1L, n_selections
);
904 // Test get_selection.
905 hr
= combo_box_accessible
->get_selection(
906 0L /* selection_index */, &selection_start
, &selection_end
);;
907 EXPECT_EQ(E_INVALIDARG
, hr
); // No selections available.
908 // Invalid in_args should not modify out_args.
909 EXPECT_EQ(-2L, selection_start
);
910 EXPECT_EQ(-2L, selection_end
);
911 hr
= text_field_accessible
->get_selection(
912 0L /* selection_index */, &selection_start
, &selection_end
);;
914 EXPECT_EQ(1L, selection_start
);
915 EXPECT_EQ(2L, selection_end
);
918 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
921 TEST_F(BrowserAccessibilityTest
, TestCaretInContentEditables
) {
924 root
.role
= ui::AX_ROLE_ROOT_WEB_AREA
;
925 root
.state
= (1 << ui::AX_STATE_READ_ONLY
) | (1 << ui::AX_STATE_FOCUSABLE
);
927 ui::AXNodeData div_editable
;
929 div_editable
.role
= ui::AX_ROLE_DIV
;
930 div_editable
.state
= (1 << ui::AX_STATE_EDITABLE
) |
931 (1 << ui::AX_STATE_FOCUSABLE
);
935 text
.role
= ui::AX_ROLE_STATIC_TEXT
;
936 text
.state
= (1 << ui::AX_STATE_EDITABLE
);
937 text
.SetName("Click ");
941 link
.role
= ui::AX_ROLE_LINK
;
942 link
.state
= (1 << ui::AX_STATE_EDITABLE
) |
943 (1 << ui::AX_STATE_FOCUSABLE
) | (1 << ui::AX_STATE_LINKED
);
944 link
.SetName("here");
946 ui::AXNodeData link_text
;
948 link_text
.role
= ui::AX_ROLE_STATIC_TEXT
;
949 link_text
.state
= (1 << ui::AX_STATE_EDITABLE
) |
950 (1 << ui::AX_STATE_FOCUSABLE
) | (1 << ui::AX_STATE_LINKED
);
951 link_text
.SetName("here");
953 // Place the caret between 'h' and 'e'.
954 root
.AddIntAttribute(ui::AX_ATTR_ANCHOR_OBJECT_ID
, 4);
955 root
.AddIntAttribute(ui::AX_ATTR_ANCHOR_OFFSET
, 1);
956 root
.AddIntAttribute(ui::AX_ATTR_FOCUS_OBJECT_ID
, 4);
957 root
.AddIntAttribute(ui::AX_ATTR_FOCUS_OFFSET
, 1);
959 root
.child_ids
.push_back(2);
960 div_editable
.child_ids
.push_back(3);
961 div_editable
.child_ids
.push_back(4);
962 link
.child_ids
.push_back(5);
964 CountedBrowserAccessibility::reset();
965 scoped_ptr
<BrowserAccessibilityManager
> manager(
966 BrowserAccessibilityManager::Create(
967 MakeAXTreeUpdate(root
, div_editable
, link
, link_text
, text
),
968 nullptr, new CountedBrowserAccessibilityFactory()));
969 ASSERT_EQ(5, CountedBrowserAccessibility::num_instances());
971 ASSERT_NE(nullptr, manager
->GetRoot());
972 BrowserAccessibilityWin
* root_accessible
=
973 manager
->GetRoot()->ToBrowserAccessibilityWin();
974 ASSERT_NE(nullptr, root_accessible
);
975 ASSERT_EQ(1, root_accessible
->PlatformChildCount());
977 BrowserAccessibilityWin
* div_editable_accessible
=
978 root_accessible
->PlatformGetChild(0)->ToBrowserAccessibilityWin();
979 ASSERT_NE(nullptr, div_editable_accessible
);
980 ASSERT_EQ(2, div_editable_accessible
->PlatformChildCount());
982 // -2 is never a valid offset.
983 LONG caret_offset
= -2;
985 // The caret should be on the embedded object character.
986 HRESULT hr
= div_editable_accessible
->get_caretOffset(&caret_offset
);;
988 EXPECT_EQ(6L, caret_offset
);
990 // Move the focus to the content editable.
991 div_editable
.state
|= 1 << ui::AX_STATE_FOCUSED
;
992 manager
->SetFocus(div_editable_accessible
, false /* notify */);
993 ASSERT_EQ(div_editable_accessible
,
994 manager
->GetFocus(root_accessible
)->ToBrowserAccessibilityWin());
996 BrowserAccessibilityWin
* text_accessible
=
997 div_editable_accessible
->PlatformGetChild(0)->ToBrowserAccessibilityWin();
998 ASSERT_NE(nullptr, text_accessible
);
999 BrowserAccessibilityWin
* link_accessible
=
1000 div_editable_accessible
->PlatformGetChild(1)->ToBrowserAccessibilityWin();
1001 ASSERT_NE(nullptr, link_accessible
);
1002 ASSERT_EQ(1, link_accessible
->PlatformChildCount());
1004 BrowserAccessibilityWin
* link_text_accessible
=
1005 link_accessible
->PlatformGetChild(0)->ToBrowserAccessibilityWin();
1006 ASSERT_NE(nullptr, link_text_accessible
);
1008 // The caret should not have moved.
1009 hr
= div_editable_accessible
->get_caretOffset(&caret_offset
);;
1010 EXPECT_EQ(S_OK
, hr
);
1011 EXPECT_EQ(6L, caret_offset
);
1013 hr
= link_accessible
->get_caretOffset(&caret_offset
);;
1014 EXPECT_EQ(S_OK
, hr
);
1015 EXPECT_EQ(1L, caret_offset
);
1016 hr
= link_text_accessible
->get_caretOffset(&caret_offset
);;
1017 EXPECT_EQ(S_OK
, hr
);
1018 EXPECT_EQ(1L, caret_offset
);
1021 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
1024 TEST_F(BrowserAccessibilityTest
, DISABLED_TestSelectionInContentEditables
) {
1025 ui::AXNodeData root
;
1027 root
.role
= ui::AX_ROLE_ROOT_WEB_AREA
;
1028 root
.state
= (1 << ui::AX_STATE_READ_ONLY
) | (1 << ui::AX_STATE_FOCUSABLE
);
1030 ui::AXNodeData div_editable
;
1031 div_editable
.id
= 2;
1032 div_editable
.role
= ui::AX_ROLE_DIV
;
1033 div_editable
.state
= (1 << ui::AX_STATE_FOCUSABLE
);
1035 ui::AXNodeData text
;
1037 text
.role
= ui::AX_ROLE_STATIC_TEXT
;
1038 text
.SetName("Click ");
1040 ui::AXNodeData link
;
1042 link
.role
= ui::AX_ROLE_LINK
;
1043 link
.state
= (1 << ui::AX_STATE_FOCUSABLE
) | (1 << ui::AX_STATE_LINKED
);
1044 link
.SetName("here");
1046 ui::AXNodeData link_text
;
1048 link_text
.role
= ui::AX_ROLE_STATIC_TEXT
;
1049 link_text
.state
= (1 << ui::AX_STATE_FOCUSABLE
) | (1 << ui::AX_STATE_LINKED
);
1050 link_text
.SetName("here");
1052 // Select the part of the text "lick here".
1053 root
.AddIntAttribute(ui::AX_ATTR_ANCHOR_OBJECT_ID
, 3);
1054 root
.AddIntAttribute(ui::AX_ATTR_ANCHOR_OFFSET
, 1);
1055 root
.AddIntAttribute(ui::AX_ATTR_FOCUS_OBJECT_ID
, 5);
1056 root
.AddIntAttribute(ui::AX_ATTR_FOCUS_OFFSET
, 4);
1058 root
.child_ids
.push_back(2);
1059 div_editable
.child_ids
.push_back(3);
1060 div_editable
.child_ids
.push_back(4);
1061 link
.child_ids
.push_back(5);
1063 CountedBrowserAccessibility::reset();
1064 scoped_ptr
<BrowserAccessibilityManager
> manager(
1065 BrowserAccessibilityManager::Create(
1066 MakeAXTreeUpdate(root
, div_editable
, link
, link_text
, text
),
1067 nullptr, new CountedBrowserAccessibilityFactory()));
1068 ASSERT_EQ(5, CountedBrowserAccessibility::num_instances());
1070 ASSERT_NE(nullptr, manager
->GetRoot());
1071 BrowserAccessibilityWin
* root_accessible
=
1072 manager
->GetRoot()->ToBrowserAccessibilityWin();
1073 ASSERT_NE(nullptr, root_accessible
);
1074 ASSERT_EQ(1, root_accessible
->PlatformChildCount());
1076 BrowserAccessibilityWin
* div_editable_accessible
=
1077 root_accessible
->PlatformGetChild(0)->ToBrowserAccessibilityWin();
1078 ASSERT_NE(nullptr, div_editable_accessible
);
1079 ASSERT_EQ(2, div_editable_accessible
->PlatformChildCount());
1081 // -2 is never a valid offset.
1082 LONG caret_offset
= -2;
1083 LONG n_selections
= -2;
1084 LONG selection_start
= -2;
1085 LONG selection_end
= -2;
1087 BrowserAccessibilityWin
* text_accessible
=
1088 div_editable_accessible
->PlatformGetChild(0)->ToBrowserAccessibilityWin();
1089 ASSERT_NE(nullptr, text_accessible
);
1090 BrowserAccessibilityWin
* link_accessible
=
1091 div_editable_accessible
->PlatformGetChild(1)->ToBrowserAccessibilityWin();
1092 ASSERT_NE(nullptr, link_accessible
);
1093 ASSERT_EQ(1, link_accessible
->PlatformChildCount());
1095 BrowserAccessibilityWin
* link_text_accessible
=
1096 link_accessible
->PlatformGetChild(0)->ToBrowserAccessibilityWin();
1097 ASSERT_NE(nullptr, link_text_accessible
);
1099 // get_nSelections should work on all objects.
1100 HRESULT hr
= div_editable_accessible
->get_nSelections(&n_selections
);;
1101 EXPECT_EQ(S_OK
, hr
);
1102 EXPECT_EQ(1L, n_selections
);
1103 hr
= text_accessible
->get_nSelections(&n_selections
);;
1104 EXPECT_EQ(S_OK
, hr
);
1105 EXPECT_EQ(1L, n_selections
);
1106 hr
= link_accessible
->get_nSelections(&n_selections
);;
1107 EXPECT_EQ(S_OK
, hr
);
1108 EXPECT_EQ(1L, n_selections
);
1109 hr
= link_text_accessible
->get_nSelections(&n_selections
);;
1110 EXPECT_EQ(S_OK
, hr
);
1111 EXPECT_EQ(1L, n_selections
);
1113 // get_selection should be unaffected by focus placement.
1114 hr
= div_editable_accessible
->get_selection(
1115 0L /* selection_index */, &selection_start
, &selection_end
);;
1116 EXPECT_EQ(S_OK
, hr
);
1117 EXPECT_EQ(1L, selection_start
);
1118 // selection_end should be after embedded object character.
1119 EXPECT_EQ(7L, selection_end
);
1121 hr
= text_accessible
->get_selection(
1122 0L /* selection_index */, &selection_start
, &selection_end
);;
1123 EXPECT_EQ(S_OK
, hr
);
1124 EXPECT_EQ(1L, selection_start
);
1125 // No embedded character on this object, only the first part of the text.
1126 EXPECT_EQ(6L, selection_end
);
1127 hr
= link_accessible
->get_selection(
1128 0L /* selection_index */, &selection_start
, &selection_end
);;
1129 EXPECT_EQ(S_OK
, hr
);
1130 EXPECT_EQ(0L, selection_start
);
1131 EXPECT_EQ(4L, selection_end
);
1132 hr
= link_text_accessible
->get_selection(
1133 0L /* selection_index */, &selection_start
, &selection_end
);;
1134 EXPECT_EQ(S_OK
, hr
);
1135 EXPECT_EQ(0L, selection_start
);
1136 EXPECT_EQ(4L, selection_end
);
1138 // The caret should be at the anchor (the start) of the selection.
1139 hr
= div_editable_accessible
->get_caretOffset(&caret_offset
);;
1140 EXPECT_EQ(S_OK
, hr
);
1141 EXPECT_EQ(1L, caret_offset
);
1143 // Move the focus to the content editable.
1144 div_editable
.state
|= 1 << ui::AX_STATE_FOCUSED
;
1145 manager
->SetFocus(div_editable_accessible
, false /* notify */);
1146 ASSERT_EQ(div_editable_accessible
,
1147 manager
->GetFocus(root_accessible
)->ToBrowserAccessibilityWin());
1149 // The caret should not have moved.
1150 hr
= div_editable_accessible
->get_caretOffset(&caret_offset
);;
1151 EXPECT_EQ(S_OK
, hr
);
1152 EXPECT_EQ(1L, caret_offset
);
1154 // The HRESULT should be S_FALSE if the caret is not in the given object.
1155 hr
= link_accessible
->get_caretOffset(&caret_offset
);;
1156 EXPECT_EQ(S_FALSE
, hr
);
1157 EXPECT_EQ(-1L, caret_offset
);
1158 hr
= link_text_accessible
->get_caretOffset(&caret_offset
);;
1159 EXPECT_EQ(S_FALSE
, hr
);
1160 EXPECT_EQ(-1L, caret_offset
);
1162 hr
= div_editable_accessible
->get_selection(
1163 0L /* selection_index */, &selection_start
, &selection_end
);;
1164 EXPECT_EQ(S_OK
, hr
);
1165 EXPECT_EQ(1L, selection_start
);
1166 EXPECT_EQ(7L, selection_end
);
1169 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
1172 } // namespace content