Roll src/third_party/WebKit f298044:aa8346d (svn 202628:202629)
[chromium-blink-merge.git] / content / browser / accessibility / android_granularity_movement_browsertest.cc
blob6ddf830423ed64675cae93d9663957380b98e813
1 // Copyright 2014 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 <set>
6 #include <string>
7 #include <vector>
9 #include "base/logging.h"
10 #include "base/strings/string16.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "content/browser/accessibility/browser_accessibility_android.h"
14 #include "content/browser/accessibility/browser_accessibility_manager_android.h"
15 #include "content/browser/web_contents/web_contents_impl.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/common/url_constants.h"
18 #include "content/public/test/content_browser_test.h"
19 #include "content/public/test/content_browser_test_utils.h"
20 #include "content/shell/browser/shell.h"
21 #include "content/test/accessibility_browser_test_utils.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 namespace content {
26 const int GRANULARITY_CHARACTER =
27 ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_CHARACTER;
28 const int GRANULARITY_WORD =
29 ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_WORD;
30 const int GRANULARITY_LINE =
31 ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_LINE;
33 class AndroidGranularityMovementBrowserTest : public ContentBrowserTest {
34 public:
35 AndroidGranularityMovementBrowserTest() {}
36 ~AndroidGranularityMovementBrowserTest() override {}
38 BrowserAccessibility* LoadUrlAndGetAccessibilityRoot(const GURL& url) {
39 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
41 // Load the page.
42 AccessibilityNotificationWaiter waiter(
43 shell(), AccessibilityModeComplete,
44 ui::AX_EVENT_LOAD_COMPLETE);
45 NavigateToURL(shell(), url);
46 waiter.WaitForNotification();
48 // Get the BrowserAccessibilityManager.
49 WebContentsImpl* web_contents =
50 static_cast<WebContentsImpl*>(shell()->web_contents());
51 return web_contents->GetRootBrowserAccessibilityManager()->GetRoot();
54 // First, set accessibility focus to a node and wait for the update that
55 // loads inline text boxes for that node. (We load inline text boxes
56 // asynchronously on Android since we only ever need them for the node
57 // with accessibility focus.)
59 // Then call NextAtGranularity repeatedly and return a string that
60 // concatenates all of the text of the returned text ranges.
62 // As an example, if the node's text is "cat dog" and you traverse by
63 // word, this returns "'cat', 'dog'".
65 // Also calls PreviousAtGranularity from the end back to the beginning
66 // and fails (by logging an error and returning the empty string) if
67 // the result when traversing backwards is not the same
68 // (but in reverse order).
69 base::string16 TraverseNodeAtGranularity(
70 BrowserAccessibility* node,
71 int granularity) {
72 AccessibilityNotificationWaiter waiter(
73 shell(), AccessibilityModeComplete,
74 ui::AX_EVENT_TREE_CHANGED);
75 node->manager()->delegate()->AccessibilitySetAccessibilityFocus(
76 node->GetId());
77 waiter.WaitForNotification();
79 int start_index = -1;
80 int end_index = -1;
81 BrowserAccessibilityAndroid* android_node =
82 static_cast<BrowserAccessibilityAndroid*>(node);
83 BrowserAccessibilityManagerAndroid* manager =
84 static_cast<BrowserAccessibilityManagerAndroid*>(node->manager());
85 base::string16 text = android_node->GetText();
86 base::string16 concatenated;
87 int previous_end_index = -1;
88 while (manager->NextAtGranularity(
89 granularity, end_index, android_node,
90 &start_index, &end_index)) {
91 int len = (granularity == GRANULARITY_CHARACTER) ?
92 1 : end_index - start_index;
93 base::string16 selection = text.substr(start_index, len);
94 if (base::EndsWith(selection, base::ASCIIToUTF16("\n"),
95 base::CompareCase::INSENSITIVE_ASCII))
96 selection.erase(selection.size() - 1);
97 if (!selection.empty()) {
98 if (!concatenated.empty())
99 concatenated += base::ASCIIToUTF16(", ");
100 concatenated += base::ASCIIToUTF16("'") + selection +
101 base::ASCIIToUTF16("'");
104 // Prevent an endless loop.
105 if (end_index == previous_end_index) {
106 LOG(ERROR) << "Bailing from loop, NextAtGranularity didn't advance";
107 break;
109 previous_end_index = end_index;
112 base::string16 reverse;
113 previous_end_index = -1;
114 start_index = end_index;
115 while (manager->PreviousAtGranularity(
116 granularity, start_index, android_node, &start_index, &end_index)) {
117 int len = (granularity == GRANULARITY_CHARACTER) ?
118 1 : end_index - start_index;
119 base::string16 selection = text.substr(start_index, len);
120 if (base::EndsWith(selection, base::ASCIIToUTF16("\n"),
121 base::CompareCase::INSENSITIVE_ASCII))
122 selection = selection.substr(0, selection.size() - 1);
123 if (!reverse.empty())
124 reverse = base::ASCIIToUTF16(", ") + reverse;
125 reverse = base::ASCIIToUTF16("'") + selection +
126 base::ASCIIToUTF16("'") + reverse;
128 // Prevent an endless loop.
129 if (end_index == previous_end_index) {
130 LOG(ERROR) << "Bailing from loop, PreviousAtGranularity didn't advance";
131 break;
133 previous_end_index = end_index;
136 if (concatenated != reverse) {
137 LOG(ERROR) << "Did not get the same sequence in the forwards and "
138 << "reverse directions!";
139 LOG(ERROR) << "Forwards: " << concatenated;
140 LOG(ERROR) << "Backwards " << reverse;
141 return base::string16();
144 return concatenated;
148 IN_PROC_BROWSER_TEST_F(AndroidGranularityMovementBrowserTest,
149 NavigateByCharacters) {
150 GURL url("data:text/html,"
151 "<body>"
152 "<p>One, two, three!</p>"
153 "<button aria-label='Seven, eight, nine!'>Four, five, six!</button>"
154 "</body></html>");
155 BrowserAccessibility* root = LoadUrlAndGetAccessibilityRoot(url);
156 ASSERT_EQ(2U, root->PlatformChildCount());
157 BrowserAccessibility* para = root->PlatformGetChild(0);
158 ASSERT_EQ(0U, para->PlatformChildCount());
159 BrowserAccessibility* button_container = root->PlatformGetChild(1);
160 ASSERT_EQ(1U, button_container->PlatformChildCount());
161 BrowserAccessibility* button = button_container->PlatformGetChild(0);
162 ASSERT_EQ(0U, button->PlatformChildCount());
164 ASSERT_EQ(
165 base::ASCIIToUTF16("'O', 'n', 'e', ',', ' ', 't', 'w', 'o', "
166 "',', ' ', 't', 'h', 'r', 'e', 'e', '!'"),
167 TraverseNodeAtGranularity(para, GRANULARITY_CHARACTER));
168 ASSERT_EQ(
169 base::ASCIIToUTF16("'S', 'e', 'v', 'e', 'n', ',', ' ', 'e', 'i', 'g', "
170 "'h', 't', ',', ' ', 'n', 'i', 'n', 'e', '!'"),
171 TraverseNodeAtGranularity(button, GRANULARITY_CHARACTER));
174 IN_PROC_BROWSER_TEST_F(AndroidGranularityMovementBrowserTest,
175 NavigateByWords) {
176 GURL url("data:text/html,"
177 "<body>"
178 "<p>One, two, three!</p>"
179 "<button aria-label='Seven, eight, nine!'>Four, five, six!</button>"
180 "</body></html>");
181 BrowserAccessibility* root = LoadUrlAndGetAccessibilityRoot(url);
182 ASSERT_EQ(2U, root->PlatformChildCount());
183 BrowserAccessibility* para = root->PlatformGetChild(0);
184 ASSERT_EQ(0U, para->PlatformChildCount());
185 BrowserAccessibility* button_container = root->PlatformGetChild(1);
186 ASSERT_EQ(1U, button_container->PlatformChildCount());
187 BrowserAccessibility* button = button_container->PlatformGetChild(0);
188 ASSERT_EQ(0U, button->PlatformChildCount());
190 ASSERT_EQ(base::ASCIIToUTF16("'One', 'two', 'three'"),
191 TraverseNodeAtGranularity(para, GRANULARITY_WORD));
192 ASSERT_EQ(base::ASCIIToUTF16("'Seven', 'eight', 'nine'"),
193 TraverseNodeAtGranularity(button, GRANULARITY_WORD));
196 IN_PROC_BROWSER_TEST_F(AndroidGranularityMovementBrowserTest,
197 NavigateByLine) {
198 GURL url("data:text/html,"
199 "<body>"
200 "<pre>One,%0dtwo,%0dthree!</pre>"
201 "</body>");
202 BrowserAccessibility* root = LoadUrlAndGetAccessibilityRoot(url);
203 ASSERT_EQ(1U, root->PlatformChildCount());
204 BrowserAccessibility* pre = root->PlatformGetChild(0);
205 ASSERT_EQ(0U, pre->PlatformChildCount());
207 ASSERT_EQ(base::ASCIIToUTF16("'One,', 'two,', 'three!'"),
208 TraverseNodeAtGranularity(pre, GRANULARITY_LINE));
211 } // namespace content