Index: Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py |
diff --git a/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py b/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py |
index 5c02dc20b3693009d9403e4eca94ddef43529e79..27f5e211dcaf5013243e64703c2ac5441b3ea94a 100644 |
--- a/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py |
+++ b/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py |
@@ -57,7 +57,9 @@ MISSING_KEYWORD = 'Missing' |
NEEDS_REBASELINE_KEYWORD = 'NeedsRebaseline' |
NEEDS_MANUAL_REBASELINE_KEYWORD = 'NeedsManualRebaseline' |
+ |
class ParseError(Exception): |
+ |
def __init__(self, warnings): |
super(ParseError, self).__init__() |
self.warnings = warnings |
@@ -70,9 +72,11 @@ class ParseError(Exception): |
class TestExpectationParser(object): |
+ |
"""Provides parsing facilities for lines in the test_expectation.txt file.""" |
- # FIXME: Rename these to *_KEYWORD as in MISSING_KEYWORD above, but make the case studdly-caps to match the actual file contents. |
+ # FIXME: Rename these to *_KEYWORD as in MISSING_KEYWORD above, but make |
+ # the case studdly-caps to match the actual file contents. |
REBASELINE_MODIFIER = 'rebaseline' |
NEEDS_REBASELINE_MODIFIER = 'needsrebaseline' |
NEEDS_MANUAL_REBASELINE_MODIFIER = 'needsmanualrebaseline' |
@@ -87,14 +91,15 @@ class TestExpectationParser(object): |
def __init__(self, port, full_test_list, is_lint_mode): |
self._port = port |
- self._test_configuration_converter = TestConfigurationConverter(set(port.all_test_configurations()), port.configuration_specifier_macros()) |
+ self._test_configuration_converter = TestConfigurationConverter( |
+ set(port.all_test_configurations()), port.configuration_specifier_macros()) |
self._full_test_list = full_test_list |
self._is_lint_mode = is_lint_mode |
def parse(self, filename, expectations_string): |
expectation_lines = [] |
line_number = 0 |
- for line in expectations_string.split("\n"): |
+ for line in expectations_string.split('\n'): |
line_number += 1 |
test_expectation = self._tokenize_line(filename, line, line_number) |
self._parse_line(test_expectation) |
@@ -114,7 +119,6 @@ class TestExpectationParser(object): |
self._parse_line(expectation_line) |
return expectation_line |
- |
def expectation_for_skipped_test(self, test_name): |
if not self._port.test_exists(test_name): |
_log.warning('The following test %s from the Skipped list doesn\'t exist' % test_name) |
@@ -147,7 +151,9 @@ class TestExpectationParser(object): |
self._lint_line(expectation_line) |
parsed_specifiers = set([specifier.lower() for specifier in expectation_line.specifiers]) |
- expectation_line.matching_configurations = self._test_configuration_converter.to_config_set(parsed_specifiers, expectation_line.warnings) |
+ expectation_line.matching_configurations = self._test_configuration_converter.to_config_set( |
+ parsed_specifiers, |
+ expectation_line.warnings) |
def _lint_line(self, expectation_line): |
expectations = [expectation.lower() for expectation in expectation_line.expectations] |
@@ -256,13 +262,13 @@ class TestExpectationParser(object): |
expectation_line.filename = filename |
expectation_line.line_numbers = str(line_number) |
- comment_index = expectation_string.find("#") |
+ comment_index = expectation_string.find('#') |
if comment_index == -1: |
comment_index = len(expectation_string) |
else: |
expectation_line.comment = expectation_string[comment_index + 1:] |
- remaining_string = re.sub(r"\s+", " ", expectation_string[:comment_index].strip()) |
+ remaining_string = re.sub(r"\s+", ' ', expectation_string[:comment_index].strip()) |
if len(remaining_string) == 0: |
return expectation_line |
@@ -282,9 +288,9 @@ class TestExpectationParser(object): |
state = 'start' |
for token in tokens: |
if (token.startswith(WEBKIT_BUG_PREFIX) or |
- token.startswith(CHROMIUM_BUG_PREFIX) or |
- token.startswith(V8_BUG_PREFIX) or |
- token.startswith(NAMED_BUG_PREFIX)): |
+ token.startswith(CHROMIUM_BUG_PREFIX) or |
+ token.startswith(V8_BUG_PREFIX) or |
+ token.startswith(NAMED_BUG_PREFIX)): |
if state != 'start': |
warnings.append('"%s" is not at the start of the line.' % token) |
break |
@@ -364,13 +370,14 @@ class TestExpectationParser(object): |
class TestExpectationLine(object): |
+ |
"""Represents a line in test expectations file.""" |
def __init__(self): |
"""Initializes a blank-line equivalent of an expectation.""" |
self.original_string = None |
self.filename = None # this is the path to the expectations file for this line |
- self.line_numbers = "0" |
+ self.line_numbers = '0' |
self.name = None # this is the path in the line itself |
self.path = None # this is the normpath of self.name |
self.bugs = [] |
@@ -386,20 +393,20 @@ class TestExpectationLine(object): |
def __eq__(self, other): |
return (self.original_string == other.original_string |
- and self.filename == other.filename |
- and self.line_numbers == other.line_numbers |
- and self.name == other.name |
- and self.path == other.path |
- and self.bugs == other.bugs |
- and self.specifiers == other.specifiers |
- and self.parsed_specifiers == other.parsed_specifiers |
- and self.matching_configurations == other.matching_configurations |
- and self.expectations == other.expectations |
- and self.parsed_expectations == other.parsed_expectations |
- and self.comment == other.comment |
- and self.matching_tests == other.matching_tests |
- and self.warnings == other.warnings |
- and self.is_skipped_outside_expectations_file == other.is_skipped_outside_expectations_file) |
+ and self.filename == other.filename |
+ and self.line_numbers == other.line_numbers |
+ and self.name == other.name |
+ and self.path == other.path |
+ and self.bugs == other.bugs |
+ and self.specifiers == other.specifiers |
+ and self.parsed_specifiers == other.parsed_specifiers |
+ and self.matching_configurations == other.matching_configurations |
+ and self.expectations == other.expectations |
+ and self.parsed_expectations == other.parsed_expectations |
+ and self.comment == other.comment |
+ and self.matching_tests == other.matching_tests |
+ and self.warnings == other.warnings |
+ and self.is_skipped_outside_expectations_file == other.is_skipped_outside_expectations_file) |
def is_invalid(self): |
return bool(self.warnings and self.warnings != [TestExpectationParser.MISSING_BUG_WARNING]) |
@@ -408,7 +415,7 @@ class TestExpectationLine(object): |
return len(self.parsed_expectations) > 1 |
def is_whitespace_or_comment(self): |
- return bool(re.match("^\s*$", self.original_string.split('#')[0])) |
+ return bool(re.match('^\s*$', self.original_string.split('#')[0])) |
@staticmethod |
def create_passing_expectation(test): |
@@ -436,7 +443,7 @@ class TestExpectationLine(object): |
# Not clear that there's anything better to do when not linting and the filenames are different. |
if model_all_expectations: |
result.filename = line2.filename |
- result.line_numbers = line1.line_numbers + "," + line2.line_numbers |
+ result.line_numbers = line1.line_numbers + ',' + line2.line_numbers |
result.name = line1.name |
result.path = line1.path |
result.parsed_expectations = set(line1.parsed_expectations) | set(line2.parsed_expectations) |
@@ -451,13 +458,14 @@ class TestExpectationLine(object): |
return result |
def to_string(self, test_configuration_converter, include_specifiers=True, include_expectations=True, include_comment=True): |
- parsed_expectation_to_string = dict([[parsed_expectation, expectation_string] for expectation_string, parsed_expectation in TestExpectations.EXPECTATIONS.items()]) |
+ parsed_expectation_to_string = dict([[parsed_expectation, expectation_string] |
+ for expectation_string, parsed_expectation in TestExpectations.EXPECTATIONS.items()]) |
if self.is_invalid(): |
return self.original_string or '' |
if self.name is None: |
- return '' if self.comment is None else "#%s" % self.comment |
+ return '' if self.comment is None else '#%s' % self.comment |
if test_configuration_converter and self.bugs: |
specifiers_list = test_configuration_converter.to_specifiers_list(self.matching_configurations) |
@@ -467,10 +475,10 @@ class TestExpectationLine(object): |
specifiers = self._serialize_parsed_specifiers(test_configuration_converter, specifiers).split() |
expectations = self._serialize_parsed_expectations(parsed_expectation_to_string).split() |
result.append(self._format_line(self.bugs, specifiers, self.name, expectations, self.comment)) |
- return "\n".join(result) if result else None |
+ return '\n'.join(result) if result else None |
return self._format_line(self.bugs, self.specifiers, self.name, self.expectations, self.comment, |
- include_specifiers, include_expectations, include_comment) |
+ include_specifiers, include_expectations, include_comment) |
def to_csv(self): |
# Note that this doesn't include the comments. |
@@ -498,7 +506,8 @@ class TestExpectationLine(object): |
return expectations |
@staticmethod |
- def _format_line(bugs, specifiers, name, expectations, comment, include_specifiers=True, include_expectations=True, include_comment=True): |
+ def _format_line(bugs, specifiers, name, expectations, comment, include_specifiers=True, |
+ include_expectations=True, include_comment=True): |
new_specifiers = [] |
new_expectations = [] |
for specifier in specifiers: |
@@ -521,12 +530,13 @@ class TestExpectationLine(object): |
new_expectations = TestExpectationLine._filter_redundant_expectations(new_expectations) |
result += ' [ %s ]' % ' '.join(sorted(set(new_expectations))) |
if include_comment and comment is not None: |
- result += " #%s" % comment |
+ result += ' #%s' % comment |
return result |
# FIXME: Refactor API to be a proper CRUD. |
class TestExpectationsModel(object): |
+ |
"""Represents relational store of all expectations and provides CRUD semantics to manage it.""" |
def __init__(self, shorten_filename=None): |
@@ -561,7 +571,10 @@ class TestExpectationsModel(object): |
for test, line in other._test_to_expectation_line.items(): |
if test in self._test_to_expectation_line: |
- line = TestExpectationLine.merge_expectation_lines(self._test_to_expectation_line[test], line, model_all_expectations=False) |
+ line = TestExpectationLine.merge_expectation_lines( |
+ self._test_to_expectation_line[test], |
+ line, |
+ model_all_expectations=False) |
self._test_to_expectation_line[test] = line |
self._merge_dict_of_sets(self._expectation_to_tests, other._expectation_to_tests) |
@@ -624,7 +637,7 @@ class TestExpectationsModel(object): |
for expectation in expectations: |
retval.append(self.expectation_to_string(expectation)) |
- return " ".join(retval) |
+ return ' '.join(retval) |
def expectation_to_string(self, expectation): |
"""Return the uppercased string equivalent of a given expectation.""" |
@@ -651,7 +664,10 @@ class TestExpectationsModel(object): |
continue |
if model_all_expectations: |
- expectation_line = TestExpectationLine.merge_expectation_lines(self.get_expectation_line(test), expectation_line, model_all_expectations) |
+ expectation_line = TestExpectationLine.merge_expectation_lines( |
+ self.get_expectation_line(test), |
+ expectation_line, |
+ model_all_expectations) |
self._clear_expectations_for_test(test) |
self._test_to_expectation_line[test] = expectation_line |
@@ -748,21 +764,24 @@ class TestExpectationsModel(object): |
if prev_expectation_line.matching_configurations >= expectation_line.matching_configurations: |
expectation_line.warnings.append('More specific entry for %s on line %s:%s overrides line %s:%s.' % (expectation_line.name, |
- self._shorten_filename(prev_expectation_line.filename), prev_expectation_line.line_numbers, |
- self._shorten_filename(expectation_line.filename), expectation_line.line_numbers)) |
+ self._shorten_filename( |
+ prev_expectation_line.filename), prev_expectation_line.line_numbers, |
+ self._shorten_filename(expectation_line.filename), expectation_line.line_numbers)) |
# FIXME: return False if we want more specific to win. |
return True |
if prev_expectation_line.matching_configurations <= expectation_line.matching_configurations: |
expectation_line.warnings.append('More specific entry for %s on line %s:%s overrides line %s:%s.' % (expectation_line.name, |
- self._shorten_filename(expectation_line.filename), expectation_line.line_numbers, |
- self._shorten_filename(prev_expectation_line.filename), prev_expectation_line.line_numbers)) |
+ self._shorten_filename( |
+ expectation_line.filename), expectation_line.line_numbers, |
+ self._shorten_filename(prev_expectation_line.filename), prev_expectation_line.line_numbers)) |
return True |
if prev_expectation_line.matching_configurations & expectation_line.matching_configurations: |
expectation_line.warnings.append('Entries for %s on lines %s:%s and %s:%s match overlapping sets of configurations.' % (expectation_line.name, |
- self._shorten_filename(prev_expectation_line.filename), prev_expectation_line.line_numbers, |
- self._shorten_filename(expectation_line.filename), expectation_line.line_numbers)) |
+ self._shorten_filename( |
+ prev_expectation_line.filename), prev_expectation_line.line_numbers, |
+ self._shorten_filename(expectation_line.filename), expectation_line.line_numbers)) |
return True |
# Configuration sets are disjoint, then. |
@@ -770,6 +789,7 @@ class TestExpectationsModel(object): |
class TestExpectations(object): |
+ |
"""Test expectations consist of lines with specifications of what |
to expect from layout test cases. The test cases can be directories |
in which case the expectations apply to all test cases in that |
@@ -815,7 +835,7 @@ class TestExpectations(object): |
TestExpectationParser.WONTFIX_MODIFIER: WONTFIX, |
TestExpectationParser.SLOW_MODIFIER: SLOW, |
TestExpectationParser.REBASELINE_MODIFIER: REBASELINE, |
- } |
+ } |
EXPECTATIONS_TO_STRING = dict((k, v) for (v, k) in EXPECTATIONS.iteritems()) |
@@ -861,7 +881,8 @@ class TestExpectations(object): |
if result in expected_results: |
return True |
- if result in (PASS, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, MISSING) and (NEEDS_REBASELINE in expected_results or NEEDS_MANUAL_REBASELINE in expected_results): |
+ if result in (PASS, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, MISSING) and ( |
+ NEEDS_REBASELINE in expected_results or NEEDS_MANUAL_REBASELINE in expected_results): |
return True |
if result in (TEXT, IMAGE_PLUS_TEXT, AUDIO) and (FAIL in expected_results): |
return True |
@@ -927,7 +948,8 @@ class TestExpectations(object): |
# FIXME: This constructor does too much work. We should move the actual parsing of |
# the expectations into separate routines so that linting and handling overrides |
# can be controlled separately, and the constructor can be more of a no-op. |
- def __init__(self, port, tests=None, include_overrides=True, expectations_dict=None, model_all_expectations=False, is_lint_mode=False): |
+ def __init__(self, port, tests=None, include_overrides=True, expectations_dict=None, |
+ model_all_expectations=False, is_lint_mode=False): |
self._full_test_list = tests |
self._test_config = port.test_configuration() |
self._is_lint_mode = is_lint_mode |
@@ -1019,7 +1041,7 @@ class TestExpectations(object): |
for expectation in self._expectations: |
for warning in expectation.warnings: |
warnings.append('%s:%s %s %s' % (self._shorten_filename(expectation.filename), expectation.line_numbers, |
- warning, expectation.name if expectation.expectations else expectation.original_string)) |
+ warning, expectation.name if expectation.expectations else expectation.original_string)) |
if warnings: |
self._has_warnings = True |
@@ -1123,4 +1145,4 @@ class TestExpectations(object): |
def nones_out(expectation_line): |
return expectation_line is not None |
- return "\n".join(filter(nones_out, map(serialize, expectation_lines))) |
+ return '\n'.join(filter(nones_out, map(serialize, expectation_lines))) |