OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/accessibility/dump_accessibility_browsertest_base.h" | 5 #include "content/browser/accessibility/dump_accessibility_browsertest_base.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include <string> | 8 #include <string> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
(...skipping 12 matching lines...) Expand all Loading... | |
23 #include "content/browser/accessibility/browser_accessibility_state_impl.h" | 23 #include "content/browser/accessibility/browser_accessibility_state_impl.h" |
24 #include "content/browser/web_contents/web_contents_impl.h" | 24 #include "content/browser/web_contents/web_contents_impl.h" |
25 #include "content/public/browser/web_contents.h" | 25 #include "content/public/browser/web_contents.h" |
26 #include "content/public/common/content_paths.h" | 26 #include "content/public/common/content_paths.h" |
27 #include "content/public/common/content_switches.h" | 27 #include "content/public/common/content_switches.h" |
28 #include "content/public/common/url_constants.h" | 28 #include "content/public/common/url_constants.h" |
29 #include "content/public/test/content_browser_test.h" | 29 #include "content/public/test/content_browser_test.h" |
30 #include "content/public/test/content_browser_test_utils.h" | 30 #include "content/public/test/content_browser_test_utils.h" |
31 #include "content/shell/browser/shell.h" | 31 #include "content/shell/browser/shell.h" |
32 #include "content/test/accessibility_browser_test_utils.h" | 32 #include "content/test/accessibility_browser_test_utils.h" |
33 #include "content/test/content_browser_test_utils_internal.h" | |
33 | 34 |
34 namespace content { | 35 namespace content { |
35 | 36 |
36 namespace { | 37 namespace { |
37 | 38 |
38 const char kCommentToken = '#'; | 39 const char kCommentToken = '#'; |
39 const char kMarkSkipFile[] = "#<skip"; | 40 const char kMarkSkipFile[] = "#<skip"; |
40 const char kMarkEndOfFile[] = "<-- End-of-file -->"; | 41 const char kMarkEndOfFile[] = "<-- End-of-file -->"; |
41 const char kSignalDiff[] = "*"; | 42 const char kSignalDiff[] = "*"; |
42 | 43 |
44 // Helper function to be used with FrameTree::ForEach, so that | |
45 // AccessibilityNotificationWaiter can listen for accessibility | |
46 // events in all frames. | |
47 bool ListenToFrame(AccessibilityNotificationWaiter* waiter, | |
48 FrameTreeNode* frame_tree_node) { | |
49 waiter->ListenToAdditionalFrame(frame_tree_node->current_frame_host()); | |
50 return true; | |
nasko
2016/01/07 00:07:37
nit: This is a small enough function that it can b
dmazzoni
2016/01/07 19:19:08
Done, though unfortunately it doesn't seem to pass
| |
51 } | |
52 | |
53 // Helper function to be used with FrameTree::ForEach, to get the | |
54 // url of all frames. | |
55 bool GetFrameUrl(std::vector<std::string>* all_frame_urls, | |
56 FrameTreeNode* frame_tree_node) { | |
57 std::string url = frame_tree_node->current_url().spec(); | |
58 if (url != url::kAboutBlankURL) | |
dcheng
2016/01/07 00:07:11
Just curious: any particular reason to filter out
dmazzoni
2016/01/07 19:19:08
Removed. I added this while debugging but it shoul
dmazzoni
2016/01/11 19:40:53
Turns out this was needed for one test.
Consider
| |
59 all_frame_urls->push_back(url); | |
60 return true; | |
61 } | |
62 | |
63 // Searches recursively and returns true if an accessibility node | |
David Tseng
2016/01/07 00:02:29
nit: lines can fit more characters.
dmazzoni
2016/01/07 19:19:08
Done.
| |
64 // is found that represents a fully loaded web document with the | |
65 // given url. | |
66 bool AccessibilityTreeContainsLoadedDocWithUrl(BrowserAccessibility* node, | |
67 const std::string& url) { | |
68 if ((node->GetRole() == ui::AX_ROLE_WEB_AREA || | |
69 node->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) && | |
70 node->GetStringAttribute(ui::AX_ATTR_URL) == url) { | |
71 // If possible, ensure the doc has finished loading. That's currently | |
72 // not possible with same-process iframes until bug 532249 is | |
nasko
2016/01/07 00:07:37
nit: https://crbug.com/532249 as it will likify an
dmazzoni
2016/01/07 19:19:08
Done.
| |
73 // fixed. | |
74 if (node->manager()->GetTreeData().url == url && | |
75 !node->manager()->GetTreeData().loaded) { | |
76 return false; | |
77 } | |
78 | |
79 return true; | |
David Tseng
2016/01/07 00:02:29
You could negate the above if clauses and return t
dmazzoni
2016/01/07 19:19:08
Done.
| |
80 } | |
81 | |
82 for (unsigned i = 0; i < node->PlatformChildCount(); i++) { | |
83 if (AccessibilityTreeContainsLoadedDocWithUrl( | |
84 node->PlatformGetChild(i), url)) { | |
85 return true; | |
86 } | |
87 } | |
88 return false; | |
89 } | |
90 | |
43 } // namespace | 91 } // namespace |
44 | 92 |
45 typedef AccessibilityTreeFormatter::Filter Filter; | 93 typedef AccessibilityTreeFormatter::Filter Filter; |
46 | 94 |
47 DumpAccessibilityTestBase::DumpAccessibilityTestBase() { | 95 DumpAccessibilityTestBase::DumpAccessibilityTestBase() { |
48 } | 96 } |
49 | 97 |
50 DumpAccessibilityTestBase::~DumpAccessibilityTestBase() { | 98 DumpAccessibilityTestBase::~DumpAccessibilityTestBase() { |
51 } | 99 } |
52 | 100 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
88 ++j; | 136 ++j; |
89 } | 137 } |
90 | 138 |
91 // Actual file has been fully checked. | 139 // Actual file has been fully checked. |
92 return diff_lines; | 140 return diff_lines; |
93 } | 141 } |
94 | 142 |
95 void DumpAccessibilityTestBase::ParseHtmlForExtraDirectives( | 143 void DumpAccessibilityTestBase::ParseHtmlForExtraDirectives( |
96 const std::string& test_html, | 144 const std::string& test_html, |
97 std::vector<Filter>* filters, | 145 std::vector<Filter>* filters, |
98 std::string* wait_for) { | 146 std::vector<std::string>* wait_for) { |
99 for (const std::string& line : | 147 for (const std::string& line : |
100 base::SplitString(test_html, "\n", base::TRIM_WHITESPACE, | 148 base::SplitString(test_html, "\n", base::TRIM_WHITESPACE, |
101 base::SPLIT_WANT_ALL)) { | 149 base::SPLIT_WANT_ALL)) { |
102 const std::string& allow_empty_str = formatter_->GetAllowEmptyString(); | 150 const std::string& allow_empty_str = formatter_->GetAllowEmptyString(); |
103 const std::string& allow_str = formatter_->GetAllowString(); | 151 const std::string& allow_str = formatter_->GetAllowString(); |
104 const std::string& deny_str = formatter_->GetDenyString(); | 152 const std::string& deny_str = formatter_->GetDenyString(); |
105 const std::string& wait_str = "@WAIT-FOR:"; | 153 const std::string& wait_str = "@WAIT-FOR:"; |
106 if (base::StartsWith(line, allow_empty_str, | 154 if (base::StartsWith(line, allow_empty_str, |
107 base::CompareCase::SENSITIVE)) { | 155 base::CompareCase::SENSITIVE)) { |
108 filters->push_back( | 156 filters->push_back( |
109 Filter(base::UTF8ToUTF16(line.substr(allow_empty_str.size())), | 157 Filter(base::UTF8ToUTF16(line.substr(allow_empty_str.size())), |
110 Filter::ALLOW_EMPTY)); | 158 Filter::ALLOW_EMPTY)); |
111 } else if (base::StartsWith(line, allow_str, | 159 } else if (base::StartsWith(line, allow_str, |
112 base::CompareCase::SENSITIVE)) { | 160 base::CompareCase::SENSITIVE)) { |
113 filters->push_back(Filter(base::UTF8ToUTF16( | 161 filters->push_back(Filter(base::UTF8ToUTF16( |
114 line.substr(allow_str.size())), | 162 line.substr(allow_str.size())), |
115 Filter::ALLOW)); | 163 Filter::ALLOW)); |
116 } else if (base::StartsWith(line, deny_str, | 164 } else if (base::StartsWith(line, deny_str, |
117 base::CompareCase::SENSITIVE)) { | 165 base::CompareCase::SENSITIVE)) { |
118 filters->push_back(Filter(base::UTF8ToUTF16( | 166 filters->push_back(Filter(base::UTF8ToUTF16( |
119 line.substr(deny_str.size())), | 167 line.substr(deny_str.size())), |
120 Filter::DENY)); | 168 Filter::DENY)); |
121 } else if (base::StartsWith(line, wait_str, | 169 } else if (base::StartsWith(line, wait_str, |
122 base::CompareCase::SENSITIVE)) { | 170 base::CompareCase::SENSITIVE)) { |
123 *wait_for = line.substr(wait_str.size()); | 171 wait_for->push_back(line.substr(wait_str.size())); |
124 } | 172 } |
125 } | 173 } |
126 } | 174 } |
127 | 175 |
128 AccessibilityTreeFormatter* | 176 AccessibilityTreeFormatter* |
129 DumpAccessibilityTestBase::CreateAccessibilityTreeFormatter() { | 177 DumpAccessibilityTestBase::CreateAccessibilityTreeFormatter() { |
130 if (is_blink_pass_) | 178 if (is_blink_pass_) |
131 return new AccessibilityTreeFormatterBlink(); | 179 return new AccessibilityTreeFormatterBlink(); |
132 else | 180 else |
133 return AccessibilityTreeFormatter::Create(); | 181 return AccessibilityTreeFormatter::Create(); |
134 } | 182 } |
135 | 183 |
136 void DumpAccessibilityTestBase::RunTest( | 184 void DumpAccessibilityTestBase::RunTest( |
137 const base::FilePath file_path, const char* file_dir) { | 185 const base::FilePath file_path, const char* file_dir) { |
138 #if !defined(OS_ANDROID) | 186 #if !defined(OS_ANDROID) |
139 // The blink tree is different on Android because we exclude inline | 187 // The blink tree is different on Android because we exclude inline |
140 // text boxes, for performance. | 188 // text boxes, for performance. |
141 is_blink_pass_ = true; | 189 is_blink_pass_ = true; |
142 RunTestForPlatform(file_path, file_dir); | 190 RunTestForPlatform(file_path, file_dir); |
143 #endif | 191 #endif |
144 is_blink_pass_ = false; | 192 is_blink_pass_ = false; |
145 RunTestForPlatform(file_path, file_dir); | 193 RunTestForPlatform(file_path, file_dir); |
146 } | 194 } |
147 | 195 |
148 void DumpAccessibilityTestBase::RunTestForPlatform( | 196 void DumpAccessibilityTestBase::RunTestForPlatform( |
149 const base::FilePath file_path, const char* file_dir) { | 197 const base::FilePath file_path, const char* file_dir) { |
198 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( | |
199 shell()->web_contents()); | |
200 web_contents->AddAccessibilityMode(AccessibilityModeComplete); | |
201 | |
150 formatter_.reset(CreateAccessibilityTreeFormatter()); | 202 formatter_.reset(CreateAccessibilityTreeFormatter()); |
151 | 203 |
152 // Disable the "hot tracked" state (set when the mouse is hovering over | 204 // Disable the "hot tracked" state (set when the mouse is hovering over |
153 // an object) because it makes test output change based on the mouse position. | 205 // an object) because it makes test output change based on the mouse position. |
154 BrowserAccessibilityStateImpl::GetInstance()-> | 206 BrowserAccessibilityStateImpl::GetInstance()-> |
155 set_disable_hot_tracking_for_testing(true); | 207 set_disable_hot_tracking_for_testing(true); |
156 | 208 |
157 NavigateToURL(shell(), GURL(url::kAboutBlankURL)); | 209 NavigateToURL(shell(), GURL(url::kAboutBlankURL)); |
158 | 210 |
159 // Output the test path to help anyone who encounters a failure and needs | 211 // Output the test path to help anyone who encounters a failure and needs |
(...skipping 26 matching lines...) Expand all Loading... | |
186 // normalize by deleting all \r from the file (if any) to leave only \n. | 238 // normalize by deleting all \r from the file (if any) to leave only \n. |
187 std::string expected_contents; | 239 std::string expected_contents; |
188 base::RemoveChars(expected_contents_raw, "\r", &expected_contents); | 240 base::RemoveChars(expected_contents_raw, "\r", &expected_contents); |
189 | 241 |
190 if (!expected_contents.compare(0, strlen(kMarkSkipFile), kMarkSkipFile)) { | 242 if (!expected_contents.compare(0, strlen(kMarkSkipFile), kMarkSkipFile)) { |
191 LOG(INFO) << "Skipping this test on this platform."; | 243 LOG(INFO) << "Skipping this test on this platform."; |
192 return; | 244 return; |
193 } | 245 } |
194 | 246 |
195 // Parse filters and other directives in the test file. | 247 // Parse filters and other directives in the test file. |
196 std::string wait_for; | 248 std::vector<std::string> wait_for; |
197 AddDefaultFilters(&filters_); | 249 AddDefaultFilters(&filters_); |
198 ParseHtmlForExtraDirectives(html_contents, &filters_, &wait_for); | 250 ParseHtmlForExtraDirectives(html_contents, &filters_, &wait_for); |
199 | 251 |
200 // Load the page. | 252 // Load the page. |
201 base::string16 html_contents16; | 253 GURL url(embedded_test_server()->GetURL( |
202 html_contents16 = base::UTF8ToUTF16(html_contents); | 254 "/" + std::string(file_dir) + "/" + file_path.BaseName().MaybeAsASCII())); |
203 GURL url = GetTestUrl(file_dir, file_path.BaseName().MaybeAsASCII().c_str()); | |
204 | |
205 // If there's a @WAIT-FOR directive, set up an accessibility notification | |
206 // waiter that returns on any event; we'll stop when we get the text we're | |
207 // waiting for, or time out. Otherwise just wait specifically for | |
208 // the "load complete" event. | |
209 scoped_ptr<AccessibilityNotificationWaiter> waiter; | |
210 if (!wait_for.empty()) { | |
211 waiter.reset(new AccessibilityNotificationWaiter( | |
212 shell(), AccessibilityModeComplete, ui::AX_EVENT_NONE)); | |
213 } else { | |
214 waiter.reset(new AccessibilityNotificationWaiter( | |
215 shell(), AccessibilityModeComplete, ui::AX_EVENT_LOAD_COMPLETE)); | |
216 } | |
217 | 255 |
218 // Load the test html. | 256 // Load the test html. |
219 NavigateToURL(shell(), url); | 257 NavigateToURL(shell(), url); |
220 | 258 |
221 // Wait for notifications. If there's a @WAIT-FOR directive, break when | 259 // Navigate frames with the @CROSS-SITE: directive to a cross-site url. |
222 // the text we're waiting for appears in the dump, otherwise break after | 260 const std::string& cross_site_str = "@CROSS-SITE:"; |
223 // the first notification, which will be a load complete. | 261 FrameTree* frame_tree = web_contents->GetFrameTree(); |
224 do { | 262 FrameTreeNode* root = frame_tree->root(); |
225 waiter->WaitForNotification(); | 263 for (size_t i = 0; i < root->child_count(); ++i) { |
226 if (!wait_for.empty()) { | 264 FrameTreeNode* child_frame_tree_node = root->child_at(i); |
227 base::string16 tree_dump = DumpUnfilteredAccessibilityTreeAsString(); | 265 GURL url = child_frame_tree_node->current_url(); |
228 if (base::UTF16ToUTF8(tree_dump).find(wait_for) != std::string::npos) | 266 std::string path = url.path(); |
229 wait_for.clear(); | 267 auto pos = path.find(cross_site_str); |
268 if (pos != std::string::npos) { | |
269 std::string host = base::StringPrintf("site%d.com", static_cast<int>(i)); | |
dcheng
2016/01/07 00:07:11
Per http://google.github.io/styleguide/cppguide.ht
dmazzoni
2016/01/07 19:19:08
Moot due to comment below.
| |
270 GURL cross_site_url(embedded_test_server()->GetURL( | |
271 host, path.replace(pos, cross_site_str.size(), ""))); | |
272 NavigateFrameToURL(child_frame_tree_node, cross_site_url); | |
273 | |
274 SiteInstance* site_instance = | |
275 child_frame_tree_node->current_frame_host()->GetSiteInstance(); | |
276 EXPECT_NE(web_contents->GetSiteInstance(), site_instance); | |
230 } | 277 } |
231 } while (!wait_for.empty()); | 278 } |
nasko
2016/01/07 00:07:37
This loop is unnecessary as we have enough facilit
dmazzoni
2016/01/07 19:19:08
Great idea! For some reason I didn't think I could
| |
279 | |
280 // Get the url of every frame in the frame tree. | |
281 std::vector<std::string> all_frame_urls; | |
282 frame_tree->ForEach(base::Bind(GetFrameUrl, &all_frame_urls)); | |
283 | |
284 // Wait for the accessibility tree to fully load for all frames, | |
285 // by searching for the WEB_AREA node in the accessibility tree | |
286 // with the url of each frame in our frame tree. Note that this | |
287 // doesn't support cases where there are two iframes with the | |
288 // exact same url. If all frames haven't loaded yet, set up a | |
289 // listener for accessibility events on any frame and block | |
290 // until the next one is received. | |
291 // | |
292 // If the original page has a @WAIT-FOR directive, don't break until | |
293 // the text we're waiting for appears in the full text dump of the | |
294 // accessibility tree, either. | |
295 for (;;) { | |
296 VLOG(1) << "Top of loop"; | |
297 RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>( | |
298 web_contents->GetMainFrame()); | |
299 BrowserAccessibility* accessibility_root = | |
300 main_frame->browser_accessibility_manager()->GetRoot(); | |
301 | |
302 // Check to see if all frames have loaded. | |
303 bool all_frames_loaded = true; | |
304 for (auto& url : all_frame_urls) { | |
dcheng
2016/01/07 00:07:11
const auto&, since mutability isn't required
dmazzoni
2016/01/07 19:19:08
Done.
| |
305 if (!AccessibilityTreeContainsLoadedDocWithUrl(accessibility_root, url)) { | |
306 VLOG(1) << "Still waiting on this frame to load: " << url; | |
307 all_frames_loaded = false; | |
308 break; | |
309 } | |
310 } | |
311 | |
312 // Check to see if the @WAIT-FOR text has appeared yet. | |
313 bool all_wait_for_strings_found = true; | |
314 base::string16 tree_dump = DumpUnfilteredAccessibilityTreeAsString(); | |
315 for (auto& str : wait_for) { | |
dcheng
2016/01/07 00:07:11
const auto&
dmazzoni
2016/01/07 19:19:08
Done.
| |
316 if (base::UTF16ToUTF8(tree_dump).find(str) == std::string::npos) { | |
317 VLOG(1) << "Still waiting on this text to be found: " << str; | |
318 all_wait_for_strings_found = false; | |
319 break; | |
320 } | |
321 } | |
322 | |
323 // If all frames have loaded and the @WAIT-FOR text has appeared, | |
324 // we're done. | |
325 if (all_frames_loaded && all_wait_for_strings_found) | |
326 break; | |
327 | |
328 // Block until the next accessibility notification in any frame. | |
329 VLOG(1) << "Waiting until the next accessibility event"; | |
330 AccessibilityNotificationWaiter accessibility_waiter(main_frame, | |
331 ui::AX_EVENT_NONE); | |
332 frame_tree->ForEach(base::Bind(ListenToFrame, &accessibility_waiter)); | |
333 accessibility_waiter.WaitForNotification(); | |
334 } | |
232 | 335 |
233 // Call the subclass to dump the output. | 336 // Call the subclass to dump the output. |
234 std::vector<std::string> actual_lines = Dump(); | 337 std::vector<std::string> actual_lines = Dump(); |
235 | 338 |
236 // Perform a diff (or write the initial baseline). | 339 // Perform a diff (or write the initial baseline). |
237 std::vector<std::string> expected_lines = base::SplitString( | 340 std::vector<std::string> expected_lines = base::SplitString( |
238 expected_contents, "\n", base::KEEP_WHITESPACE, | 341 expected_contents, "\n", base::KEEP_WHITESPACE, |
239 base::SPLIT_WANT_NONEMPTY); | 342 base::SPLIT_WANT_NONEMPTY); |
240 // Marking the end of the file with a line of text ensures that | 343 // Marking the end of the file with a line of text ensures that |
241 // file length differences are found. | 344 // file length differences are found. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
278 expected_file, actual_contents.c_str(), actual_contents.size())); | 381 expected_file, actual_contents.c_str(), actual_contents.size())); |
279 LOG(INFO) << "Wrote expectations to: " | 382 LOG(INFO) << "Wrote expectations to: " |
280 << expected_file.LossyDisplayName(); | 383 << expected_file.LossyDisplayName(); |
281 } | 384 } |
282 } else { | 385 } else { |
283 LOG(INFO) << "Test output matches expectations."; | 386 LOG(INFO) << "Test output matches expectations."; |
284 } | 387 } |
285 } | 388 } |
286 | 389 |
287 } // namespace content | 390 } // namespace content |
OLD | NEW |