Skip to content

Commit

Permalink
Allow filters in accessibility tests to specify which attributes to c…
Browse files Browse the repository at this point in the history
…heck.

With this change, a DumpAccessibilityTree test can specify filters to
control which attributes are printed. This keeps each test expectation file
small and readable, while making it easy to test for all sorts of attributes,
including obscure ones.

Each platform will have a few attributes that print by default, like the
role and name. HTML files add rules of this form to override the defaults:

  @MAC-DENY:subrole*
  @MAC-DENY:value*
  @MAC-ALLOW:description*

You can also specify @MAC-ALLOW:* or @WIN-ALLOW:* if you want to dump everything - helpful
during development sometimes.

BUG=124314


Review URL: https://chromiumcodereview.appspot.com/10662003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149510 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
dmazzoni@chromium.org committed Aug 1, 2012
1 parent c321b05 commit aef706d
Show file tree
Hide file tree
Showing 22 changed files with 448 additions and 234 deletions.
11 changes: 8 additions & 3 deletions content/browser/accessibility/browser_accessibility_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -747,9 +747,14 @@ BrowserAccessibilityWin
REFIID iid,
void** object);

// Accessors to IA2 role and state.
int32 ia2_role() { return ia2_role_; }
int32 ia2_state() { return ia2_state_; }
// Accessors.
int32 ia_role() const { return ia_role_; }
int32 ia_state() const { return ia_state_; }
int32 ia2_role() const { return ia2_role_; }
int32 ia2_state() const { return ia2_state_; }
const std::vector<string16>& ia2_attributes() const {
return ia2_attributes_;\
}

private:
// Add one to the reference count and return the same object. Always
Expand Down
262 changes: 161 additions & 101 deletions content/browser/accessibility/dump_accessibility_tree_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <set>
#include <string>
#include <vector>

#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
Expand All @@ -26,8 +28,6 @@
#include "testing/gtest/include/gtest/gtest.h"

