Chromium Code Reviews| Index: content/browser/accessibility/accessibility_win_browsertest.cc |
| diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc |
| index 058e033ae4e4fb959d92411fde0d05f5f6440969..ed0a6700fe224b6dc92e361f91973f49fb3c136a 100644 |
| --- a/content/browser/accessibility/accessibility_win_browsertest.cc |
| +++ b/content/browser/accessibility/accessibility_win_browsertest.cc |
| @@ -5,11 +5,13 @@ |
| #include <vector> |
| #include "base/memory/scoped_ptr.h" |
| +#include "net/base/escape.h" |
|
dmazzoni
2014/11/17 19:06:46
nit: sort this
|
| #include "base/strings/utf_string_conversions.h" |
| #include "base/win/scoped_bstr.h" |
| #include "base/win/scoped_comptr.h" |
| #include "base/win/scoped_variant.h" |
| #include "content/browser/accessibility/accessibility_mode_helper.h" |
| +#include "content/browser/accessibility/accessibility_tree_formatter.h" |
| #include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h" |
| #include "content/browser/renderer_host/render_view_host_impl.h" |
| #include "content/public/browser/notification_service.h" |
| @@ -31,9 +33,162 @@ namespace content { |
| namespace { |
| -// Helpers -------------------------------------------------------------------- |
| -base::win::ScopedComPtr<IAccessible> GetAccessibleFromResultVariant( |
| +const char INPUT_CONTENTS[] = "Moz/5.0 (ST 6.x; WWW33) " |
| + "WebKit \"KHTML, like\"."; |
| +const char TEXTAREA_CONTENTS[] = "Moz/5.0 (ST 6.x; WWW33)\n" |
| + "WebKit \n\"KHTML, like\"."; |
| +const LONG CONTENTS_LENGTH = static_cast<LONG>( |
| + (sizeof(INPUT_CONTENTS) - 1) / sizeof(char)); |
| + |
| + |
| +// AccessibilityWinBrowserTest ------------------------------------------------ |
| + |
| +class AccessibilityWinBrowserTest : public ContentBrowserTest { |
| + public: |
| + AccessibilityWinBrowserTest(); |
| + virtual ~AccessibilityWinBrowserTest(); |
| + |
| + protected: |
| + class AccessibleChecker; |
| + void LoadInitialAccessibilityTreeFromHtml(const std::string& html); |
| + IAccessible* GetRendererAccessible(); |
| + void ExecuteScript(const std::wstring& script); |
| + void SetUpTextFields( |
| + base::win::ScopedComPtr<IAccessibleText>* input_text, |
| + base::win::ScopedComPtr<IAccessibleText>* textarea_text); |
| + |
| + static base::win::ScopedComPtr<IAccessible> |
| + AccessibilityWinBrowserTest::GetAccessibleFromVariant( |
| + IAccessible* parent, |
| + VARIANT* var); |
| + static HRESULT QueryIAccessible2(IAccessible* accessible, |
| + IAccessible2** accessible2); |
| + static void FindNodeInAccessibilityTree(IAccessible* node, |
| + int32 expected_role, |
| + const std::wstring& expected_name, |
| + int32 depth, |
| + bool* found); |
| + static void CheckTextAtOffset(IAccessibleText* element, |
| + LONG offset, |
| + IA2TextBoundaryType boundary_type, |
| + LONG expected_start_offset, |
| + LONG expected_end_offset, |
| + const std::wstring& expected_text); |
| + static std::vector<base::win::ScopedVariant> GetAllAccessibleChildren( |
| + IAccessible* element); |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(AccessibilityWinBrowserTest); |
| +}; |
| + |
| +AccessibilityWinBrowserTest::AccessibilityWinBrowserTest() { |
| +} |
| + |
| +AccessibilityWinBrowserTest::~AccessibilityWinBrowserTest() { |
| +} |
| + |
| +void AccessibilityWinBrowserTest::LoadInitialAccessibilityTreeFromHtml( |
| + const std::string& html) { |
| + AccessibilityNotificationWaiter waiter( |
| + shell(), AccessibilityModeComplete, |
| + ui::AX_EVENT_LOAD_COMPLETE); |
| + GURL html_data_url("data:text/html," + html); |
| + NavigateToURL(shell(), html_data_url); |
| + waiter.WaitForNotification(); |
| +} |
| + |
| +// Retrieve the MSAA client accessibility object for the Render Widget Host View |
| +// of the selected tab. |
| +IAccessible* AccessibilityWinBrowserTest::GetRendererAccessible() { |
| + content::WebContents* web_contents = shell()->web_contents(); |
| + base::string16 contents; |
| + AccessibilityTreeFormatter* atf = AccessibilityTreeFormatter::Create(web_contents); |
|
dmazzoni
2014/11/17 19:06:46
Use a scoped_ptr rather than manually deleting a p
|
| + atf->FormatAccessibilityTree(&contents); |
| + DLOG(INFO) << contents; |
| + delete atf; |
| + return web_contents->GetRenderWidgetHostView()->GetNativeViewAccessible(); |
| +} |
| + |
| +void AccessibilityWinBrowserTest::ExecuteScript(const std::wstring& script) { |
| + shell()->web_contents()->GetMainFrame()->ExecuteJavaScript(script); |
| +} |
| + |
| +// Loads a page with two text fields, one using the input and one the textarea |
| +// tags, and places the same sample text in both. Also, places the caret on the |
| +// last character. |
| +// Returns true if successful and false otherwise. |
|
dmazzoni
2014/11/17 19:06:46
nit: no longer returns a bool
|
| +void AccessibilityWinBrowserTest::SetUpTextFields( |
| + base::win::ScopedComPtr<IAccessibleText>* input_text, |
| + base::win::ScopedComPtr<IAccessibleText>* textarea_text) { |
| + ASSERT_NE(nullptr, input_text); |
| + ASSERT_NE(nullptr, textarea_text); |
| + LoadInitialAccessibilityTreeFromHtml(std::string("<!DOCTYPE html>" |
| + "<html><body><form>" |
| + "<label for='name'>Browser name:</label>" |
| + "<input type='text' id='name' name='name' value='") + |
| + net::EscapeQueryParamValue(INPUT_CONTENTS, false) + std::string( |
| + "'></form><textarea rows='3' cols='60'>") + |
| + net::EscapeQueryParamValue(TEXTAREA_CONTENTS, false) + std::string( |
| + "</textarea></body></html>")); |
| + |
| + // Retrieve the IAccessible interface for the web page. |
| + base::win::ScopedComPtr<IAccessible> document(GetRendererAccessible()); |
| + std::vector<base::win::ScopedVariant> document_children = |
| + GetAllAccessibleChildren(document); |
| + ASSERT_EQ(2, document_children.size()); |
| + |
| + base::win::ScopedComPtr<IAccessible2> form; |
| + HRESULT hr = QueryIAccessible2(GetAccessibleFromVariant( |
| + document, document_children[0].AsInput()), form.Receive()); |
| + ASSERT_EQ(S_OK, hr); |
| + std::vector<base::win::ScopedVariant> form_children = |
| + GetAllAccessibleChildren(form); |
| + ASSERT_EQ(2, form_children.size()); |
| + base::win::ScopedComPtr<IAccessible2> div; |
| + hr = QueryIAccessible2(GetAccessibleFromVariant( |
| + document, document_children[1].AsInput()), div.Receive()); |
| + ASSERT_EQ(S_OK, hr); |
| + std::vector<base::win::ScopedVariant> div_children = |
| + GetAllAccessibleChildren(div); |
| + ASSERT_EQ(1, div_children.size()); |
| + |
| + // Find the two edit fields (simple and text area). |
| + base::win::ScopedComPtr<IAccessible2> input; |
| + hr = QueryIAccessible2(GetAccessibleFromVariant( |
| + form, form_children[1].AsInput()), input.Receive()); |
| + ASSERT_EQ(S_OK, hr); |
| + LONG input_role = 0; |
| + hr = input->role(&input_role); |
| + ASSERT_EQ(S_OK, hr); |
| + ASSERT_EQ(ROLE_SYSTEM_TEXT, input_role); |
| + |
| + base::win::ScopedComPtr<IAccessible2> textarea; |
| + hr = QueryIAccessible2(GetAccessibleFromVariant( |
| + div, div_children[0].AsInput()), textarea.Receive()); |
| + ASSERT_EQ(S_OK, hr); |
| + LONG textarea_role = 0; |
| + hr = textarea->role(&textarea_role); |
| + ASSERT_EQ(S_OK, hr); |
| + ASSERT_EQ(ROLE_SYSTEM_TEXT, input_role); |
| + |
| + // Retrieve the IAccessibleText interface for both of the fields. |
| + hr = input_text->QueryFrom(input); |
| + ASSERT_EQ(S_OK, hr); |
| + hr = textarea_text->QueryFrom(textarea); |
| + ASSERT_EQ(S_OK, hr); |
| + // Set the caret on the last character. |
| + LONG caret_offset = CONTENTS_LENGTH - 1; |
| + hr = (*input_text)->setCaretOffset(caret_offset); |
| + ASSERT_EQ(S_OK, hr); |
| + hr = (*textarea_text)->setCaretOffset(caret_offset); |
| + ASSERT_EQ(S_OK, hr); |
| +} |
| + |
| +// Static helpers ------------------------------------------------ |
| + |
| +base::win::ScopedComPtr<IAccessible> |
| +AccessibilityWinBrowserTest::GetAccessibleFromVariant( |
| IAccessible* parent, |
| VARIANT* var) { |
| base::win::ScopedComPtr<IAccessible> ptr; |
| @@ -57,9 +212,11 @@ base::win::ScopedComPtr<IAccessible> GetAccessibleFromResultVariant( |
| return ptr; |
| } |
| -HRESULT QueryIAccessible2(IAccessible* accessible, IAccessible2** accessible2) { |
| - // TODO(ctguil): For some reason querying the IAccessible2 interface from |
| - // IAccessible fails. |
| +HRESULT AccessibilityWinBrowserTest::QueryIAccessible2( |
| + IAccessible* accessible, |
| + IAccessible2** accessible2) { |
| + // IA2 Spec dictates that IServiceProvider should be used instead of |
| + // QueryInterface when retrieving IAccessible2. |
| base::win::ScopedComPtr<IServiceProvider> service_provider; |
| HRESULT hr = accessible->QueryInterface(service_provider.Receive()); |
| return SUCCEEDED(hr) ? |
| @@ -69,11 +226,12 @@ HRESULT QueryIAccessible2(IAccessible* accessible, IAccessible2** accessible2) { |
| // Recursively search through all of the descendants reachable from an |
| // IAccessible node and return true if we find one with the given role |
| // and name. |
| -void RecursiveFindNodeInAccessibilityTree(IAccessible* node, |
| - int32 expected_role, |
| - const std::wstring& expected_name, |
| - int32 depth, |
| - bool* found) { |
| +void AccessibilityWinBrowserTest::FindNodeInAccessibilityTree( |
| + IAccessible* node, |
| + int32 expected_role, |
| + const std::wstring& expected_name, |
| + int32 depth, |
| + bool* found) { |
| base::win::ScopedBstr name_bstr; |
| base::win::ScopedVariant childid_self(CHILDID_SELF); |
| node->get_accName(childid_self, name_bstr.Receive()); |
| @@ -95,22 +253,13 @@ void RecursiveFindNodeInAccessibilityTree(IAccessible* node, |
| return; |
| } |
| - LONG child_count = 0; |
| - HRESULT hr = node->get_accChildCount(&child_count); |
| - ASSERT_EQ(S_OK, hr); |
| - |
| - scoped_ptr<VARIANT[]> child_array(new VARIANT[child_count]); |
| - LONG obtained_count = 0; |
| - hr = AccessibleChildren( |
| - node, 0, child_count, child_array.get(), &obtained_count); |
| - ASSERT_EQ(S_OK, hr); |
| - ASSERT_EQ(child_count, obtained_count); |
| - |
| - for (int index = 0; index < obtained_count; index++) { |
| + std::vector<base::win::ScopedVariant> children = GetAllAccessibleChildren( |
| + node); |
| + for (size_t i = 0; i < children.size(); ++i) { |
| base::win::ScopedComPtr<IAccessible> child_accessible( |
| - GetAccessibleFromResultVariant(node, &child_array.get()[index])); |
| + GetAccessibleFromVariant(node, children[i].AsInput())); |
| if (child_accessible) { |
| - RecursiveFindNodeInAccessibilityTree( |
| + FindNodeInAccessibilityTree( |
| child_accessible.get(), expected_role, expected_name, depth + 1, |
| found); |
| if (*found) |
| @@ -119,54 +268,59 @@ void RecursiveFindNodeInAccessibilityTree(IAccessible* node, |
| } |
| } |
| - |
| -// AccessibilityWinBrowserTest ------------------------------------------------ |
| - |
| -class AccessibilityWinBrowserTest : public ContentBrowserTest { |
| - public: |
| - AccessibilityWinBrowserTest(); |
| - virtual ~AccessibilityWinBrowserTest(); |
| - |
| - protected: |
| - void LoadInitialAccessibilityTreeFromHtml(const std::string& html); |
| - IAccessible* GetRendererAccessible(); |
| - void ExecuteScript(const std::wstring& script); |
| - |
| - private: |
| - DISALLOW_COPY_AND_ASSIGN(AccessibilityWinBrowserTest); |
| -}; |
| - |
| -AccessibilityWinBrowserTest::AccessibilityWinBrowserTest() { |
| -} |
| - |
| -AccessibilityWinBrowserTest::~AccessibilityWinBrowserTest() { |
| +// Ensures that the text and the start and end offsets retrieved using |
| +// get_textAtOffset match the expected values. |
| +void AccessibilityWinBrowserTest::CheckTextAtOffset(IAccessibleText* element, |
| + LONG offset, |
| + IA2TextBoundaryType boundary_type, |
| + LONG expected_start_offset, |
| + LONG expected_end_offset, |
| + const std::wstring& expected_text) { |
| + testing::Message message; |
| + message << "While checking for \'" << expected_text << "\' at " << |
| + expected_start_offset << '-' << expected_end_offset << '.'; |
| + SCOPED_TRACE(message); |
| + |
| + LONG start_offset = 0; |
| + LONG end_offset = 0; |
| + base::win::ScopedBstr text; |
| + HRESULT hr = element->get_textAtOffset( |
| + offset, boundary_type, |
| + &start_offset, &end_offset, text.Receive()); |
| + EXPECT_EQ(S_OK, hr); |
| + EXPECT_EQ(expected_start_offset, start_offset); |
| + EXPECT_EQ(expected_end_offset, end_offset); |
| + EXPECT_EQ(expected_text, std::wstring(text, text.Length())); |
| } |
| -void AccessibilityWinBrowserTest::LoadInitialAccessibilityTreeFromHtml( |
| - const std::string& html) { |
| - AccessibilityNotificationWaiter waiter( |
| - shell(), AccessibilityModeComplete, |
| - ui::AX_EVENT_LOAD_COMPLETE); |
| - GURL html_data_url("data:text/html," + html); |
| - NavigateToURL(shell(), html_data_url); |
| - waiter.WaitForNotification(); |
| -} |
| +std::vector<base::win::ScopedVariant> |
| +AccessibilityWinBrowserTest::GetAllAccessibleChildren( |
| + IAccessible* element) { |
| + LONG child_count = 0; |
| + HRESULT hr = element->get_accChildCount(&child_count); |
| + EXPECT_EQ(S_OK, hr); |
| + if (child_count <= 0) |
| + return std::vector<base::win::ScopedVariant>(); |
| -// Retrieve the MSAA client accessibility object for the Render Widget Host View |
| -// of the selected tab. |
| -IAccessible* AccessibilityWinBrowserTest::GetRendererAccessible() { |
| - content::WebContents* web_contents = shell()->web_contents(); |
| - return web_contents->GetRenderWidgetHostView()->GetNativeViewAccessible(); |
| -} |
| + scoped_ptr<VARIANT[]> children_array(new VARIANT[child_count]); |
| + LONG obtained_count = 0; |
| + hr = AccessibleChildren( |
| + element, 0, child_count, children_array.get(), &obtained_count); |
| + EXPECT_EQ(S_OK, hr); |
| + EXPECT_EQ(child_count, obtained_count); |
| -void AccessibilityWinBrowserTest::ExecuteScript(const std::wstring& script) { |
| - shell()->web_contents()->GetMainFrame()->ExecuteJavaScript(script); |
| + std::vector<base::win::ScopedVariant> children( |
| + static_cast<size_t>(child_count)); |
| + for (size_t i = 0; i < children.size(); i++) { |
| + children[i].Reset(children_array[i]); |
| + } |
| + return children; |
| } |
| // AccessibleChecker ---------------------------------------------------------- |
| -class AccessibleChecker { |
| +class AccessibilityWinBrowserTest::AccessibleChecker { |
| public: |
| // This constructor can be used if the IA2 role will be the same as the MSAA |
| // role. |
| @@ -228,9 +382,10 @@ class AccessibleChecker { |
| AccessibleCheckerVector children_; |
| }; |
| -AccessibleChecker::AccessibleChecker(const std::wstring& expected_name, |
| - int32 expected_role, |
| - const std::wstring& expected_value) |
| +AccessibilityWinBrowserTest::AccessibleChecker::AccessibleChecker( |
| + const std::wstring& expected_name, |
| + int32 expected_role, |
| + const std::wstring& expected_value) |
| : name_(expected_name), |
| role_(expected_role), |
| ia2_role_(expected_role), |
| @@ -238,10 +393,11 @@ AccessibleChecker::AccessibleChecker(const std::wstring& expected_name, |
| state_(-1) { |
| } |
| -AccessibleChecker::AccessibleChecker(const std::wstring& expected_name, |
| - int32 expected_role, |
| - int32 expected_ia2_role, |
| - const std::wstring& expected_value) |
| +AccessibilityWinBrowserTest::AccessibleChecker::AccessibleChecker( |
| + const std::wstring& expected_name, |
| + int32 expected_role, |
| + int32 expected_ia2_role, |
| + const std::wstring& expected_value) |
| : name_(expected_name), |
| role_(expected_role), |
| ia2_role_(expected_ia2_role), |
| @@ -249,10 +405,11 @@ AccessibleChecker::AccessibleChecker(const std::wstring& expected_name, |
| state_(-1) { |
| } |
| -AccessibleChecker::AccessibleChecker(const std::wstring& expected_name, |
| - const std::wstring& expected_role, |
| - int32 expected_ia2_role, |
| - const std::wstring& expected_value) |
| +AccessibilityWinBrowserTest::AccessibleChecker::AccessibleChecker( |
| + const std::wstring& expected_name, |
| + const std::wstring& expected_role, |
| + int32 expected_ia2_role, |
| + const std::wstring& expected_value) |
| : name_(expected_name), |
| role_(expected_role.c_str()), |
| ia2_role_(expected_ia2_role), |
| @@ -260,14 +417,15 @@ AccessibleChecker::AccessibleChecker(const std::wstring& expected_name, |
| state_(-1) { |
| } |
| -void AccessibleChecker::AppendExpectedChild( |
| +void AccessibilityWinBrowserTest::AccessibleChecker::AppendExpectedChild( |
| AccessibleChecker* expected_child) { |
| children_.push_back(expected_child); |
| } |
| -void AccessibleChecker::CheckAccessible(IAccessible* accessible) { |
| - SCOPED_TRACE("while checking " + |
| - base::UTF16ToUTF8(RoleVariantToString(role_))); |
| +void AccessibilityWinBrowserTest::AccessibleChecker::CheckAccessible( |
| + IAccessible* accessible) { |
| + SCOPED_TRACE("While checking " |
| + + base::UTF16ToUTF8(RoleVariantToString(role_))); |
| CheckAccessibleName(accessible); |
| CheckAccessibleRole(accessible); |
| CheckIA2Role(accessible); |
| @@ -276,15 +434,18 @@ void AccessibleChecker::CheckAccessible(IAccessible* accessible) { |
| CheckAccessibleChildren(accessible); |
| } |
| -void AccessibleChecker::SetExpectedValue(const std::wstring& expected_value) { |
| +void AccessibilityWinBrowserTest::AccessibleChecker::SetExpectedValue( |
| + const std::wstring& expected_value) { |
| value_ = expected_value; |
| } |
| -void AccessibleChecker::SetExpectedState(LONG expected_state) { |
| +void AccessibilityWinBrowserTest::AccessibleChecker::SetExpectedState( |
| + LONG expected_state) { |
| state_ = expected_state; |
| } |
| -void AccessibleChecker::CheckAccessibleName(IAccessible* accessible) { |
| +void AccessibilityWinBrowserTest::AccessibleChecker::CheckAccessibleName( |
| + IAccessible* accessible) { |
| base::win::ScopedBstr name; |
| base::win::ScopedVariant childid_self(CHILDID_SELF); |
| HRESULT hr = accessible->get_accName(childid_self, name.Receive()); |
| @@ -299,7 +460,8 @@ void AccessibleChecker::CheckAccessibleName(IAccessible* accessible) { |
| } |
| } |
| -void AccessibleChecker::CheckAccessibleRole(IAccessible* accessible) { |
| +void AccessibilityWinBrowserTest::AccessibleChecker::CheckAccessibleRole( |
| + IAccessible* accessible) { |
| base::win::ScopedVariant role; |
| base::win::ScopedVariant childid_self(CHILDID_SELF); |
| HRESULT hr = accessible->get_accRole(childid_self, role.Receive()); |
| @@ -309,7 +471,8 @@ void AccessibleChecker::CheckAccessibleRole(IAccessible* accessible) { |
| << "\nGot role: " << RoleVariantToString(role); |
| } |
| -void AccessibleChecker::CheckIA2Role(IAccessible* accessible) { |
| +void AccessibilityWinBrowserTest::AccessibleChecker::CheckIA2Role( |
| + IAccessible* accessible) { |
| base::win::ScopedComPtr<IAccessible2> accessible2; |
| HRESULT hr = QueryIAccessible2(accessible, accessible2.Receive()); |
| ASSERT_EQ(S_OK, hr); |
| @@ -321,7 +484,8 @@ void AccessibleChecker::CheckIA2Role(IAccessible* accessible) { |
| << "\nGot ia2 role: " << IAccessible2RoleToString(ia2_role); |
| } |
| -void AccessibleChecker::CheckAccessibleValue(IAccessible* accessible) { |
| +void AccessibilityWinBrowserTest::AccessibleChecker::CheckAccessibleValue( |
| + IAccessible* accessible) { |
| // Don't check the value if if's a DOCUMENT role, because the value |
| // is supposed to be the url (and we don't keep track of that in the |
| // test expectations). |
| @@ -341,7 +505,8 @@ void AccessibleChecker::CheckAccessibleValue(IAccessible* accessible) { |
| EXPECT_EQ(value_, std::wstring(value, value.Length())); |
| } |
| -void AccessibleChecker::CheckAccessibleState(IAccessible* accessible) { |
| +void AccessibilityWinBrowserTest::AccessibleChecker::CheckAccessibleState( |
| + IAccessible* accessible) { |
| if (state_ < 0) |
| return; |
| @@ -360,31 +525,29 @@ void AccessibleChecker::CheckAccessibleState(IAccessible* accessible) { |
| << "\nGot state: " << IAccessibleStateToString(obj_state); |
| } |
| -void AccessibleChecker::CheckAccessibleChildren(IAccessible* parent) { |
| - LONG child_count = 0; |
| - HRESULT hr = parent->get_accChildCount(&child_count); |
| - EXPECT_EQ(S_OK, hr); |
| +void AccessibilityWinBrowserTest::AccessibleChecker::CheckAccessibleChildren( |
| + IAccessible* parent) { |
| + std::vector<base::win::ScopedVariant> obtained_children = |
| + GetAllAccessibleChildren(parent); |
| + size_t child_count = obtained_children.size(); |
| ASSERT_EQ(child_count, children_.size()); |
| - scoped_ptr<VARIANT[]> child_array(new VARIANT[child_count]); |
| - LONG obtained_count = 0; |
| - hr = AccessibleChildren(parent, 0, child_count, |
| - child_array.get(), &obtained_count); |
| - ASSERT_EQ(S_OK, hr); |
| - ASSERT_EQ(child_count, obtained_count); |
| - |
| - VARIANT* child = child_array.get(); |
| - for (AccessibleCheckerVector::iterator child_checker = children_.begin(); |
| - child_checker != children_.end(); |
| + AccessibleCheckerVector::iterator child_checker; |
| + std::vector<base::win::ScopedVariant>::iterator child; |
| + for (child_checker = children_.begin(), |
| + child = obtained_children.begin(); |
| + child_checker != children_.end() |
| + && child != obtained_children.end(); |
| ++child_checker, ++child) { |
| base::win::ScopedComPtr<IAccessible> child_accessible( |
| - GetAccessibleFromResultVariant(parent, child)); |
| + GetAccessibleFromVariant(parent, child->AsInput())); |
| ASSERT_TRUE(child_accessible.get()); |
| (*child_checker)->CheckAccessible(child_accessible); |
| } |
| } |
| -base::string16 AccessibleChecker::RoleVariantToString( |
| +base::string16 |
| +AccessibilityWinBrowserTest::AccessibleChecker::RoleVariantToString( |
| const base::win::ScopedVariant& role) { |
| if (role.type() == VT_I4) |
| return IAccessibleRoleToString(V_I4(&role)); |
| @@ -667,7 +830,7 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, |
| ASSERT_EQ(S_OK, hr); |
| bool found = false; |
| - RecursiveFindNodeInAccessibilityTree( |
| + FindNodeInAccessibilityTree( |
| browser_accessible.get(), ROLE_SYSTEM_DOCUMENT, L"MyDocument", 0, &found); |
| ASSERT_EQ(found, true); |
| } |
| @@ -753,4 +916,227 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, TestRoleGroup) { |
| document_checker.CheckAccessible(GetRendererAccessible()); |
| } |
| +IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, |
| + TestTextAtOffsetWithInvalidArgs) { |
| + base::win::ScopedComPtr<IAccessibleText> input_text; |
| + base::win::ScopedComPtr<IAccessibleText> textarea_text; |
| + SetUpTextFields(&input_text, &textarea_text); |
| + HRESULT hr = input_text->get_textAtOffset( |
| + 0, IA2_TEXT_BOUNDARY_CHAR, NULL, NULL, NULL); |
| + EXPECT_EQ(E_INVALIDARG, hr); |
| + hr = textarea_text->get_textAtOffset( |
| + 0, IA2_TEXT_BOUNDARY_CHAR, NULL, NULL, NULL); |
| + EXPECT_EQ(E_INVALIDARG, hr); |
| + |
| + // Test invalid offset. |
| + LONG start_offset = 0; |
| + LONG end_offset = 0; |
| + base::win::ScopedBstr text; |
| + LONG invalid_offset = -5; |
| + hr = input_text->get_textAtOffset( |
| + invalid_offset, IA2_TEXT_BOUNDARY_CHAR, |
| + &start_offset, &end_offset, text.Receive()); |
| + EXPECT_EQ(E_INVALIDARG, hr); |
| + hr = textarea_text->get_textAtOffset( |
| + invalid_offset, IA2_TEXT_BOUNDARY_WORD, |
| + &start_offset, &end_offset, text.Receive()); |
| + EXPECT_EQ(E_INVALIDARG, hr); |
| + |
| + // According to the IA2 Spec, only line boundaries should succeed when |
| + // the offset is one past the end of the text. |
| + invalid_offset = CONTENTS_LENGTH; |
| + hr = input_text->get_textAtOffset( |
| + invalid_offset, IA2_TEXT_BOUNDARY_LINE, |
| + &start_offset, &end_offset, text.Receive()); |
| + EXPECT_EQ(S_OK, hr); |
| + hr = textarea_text->get_textAtOffset( |
| + invalid_offset, IA2_TEXT_BOUNDARY_LINE, |
| + &start_offset, &end_offset, text.Receive()); |
| + EXPECT_EQ(S_OK, hr); |
| + |
| + hr = input_text->get_textAtOffset( |
| + invalid_offset, IA2_TEXT_BOUNDARY_CHAR, |
| + &start_offset, &end_offset, text.Receive()); |
| + EXPECT_EQ(S_FALSE, hr); |
| + hr = input_text->get_textAtOffset( |
| + invalid_offset, IA2_TEXT_BOUNDARY_WORD, |
| + &start_offset, &end_offset, text.Receive()); |
| + EXPECT_EQ(S_FALSE, hr); |
| + hr = textarea_text->get_textAtOffset( |
| + invalid_offset, IA2_TEXT_BOUNDARY_SENTENCE, |
| + &start_offset, &end_offset, text.Receive()); |
| + EXPECT_EQ(S_FALSE, hr); |
| + hr = textarea_text->get_textAtOffset( |
| + invalid_offset, IA2_TEXT_BOUNDARY_ALL, |
| + &start_offset, &end_offset, text.Receive()); |
| + EXPECT_EQ(S_FALSE, hr); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, |
| + TestTextAtOffsetWithBoundaryCharacter) { |
| + base::win::ScopedComPtr<IAccessibleText> input_text; |
| + base::win::ScopedComPtr<IAccessibleText> textarea_text; |
| + SetUpTextFields(&input_text, &textarea_text); |
| + for (LONG offset = 0; offset < CONTENTS_LENGTH; ++offset) { |
| + std::wstring expected_text(1, INPUT_CONTENTS[offset]); |
| + LONG expected_start_offset = offset; |
| + LONG expected_end_offset = offset + 1; |
| + CheckTextAtOffset(input_text, offset, IA2_TEXT_BOUNDARY_CHAR, |
| + expected_start_offset, expected_end_offset, expected_text); |
| + } |
| + for (LONG offset = CONTENTS_LENGTH - 1; offset >= 0; --offset) { |
| + std::wstring expected_text(1, TEXTAREA_CONTENTS[offset]); |
| + LONG expected_start_offset = offset; |
| + LONG expected_end_offset = offset + 1; |
| + CheckTextAtOffset(textarea_text, offset, IA2_TEXT_BOUNDARY_CHAR, |
| + expected_start_offset, expected_end_offset, expected_text); |
| + } |
| + // Test special offsets. |
| + CheckTextAtOffset(input_text, IA2_TEXT_OFFSET_LENGTH, |
| + IA2_TEXT_BOUNDARY_CHAR, CONTENTS_LENGTH - 1, CONTENTS_LENGTH, L"."); |
| + CheckTextAtOffset(input_text, IA2_TEXT_OFFSET_CARET, |
| + IA2_TEXT_BOUNDARY_CHAR, CONTENTS_LENGTH - 1, CONTENTS_LENGTH, L"."); |
| + CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_LENGTH, |
| + IA2_TEXT_BOUNDARY_CHAR, CONTENTS_LENGTH - 1, CONTENTS_LENGTH, L"."); |
| + CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_CARET, |
| + IA2_TEXT_BOUNDARY_CHAR, CONTENTS_LENGTH - 1, CONTENTS_LENGTH, L"."); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, |
| + TestTextAtOffsetWithBoundaryWord) { |
| + base::win::ScopedComPtr<IAccessibleText> input_text; |
| + base::win::ScopedComPtr<IAccessibleText> textarea_text; |
| + SetUpTextFields(&input_text, &textarea_text); |
| + |
| + // Trailing punctuation should be included as part of the previous word. |
| + CheckTextAtOffset(input_text, 0, IA2_TEXT_BOUNDARY_WORD, |
| + 0, 4, L"Moz/"); |
| + CheckTextAtOffset(textarea_text, 2, IA2_TEXT_BOUNDARY_WORD, |
| + 0, 4, L"Moz/"); |
| + |
| + // If the offset is at the punctuation, it should return |
| + // the previous word. |
| + CheckTextAtOffset(textarea_text, 3, IA2_TEXT_BOUNDARY_WORD, |
| + 0, 4, L"Moz/"); |
| + |
| + // Numbers with a decimal point ("." for U.S), should be treated as one word. |
| + // Also, trailing punctuation that occurs after empty space should be part of |
| + // the word. ("5.0 (" and not "5.0 ".) |
| + CheckTextAtOffset(input_text, 4, IA2_TEXT_BOUNDARY_WORD, |
| + 4, 9, L"5.0 ("); |
| + CheckTextAtOffset(textarea_text, 5, IA2_TEXT_BOUNDARY_WORD, |
| + 4, 9, L"5.0 ("); |
| + CheckTextAtOffset(input_text, 6, IA2_TEXT_BOUNDARY_WORD, |
| + 4, 9, L"5.0 ("); |
| + CheckTextAtOffset(textarea_text, 7, IA2_TEXT_BOUNDARY_WORD, |
| + 4, 9, L"5.0 ("); |
| + |
| + // Leading punctuation should not be included with the word after it. |
| + CheckTextAtOffset(input_text, 8, IA2_TEXT_BOUNDARY_WORD, |
| + 4, 9, L"5.0 ("); |
| + CheckTextAtOffset(textarea_text, 11, IA2_TEXT_BOUNDARY_WORD, |
| + 9, 12, L"ST "); |
| + |
| + // Numbers separated from letters with trailing punctuation should |
| + // be split into two words. Same for abreviations like "i.e.". |
| + CheckTextAtOffset(input_text, 12, IA2_TEXT_BOUNDARY_WORD, |
| + 12, 14, L"6."); |
| + CheckTextAtOffset(textarea_text, 15, IA2_TEXT_BOUNDARY_WORD, |
| + 14, 17, L"x; "); |
| + |
| + // Words with numbers should be treated like ordinary words. |
| + CheckTextAtOffset(input_text, 17, IA2_TEXT_BOUNDARY_WORD, |
| + 17, 24, L"WWW33) "); |
| + CheckTextAtOffset(textarea_text, 23, IA2_TEXT_BOUNDARY_WORD, |
| + 17, 24, L"WWW33)\n"); |
| + // Multiple trailing empty spaces should be part of the word preceding it. |
| + CheckTextAtOffset(input_text, 28, IA2_TEXT_BOUNDARY_WORD, |
| + 24, 33, L"WebKit \""); |
| + CheckTextAtOffset(textarea_text, 31, IA2_TEXT_BOUNDARY_WORD, |
| + 24, 33, L"WebKit \n\""); |
| + // Leading punctuation such as quotation marks should not be part of the word. |
| + CheckTextAtOffset(input_text, 32, IA2_TEXT_BOUNDARY_WORD, |
| + 24, 33, L"WebKit \""); |
| + CheckTextAtOffset(textarea_text, 32, IA2_TEXT_BOUNDARY_WORD, |
| + 24, 33, L"WebKit \n\""); |
| + CheckTextAtOffset(input_text, 33, IA2_TEXT_BOUNDARY_WORD, |
| + 33, 40, L"KHTML, "); |
| + CheckTextAtOffset(textarea_text, 38, IA2_TEXT_BOUNDARY_WORD, |
| + 33, 40, L"KHTML, "); |
| + // Trailing final punctuation should be part of the last word. |
| + CheckTextAtOffset(input_text, 45, IA2_TEXT_BOUNDARY_WORD, |
| + 40, CONTENTS_LENGTH, L"like\"."); |
| + CheckTextAtOffset(textarea_text, 41, IA2_TEXT_BOUNDARY_WORD, |
| + 40, CONTENTS_LENGTH, L"like\"."); |
| + // Test special offsets. |
| + CheckTextAtOffset(input_text, IA2_TEXT_OFFSET_LENGTH, |
| + IA2_TEXT_BOUNDARY_WORD, 40, CONTENTS_LENGTH, L"like\"."); |
| + CheckTextAtOffset(input_text, IA2_TEXT_OFFSET_CARET, |
| + IA2_TEXT_BOUNDARY_WORD, 40, CONTENTS_LENGTH, L"like\"."); |
| + CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_LENGTH, |
| + IA2_TEXT_BOUNDARY_WORD, 40, CONTENTS_LENGTH, L"like\"."); |
| + CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_CARET, |
| + IA2_TEXT_BOUNDARY_WORD, 40, CONTENTS_LENGTH, L"like\"."); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, |
| + TestTextAtOffsetWithBoundarySentence) { |
| + base::win::ScopedComPtr<IAccessibleText> input_text; |
| + base::win::ScopedComPtr<IAccessibleText> textarea_text; |
| + SetUpTextFields(&input_text, &textarea_text); |
| + |
| + // Sentence navigation is not currently implemented. |
| + LONG start_offset = 0; |
| + LONG end_offset = 0; |
| + base::win::ScopedBstr text; |
| + HRESULT hr = input_text->get_textAtOffset( |
| + 5, IA2_TEXT_BOUNDARY_SENTENCE, |
| + &start_offset, &end_offset, text.Receive()); |
| + EXPECT_EQ(S_FALSE, hr); |
| + hr = textarea_text->get_textAtOffset( |
| + 25, IA2_TEXT_BOUNDARY_SENTENCE, |
| + &start_offset, &end_offset, text.Receive()); |
| + EXPECT_EQ(S_FALSE, hr); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, |
| + TestTextAtOffsetWithBoundaryLine) { |
| + base::win::ScopedComPtr<IAccessibleText> input_text; |
| + base::win::ScopedComPtr<IAccessibleText> textarea_text; |
| + SetUpTextFields(&input_text, &textarea_text); |
| + |
| + // Single line text fields should return the whole text. |
| + CheckTextAtOffset(input_text, 0, IA2_TEXT_BOUNDARY_LINE, |
| + 0, CONTENTS_LENGTH, base::ASCIIToWide(INPUT_CONTENTS)); |
| + // Textarea is a multi-line text field. |
| + CheckTextAtOffset(textarea_text, 0, IA2_TEXT_BOUNDARY_LINE, |
| + 0, 24, L"Moz/5.0 (ST 6.x; WWW33)\n"); |
| + // If the offset is at the newline, return the line preceding it. |
| + CheckTextAtOffset(textarea_text, 31, IA2_TEXT_BOUNDARY_LINE, |
| + 24, 32, L"WebKit \n"); |
| + // Last line does not have a trailing newline. |
| + CheckTextAtOffset(textarea_text, 32, IA2_TEXT_BOUNDARY_LINE, |
| + 32, CONTENTS_LENGTH, L"\"KHTML, like\"."); |
| + // An offset one past the last character should return the last line. |
| + CheckTextAtOffset(textarea_text, CONTENTS_LENGTH, IA2_TEXT_BOUNDARY_LINE, |
| + 32, CONTENTS_LENGTH, L"\"KHTML, like\"."); |
| + // Test special offsets. |
| + CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_LENGTH, |
| + IA2_TEXT_BOUNDARY_LINE, 32, CONTENTS_LENGTH, L"\"KHTML, like\"."); |
| + CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_CARET, |
| + IA2_TEXT_BOUNDARY_LINE, 32, CONTENTS_LENGTH, L"\"KHTML, like\"."); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, |
| + TestTextAtOffsetWithBoundaryAll) { |
| + base::win::ScopedComPtr<IAccessibleText> input_text; |
| + base::win::ScopedComPtr<IAccessibleText> textarea_text; |
| + SetUpTextFields(&input_text, &textarea_text); |
| + |
| + CheckTextAtOffset(input_text, 0, IA2_TEXT_BOUNDARY_ALL, |
| + 0, CONTENTS_LENGTH, base::ASCIIToWide(INPUT_CONTENTS)); |
| + CheckTextAtOffset(textarea_text, CONTENTS_LENGTH - 1, IA2_TEXT_BOUNDARY_ALL, |
| + 0, CONTENTS_LENGTH, base::ASCIIToWide(TEXTAREA_CONTENTS)); |
| +} |
| + |
| } // namespace content |