Home | History | Annotate | Download | only in accessibility
      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 <set>
      6 #include <string>
      7 #include <vector>
      8 
      9 #include "base/command_line.h"
     10 #include "base/file_util.h"
     11 #include "base/logging.h"
     12 #include "base/path_service.h"
     13 #include "base/strings/string16.h"
     14 #include "base/strings/string_split.h"
     15 #include "base/strings/string_util.h"
     16 #include "base/strings/utf_string_conversions.h"
     17 #include "content/browser/accessibility/accessibility_tree_formatter.h"
     18 #include "content/browser/accessibility/browser_accessibility.h"
     19 #include "content/browser/accessibility/browser_accessibility_manager.h"
     20 #include "content/browser/renderer_host/render_view_host_impl.h"
     21 #include "content/port/browser/render_widget_host_view_port.h"
     22 #include "content/public/browser/web_contents.h"
     23 #include "content/public/common/content_paths.h"
     24 #include "content/public/common/content_switches.h"
     25 #include "content/public/common/url_constants.h"
     26 #include "content/shell/browser/shell.h"
     27 #include "content/test/accessibility_browser_test_utils.h"
     28 #include "content/test/content_browser_test.h"
     29 #include "content/test/content_browser_test_utils.h"
     30 #include "testing/gtest/include/gtest/gtest.h"
     31 
     32 // TODO(dmazzoni): Disabled accessibility tests on Win64. crbug.com/179717
     33 #if defined(OS_WIN) && defined(ARCH_CPU_X86_64)
     34 #define MAYBE(x) DISABLED_##x
     35 #else
     36 #define MAYBE(x) x
     37 #endif
     38 
     39 namespace content {
     40 
     41 namespace {
     42 
     43 const char kCommentToken = '#';
     44 const char kMarkSkipFile[] = "#<skip";
     45 const char kMarkEndOfFile[] = "<-- End-of-file -->";
     46 const char kSignalDiff[] = "*";
     47 
     48 }  // namespace
     49 
     50 typedef AccessibilityTreeFormatter::Filter Filter;
     51 
     52 // This test takes a snapshot of the platform BrowserAccessibility tree and
     53 // tests it against an expected baseline.
     54 //
     55 // The flow of the test is as outlined below.
     56 // 1. Load an html file from chrome/test/data/accessibility.
     57 // 2. Read the expectation.
     58 // 3. Browse to the page and serialize the platform specific tree into a human
     59 //    readable string.
     60 // 4. Perform a comparison between actual and expected and fail if they do not
     61 //    exactly match.
     62 class DumpAccessibilityTreeTest : public ContentBrowserTest {
     63  public:
     64   // Utility helper that does a comment aware equality check.
     65   // Returns array of lines from expected file which are different.
     66   std::vector<int> DiffLines(const std::vector<std::string>& expected_lines,
     67                              const std::vector<std::string>& actual_lines) {
     68     int actual_lines_count = actual_lines.size();
     69     int expected_lines_count = expected_lines.size();
     70     std::vector<int> diff_lines;
     71     int i = 0, j = 0;
     72     while (i < actual_lines_count && j < expected_lines_count) {
     73       if (expected_lines[j].size() == 0 ||
     74           expected_lines[j][0] == kCommentToken) {
     75         // Skip comment lines and blank lines in expected output.
     76         ++j;
     77         continue;
     78       }
     79 
     80       if (actual_lines[i] != expected_lines[j])
     81         diff_lines.push_back(j);
     82       ++i;
     83       ++j;
     84     }
     85 
     86     // Actual file has been fully checked.
     87     return diff_lines;
     88   }
     89 
     90   void AddDefaultFilters(std::vector<Filter>* filters) {
     91     filters->push_back(Filter(ASCIIToUTF16("FOCUSABLE"), Filter::ALLOW));
     92     filters->push_back(Filter(ASCIIToUTF16("READONLY"), Filter::ALLOW));
     93     filters->push_back(Filter(ASCIIToUTF16("*=''"), Filter::DENY));
     94   }
     95 
     96   void ParseFilters(const std::string& test_html,
     97                     std::vector<Filter>* filters) {
     98     std::vector<std::string> lines;
     99     base::SplitString(test_html, '\n', &lines);
    100     for (std::vector<std::string>::const_iterator iter = lines.begin();
    101          iter != lines.end();
    102          ++iter) {
    103       const std::string& line = *iter;
    104       const std::string& allow_empty_str =
    105           AccessibilityTreeFormatter::GetAllowEmptyString();
    106       const std::string& allow_str =
    107           AccessibilityTreeFormatter::GetAllowString();
    108       const std::string& deny_str =
    109           AccessibilityTreeFormatter::GetDenyString();
    110       if (StartsWithASCII(line, allow_empty_str, true)) {
    111         filters->push_back(
    112           Filter(UTF8ToUTF16(line.substr(allow_empty_str.size())),
    113                  Filter::ALLOW_EMPTY));
    114       } else if (StartsWithASCII(line, allow_str, true)) {
    115         filters->push_back(Filter(UTF8ToUTF16(line.substr(allow_str.size())),
    116                                   Filter::ALLOW));
    117       } else if (StartsWithASCII(line, deny_str, true)) {
    118         filters->push_back(Filter(UTF8ToUTF16(line.substr(deny_str.size())),
    119                                   Filter::DENY));
    120       }
    121     }
    122   }
    123 
    124   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    125     ContentBrowserTest::SetUpCommandLine(command_line);
    126     // Enable <dialog>, which is used in some tests.
    127     CommandLine::ForCurrentProcess()->AppendSwitch(
    128         switches::kEnableExperimentalWebPlatformFeatures);
    129   }
    130 
    131   void RunTest(const base::FilePath::CharType* file_path);
    132 };
    133 
    134 void DumpAccessibilityTreeTest::RunTest(
    135     const base::FilePath::CharType* file_path) {
    136   NavigateToURL(shell(), GURL(kAboutBlankURL));
    137 
    138   // Setup test paths.
    139   base::FilePath dir_test_data;
    140   ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &dir_test_data));
    141   base::FilePath test_path(
    142       dir_test_data.Append(FILE_PATH_LITERAL("accessibility")));
    143   ASSERT_TRUE(base::PathExists(test_path))
    144       << test_path.LossyDisplayName();
    145 
    146   base::FilePath html_file = test_path.Append(base::FilePath(file_path));
    147   // Output the test path to help anyone who encounters a failure and needs
    148   // to know where to look.
    149   printf("Testing: %s\n", html_file.MaybeAsASCII().c_str());
    150 
    151   std::string html_contents;
    152   base::ReadFileToString(html_file, &html_contents);
    153 
    154   // Read the expected file.
    155   std::string expected_contents_raw;
    156   base::FilePath expected_file =
    157     base::FilePath(html_file.RemoveExtension().value() +
    158                    AccessibilityTreeFormatter::GetExpectedFileSuffix());
    159   base::ReadFileToString(expected_file, &expected_contents_raw);
    160 
    161   // Tolerate Windows-style line endings (\r\n) in the expected file:
    162   // normalize by deleting all \r from the file (if any) to leave only \n.
    163   std::string expected_contents;
    164   base::RemoveChars(expected_contents_raw, "\r", &expected_contents);
    165 
    166   if (!expected_contents.compare(0, strlen(kMarkSkipFile), kMarkSkipFile)) {
    167     printf("Skipping this test on this platform.\n");
    168     return;
    169   }
    170 
    171   // Load the page.
    172   base::string16 html_contents16;
    173   html_contents16 = UTF8ToUTF16(html_contents);
    174   GURL url = GetTestUrl("accessibility",
    175                         html_file.BaseName().MaybeAsASCII().c_str());
    176   AccessibilityNotificationWaiter waiter(
    177       shell(), AccessibilityModeComplete,
    178       blink::WebAXEventLoadComplete);
    179   NavigateToURL(shell(), url);
    180   waiter.WaitForNotification();
    181 
    182   RenderWidgetHostViewPort* host_view = RenderWidgetHostViewPort::FromRWHV(
    183       shell()->web_contents()->GetRenderWidgetHostView());
    184   AccessibilityTreeFormatter formatter(
    185       host_view->GetBrowserAccessibilityManager()->GetRoot());
    186 
    187   // Parse filters in the test file.
    188   std::vector<Filter> filters;
    189   AddDefaultFilters(&filters);
    190   ParseFilters(html_contents, &filters);
    191   formatter.SetFilters(filters);
    192 
    193   // Perform a diff (or write the initial baseline).
    194   base::string16 actual_contents_utf16;
    195   formatter.FormatAccessibilityTree(&actual_contents_utf16);
    196   std::string actual_contents = UTF16ToUTF8(actual_contents_utf16);
    197   std::vector<std::string> actual_lines, expected_lines;
    198   Tokenize(actual_contents, "\n", &actual_lines);
    199   Tokenize(expected_contents, "\n", &expected_lines);
    200   // Marking the end of the file with a line of text ensures that
    201   // file length differences are found.
    202   expected_lines.push_back(kMarkEndOfFile);
    203   actual_lines.push_back(kMarkEndOfFile);
    204 
    205   std::vector<int> diff_lines = DiffLines(expected_lines, actual_lines);
    206   bool is_different = diff_lines.size() > 0;
    207   EXPECT_FALSE(is_different);
    208   if (is_different) {
    209     // Mark the expected lines which did not match actual output with a *.
    210     printf("* Line Expected\n");
    211     printf("- ---- --------\n");
    212     for (int line = 0, diff_index = 0;
    213          line < static_cast<int>(expected_lines.size());
    214          ++line) {
    215       bool is_diff = false;
    216       if (diff_index < static_cast<int>(diff_lines.size()) &&
    217           diff_lines[diff_index] == line) {
    218         is_diff = true;
    219         ++diff_index;
    220       }
    221       printf("%1s %4d %s\n", is_diff? kSignalDiff : "", line + 1,
    222              expected_lines[line].c_str());
    223     }
    224     printf("\nActual\n");
    225     printf("------\n");
    226     printf("%s\n", actual_contents.c_str());
    227   }
    228 
    229   if (!base::PathExists(expected_file)) {
    230     base::FilePath actual_file =
    231         base::FilePath(html_file.RemoveExtension().value() +
    232                        AccessibilityTreeFormatter::GetActualFileSuffix());
    233 
    234     EXPECT_TRUE(file_util::WriteFile(
    235         actual_file, actual_contents.c_str(), actual_contents.size()));
    236 
    237     ADD_FAILURE() << "No expectation found. Create it by doing:\n"
    238                   << "mv " << actual_file.LossyDisplayName() << " "
    239                   << expected_file.LossyDisplayName();
    240   }
    241 }
    242 
    243 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityA) {
    244   RunTest(FILE_PATH_LITERAL("a.html"));
    245 }
    246 
    247 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAddress) {
    248   RunTest(FILE_PATH_LITERAL("address.html"));
    249 }
    250 
    251 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAName) {
    252   RunTest(FILE_PATH_LITERAL("a-name.html"));
    253 }
    254 
    255 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAOnclick) {
    256   RunTest(FILE_PATH_LITERAL("a-onclick.html"));
    257 }
    258 
    259 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    260                        AccessibilityAriaApplication) {
    261   RunTest(FILE_PATH_LITERAL("aria-application.html"));
    262 }
    263 
    264 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    265                        AccessibilityAriaAutocomplete) {
    266   RunTest(FILE_PATH_LITERAL("aria-autocomplete.html"));
    267 }
    268 
    269 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaCombobox) {
    270   RunTest(FILE_PATH_LITERAL("aria-combobox.html"));
    271 }
    272 
    273 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaInvalid) {
    274   RunTest(FILE_PATH_LITERAL("aria-invalid.html"));
    275 }
    276 
    277 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaLevel) {
    278   RunTest(FILE_PATH_LITERAL("aria-level.html"));
    279 }
    280 
    281 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaMenu) {
    282   RunTest(FILE_PATH_LITERAL("aria-menu.html"));
    283 }
    284 
    285 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    286                        AccessibilityAriaMenuitemradio) {
    287   RunTest(FILE_PATH_LITERAL("aria-menuitemradio.html"));
    288 }
    289 
    290 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    291                        AccessibilityAriaPressed) {
    292   RunTest(FILE_PATH_LITERAL("aria-pressed.html"));
    293 }
    294 
    295 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    296                        AccessibilityAriaProgressbar) {
    297   RunTest(FILE_PATH_LITERAL("aria-progressbar.html"));
    298 }
    299 
    300 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    301                        AccessibilityAriaToolbar) {
    302   RunTest(FILE_PATH_LITERAL("toolbar.html"));
    303 }
    304 
    305 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    306                        AccessibilityAriaValueMin) {
    307   RunTest(FILE_PATH_LITERAL("aria-valuemin.html"));
    308 }
    309 
    310 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    311                        AccessibilityAriaValueMax) {
    312   RunTest(FILE_PATH_LITERAL("aria-valuemax.html"));
    313 }
    314 
    315 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityArticle) {
    316   RunTest(FILE_PATH_LITERAL("article.html"));
    317 }
    318 
    319 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAWithImg) {
    320   RunTest(FILE_PATH_LITERAL("a-with-img.html"));
    321 }
    322 
    323 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBdo) {
    324   RunTest(FILE_PATH_LITERAL("bdo.html"));
    325 }
    326 
    327 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBR) {
    328   RunTest(FILE_PATH_LITERAL("br.html"));
    329 }
    330 
    331 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityButtonNameCalc) {
    332   RunTest(FILE_PATH_LITERAL("button-name-calc.html"));
    333 }
    334 
    335 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCanvas) {
    336   RunTest(FILE_PATH_LITERAL("canvas.html"));
    337 }
    338 
    339 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    340                        AccessibilityCheckboxNameCalc) {
    341   RunTest(FILE_PATH_LITERAL("checkbox-name-calc.html"));
    342 }
    343 
    344 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDialog) {
    345   RunTest(FILE_PATH_LITERAL("dialog.html"));
    346 }
    347 
    348 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDiv) {
    349   RunTest(FILE_PATH_LITERAL("div.html"));
    350 }
    351 
    352 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDl) {
    353   RunTest(FILE_PATH_LITERAL("dl.html"));
    354 }
    355 
    356 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    357                        AccessibilityContenteditableDescendants) {
    358   RunTest(FILE_PATH_LITERAL("contenteditable-descendants.html"));
    359 }
    360 
    361 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityEm) {
    362   RunTest(FILE_PATH_LITERAL("em.html"));
    363 }
    364 
    365 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityFooter) {
    366   RunTest(FILE_PATH_LITERAL("footer.html"));
    367 }
    368 
    369 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityForm) {
    370   RunTest(FILE_PATH_LITERAL("form.html"));
    371 }
    372 
    373 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityHeading) {
    374   RunTest(FILE_PATH_LITERAL("heading.html"));
    375 }
    376 
    377 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityHR) {
    378   RunTest(FILE_PATH_LITERAL("hr.html"));
    379 }
    380 
    381 // crbug.com/179717 and crbug.com/224659
    382 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    383                        DISABLED_AccessibilityIframeCoordinates) {
    384   RunTest(FILE_PATH_LITERAL("iframe-coordinates.html"));
    385 }
    386 
    387 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputButton) {
    388   RunTest(FILE_PATH_LITERAL("input-button.html"));
    389 }
    390 
    391 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    392                        AccessibilityInputButtonInMenu) {
    393   RunTest(FILE_PATH_LITERAL("input-button-in-menu.html"));
    394 }
    395 
    396 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputColor) {
    397   RunTest(FILE_PATH_LITERAL("input-color.html"));
    398 }
    399 
    400 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    401                        AccessibilityInputImageButtonInMenu) {
    402   RunTest(FILE_PATH_LITERAL("input-image-button-in-menu.html"));
    403 }
    404 
    405 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputRange) {
    406   RunTest(FILE_PATH_LITERAL("input-range.html"));
    407 }
    408 
    409 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    410                        AccessibilityInputTextNameCalc) {
    411   RunTest(FILE_PATH_LITERAL("input-text-name-calc.html"));
    412 }
    413 
    414 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputTypes) {
    415   RunTest(FILE_PATH_LITERAL("input-types.html"));
    416 }
    417 
    418 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityLabel) {
    419   RunTest(FILE_PATH_LITERAL("label.html"));
    420 }
    421 
    422 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityListMarkers) {
    423   RunTest(FILE_PATH_LITERAL("list-markers.html"));
    424 }
    425 
    426 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    427                        AccessibilityModalDialogClosed) {
    428   RunTest(FILE_PATH_LITERAL("modal-dialog-closed.html"));
    429 }
    430 
    431 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    432                        AccessibilityModalDialogOpened) {
    433   RunTest(FILE_PATH_LITERAL("modal-dialog-opened.html"));
    434 }
    435 
    436 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    437                        AccessibilityModalDialogInIframeClosed) {
    438   RunTest(FILE_PATH_LITERAL("modal-dialog-in-iframe-closed.html"));
    439 }
    440 
    441 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    442                        AccessibilityModalDialogInIframeOpened) {
    443   RunTest(FILE_PATH_LITERAL("modal-dialog-in-iframe-opened.html"));
    444 }
    445 
    446 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    447                        AccessibilityModalDialogStack) {
    448   RunTest(FILE_PATH_LITERAL("modal-dialog-stack.html"));
    449 }
    450 
    451 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityP) {
    452   RunTest(FILE_PATH_LITERAL("p.html"));
    453 }
    454 
    455 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySelect) {
    456   RunTest(FILE_PATH_LITERAL("select.html"));
    457 }
    458 
    459 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySpan) {
    460   RunTest(FILE_PATH_LITERAL("span.html"));
    461 }
    462 
    463 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySpinButton) {
    464   RunTest(FILE_PATH_LITERAL("spinbutton.html"));
    465 }
    466 
    467 // TODO(dmazzoni): Rebaseline this test after Blink rolls past r155083.
    468 // See http://crbug.com/265619
    469 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, DISABLED_AccessibilitySvg) {
    470   RunTest(FILE_PATH_LITERAL("svg.html"));
    471 }
    472 
    473 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTab) {
    474   RunTest(FILE_PATH_LITERAL("tab.html"));
    475 }
    476 
    477 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTableSimple) {
    478   RunTest(FILE_PATH_LITERAL("table-simple.html"));
    479 }
    480 
    481 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTableSpans) {
    482   RunTest(FILE_PATH_LITERAL("table-spans.html"));
    483 }
    484 
    485 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
    486                        AccessibilityToggleButton) {
    487   RunTest(FILE_PATH_LITERAL("togglebutton.html"));
    488 }
    489 
    490 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityUl) {
    491   RunTest(FILE_PATH_LITERAL("ul.html"));
    492 }
    493 
    494 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityWbr) {
    495   RunTest(FILE_PATH_LITERAL("wbr.html"));
    496 }
    497 
    498 }  // namespace content
    499