namespace {
// Required to enter html content into a url.
static const std::string kUrlPreamble = "data:text/html,\n<!doctype html>";
static const char kCommentToken = '#';
static const char* kMarkSkipFile = "#<skip";
static const char* kMarkEndOfFile = "<-- End-of-file -->";
Expand All @@ -51,7 +51,7 @@ class DumpAccessibilityTreeTest : public ContentBrowserTest {
// Utility helper that does a comment aware equality check.
// Returns array of lines from expected file which are different.
std::vector<int> DiffLines(std::vector<std::string>& expected_lines,
std::vector<std::string>& actual_lines) {
std::vector<std::string>& actual_lines) {
int actual_lines_count = actual_lines.size();
int expected_lines_count = expected_lines.size();
std::vector<int> diff_lines;
Expand All @@ -74,16 +74,42 @@ class DumpAccessibilityTreeTest : public ContentBrowserTest {
return diff_lines;
}

void AddDefaultFilters(std::set<string16>* allow_filters,
std::set<string16>* deny_filters) {
allow_filters->insert(ASCIIToUTF16("FOCUSABLE"));
allow_filters->insert(ASCIIToUTF16("READONLY"));
}

void ParseFilters(const std::string& test_html,
std::set<string16>* allow_filters,
std::set<string16>* deny_filters) {
std::vector<std::string> lines;
base::SplitString(test_html, '\n', &lines);
for (std::vector<std::string>::const_iterator iter = lines.begin();
iter != lines.end();
++iter) {
const std::string& line = *iter;
const std::string& allow_str = helper_.GetAllowString();
const std::string& deny_str = helper_.GetDenyString();
if (StartsWithASCII(line, allow_str, true))
allow_filters->insert(UTF8ToUTF16(line.substr(allow_str.size())));
else if (StartsWithASCII(line, deny_str, true))
deny_filters->insert(UTF8ToUTF16(line.substr(deny_str.size())));
}
}

void RunTest(const FilePath::CharType* file_path);

DumpAccessibilityTreeHelper helper_;
};

IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
DISABLED_PlatformTreeDifferenceTest) {
void DumpAccessibilityTreeTest::RunTest(const FilePath::CharType* file_path) {
NavigateToURL(shell(), GURL("about:blank"));
RenderWidgetHostViewPort* host_view = static_cast<RenderWidgetHostViewPort*>(
shell()->web_contents()->GetRenderWidgetHostView());
RenderWidgetHost* host = host_view->GetRenderWidgetHost();
RenderViewHostImpl* view_host =
static_cast<RenderViewHostImpl*>(RenderWidgetHostImpl::From(host));
RenderWidgetHostImpl* host =
RenderWidgetHostImpl::From(host_view->GetRenderWidgetHost());
RenderViewHostImpl* view_host = static_cast<RenderViewHostImpl*>(host);
view_host->set_save_accessibility_tree_for_testing(true);
view_host->SetAccessibilityMode(AccessibilityModeComplete);

Expand All @@ -94,107 +120,141 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
EXPECT_TRUE(file_util::PathExists(test_path))
<< test_path.LossyDisplayName();

FilePath html_file = test_path.Append(FilePath(file_path));
// Output the test path to help anyone who encounters a failure and needs
// to know where to look.
printf("Path to test files: %s\n", test_path.MaybeAsASCII().c_str());

// Grab all HTML files.
file_util::FileEnumerator file_enumerator(test_path,
false,
file_util::FileEnumerator::FILES,
FILE_PATH_LITERAL("*.html"));

// TODO(dtseng): Make each of these a gtest with script.
FilePath html_file(file_enumerator.Next());
ASSERT_FALSE(html_file.empty());
do {
std::string html_contents;
file_util::ReadFileToString(html_file, &html_contents);

// Read the expected file.
std::string expected_contents_raw;
FilePath expected_file =
FilePath(html_file.RemoveExtension().value() +
helper_.GetExpectedFileSuffix());
file_util::ReadFileToString(
expected_file,
&expected_contents_raw);

// Tolerate Windows-style line endings (\r\n) in the expected file:
// normalize by deleting all \r from the file (if any) to leave only \n.
std::string expected_contents;
RemoveChars(expected_contents_raw, "\r", &expected_contents);

if (!expected_contents.compare(0, strlen(kMarkSkipFile), kMarkSkipFile)) {
printf("Skipping %s\n", html_file.BaseName().MaybeAsASCII().c_str());
continue;
}
printf("Testing: %s\n", html_file.MaybeAsASCII().c_str());

std::string html_contents;
file_util::ReadFileToString(html_file, &html_contents);

// Parse filters in the test file.
std::set<string16> allow_filters;
std::set<string16> deny_filters;
AddDefaultFilters(&allow_filters, &deny_filters);
ParseFilters(html_contents, &allow_filters, &deny_filters);
helper_.SetFilters(allow_filters, deny_filters);

printf("Testing %s\n", html_file.BaseName().MaybeAsASCII().c_str());

// Load the page.
WindowedNotificationObserver tree_updated_observer(
NOTIFICATION_RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED,
NotificationService::AllSources());
string16 html_contents16;
html_contents16 = UTF8ToUTF16(html_contents);
GURL url(UTF8ToUTF16(kUrlPreamble) + html_contents16);
NavigateToURL(shell(), url);

// Wait for the tree.
tree_updated_observer.Wait();

// Perform a diff (or write the initial baseline).
string16 actual_contents_utf16;
helper_.DumpAccessibilityTree(
host_view->GetBrowserAccessibilityManager()->GetRoot(),
&actual_contents_utf16);
std::string actual_contents = UTF16ToUTF8(actual_contents_utf16);
std::vector<std::string> actual_lines, expected_lines;
Tokenize(actual_contents, "\n", &actual_lines);
Tokenize(expected_contents, "\n", &expected_lines);
// Marking the end of the file with a line of text ensures that
// file length differences are found.
expected_lines.push_back(kMarkEndOfFile);
actual_lines.push_back(kMarkEndOfFile);

std::vector<int> diff_lines = DiffLines(expected_lines, actual_lines);
bool is_different = diff_lines.size() > 0;
EXPECT_FALSE(is_different);
if (is_different) {
// Mark the expected lines which did not match actual output with a *.
printf("* Line Expected\n");
printf("- ---- --------\n");
for (int line = 0, diff_index = 0;
line < static_cast<int>(expected_lines.size());
++line) {
bool is_diff = false;
if (diff_index < static_cast<int>(diff_lines.size()) &&
diff_lines[diff_index] == line) {
is_diff = true;
++ diff_index;
}
printf("%1s %4d %s\n", is_diff? kSignalDiff : "", line + 1,
expected_lines[line].c_str());
// Read the expected file.
std::string expected_contents_raw;
FilePath expected_file =
FilePath(html_file.RemoveExtension().value() +
helper_.GetExpectedFileSuffix());
file_util::ReadFileToString(
expected_file,
&expected_contents_raw);

// Tolerate Windows-style line endings (\r\n) in the expected file:
// normalize by deleting all \r from the file (if any) to leave only \n.
std::string expected_contents;
RemoveChars(expected_contents_raw, "\r", &expected_contents);

if (!expected_contents.compare(0, strlen(kMarkSkipFile), kMarkSkipFile)) {
printf("Skipping this test on this platform.\n");
return;
}

// Load the page.
WindowedNotificationObserver tree_updated_observer(
NOTIFICATION_RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED,
NotificationService::AllSources());
string16 html_contents16;
html_contents16 = UTF8ToUTF16(html_contents);
GURL url = GetTestUrl("accessibility",
html_file.BaseName().MaybeAsASCII().c_str());
NavigateToURL(shell(), url);

// Wait for the tree.
tree_updated_observer.Wait();

// Perform a diff (or write the initial baseline).
string16 actual_contents_utf16;
helper_.DumpAccessibilityTree(
host_view->GetBrowserAccessibilityManager()->GetRoot(),
&actual_contents_utf16);
std::string actual_contents = UTF16ToUTF8(actual_contents_utf16);
std::vector<std::string> actual_lines, expected_lines;
Tokenize(actual_contents, "\n", &actual_lines);
Tokenize(expected_contents, "\n", &expected_lines);
// Marking the end of the file with a line of text ensures that
// file length differences are found.
expected_lines.push_back(kMarkEndOfFile);
actual_lines.push_back(kMarkEndOfFile);

std::vector<int> diff_lines = DiffLines(expected_lines, actual_lines);
bool is_different = diff_lines.size() > 0;
EXPECT_FALSE(is_different);
if (is_different) {
// Mark the expected lines which did not match actual output with a *.
printf("* Line Expected\n");
printf("- ---- --------\n");
for (int line = 0, diff_index = 0;
line < static_cast<int>(expected_lines.size());
++line) {
bool is_diff = false;
if (diff_index < static_cast<int>(diff_lines.size()) &&
diff_lines[diff_index] == line) {
is_diff = true;
++ diff_index;
}
printf("\nActual\n");
printf("------\n");
printf("%s\n", actual_contents.c_str());
printf("%1s %4d %s\n", is_diff? kSignalDiff : "", line + 1,
expected_lines[line].c_str());
}
printf("\nActual\n");
printf("------\n");
printf("%s\n", actual_contents.c_str());
}

if (!file_util::PathExists(expected_file)) {
FilePath actual_file =
FilePath(html_file.RemoveExtension().value() +
helper_.GetActualFileSuffix());
if (!file_util::PathExists(expected_file)) {
FilePath actual_file =
FilePath(html_file.RemoveExtension().value() +
helper_.GetActualFileSuffix());

EXPECT_TRUE(file_util::WriteFile(
actual_file, actual_contents.c_str(), actual_contents.size()));
EXPECT_TRUE(file_util::WriteFile(
actual_file, actual_contents.c_str(), actual_contents.size()));

ADD_FAILURE() << "No expectation found. Create it by doing:\n"
<< "mv " << actual_file.LossyDisplayName() << " "
<< expected_file.LossyDisplayName();
}
} while (!(html_file = file_enumerator.Next()).empty());
ADD_FAILURE() << "No expectation found. Create it by doing:\n"
<< "mv " << actual_file.LossyDisplayName() << " "
<< expected_file.LossyDisplayName();
}
}

IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityA) {
RunTest(FILE_PATH_LITERAL("a.html"));
}

IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAName) {
RunTest(FILE_PATH_LITERAL("a-name.html"));
}

IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAOnclick) {
RunTest(FILE_PATH_LITERAL("a-onclick.html"));
}

IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaApplication) {
RunTest(FILE_PATH_LITERAL("aria-application.html"));
}

IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAWithImg) {
RunTest(FILE_PATH_LITERAL("a-with-img.html"));
}

IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityContenteditableDescendants) {
RunTest(FILE_PATH_LITERAL("contenteditable-descendants.html"));
}

IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityFooter) {
RunTest(FILE_PATH_LITERAL("footer.html"));
}

IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityListMarkers) {
RunTest(FILE_PATH_LITERAL("list-markers.html"));
}

IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityUl) {
RunTest(FILE_PATH_LITERAL("ul.html"));
}

} // namespace content
47 changes: 47 additions & 0 deletions content/browser/accessibility/dump_accessibility_tree_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@

#include "content/browser/accessibility/dump_accessibility_tree_helper.h"

#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/string_util.h"

namespace {
const int kIndentSpaces = 4;
}

DumpAccessibilityTreeHelper::DumpAccessibilityTreeHelper() {
Initialize();
}

DumpAccessibilityTreeHelper::~DumpAccessibilityTreeHelper() {
}

void DumpAccessibilityTreeHelper::DumpAccessibilityTree(
BrowserAccessibility* node, string16* contents) {
RecursiveDumpAccessibilityTree(node, contents, 0);
Expand All @@ -28,3 +37,41 @@ void DumpAccessibilityTreeHelper::RecursiveDumpAccessibilityTree(
indent + kIndentSpaces);
}
}

void DumpAccessibilityTreeHelper::SetFilters(
const std::set<string16>& allow_filters,
const std::set<string16>& deny_filters) {
allow_filters_ = allow_filters;
deny_filters_ = deny_filters;
}

bool DumpAccessibilityTreeHelper::MatchesFilters(
const string16& text, bool default_result) {
std::set<string16>::const_iterator iter = allow_filters_.begin();
for (iter = allow_filters_.begin(); iter != allow_filters_.end(); ++iter) {
if (MatchPattern(text, *iter))
return true;
}
for (iter = deny_filters_.begin(); iter != deny_filters_.end(); ++iter) {
if (MatchPattern(text, *iter))
return false;
}
return default_result;
}

void DumpAccessibilityTreeHelper::StartLine() {
line_.clear();
}

void DumpAccessibilityTreeHelper::Add(
bool include_by_default, const string16& attr) {
if (!MatchesFilters(attr, include_by_default))
return;
if (!line_.empty())
line_ += ASCIIToUTF16(" ");
line_ += attr;
}

string16 DumpAccessibilityTreeHelper::FinishLine() {
return line_;
}
Loading

0 comments on commit aef706d

Please sign in to comment.