| 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)))
|
|
|