diff options
Diffstat (limited to 'chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc')
-rw-r--r-- | chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc | 553 |
1 files changed, 508 insertions, 45 deletions
diff --git a/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc b/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc index 3f60adb5a40..e10e8195583 100644 --- a/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc +++ b/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc @@ -149,7 +149,7 @@ TEST_F(BrowserAccessibilityTest, TestNoLeaks) { CountedBrowserAccessibility::reset(); std::unique_ptr<BrowserAccessibilityManager> manager( BrowserAccessibilityManager::Create( - MakeAXTreeUpdate(root, button, checkbox), NULL, + MakeAXTreeUpdate(root, button, checkbox), nullptr, new CountedBrowserAccessibilityFactory())); ASSERT_EQ(3, CountedBrowserAccessibility::num_instances()); @@ -160,8 +160,8 @@ TEST_F(BrowserAccessibilityTest, TestNoLeaks) { // Construct a manager again, and this time use the IAccessible interface // to get new references to two of the three nodes in the tree. manager.reset(BrowserAccessibilityManager::Create( - MakeAXTreeUpdate(root, button, checkbox), - NULL, new CountedBrowserAccessibilityFactory())); + MakeAXTreeUpdate(root, button, checkbox), nullptr, + new CountedBrowserAccessibilityFactory())); ASSERT_EQ(3, CountedBrowserAccessibility::num_instances()); IAccessible* root_accessible = ToBrowserAccessibilityWin(manager->GetRoot()); IDispatch* root_iaccessible = NULL; @@ -209,7 +209,7 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChange) { CountedBrowserAccessibility::reset(); std::unique_ptr<BrowserAccessibilityManager> manager( BrowserAccessibilityManager::Create( - MakeAXTreeUpdate(root, text), NULL, + MakeAXTreeUpdate(root, text), nullptr, new CountedBrowserAccessibilityFactory())); // Query for the text IAccessible and verify that it returns "old text" as its @@ -305,7 +305,7 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) { CountedBrowserAccessibility::reset(); std::unique_ptr<BrowserAccessibilityManager> manager( BrowserAccessibilityManager::Create( - MakeAXTreeUpdate(root, div, text3, text4), NULL, + MakeAXTreeUpdate(root, div, text3, text4), nullptr, new CountedBrowserAccessibilityFactory())); ASSERT_EQ(4, CountedBrowserAccessibility::num_instances()); @@ -736,7 +736,7 @@ TEST_F(BrowserAccessibilityTest, TestCreateEmptyDocument) { const int32_t enabled_state = 1 << ui::AX_STATE_ENABLED; std::unique_ptr<BrowserAccessibilityManager> manager( new BrowserAccessibilityManagerWin( - BrowserAccessibilityManagerWin::GetEmptyDocument(), NULL, + BrowserAccessibilityManagerWin::GetEmptyDocument(), nullptr, new CountedBrowserAccessibilityFactory())); // Verify the root is as we expect by default. @@ -816,7 +816,7 @@ TEST_F(BrowserAccessibilityTest, TestCreateEmptyDocument) { TEST_F(BrowserAccessibilityTest, EmptyDocHasUniqueIdWin) { std::unique_ptr<BrowserAccessibilityManagerWin> manager( new BrowserAccessibilityManagerWin( - BrowserAccessibilityManagerWin::GetEmptyDocument(), NULL, + BrowserAccessibilityManagerWin::GetEmptyDocument(), nullptr, new CountedBrowserAccessibilityFactory())); // Verify the root is as we expect by default. @@ -1253,11 +1253,11 @@ TEST_F(BrowserAccessibilityTest, TestCaretAndSelectionInSimpleFields) { // Test get_caretOffset. HRESULT hr = combo_box_accessible->get_caretOffset(&caret_offset); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(1L, caret_offset); + EXPECT_EQ(1, caret_offset); // The caret should be at the end of the selection. hr = text_field_accessible->get_caretOffset(&caret_offset); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(2L, caret_offset); + EXPECT_EQ(2, caret_offset); // Move the focus to the text field. manager->SetFocusLocallyForTesting(text_field_accessible); @@ -1267,28 +1267,28 @@ TEST_F(BrowserAccessibilityTest, TestCaretAndSelectionInSimpleFields) { // The caret should not have moved. hr = text_field_accessible->get_caretOffset(&caret_offset); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(2L, caret_offset); + EXPECT_EQ(2, caret_offset); // Test get_nSelections. hr = combo_box_accessible->get_nSelections(&n_selections); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(0L, n_selections); + EXPECT_EQ(0, n_selections); hr = text_field_accessible->get_nSelections(&n_selections); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(1L, n_selections); + EXPECT_EQ(1, n_selections); // Test get_selection. hr = combo_box_accessible->get_selection( 0L /* selection_index */, &selection_start, &selection_end); EXPECT_EQ(E_INVALIDARG, hr); // No selections available. // Invalid in_args should not modify out_args. - EXPECT_EQ(-2L, selection_start); - EXPECT_EQ(-2L, selection_end); + EXPECT_EQ(-2, selection_start); + EXPECT_EQ(-2, selection_end); hr = text_field_accessible->get_selection( 0L /* selection_index */, &selection_start, &selection_end); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(1L, selection_start); - EXPECT_EQ(2L, selection_end); + EXPECT_EQ(1, selection_start); + EXPECT_EQ(2, selection_end); manager.reset(); ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); @@ -1365,12 +1365,12 @@ TEST_F(BrowserAccessibilityTest, TestCaretInContentEditables) { // No selection should be present. HRESULT hr = div_editable_accessible->get_nSelections(&n_selections); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(0L, n_selections); + EXPECT_EQ(0, n_selections); // The caret should be on the embedded object character. hr = div_editable_accessible->get_caretOffset(&caret_offset); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(6L, caret_offset); + EXPECT_EQ(6, caret_offset); // Move the focus to the content editable. manager->SetFocusLocallyForTesting(div_editable_accessible); @@ -1392,24 +1392,24 @@ TEST_F(BrowserAccessibilityTest, TestCaretInContentEditables) { // The caret should not have moved. hr = div_editable_accessible->get_nSelections(&n_selections); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(0L, n_selections); + EXPECT_EQ(0, n_selections); hr = div_editable_accessible->get_caretOffset(&caret_offset); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(6L, caret_offset); + EXPECT_EQ(6, caret_offset); hr = link_accessible->get_nSelections(&n_selections); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(0L, n_selections); + EXPECT_EQ(0, n_selections); hr = link_text_accessible->get_nSelections(&n_selections); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(0L, n_selections); + EXPECT_EQ(0, n_selections); hr = link_accessible->get_caretOffset(&caret_offset); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(1L, caret_offset); + EXPECT_EQ(1, caret_offset); hr = link_text_accessible->get_caretOffset(&caret_offset); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(1L, caret_offset); + EXPECT_EQ(1, caret_offset); manager.reset(); ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); @@ -1424,23 +1424,27 @@ TEST_F(BrowserAccessibilityTest, TestSelectionInContentEditables) { ui::AXNodeData div_editable; div_editable.id = 2; div_editable.role = ui::AX_ROLE_DIV; - div_editable.state = (1 << ui::AX_STATE_FOCUSABLE); + div_editable.state = + (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_EDITABLE); ui::AXNodeData text; text.id = 3; text.role = ui::AX_ROLE_STATIC_TEXT; + text.state = (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_EDITABLE); text.SetName("Click "); ui::AXNodeData link; link.id = 4; link.role = ui::AX_ROLE_LINK; - link.state = (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_LINKED); + link.state = (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_EDITABLE) | + (1 << ui::AX_STATE_LINKED); link.SetName("here"); ui::AXNodeData link_text; link_text.id = 5; link_text.role = ui::AX_ROLE_STATIC_TEXT; - link_text.state = (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_LINKED); + link_text.state = (1 << ui::AX_STATE_FOCUSABLE) | + (1 << ui::AX_STATE_EDITABLE) | (1 << ui::AX_STATE_LINKED); link_text.SetName("here"); root.child_ids.push_back(2); @@ -1496,46 +1500,46 @@ TEST_F(BrowserAccessibilityTest, TestSelectionInContentEditables) { // get_nSelections should work on all objects. HRESULT hr = div_editable_accessible->get_nSelections(&n_selections); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(1L, n_selections); + EXPECT_EQ(1, n_selections); hr = text_accessible->get_nSelections(&n_selections); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(1L, n_selections); + EXPECT_EQ(1, n_selections); hr = link_accessible->get_nSelections(&n_selections); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(1L, n_selections); + EXPECT_EQ(1, n_selections); hr = link_text_accessible->get_nSelections(&n_selections); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(1L, n_selections); + EXPECT_EQ(1, n_selections); // get_selection should be unaffected by focus placement. hr = div_editable_accessible->get_selection( 0L /* selection_index */, &selection_start, &selection_end); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(1L, selection_start); + EXPECT_EQ(1, selection_start); // selection_end should be after embedded object character. - EXPECT_EQ(7L, selection_end); + EXPECT_EQ(7, selection_end); hr = text_accessible->get_selection( 0L /* selection_index */, &selection_start, &selection_end); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(1L, selection_start); + EXPECT_EQ(1, selection_start); // No embedded character on this object, only the first part of the text. - EXPECT_EQ(6L, selection_end); + EXPECT_EQ(6, selection_end); hr = link_accessible->get_selection( 0L /* selection_index */, &selection_start, &selection_end); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(0L, selection_start); - EXPECT_EQ(4L, selection_end); + EXPECT_EQ(0, selection_start); + EXPECT_EQ(4, selection_end); hr = link_text_accessible->get_selection( 0L /* selection_index */, &selection_start, &selection_end); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(0L, selection_start); - EXPECT_EQ(4L, selection_end); + EXPECT_EQ(0, selection_start); + EXPECT_EQ(4, selection_end); // The caret should be at the focus (the end) of the selection. hr = div_editable_accessible->get_caretOffset(&caret_offset); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(7L, caret_offset); + EXPECT_EQ(7, caret_offset); // Move the focus to the content editable. manager->SetFocusLocallyForTesting(div_editable_accessible); @@ -1545,22 +1549,22 @@ TEST_F(BrowserAccessibilityTest, TestSelectionInContentEditables) { // The caret should not have moved. hr = div_editable_accessible->get_caretOffset(&caret_offset); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(7L, caret_offset); + EXPECT_EQ(7, caret_offset); // The caret offset should reflect the position of the selection's focus in // any given object. hr = link_accessible->get_caretOffset(&caret_offset); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(4L, caret_offset); + EXPECT_EQ(4, caret_offset); hr = link_text_accessible->get_caretOffset(&caret_offset); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(4L, caret_offset); + EXPECT_EQ(4, caret_offset); hr = div_editable_accessible->get_selection( 0L /* selection_index */, &selection_start, &selection_end); EXPECT_EQ(S_OK, hr); - EXPECT_EQ(1L, selection_start); - EXPECT_EQ(7L, selection_end); + EXPECT_EQ(1, selection_start); + EXPECT_EQ(7, selection_end); manager.reset(); ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); @@ -1720,6 +1724,333 @@ TEST_F(BrowserAccessibilityTest, TestIAccessibleHyperlink) { EXPECT_EQ(7, end_index); } +TEST_F(BrowserAccessibilityTest, TestTextAttributesInContentEditables) { + ui::AXNodeData root; + root.id = 1; + root.role = ui::AX_ROLE_ROOT_WEB_AREA; + root.state = (1 << ui::AX_STATE_READ_ONLY) | (1 << ui::AX_STATE_FOCUSABLE); + + ui::AXNodeData div_editable; + div_editable.id = 2; + div_editable.role = ui::AX_ROLE_DIV; + div_editable.state = + (1 << ui::AX_STATE_EDITABLE) | (1 << ui::AX_STATE_FOCUSABLE); + div_editable.AddStringAttribute(ui::AX_ATTR_FONT_FAMILY, "Helvetica"); + + ui::AXNodeData text_before; + text_before.id = 3; + text_before.role = ui::AX_ROLE_STATIC_TEXT; + text_before.state = (1 << ui::AX_STATE_EDITABLE); + text_before.SetName("Before "); + text_before.AddIntAttribute( + ui::AX_ATTR_TEXT_STYLE, + (ui::AX_TEXT_STYLE_BOLD | ui::AX_TEXT_STYLE_ITALIC)); + + ui::AXNodeData link; + link.id = 4; + link.role = ui::AX_ROLE_LINK; + link.state = (1 << ui::AX_STATE_EDITABLE) | (1 << ui::AX_STATE_FOCUSABLE) | + (1 << ui::AX_STATE_LINKED); + link.SetName("lnk"); + link.AddIntAttribute(ui::AX_ATTR_TEXT_STYLE, ui::AX_TEXT_STYLE_UNDERLINE); + + ui::AXNodeData link_text; + link_text.id = 5; + link_text.role = ui::AX_ROLE_STATIC_TEXT; + link_text.state = (1 << ui::AX_STATE_EDITABLE) | + (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_LINKED); + link_text.SetName("lnk"); + link_text.AddIntAttribute(ui::AX_ATTR_TEXT_STYLE, + ui::AX_TEXT_STYLE_UNDERLINE); + + // The name "lnk" is misspelled. + std::vector<int32_t> marker_types; + marker_types.push_back(static_cast<int32_t>(ui::AX_MARKER_TYPE_SPELLING)); + std::vector<int32_t> marker_starts; + marker_starts.push_back(0); + std::vector<int32_t> marker_ends; + marker_ends.push_back(3); + link_text.AddIntListAttribute(ui::AX_ATTR_MARKER_TYPES, marker_types); + link_text.AddIntListAttribute(ui::AX_ATTR_MARKER_STARTS, marker_starts); + link_text.AddIntListAttribute(ui::AX_ATTR_MARKER_ENDS, marker_ends); + + ui::AXNodeData text_after; + text_after.id = 6; + text_after.role = ui::AX_ROLE_STATIC_TEXT; + text_after.state = (1 << ui::AX_STATE_EDITABLE); + text_after.SetName(" after."); + // Leave text style as normal. + + root.child_ids.push_back(div_editable.id); + div_editable.child_ids.push_back(text_before.id); + div_editable.child_ids.push_back(link.id); + div_editable.child_ids.push_back(text_after.id); + link.child_ids.push_back(link_text.id); + + ui::AXTreeUpdate update = MakeAXTreeUpdate(root, div_editable, text_before, + link, link_text, text_after); + + CountedBrowserAccessibility::reset(); + std::unique_ptr<BrowserAccessibilityManager> manager( + BrowserAccessibilityManager::Create( + update, nullptr, new CountedBrowserAccessibilityFactory())); + ASSERT_EQ(6, CountedBrowserAccessibility::num_instances()); + + ASSERT_NE(nullptr, manager->GetRoot()); + BrowserAccessibilityWin* ax_root = + ToBrowserAccessibilityWin(manager->GetRoot()); + ASSERT_NE(nullptr, ax_root); + ASSERT_EQ(1U, ax_root->PlatformChildCount()); + + BrowserAccessibilityWin* ax_div = + ToBrowserAccessibilityWin(ax_root->PlatformGetChild(0)); + ASSERT_NE(nullptr, ax_div); + ASSERT_EQ(3U, ax_div->PlatformChildCount()); + + BrowserAccessibilityWin* ax_before = + ToBrowserAccessibilityWin(ax_div->PlatformGetChild(0)); + ASSERT_NE(nullptr, ax_before); + BrowserAccessibilityWin* ax_link = + ToBrowserAccessibilityWin(ax_div->PlatformGetChild(1)); + ASSERT_NE(nullptr, ax_link); + ASSERT_EQ(1U, ax_link->PlatformChildCount()); + BrowserAccessibilityWin* ax_after = + ToBrowserAccessibilityWin(ax_div->PlatformGetChild(2)); + ASSERT_NE(nullptr, ax_after); + + BrowserAccessibilityWin* ax_link_text = + ToBrowserAccessibilityWin(ax_link->PlatformGetChild(0)); + ASSERT_NE(nullptr, ax_link_text); + + HRESULT hr; + LONG n_characters, start_offset, end_offset; + base::win::ScopedBstr text_attributes; + + ASSERT_HRESULT_SUCCEEDED(ax_root->get_nCharacters(&n_characters)); + ASSERT_EQ(1, n_characters); + ASSERT_HRESULT_SUCCEEDED(ax_div->get_nCharacters(&n_characters)); + ASSERT_EQ(15, n_characters); + + // Test the style of the root. + hr = ax_root->get_attributes(0, &start_offset, &end_offset, + text_attributes.Receive()); + EXPECT_EQ(S_OK, hr); + EXPECT_EQ(0, start_offset); + EXPECT_EQ(1, end_offset); + EXPECT_NE(base::string16::npos, + base::string16(text_attributes).find(L"font-family:Helvetica")); + text_attributes.Reset(); + + // Test the style of text_before. + for (LONG offset = 0; offset < 7; ++offset) { + hr = ax_div->get_attributes(0, &start_offset, &end_offset, + text_attributes.Receive()); + EXPECT_EQ(S_OK, hr); + EXPECT_EQ(0, start_offset); + EXPECT_EQ(7, end_offset); + base::string16 attributes(text_attributes); + EXPECT_NE(base::string16::npos, attributes.find(L"font-family:Helvetica")); + EXPECT_NE(base::string16::npos, attributes.find(L"font-weight:bold")); + EXPECT_NE(base::string16::npos, attributes.find(L"font-style:italic")); + text_attributes.Reset(); + } + + // Test the style of the link. + hr = ax_link->get_attributes(0, &start_offset, &end_offset, + text_attributes.Receive()); + EXPECT_EQ(S_OK, hr); + EXPECT_EQ(0, start_offset); + EXPECT_EQ(3, end_offset); + EXPECT_NE(base::string16::npos, + base::string16(text_attributes).find(L"font-family:Helvetica")); + EXPECT_NE(base::string16::npos, + base::string16(text_attributes).find(L"font-weight:normal")); + EXPECT_NE(base::string16::npos, + base::string16(text_attributes).find(L"font-style:underline")); + text_attributes.Reset(); + + hr = ax_link_text->get_attributes(2, &start_offset, &end_offset, + text_attributes.Receive()); + EXPECT_EQ(S_OK, hr); + EXPECT_EQ(0, start_offset); + EXPECT_EQ(3, end_offset); + EXPECT_NE(base::string16::npos, + base::string16(text_attributes).find(L"font-family:Helvetica")); + EXPECT_NE(base::string16::npos, + base::string16(text_attributes).find(L"font-weight:normal")); + EXPECT_NE(base::string16::npos, + base::string16(text_attributes).find(L"font-style:underline")); + EXPECT_NE(base::string16::npos, + base::string16(text_attributes).find(L"invalid:spelling")); + text_attributes.Reset(); + + // Test the style of text_after. + for (LONG offset = 8; offset < 15; ++offset) { + hr = ax_div->get_attributes(offset, &start_offset, &end_offset, + text_attributes.Receive()); + EXPECT_EQ(S_OK, hr); + EXPECT_EQ(8, start_offset); + EXPECT_EQ(15, end_offset); + base::string16 attributes(text_attributes); + EXPECT_NE(base::string16::npos, attributes.find(L"font-family:Helvetica")); + EXPECT_NE(base::string16::npos, attributes.find(L"font-weight:normal")); + EXPECT_NE(base::string16::npos, attributes.find(L"font-style:normal")); + EXPECT_EQ(base::string16::npos, attributes.find(L"invalid:spelling")); + text_attributes.Reset(); + } + + // Test the style of the static text nodes. + hr = ax_before->get_attributes(6, &start_offset, &end_offset, + text_attributes.Receive()); + EXPECT_EQ(S_OK, hr); + EXPECT_EQ(0, start_offset); + EXPECT_EQ(7, end_offset); + EXPECT_NE(base::string16::npos, + base::string16(text_attributes).find(L"font-family:Helvetica")); + EXPECT_NE(base::string16::npos, + base::string16(text_attributes).find(L"font-weight:bold")); + EXPECT_NE(base::string16::npos, + base::string16(text_attributes).find(L"font-style:italic")); + EXPECT_EQ(base::string16::npos, + base::string16(text_attributes).find(L"invalid:spelling")); + text_attributes.Reset(); + + hr = ax_after->get_attributes(6, &start_offset, &end_offset, + text_attributes.Receive()); + EXPECT_EQ(S_OK, hr); + EXPECT_EQ(0, start_offset); + EXPECT_EQ(7, end_offset); + EXPECT_NE(base::string16::npos, + base::string16(text_attributes).find(L"font-family:Helvetica")); + EXPECT_NE(base::string16::npos, + base::string16(text_attributes).find(L"font-weight:normal")); + EXPECT_NE(base::string16::npos, + base::string16(text_attributes).find(L"font-style:normal")); + EXPECT_EQ(base::string16::npos, + base::string16(text_attributes).find(L"invalid:spelling")); + text_attributes.Reset(); + + manager.reset(); + ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); +} + +TEST_F(BrowserAccessibilityTest, TestMisspellingsInSimpleTextFields) { + std::string value1("Testing ."); + // The word "helo" is misspelled. + std::string value2("Helo there."); + + LONG value1_length = static_cast<LONG>(value1.length()); + LONG value2_length = static_cast<LONG>(value2.length()); + LONG combo_box_value_length = value1_length + value2_length; + + ui::AXNodeData root; + root.id = 1; + root.role = ui::AX_ROLE_ROOT_WEB_AREA; + root.state = (1 << ui::AX_STATE_READ_ONLY) | (1 << ui::AX_STATE_FOCUSABLE); + + ui::AXNodeData combo_box; + combo_box.id = 2; + combo_box.role = ui::AX_ROLE_COMBO_BOX; + combo_box.state = + (1 << ui::AX_STATE_EDITABLE) | (1 << ui::AX_STATE_FOCUSABLE); + combo_box.SetValue(value1 + value2); + + ui::AXNodeData combo_box_div; + combo_box_div.id = 3; + combo_box_div.role = ui::AX_ROLE_DIV; + combo_box_div.state = 1 << ui::AX_STATE_EDITABLE; + + ui::AXNodeData static_text1; + static_text1.id = 4; + static_text1.role = ui::AX_ROLE_STATIC_TEXT; + static_text1.state = 1 << ui::AX_STATE_EDITABLE; + static_text1.SetName(value1); + + ui::AXNodeData static_text2; + static_text2.id = 5; + static_text2.role = ui::AX_ROLE_STATIC_TEXT; + static_text2.state = 1 << ui::AX_STATE_EDITABLE; + static_text2.SetName(value2); + + std::vector<int32_t> marker_types; + marker_types.push_back(static_cast<int32_t>(ui::AX_MARKER_TYPE_SPELLING)); + std::vector<int32_t> marker_starts; + marker_starts.push_back(0); + std::vector<int32_t> marker_ends; + marker_ends.push_back(4); + static_text2.AddIntListAttribute(ui::AX_ATTR_MARKER_TYPES, marker_types); + static_text2.AddIntListAttribute(ui::AX_ATTR_MARKER_STARTS, marker_starts); + static_text2.AddIntListAttribute(ui::AX_ATTR_MARKER_ENDS, marker_ends); + + root.child_ids.push_back(combo_box.id); + combo_box.child_ids.push_back(combo_box_div.id); + combo_box_div.child_ids.push_back(static_text1.id); + combo_box_div.child_ids.push_back(static_text2.id); + + CountedBrowserAccessibility::reset(); + std::unique_ptr<BrowserAccessibilityManager> manager( + BrowserAccessibilityManager::Create( + MakeAXTreeUpdate(root, combo_box, combo_box_div, static_text1, + static_text2), + nullptr, new CountedBrowserAccessibilityFactory())); + ASSERT_EQ(5, CountedBrowserAccessibility::num_instances()); + + ASSERT_NE(nullptr, manager->GetRoot()); + BrowserAccessibilityWin* ax_root = + ToBrowserAccessibilityWin(manager->GetRoot()); + ASSERT_NE(nullptr, ax_root); + ASSERT_EQ(1U, ax_root->PlatformChildCount()); + + BrowserAccessibilityWin* ax_combo_box = + ToBrowserAccessibilityWin(ax_root->PlatformGetChild(0)); + ASSERT_NE(nullptr, ax_combo_box); + ASSERT_EQ(0U, ax_combo_box->PlatformChildCount()); + + HRESULT hr; + LONG start_offset, end_offset; + base::win::ScopedBstr text_attributes; + + // Ensure that the first part of the value is not marked misspelled. + for (LONG offset = 0; offset < value1_length; ++offset) { + hr = ax_combo_box->get_attributes(offset, &start_offset, &end_offset, + text_attributes.Receive()); + EXPECT_EQ(S_OK, hr); + EXPECT_EQ(0, start_offset); + EXPECT_EQ(value1_length, end_offset); + EXPECT_EQ(base::string16::npos, + base::string16(text_attributes).find(L"invalid:spelling")); + text_attributes.Reset(); + } + + // Ensure that "helo" is marked misspelled. + for (LONG offset = value1_length; offset < value1_length + 4; ++offset) { + hr = ax_combo_box->get_attributes(offset, &start_offset, &end_offset, + text_attributes.Receive()); + EXPECT_EQ(S_OK, hr); + EXPECT_EQ(value1_length, start_offset); + EXPECT_EQ(value1_length + 4, end_offset); + EXPECT_NE(base::string16::npos, + base::string16(text_attributes).find(L"invalid:spelling")); + text_attributes.Reset(); + } + + // Ensure that the last part of the value is not marked misspelled. + for (LONG offset = value1_length + 4; offset < combo_box_value_length; + ++offset) { + hr = ax_combo_box->get_attributes(offset, &start_offset, &end_offset, + text_attributes.Receive()); + EXPECT_EQ(S_OK, hr); + EXPECT_EQ(value1_length + 4, start_offset); + EXPECT_EQ(combo_box_value_length, end_offset); + EXPECT_EQ(base::string16::npos, + base::string16(text_attributes).find(L"invalid:spelling")); + text_attributes.Reset(); + } + + manager.reset(); + ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); +} + TEST_F(BrowserAccessibilityTest, TestDeepestFirstLastChild) { ui::AXNodeData root; root.id = 1; @@ -2009,4 +2340,136 @@ TEST_F(BrowserAccessibilityTest, AccChildOnlyReturnsDescendants) { child_unique_id_variant, result.Receive())); } +TEST_F(BrowserAccessibilityTest, TestIAccessible2Relations) { + ui::AXNodeData root; + root.id = 1; + root.role = ui::AX_ROLE_ROOT_WEB_AREA; + // Reflexive relations should be ignored. + std::vector<int32_t> describedby_ids = {1, 2, 3}; + root.AddIntListAttribute(ui::AX_ATTR_DESCRIBEDBY_IDS, describedby_ids); + + ui::AXNodeData child1; + child1.id = 2; + child1.role = ui::AX_ROLE_STATIC_TEXT; + root.child_ids.push_back(2); + + ui::AXNodeData child2; + child2.id = 3; + child2.role = ui::AX_ROLE_STATIC_TEXT; + root.child_ids.push_back(3); + + std::unique_ptr<BrowserAccessibilityManager> manager( + BrowserAccessibilityManager::Create( + MakeAXTreeUpdate(root, child1, child2), nullptr, + new CountedBrowserAccessibilityFactory())); + + BrowserAccessibilityWin* ax_root = + ToBrowserAccessibilityWin(manager->GetRoot()); + ASSERT_NE(nullptr, ax_root); + BrowserAccessibilityWin* ax_child1 = + ToBrowserAccessibilityWin(ax_root->PlatformGetChild(0)); + ASSERT_NE(nullptr, ax_child1); + BrowserAccessibilityWin* ax_child2 = + ToBrowserAccessibilityWin(ax_root->PlatformGetChild(1)); + ASSERT_NE(nullptr, ax_child2); + + LONG n_relations = 0; + LONG n_targets = 0; + LONG unique_id = 0; + base::win::ScopedBstr relation_type; + base::win::ScopedComPtr<IAccessibleRelation> describedby_relation; + base::win::ScopedComPtr<IAccessibleRelation> description_for_relation; + base::win::ScopedComPtr<IUnknown> target; + base::win::ScopedComPtr<IAccessible2> ax_target; + + EXPECT_HRESULT_SUCCEEDED(ax_root->get_nRelations(&n_relations)); + EXPECT_EQ(1, n_relations); + + EXPECT_HRESULT_SUCCEEDED( + ax_root->get_relation(0, describedby_relation.Receive())); + EXPECT_HRESULT_SUCCEEDED( + describedby_relation->get_relationType(relation_type.Receive())); + EXPECT_EQ(L"describedBy", base::string16(relation_type)); + relation_type.Reset(); + + EXPECT_HRESULT_SUCCEEDED(describedby_relation->get_nTargets(&n_targets)); + EXPECT_EQ(2, n_targets); + + EXPECT_HRESULT_SUCCEEDED( + describedby_relation->get_target(0, target.Receive())); + target.QueryInterface(ax_target.Receive()); + EXPECT_HRESULT_SUCCEEDED(ax_target->get_uniqueID(&unique_id)); + EXPECT_EQ(-ax_child1->unique_id(), unique_id); + ax_target.Release(); + target.Release(); + + EXPECT_HRESULT_SUCCEEDED( + describedby_relation->get_target(1, target.Receive())); + target.QueryInterface(ax_target.Receive()); + EXPECT_HRESULT_SUCCEEDED(ax_target->get_uniqueID(&unique_id)); + EXPECT_EQ(-ax_child2->unique_id(), unique_id); + ax_target.Release(); + target.Release(); + describedby_relation.Release(); + + // Test the reverse relations. + EXPECT_HRESULT_SUCCEEDED(ax_child1->get_nRelations(&n_relations)); + EXPECT_EQ(1, n_relations); + + EXPECT_HRESULT_SUCCEEDED( + ax_child1->get_relation(0, description_for_relation.Receive())); + EXPECT_HRESULT_SUCCEEDED( + description_for_relation->get_relationType(relation_type.Receive())); + EXPECT_EQ(L"descriptionFor", base::string16(relation_type)); + relation_type.Reset(); + + EXPECT_HRESULT_SUCCEEDED(description_for_relation->get_nTargets(&n_targets)); + EXPECT_EQ(1, n_targets); + + EXPECT_HRESULT_SUCCEEDED( + description_for_relation->get_target(0, target.Receive())); + target.QueryInterface(ax_target.Receive()); + EXPECT_HRESULT_SUCCEEDED(ax_target->get_uniqueID(&unique_id)); + EXPECT_EQ(-ax_root->unique_id(), unique_id); + ax_target.Release(); + target.Release(); + description_for_relation.Release(); + + EXPECT_HRESULT_SUCCEEDED(ax_child2->get_nRelations(&n_relations)); + EXPECT_EQ(1, n_relations); + + EXPECT_HRESULT_SUCCEEDED( + ax_child2->get_relation(0, description_for_relation.Receive())); + EXPECT_HRESULT_SUCCEEDED( + description_for_relation->get_relationType(relation_type.Receive())); + EXPECT_EQ(L"descriptionFor", base::string16(relation_type)); + relation_type.Reset(); + + EXPECT_HRESULT_SUCCEEDED(description_for_relation->get_nTargets(&n_targets)); + EXPECT_EQ(1, n_targets); + + EXPECT_HRESULT_SUCCEEDED( + description_for_relation->get_target(0, target.Receive())); + target.QueryInterface(ax_target.Receive()); + EXPECT_HRESULT_SUCCEEDED(ax_target->get_uniqueID(&unique_id)); + EXPECT_EQ(-ax_root->unique_id(), unique_id); + ax_target.Release(); + target.Release(); + + // Try adding one more relation. + std::vector<int32_t> labelledby_ids = {3}; + child1.AddIntListAttribute(ui::AX_ATTR_LABELLEDBY_IDS, labelledby_ids); + AXEventNotificationDetails event; + event.event_type = ui::AX_EVENT_ARIA_ATTRIBUTE_CHANGED; + event.update.nodes.push_back(child1); + event.id = child1.id; + std::vector<AXEventNotificationDetails> events = {event}; + manager->OnAccessibilityEvents(events); + + EXPECT_HRESULT_SUCCEEDED(ax_child1->get_nRelations(&n_relations)); + EXPECT_EQ(2, n_relations); + EXPECT_HRESULT_SUCCEEDED(ax_child2->get_nRelations(&n_relations)); + EXPECT_EQ(2, n_relations); +} + } // namespace content |