browser_accessibility_win_unittest.cc revision 58537e28ecd584eab876aee8be7156509866d23a
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. 4 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_win.h" 13#include "content/common/accessibility_messages.h" 14#include "testing/gtest/include/gtest/gtest.h" 15#include "ui/base/win/atl_module.h" 16 17namespace content { 18namespace { 19 20 21// CountedBrowserAccessibility ------------------------------------------------ 22 23// Subclass of BrowserAccessibilityWin that counts the number of instances. 24class CountedBrowserAccessibility : public BrowserAccessibilityWin { 25 public: 26 CountedBrowserAccessibility(); 27 virtual ~CountedBrowserAccessibility(); 28 29 static void reset() { num_instances_ = 0; } 30 static int num_instances() { return num_instances_; } 31 32 private: 33 static int num_instances_; 34 35 DISALLOW_COPY_AND_ASSIGN(CountedBrowserAccessibility); 36}; 37 38// static 39int CountedBrowserAccessibility::num_instances_ = 0; 40 41CountedBrowserAccessibility::CountedBrowserAccessibility() { 42 ++num_instances_; 43} 44 45CountedBrowserAccessibility::~CountedBrowserAccessibility() { 46 --num_instances_; 47} 48 49 50// CountedBrowserAccessibilityFactory ----------------------------------------- 51 52// Factory that creates a CountedBrowserAccessibility. 53class CountedBrowserAccessibilityFactory : public BrowserAccessibilityFactory { 54 public: 55 CountedBrowserAccessibilityFactory(); 56 57 private: 58 virtual ~CountedBrowserAccessibilityFactory(); 59 60 virtual BrowserAccessibility* Create() OVERRIDE; 61 62 DISALLOW_COPY_AND_ASSIGN(CountedBrowserAccessibilityFactory); 63}; 64 65CountedBrowserAccessibilityFactory::CountedBrowserAccessibilityFactory() { 66} 67 68CountedBrowserAccessibilityFactory::~CountedBrowserAccessibilityFactory() { 69} 70 71BrowserAccessibility* CountedBrowserAccessibilityFactory::Create() { 72 CComObject<CountedBrowserAccessibility>* instance; 73 HRESULT hr = CComObject<CountedBrowserAccessibility>::CreateInstance( 74 &instance); 75 DCHECK(SUCCEEDED(hr)); 76 instance->AddRef(); 77 return instance; 78} 79 80} // namespace 81 82 83// BrowserAccessibilityTest --------------------------------------------------- 84 85class BrowserAccessibilityTest : public testing::Test { 86 public: 87 BrowserAccessibilityTest(); 88 virtual ~BrowserAccessibilityTest(); 89 90 private: 91 virtual void SetUp() OVERRIDE; 92 93 DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityTest); 94}; 95 96BrowserAccessibilityTest::BrowserAccessibilityTest() { 97} 98 99BrowserAccessibilityTest::~BrowserAccessibilityTest() { 100} 101 102void BrowserAccessibilityTest::SetUp() { 103 ui::win::CreateATLModuleIfNeeded(); 104} 105 106 107// Actual tests --------------------------------------------------------------- 108 109// Test that BrowserAccessibilityManager correctly releases the tree of 110// BrowserAccessibility instances upon delete. 111TEST_F(BrowserAccessibilityTest, TestNoLeaks) { 112 // Create AccessibilityNodeData objects for a simple document tree, 113 // representing the accessibility information used to initialize 114 // BrowserAccessibilityManager. 115 AccessibilityNodeData button; 116 button.id = 2; 117 button.SetName("Button"); 118 button.role = WebKit::WebAXRoleButton; 119 button.state = 0; 120 121 AccessibilityNodeData checkbox; 122 checkbox.id = 3; 123 checkbox.SetName("Checkbox"); 124 checkbox.role = WebKit::WebAXRoleCheckBox; 125 checkbox.state = 0; 126 127 AccessibilityNodeData root; 128 root.id = 1; 129 root.SetName("Document"); 130 root.role = WebKit::WebAXRoleRootWebArea; 131 root.state = 0; 132 root.child_ids.push_back(2); 133 root.child_ids.push_back(3); 134 135 // Construct a BrowserAccessibilityManager with this 136 // AccessibilityNodeData tree and a factory for an instance-counting 137 // BrowserAccessibility, and ensure that exactly 3 instances were 138 // created. Note that the manager takes ownership of the factory. 139 CountedBrowserAccessibility::reset(); 140 scoped_ptr<BrowserAccessibilityManager> manager( 141 BrowserAccessibilityManager::Create( 142 root, NULL, new CountedBrowserAccessibilityFactory())); 143 manager->UpdateNodesForTesting(button, checkbox); 144 ASSERT_EQ(3, CountedBrowserAccessibility::num_instances()); 145 146 // Delete the manager and test that all 3 instances are deleted. 147 manager.reset(); 148 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); 149 150 // Construct a manager again, and this time use the IAccessible interface 151 // to get new references to two of the three nodes in the tree. 152 manager.reset(BrowserAccessibilityManager::Create( 153 root, NULL, new CountedBrowserAccessibilityFactory())); 154 manager->UpdateNodesForTesting(button, checkbox); 155 ASSERT_EQ(3, CountedBrowserAccessibility::num_instances()); 156 IAccessible* root_accessible = 157 manager->GetRoot()->ToBrowserAccessibilityWin(); 158 IDispatch* root_iaccessible = NULL; 159 IDispatch* child1_iaccessible = NULL; 160 base::win::ScopedVariant childid_self(CHILDID_SELF); 161 HRESULT hr = root_accessible->get_accChild(childid_self, &root_iaccessible); 162 ASSERT_EQ(S_OK, hr); 163 base::win::ScopedVariant one(1); 164 hr = root_accessible->get_accChild(one, &child1_iaccessible); 165 ASSERT_EQ(S_OK, hr); 166 167 // Now delete the manager, and only one of the three nodes in the tree 168 // should be released. 169 manager.reset(); 170 ASSERT_EQ(2, CountedBrowserAccessibility::num_instances()); 171 172 // Release each of our references and make sure that each one results in 173 // the instance being deleted as its reference count hits zero. 174 root_iaccessible->Release(); 175 ASSERT_EQ(1, CountedBrowserAccessibility::num_instances()); 176 child1_iaccessible->Release(); 177 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); 178} 179 180TEST_F(BrowserAccessibilityTest, TestChildrenChange) { 181 // Create AccessibilityNodeData objects for a simple document tree, 182 // representing the accessibility information used to initialize 183 // BrowserAccessibilityManager. 184 AccessibilityNodeData text; 185 text.id = 2; 186 text.role = WebKit::WebAXRoleStaticText; 187 text.SetName("old text"); 188 text.state = 0; 189 190 AccessibilityNodeData root; 191 root.id = 1; 192 root.SetName("Document"); 193 root.role = WebKit::WebAXRoleRootWebArea; 194 root.state = 0; 195 root.child_ids.push_back(2); 196 197 // Construct a BrowserAccessibilityManager with this 198 // AccessibilityNodeData tree and a factory for an instance-counting 199 // BrowserAccessibility. 200 CountedBrowserAccessibility::reset(); 201 scoped_ptr<BrowserAccessibilityManager> manager( 202 BrowserAccessibilityManager::Create( 203 root, NULL, new CountedBrowserAccessibilityFactory())); 204 manager->UpdateNodesForTesting(text); 205 206 // Query for the text IAccessible and verify that it returns "old text" as its 207 // value. 208 base::win::ScopedVariant one(1); 209 base::win::ScopedComPtr<IDispatch> text_dispatch; 210 HRESULT hr = manager->GetRoot()->ToBrowserAccessibilityWin()->get_accChild( 211 one, text_dispatch.Receive()); 212 ASSERT_EQ(S_OK, hr); 213 214 base::win::ScopedComPtr<IAccessible> text_accessible; 215 hr = text_dispatch.QueryInterface(text_accessible.Receive()); 216 ASSERT_EQ(S_OK, hr); 217 218 base::win::ScopedVariant childid_self(CHILDID_SELF); 219 base::win::ScopedBstr name; 220 hr = text_accessible->get_accName(childid_self, name.Receive()); 221 ASSERT_EQ(S_OK, hr); 222 EXPECT_EQ(L"old text", string16(name)); 223 name.Reset(); 224 225 text_dispatch.Release(); 226 text_accessible.Release(); 227 228 // Notify the BrowserAccessibilityManager that the text child has changed. 229 AccessibilityNodeData text2; 230 text2.id = 2; 231 text2.role = WebKit::WebAXRoleStaticText; 232 text2.SetName("new text"); 233 text2.SetName("old text"); 234 AccessibilityHostMsg_EventParams param; 235 param.event_type = WebKit::WebAXEventChildrenChanged; 236 param.nodes.push_back(text2); 237 param.id = text2.id; 238 std::vector<AccessibilityHostMsg_EventParams> events; 239 events.push_back(param); 240 manager->OnAccessibilityEvents(events); 241 242 // Query for the text IAccessible and verify that it now returns "new text" 243 // as its value. 244 hr = manager->GetRoot()->ToBrowserAccessibilityWin()->get_accChild( 245 one, text_dispatch.Receive()); 246 ASSERT_EQ(S_OK, hr); 247 248 hr = text_dispatch.QueryInterface(text_accessible.Receive()); 249 ASSERT_EQ(S_OK, hr); 250 251 hr = text_accessible->get_accName(childid_self, name.Receive()); 252 ASSERT_EQ(S_OK, hr); 253 EXPECT_EQ(L"new text", string16(name)); 254 255 text_dispatch.Release(); 256 text_accessible.Release(); 257 258 // Delete the manager and test that all BrowserAccessibility instances are 259 // deleted. 260 manager.reset(); 261 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); 262} 263 264TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) { 265 // Create AccessibilityNodeData objects for a simple document tree, 266 // representing the accessibility information used to initialize 267 // BrowserAccessibilityManager. 268 AccessibilityNodeData div; 269 div.id = 2; 270 div.role = WebKit::WebAXRoleGroup; 271 div.state = 0; 272 273 AccessibilityNodeData text3; 274 text3.id = 3; 275 text3.role = WebKit::WebAXRoleStaticText; 276 text3.state = 0; 277 278 AccessibilityNodeData text4; 279 text4.id = 4; 280 text4.role = WebKit::WebAXRoleStaticText; 281 text4.state = 0; 282 283 div.child_ids.push_back(3); 284 div.child_ids.push_back(4); 285 286 AccessibilityNodeData root; 287 root.id = 1; 288 root.role = WebKit::WebAXRoleRootWebArea; 289 root.state = 0; 290 root.child_ids.push_back(2); 291 292 // Construct a BrowserAccessibilityManager with this 293 // AccessibilityNodeData tree and a factory for an instance-counting 294 // BrowserAccessibility and ensure that exactly 4 instances were 295 // created. Note that the manager takes ownership of the factory. 296 CountedBrowserAccessibility::reset(); 297 scoped_ptr<BrowserAccessibilityManager> manager( 298 BrowserAccessibilityManager::Create( 299 root, NULL, new CountedBrowserAccessibilityFactory())); 300 manager->UpdateNodesForTesting(div, text3, text4); 301 ASSERT_EQ(4, CountedBrowserAccessibility::num_instances()); 302 303 // Notify the BrowserAccessibilityManager that the div node and its children 304 // were removed and ensure that only one BrowserAccessibility instance exists. 305 root.child_ids.clear(); 306 AccessibilityHostMsg_EventParams param; 307 param.event_type = WebKit::WebAXEventChildrenChanged; 308 param.nodes.push_back(root); 309 param.id = root.id; 310 std::vector<AccessibilityHostMsg_EventParams> events; 311 events.push_back(param); 312 manager->OnAccessibilityEvents(events); 313 ASSERT_EQ(1, CountedBrowserAccessibility::num_instances()); 314 315 // Delete the manager and test that all BrowserAccessibility instances are 316 // deleted. 317 manager.reset(); 318 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); 319} 320 321TEST_F(BrowserAccessibilityTest, TestTextBoundaries) { 322 std::string text1_value = "One two three.\nFour five six."; 323 324 AccessibilityNodeData text1; 325 text1.id = 11; 326 text1.role = WebKit::WebAXRoleTextField; 327 text1.state = 0; 328 text1.AddStringAttribute(AccessibilityNodeData::ATTR_VALUE, text1_value); 329 std::vector<int32> line_breaks; 330 line_breaks.push_back(15); 331 text1.AddIntListAttribute( 332 AccessibilityNodeData::ATTR_LINE_BREAKS, line_breaks); 333 334 AccessibilityNodeData root; 335 root.id = 1; 336 root.role = WebKit::WebAXRoleRootWebArea; 337 root.state = 0; 338 root.child_ids.push_back(11); 339 340 CountedBrowserAccessibility::reset(); 341 scoped_ptr<BrowserAccessibilityManager> manager( 342 BrowserAccessibilityManager::Create( 343 root, NULL, new CountedBrowserAccessibilityFactory())); 344 manager->UpdateNodesForTesting(text1); 345 ASSERT_EQ(2, CountedBrowserAccessibility::num_instances()); 346 347 BrowserAccessibilityWin* root_obj = 348 manager->GetRoot()->ToBrowserAccessibilityWin(); 349 BrowserAccessibilityWin* text1_obj = 350 root_obj->GetChild(0)->ToBrowserAccessibilityWin(); 351 352 long text1_len; 353 ASSERT_EQ(S_OK, text1_obj->get_nCharacters(&text1_len)); 354 355 base::win::ScopedBstr text; 356 ASSERT_EQ(S_OK, text1_obj->get_text(0, text1_len, text.Receive())); 357 ASSERT_EQ(text1_value, base::UTF16ToUTF8(string16(text))); 358 text.Reset(); 359 360 ASSERT_EQ(S_OK, text1_obj->get_text(0, 4, text.Receive())); 361 ASSERT_STREQ(L"One ", text); 362 text.Reset(); 363 364 long start; 365 long end; 366 ASSERT_EQ(S_OK, text1_obj->get_textAtOffset( 367 1, IA2_TEXT_BOUNDARY_CHAR, &start, &end, text.Receive())); 368 ASSERT_EQ(1, start); 369 ASSERT_EQ(2, end); 370 ASSERT_STREQ(L"n", text); 371 text.Reset(); 372 373 ASSERT_EQ(S_FALSE, text1_obj->get_textAtOffset( 374 text1_len, IA2_TEXT_BOUNDARY_CHAR, &start, &end, text.Receive())); 375 ASSERT_EQ(text1_len, start); 376 ASSERT_EQ(text1_len, end); 377 text.Reset(); 378 379 ASSERT_EQ(S_OK, text1_obj->get_textAtOffset( 380 1, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive())); 381 ASSERT_EQ(0, start); 382 ASSERT_EQ(3, end); 383 ASSERT_STREQ(L"One", text); 384 text.Reset(); 385 386 ASSERT_EQ(S_OK, text1_obj->get_textAtOffset( 387 6, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive())); 388 ASSERT_EQ(4, start); 389 ASSERT_EQ(7, end); 390 ASSERT_STREQ(L"two", text); 391 text.Reset(); 392 393 ASSERT_EQ(S_OK, text1_obj->get_textAtOffset( 394 text1_len, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive())); 395 ASSERT_EQ(25, start); 396 ASSERT_EQ(29, end); 397 ASSERT_STREQ(L"six.", text); 398 text.Reset(); 399 400 ASSERT_EQ(S_OK, text1_obj->get_textAtOffset( 401 1, IA2_TEXT_BOUNDARY_LINE, &start, &end, text.Receive())); 402 ASSERT_EQ(0, start); 403 ASSERT_EQ(15, end); 404 ASSERT_STREQ(L"One two three.\n", text); 405 text.Reset(); 406 407 ASSERT_EQ(S_OK, 408 text1_obj->get_text(0, IA2_TEXT_OFFSET_LENGTH, text.Receive())); 409 ASSERT_STREQ(L"One two three.\nFour five six.", text); 410 411 // Delete the manager and test that all BrowserAccessibility instances are 412 // deleted. 413 manager.reset(); 414 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); 415} 416 417TEST_F(BrowserAccessibilityTest, TestSimpleHypertext) { 418 const std::string text1_name = "One two three."; 419 const std::string text2_name = " Four five six."; 420 421 AccessibilityNodeData text1; 422 text1.id = 11; 423 text1.role = WebKit::WebAXRoleStaticText; 424 text1.state = 1 << WebKit::WebAXStateReadonly; 425 text1.SetName(text1_name); 426 427 AccessibilityNodeData text2; 428 text2.id = 12; 429 text2.role = WebKit::WebAXRoleStaticText; 430 text2.state = 1 << WebKit::WebAXStateReadonly; 431 text2.SetName(text2_name); 432 433 AccessibilityNodeData root; 434 root.id = 1; 435 root.role = WebKit::WebAXRoleRootWebArea; 436 root.state = 1 << WebKit::WebAXStateReadonly; 437 root.child_ids.push_back(11); 438 root.child_ids.push_back(12); 439 440 CountedBrowserAccessibility::reset(); 441 scoped_ptr<BrowserAccessibilityManager> manager( 442 BrowserAccessibilityManager::Create( 443 root, NULL, new CountedBrowserAccessibilityFactory())); 444 manager->UpdateNodesForTesting(root, text1, text2); 445 ASSERT_EQ(3, CountedBrowserAccessibility::num_instances()); 446 447 BrowserAccessibilityWin* root_obj = 448 manager->GetRoot()->ToBrowserAccessibilityWin(); 449 450 long text_len; 451 ASSERT_EQ(S_OK, root_obj->get_nCharacters(&text_len)); 452 453 base::win::ScopedBstr text; 454 ASSERT_EQ(S_OK, root_obj->get_text(0, text_len, text.Receive())); 455 EXPECT_EQ(text1_name + text2_name, base::UTF16ToUTF8(string16(text))); 456 457 long hyperlink_count; 458 ASSERT_EQ(S_OK, root_obj->get_nHyperlinks(&hyperlink_count)); 459 EXPECT_EQ(0, hyperlink_count); 460 461 base::win::ScopedComPtr<IAccessibleHyperlink> hyperlink; 462 EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlink(-1, hyperlink.Receive())); 463 EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlink(0, hyperlink.Receive())); 464 EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlink(28, hyperlink.Receive())); 465 EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlink(29, hyperlink.Receive())); 466 467 long hyperlink_index; 468 EXPECT_EQ(E_FAIL, root_obj->get_hyperlinkIndex(0, &hyperlink_index)); 469 EXPECT_EQ(-1, hyperlink_index); 470 EXPECT_EQ(E_FAIL, root_obj->get_hyperlinkIndex(28, &hyperlink_index)); 471 EXPECT_EQ(-1, hyperlink_index); 472 EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlinkIndex(-1, &hyperlink_index)); 473 EXPECT_EQ(-1, hyperlink_index); 474 EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlinkIndex(29, &hyperlink_index)); 475 EXPECT_EQ(-1, hyperlink_index); 476 477 // Delete the manager and test that all BrowserAccessibility instances are 478 // deleted. 479 manager.reset(); 480 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); 481} 482 483TEST_F(BrowserAccessibilityTest, TestComplexHypertext) { 484 const std::string text1_name = "One two three."; 485 const std::string text2_name = " Four five six."; 486 const std::string button1_text_name = "red"; 487 const std::string link1_text_name = "blue"; 488 489 AccessibilityNodeData text1; 490 text1.id = 11; 491 text1.role = WebKit::WebAXRoleStaticText; 492 text1.state = 1 << WebKit::WebAXStateReadonly; 493 text1.SetName(text1_name); 494 495 AccessibilityNodeData text2; 496 text2.id = 12; 497 text2.role = WebKit::WebAXRoleStaticText; 498 text2.state = 1 << WebKit::WebAXStateReadonly; 499 text2.SetName(text2_name); 500 501 AccessibilityNodeData button1, button1_text; 502 button1.id = 13; 503 button1_text.id = 15; 504 button1_text.SetName(button1_text_name); 505 button1.role = WebKit::WebAXRoleButton; 506 button1_text.role = WebKit::WebAXRoleStaticText; 507 button1.state = 1 << WebKit::WebAXStateReadonly; 508 button1_text.state = 1 << WebKit::WebAXStateReadonly; 509 button1.child_ids.push_back(15); 510 511 AccessibilityNodeData link1, link1_text; 512 link1.id = 14; 513 link1_text.id = 16; 514 link1_text.SetName(link1_text_name); 515 link1.role = WebKit::WebAXRoleLink; 516 link1_text.role = WebKit::WebAXRoleStaticText; 517 link1.state = 1 << WebKit::WebAXStateReadonly; 518 link1_text.state = 1 << WebKit::WebAXStateReadonly; 519 link1.child_ids.push_back(16); 520 521 AccessibilityNodeData root; 522 root.id = 1; 523 root.role = WebKit::WebAXRoleRootWebArea; 524 root.state = 1 << WebKit::WebAXStateReadonly; 525 root.child_ids.push_back(11); 526 root.child_ids.push_back(13); 527 root.child_ids.push_back(12); 528 root.child_ids.push_back(14); 529 530 CountedBrowserAccessibility::reset(); 531 scoped_ptr<BrowserAccessibilityManager> manager( 532 BrowserAccessibilityManager::Create( 533 root, NULL, new CountedBrowserAccessibilityFactory())); 534 manager->UpdateNodesForTesting(root, 535 text1, button1, button1_text, 536 text2, link1, link1_text); 537 538 ASSERT_EQ(7, CountedBrowserAccessibility::num_instances()); 539 540 BrowserAccessibilityWin* root_obj = 541 manager->GetRoot()->ToBrowserAccessibilityWin(); 542 543 long text_len; 544 ASSERT_EQ(S_OK, root_obj->get_nCharacters(&text_len)); 545 546 base::win::ScopedBstr text; 547 ASSERT_EQ(S_OK, root_obj->get_text(0, text_len, text.Receive())); 548 const std::string embed = base::UTF16ToUTF8( 549 BrowserAccessibilityWin::kEmbeddedCharacter); 550 EXPECT_EQ(text1_name + embed + text2_name + embed, 551 UTF16ToUTF8(string16(text))); 552 text.Reset(); 553 554 long hyperlink_count; 555 ASSERT_EQ(S_OK, root_obj->get_nHyperlinks(&hyperlink_count)); 556 EXPECT_EQ(2, hyperlink_count); 557 558 base::win::ScopedComPtr<IAccessibleHyperlink> hyperlink; 559 base::win::ScopedComPtr<IAccessibleText> hypertext; 560 EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlink(-1, hyperlink.Receive())); 561 EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlink(2, hyperlink.Receive())); 562 EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlink(28, hyperlink.Receive())); 563 564 EXPECT_EQ(S_OK, root_obj->get_hyperlink(0, hyperlink.Receive())); 565 EXPECT_EQ(S_OK, 566 hyperlink.QueryInterface<IAccessibleText>(hypertext.Receive())); 567 EXPECT_EQ(S_OK, hypertext->get_text(0, 3, text.Receive())); 568 EXPECT_STREQ(button1_text_name.c_str(), 569 base::UTF16ToUTF8(string16(text)).c_str()); 570 text.Reset(); 571 hyperlink.Release(); 572 hypertext.Release(); 573 574 EXPECT_EQ(S_OK, root_obj->get_hyperlink(1, hyperlink.Receive())); 575 EXPECT_EQ(S_OK, 576 hyperlink.QueryInterface<IAccessibleText>(hypertext.Receive())); 577 EXPECT_EQ(S_OK, hypertext->get_text(0, 4, text.Receive())); 578 EXPECT_STREQ(link1_text_name.c_str(), 579 base::UTF16ToUTF8(string16(text)).c_str()); 580 text.Reset(); 581 hyperlink.Release(); 582 hypertext.Release(); 583 584 long hyperlink_index; 585 EXPECT_EQ(E_FAIL, root_obj->get_hyperlinkIndex(0, &hyperlink_index)); 586 EXPECT_EQ(-1, hyperlink_index); 587 EXPECT_EQ(E_FAIL, root_obj->get_hyperlinkIndex(28, &hyperlink_index)); 588 EXPECT_EQ(-1, hyperlink_index); 589 EXPECT_EQ(S_OK, root_obj->get_hyperlinkIndex(14, &hyperlink_index)); 590 EXPECT_EQ(0, hyperlink_index); 591 EXPECT_EQ(S_OK, root_obj->get_hyperlinkIndex(30, &hyperlink_index)); 592 EXPECT_EQ(1, hyperlink_index); 593 594 // Delete the manager and test that all BrowserAccessibility instances are 595 // deleted. 596 manager.reset(); 597 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); 598} 599 600TEST_F(BrowserAccessibilityTest, TestCreateEmptyDocument) { 601 // Try creating an empty document with busy state. Readonly is 602 // set automatically. 603 CountedBrowserAccessibility::reset(); 604 const int32 busy_state = 1 << WebKit::WebAXStateBusy; 605 const int32 readonly_state = 1 << WebKit::WebAXStateReadonly; 606 const int32 enabled_state = 1 << WebKit::WebAXStateEnabled; 607 scoped_ptr<BrowserAccessibilityManager> manager( 608 new BrowserAccessibilityManagerWin( 609 GetDesktopWindow(), 610 NULL, 611 BrowserAccessibilityManagerWin::GetEmptyDocument(), 612 NULL, 613 new CountedBrowserAccessibilityFactory())); 614 615 // Verify the root is as we expect by default. 616 BrowserAccessibility* root = manager->GetRoot(); 617 EXPECT_EQ(0, root->renderer_id()); 618 EXPECT_EQ(WebKit::WebAXRoleRootWebArea, root->role()); 619 EXPECT_EQ(busy_state | readonly_state | enabled_state, root->state()); 620 621 // Tree with a child textfield. 622 AccessibilityNodeData tree1_1; 623 tree1_1.id = 1; 624 tree1_1.role = WebKit::WebAXRoleRootWebArea; 625 tree1_1.child_ids.push_back(2); 626 627 AccessibilityNodeData tree1_2; 628 tree1_2.id = 2; 629 tree1_2.role = WebKit::WebAXRoleTextField; 630 631 // Process a load complete. 632 std::vector<AccessibilityHostMsg_EventParams> params; 633 params.push_back(AccessibilityHostMsg_EventParams()); 634 AccessibilityHostMsg_EventParams* msg = ¶ms[0]; 635 msg->event_type = WebKit::WebAXEventLoadComplete; 636 msg->nodes.push_back(tree1_1); 637 msg->nodes.push_back(tree1_2); 638 msg->id = tree1_1.id; 639 manager->OnAccessibilityEvents(params); 640 641 // Save for later comparison. 642 BrowserAccessibility* acc1_2 = manager->GetFromRendererID(2); 643 644 // Verify the root has changed. 645 EXPECT_NE(root, manager->GetRoot()); 646 647 // And the proper child remains. 648 EXPECT_EQ(WebKit::WebAXRoleTextField, acc1_2->role()); 649 EXPECT_EQ(2, acc1_2->renderer_id()); 650 651 // Tree with a child button. 652 AccessibilityNodeData tree2_1; 653 tree2_1.id = 1; 654 tree2_1.role = WebKit::WebAXRoleRootWebArea; 655 tree2_1.child_ids.push_back(3); 656 657 AccessibilityNodeData tree2_2; 658 tree2_2.id = 3; 659 tree2_2.role = WebKit::WebAXRoleButton; 660 661 msg->nodes.clear(); 662 msg->nodes.push_back(tree2_1); 663 msg->nodes.push_back(tree2_2); 664 msg->id = tree2_1.id; 665 666 // Fire another load complete. 667 manager->OnAccessibilityEvents(params); 668 669 BrowserAccessibility* acc2_2 = manager->GetFromRendererID(3); 670 671 // Verify the root has changed. 672 EXPECT_NE(root, manager->GetRoot()); 673 674 // And the new child exists. 675 EXPECT_EQ(WebKit::WebAXRoleButton, acc2_2->role()); 676 EXPECT_EQ(3, acc2_2->renderer_id()); 677 678 // Ensure we properly cleaned up. 679 manager.reset(); 680 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); 681} 682 683} // namespace content 684