| Index: third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
|
| diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
|
| index 4fa86268206434ea6c30b456a8d778e4e7e74470..1c69745662580df8e926fa24d751ed4212ead5c8 100644
|
| --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
|
| +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
|
| @@ -25,7 +25,6 @@
|
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| -
|
| """A helper class for reading in and dealing with tests expectations
|
| for layout tests.
|
| """
|
| @@ -39,13 +38,12 @@ from webkitpy.layout_tests.models.test_configuration import TestConfigurationCon
|
|
|
| _log = logging.getLogger(__name__)
|
|
|
| -
|
| # Test expectation and specifier constants.
|
| #
|
| # FIXME: range() starts with 0 which makes if expectation checks harder
|
| # as PASS is 0.
|
| -(PASS, FAIL, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, TIMEOUT, CRASH, LEAK, SKIP, WONTFIX,
|
| - SLOW, REBASELINE, NEEDS_REBASELINE, NEEDS_MANUAL_REBASELINE, MISSING, FLAKY, NOW, NONE) = range(19)
|
| +(PASS, FAIL, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, TIMEOUT, CRASH, LEAK, SKIP, WONTFIX, SLOW, REBASELINE, NEEDS_REBASELINE,
|
| + NEEDS_MANUAL_REBASELINE, MISSING, FLAKY, NOW, NONE) = range(19)
|
|
|
| # FIXME: Perhas these two routines should be part of the Port instead?
|
| BASELINE_SUFFIX_LIST = ('png', 'wav', 'txt')
|
| @@ -90,7 +88,8 @@ class TestExpectationParser(object):
|
|
|
| def __init__(self, port, all_tests, 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())
|
|
|
| if all_tests:
|
| self._all_tests = set(all_tests)
|
| @@ -122,7 +121,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)
|
| @@ -158,7 +156,8 @@ class TestExpectationParser(object):
|
| self._lint_line(expectation_line)
|
|
|
| parsed_specifiers = set([self._parse_specifier(specifier) 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]
|
| @@ -173,7 +172,8 @@ class TestExpectationParser(object):
|
| expectation_line.warnings.append('A reftest cannot be marked as NeedsRebaseline/NeedsManualRebaseline')
|
|
|
| specifiers = [specifier.lower() for specifier in expectation_line.specifiers]
|
| - if (self.REBASELINE_MODIFIER in expectations or self.NEEDS_REBASELINE_MODIFIER in expectations) and ('debug' in specifiers or 'release' in specifiers):
|
| + if (self.REBASELINE_MODIFIER in expectations or self.NEEDS_REBASELINE_MODIFIER in expectations) and (
|
| + 'debug' in specifiers or 'release' in specifiers):
|
| expectation_line.warnings.append('A test cannot be rebaselined for Debug/Release.')
|
|
|
| def _parse_expectations(self, expectation_line):
|
| @@ -217,9 +217,17 @@ class TestExpectationParser(object):
|
|
|
| # FIXME: Update the original specifiers and remove this once the old syntax is gone.
|
| _configuration_tokens_list = [
|
| - 'Mac', 'Mac10.9', 'Mac10.10', 'Mac10.11', 'Retina',
|
| - 'Win', 'Win7', 'Win10',
|
| - 'Linux', 'Precise', 'Trusty',
|
| + 'Mac',
|
| + 'Mac10.9',
|
| + 'Mac10.10',
|
| + 'Mac10.11',
|
| + 'Retina',
|
| + 'Win',
|
| + 'Win7',
|
| + 'Win10',
|
| + 'Linux',
|
| + 'Precise',
|
| + 'Trusty',
|
| 'Android',
|
| 'Release',
|
| 'Debug',
|
| @@ -244,8 +252,8 @@ class TestExpectationParser(object):
|
| 'WontFix': 'WONTFIX',
|
| }
|
|
|
| - _inverted_expectation_tokens = dict([(value, name) for name, value in _expectation_tokens.iteritems()] +
|
| - [('TEXT', 'Failure'), ('IMAGE', 'Failure'), ('IMAGE+TEXT', 'Failure'), ('AUDIO', 'Failure')])
|
| + _inverted_expectation_tokens = dict([(value, name) for name, value in _expectation_tokens.iteritems()] + [('TEXT', 'Failure'), (
|
| + 'IMAGE', 'Failure'), ('IMAGE+TEXT', 'Failure'), ('AUDIO', 'Failure')])
|
|
|
| # FIXME: Seems like these should be classmethods on TestExpectationLine instead of TestExpectationParser.
|
| @classmethod
|
| @@ -289,10 +297,8 @@ class TestExpectationParser(object):
|
| tokens = remaining_string.split()
|
| 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)):
|
| + if (token.startswith(WEBKIT_BUG_PREFIX) or 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
|
| @@ -359,7 +365,8 @@ class TestExpectationParser(object):
|
| warnings.append('SLOW tests should ony be added to SlowTests and not to TestExpectations.')
|
|
|
| if 'WONTFIX' in expectations and ('NeverFixTests' not in filename and 'StaleTestExpectations' not in filename):
|
| - warnings.append('WONTFIX tests should ony be added to NeverFixTests or StaleTestExpectations and not to TestExpectations.')
|
| + warnings.append(
|
| + 'WONTFIX tests should ony be added to NeverFixTests or StaleTestExpectations and not to TestExpectations.')
|
|
|
| if 'NeverFixTests' in filename and expectations != ['WONTFIX', 'SKIP']:
|
| warnings.append('Only WONTFIX expectations are allowed in NeverFixTests')
|
| @@ -405,24 +412,18 @@ class TestExpectationLine(object):
|
| self.is_skipped_outside_expectations_file = False
|
|
|
| def __str__(self):
|
| - return "TestExpectationLine{name=%s, matching_configurations=%s, original_string=%s}" % (self.name, self.matching_configurations, self.original_string)
|
| + return "TestExpectationLine{name=%s, matching_configurations=%s, original_string=%s}" % (
|
| + self.name, self.matching_configurations, self.original_string)
|
|
|
| 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)
|
| + 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)
|
|
|
| def is_invalid(self):
|
| return bool(self.warnings and self.warnings != [TestExpectationParser.MISSING_BUG_WARNING])
|
| @@ -474,7 +475,8 @@ 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 ''
|
| @@ -492,8 +494,8 @@ class TestExpectationLine(object):
|
| result.append(self._format_line(self.bugs, specifiers, self.name, expectations, self.comment))
|
| 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)
|
| + return self._format_line(self.bugs, self.specifiers, self.name, self.expectations, self.comment, include_specifiers,
|
| + include_expectations, include_comment)
|
|
|
| def to_csv(self):
|
| # Note that this doesn't include the comments.
|
| @@ -521,7 +523,14 @@ 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:
|
| @@ -595,7 +604,9 @@ class TestExpectationsModel(object):
|
|
|
| if other_line not in merge_lines_cache[self_line]:
|
| merge_lines_cache[self_line][other_line] = TestExpectationLine.merge_expectation_lines(
|
| - self_line, other_line, model_all_expectations=False)
|
| + self_line,
|
| + other_line,
|
| + model_all_expectations=False)
|
|
|
| merged_line = merge_lines_cache[self_line][other_line]
|
| else:
|
| @@ -678,8 +689,7 @@ class TestExpectationsModel(object):
|
| self._clear_expectations_for_test(test)
|
| del self._test_to_expectation_line[test]
|
|
|
| - def add_expectation_line(self, expectation_line,
|
| - model_all_expectations=False):
|
| + def add_expectation_line(self, expectation_line, model_all_expectations=False):
|
| """Returns a list of warnings encountered while matching specifiers."""
|
|
|
| if expectation_line.is_invalid():
|
| @@ -690,7 +700,8 @@ 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
|
| @@ -780,28 +791,32 @@ class TestExpectationsModel(object):
|
| # to be warnings and return False".
|
|
|
| if prev_expectation_line.matching_configurations == expectation_line.matching_configurations:
|
| - expectation_line.warnings.append('Duplicate or ambiguous entry lines %s:%s and %s:%s.' % (
|
| - self._shorten_filename(prev_expectation_line.filename), prev_expectation_line.line_numbers,
|
| - self._shorten_filename(expectation_line.filename), expectation_line.line_numbers))
|
| + expectation_line.warnings.append('Duplicate or ambiguous entry lines %s:%s and %s:%s.' %
|
| + (self._shorten_filename(prev_expectation_line.filename),
|
| + prev_expectation_line.line_numbers, self._shorten_filename(expectation_line.filename),
|
| + expectation_line.line_numbers))
|
| 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(prev_expectation_line.filename), prev_expectation_line.line_numbers,
|
| - self._shorten_filename(expectation_line.filename), expectation_line.line_numbers))
|
| + 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))
|
| # 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))
|
| + 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))
|
| 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))
|
| + 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))
|
| return True
|
|
|
| # Configuration sets are disjoint, then.
|
| @@ -853,8 +868,7 @@ class TestExpectations(object):
|
| TestExpectationParser.NEEDS_MANUAL_REBASELINE_MODIFIER: NEEDS_MANUAL_REBASELINE,
|
| TestExpectationParser.WONTFIX_MODIFIER: WONTFIX,
|
| TestExpectationParser.SLOW_MODIFIER: SLOW,
|
| - TestExpectationParser.REBASELINE_MODIFIER: REBASELINE,
|
| - }
|
| + TestExpectationParser.REBASELINE_MODIFIER: REBASELINE, }
|
|
|
| EXPECTATIONS_TO_STRING = dict((k, v) for (v, k) in EXPECTATIONS.iteritems())
|
|
|
| @@ -875,17 +889,13 @@ class TestExpectations(object):
|
|
|
| BUILD_TYPES = ('debug', 'release')
|
|
|
| - TIMELINES = {TestExpectationParser.WONTFIX_MODIFIER: WONTFIX,
|
| - 'now': NOW}
|
| + TIMELINES = {TestExpectationParser.WONTFIX_MODIFIER: WONTFIX, 'now': NOW}
|
|
|
| - RESULT_TYPES = {'skip': SKIP,
|
| - 'pass': PASS,
|
| - 'fail': FAIL,
|
| - 'flaky': FLAKY}
|
| + RESULT_TYPES = {'skip': SKIP, 'pass': PASS, 'fail': FAIL, 'flaky': FLAKY}
|
|
|
| @classmethod
|
| def expectation_from_string(cls, string):
|
| - assert(' ' not in string) # This only handles one expectation at a time.
|
| + assert (' ' not in string) # This only handles one expectation at a time.
|
| return cls.EXPECTATIONS.get(string.lower())
|
|
|
| @staticmethod
|
| @@ -900,7 +910,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, IMAGE_PLUS_TEXT, AUDIO) and (FAIL in expected_results):
|
| return True
|
| @@ -966,7 +977,13 @@ 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
|
| @@ -1057,8 +1074,8 @@ class TestExpectations(object):
|
| warnings = []
|
| 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))
|
| + warnings.append('%s:%s %s %s' % (self._shorten_filename(expectation.filename), expectation.line_numbers, warning,
|
| + expectation.name if expectation.expectations else expectation.original_string))
|
|
|
| if warnings:
|
| self._has_warnings = True
|
|
|