Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (C) 2010 Google Inc. All rights reserved. | 1 # Copyright (C) 2010 Google Inc. All rights reserved. |
| 2 # | 2 # |
| 3 # Redistribution and use in source and binary forms, with or without | 3 # Redistribution and use in source and binary forms, with or without |
| 4 # modification, are permitted provided that the following conditions are | 4 # modification, are permitted provided that the following conditions are |
| 5 # met: | 5 # met: |
| 6 # | 6 # |
| 7 # * Redistributions of source code must retain the above copyright | 7 # * Redistributions of source code must retain the above copyright |
| 8 # notice, this list of conditions and the following disclaimer. | 8 # notice, this list of conditions and the following disclaimer. |
| 9 # * Redistributions in binary form must reproduce the above | 9 # * Redistributions in binary form must reproduce the above |
| 10 # copyright notice, this list of conditions and the following disclaimer | 10 # copyright notice, this list of conditions and the following disclaimer |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 31 """ | 31 """ |
| 32 | 32 |
| 33 import logging | 33 import logging |
| 34 import re | 34 import re |
| 35 | 35 |
| 36 from webkitpy.layout_tests.models.test_configuration import TestConfigurationCon verter | 36 from webkitpy.layout_tests.models.test_configuration import TestConfigurationCon verter |
| 37 | 37 |
| 38 _log = logging.getLogger(__name__) | 38 _log = logging.getLogger(__name__) |
| 39 | 39 |
| 40 | 40 |
| 41 # Test expectation and modifier constants. | 41 # Test expectation and specifier constants. |
| 42 # | 42 # |
| 43 # FIXME: range() starts with 0 which makes if expectation checks harder | 43 # FIXME: range() starts with 0 which makes if expectation checks harder |
| 44 # as PASS is 0. | 44 # as PASS is 0. |
| 45 (PASS, FAIL, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, TIMEOUT, CRASH, SKIP, WONTFIX, | 45 (PASS, FAIL, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, TIMEOUT, CRASH, SKIP, WONTFIX, |
| 46 SLOW, REBASELINE, NEEDS_REBASELINE, NEEDS_MANUAL_REBASELINE, MISSING, FLAKY, NO W, NONE) = range(18) | 46 SLOW, REBASELINE, NEEDS_REBASELINE, NEEDS_MANUAL_REBASELINE, MISSING, FLAKY, NO W, NONE) = range(18) |
| 47 | 47 |
| 48 # FIXME: Perhas these two routines should be part of the Port instead? | 48 # FIXME: Perhas these two routines should be part of the Port instead? |
| 49 BASELINE_SUFFIX_LIST = ('png', 'wav', 'txt') | 49 BASELINE_SUFFIX_LIST = ('png', 'wav', 'txt') |
| 50 | 50 |
| 51 WEBKIT_BUG_PREFIX = 'webkit.org/b/' | 51 WEBKIT_BUG_PREFIX = 'webkit.org/b/' |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 65 def __str__(self): | 65 def __str__(self): |
| 66 return '\n'.join(map(str, self.warnings)) | 66 return '\n'.join(map(str, self.warnings)) |
| 67 | 67 |
| 68 def __repr__(self): | 68 def __repr__(self): |
| 69 return 'ParseError(warnings=%s)' % self.warnings | 69 return 'ParseError(warnings=%s)' % self.warnings |
| 70 | 70 |
| 71 | 71 |
| 72 class TestExpectationParser(object): | 72 class TestExpectationParser(object): |
| 73 """Provides parsing facilities for lines in the test_expectation.txt file."" " | 73 """Provides parsing facilities for lines in the test_expectation.txt file."" " |
| 74 | 74 |
| 75 # FIXME: Rename these to *_KEYWORD as in MISSING_KEYWORD above, but make the case studdly-caps to match the actual file contents. | |
|
Dirk Pranke
2013/07/26 23:07:28
"studly" ?
| |
| 75 REBASELINE_MODIFIER = 'rebaseline' | 76 REBASELINE_MODIFIER = 'rebaseline' |
| 76 NEEDS_REBASELINE_MODIFIER = 'needsrebaseline' | 77 NEEDS_REBASELINE_MODIFIER = 'needsrebaseline' |
| 77 NEEDS_MANUAL_REBASELINE_MODIFIER = 'needsmanualrebaseline' | 78 NEEDS_MANUAL_REBASELINE_MODIFIER = 'needsmanualrebaseline' |
| 78 PASS_EXPECTATION = 'pass' | 79 PASS_EXPECTATION = 'pass' |
| 79 SKIP_MODIFIER = 'skip' | 80 SKIP_MODIFIER = 'skip' |
| 80 SLOW_MODIFIER = 'slow' | 81 SLOW_MODIFIER = 'slow' |
| 81 WONTFIX_MODIFIER = 'wontfix' | 82 WONTFIX_MODIFIER = 'wontfix' |
| 82 | 83 |
| 83 TIMEOUT_EXPECTATION = 'timeout' | 84 TIMEOUT_EXPECTATION = 'timeout' |
| 84 | 85 |
| 85 MISSING_BUG_WARNING = 'Test lacks BUG modifier.' | 86 MISSING_BUG_WARNING = 'Test lacks BUG specifier.' |
| 86 | 87 |
| 87 def __init__(self, port, full_test_list, allow_rebaseline_modifier): | 88 def __init__(self, port, full_test_list, allow_rebaseline): |
| 88 self._port = port | 89 self._port = port |
| 89 self._test_configuration_converter = TestConfigurationConverter(set(port .all_test_configurations()), port.configuration_specifier_macros()) | 90 self._test_configuration_converter = TestConfigurationConverter(set(port .all_test_configurations()), port.configuration_specifier_macros()) |
| 90 self._full_test_list = full_test_list | 91 self._full_test_list = full_test_list |
| 91 self._allow_rebaseline_modifier = allow_rebaseline_modifier | 92 self._allow_rebaseline = allow_rebaseline |
| 92 | 93 |
| 93 def parse(self, filename, expectations_string): | 94 def parse(self, filename, expectations_string): |
| 94 expectation_lines = [] | 95 expectation_lines = [] |
| 95 line_number = 0 | 96 line_number = 0 |
| 96 for line in expectations_string.split("\n"): | 97 for line in expectations_string.split("\n"): |
| 97 line_number += 1 | 98 line_number += 1 |
| 98 test_expectation = self._tokenize_line(filename, line, line_number) | 99 test_expectation = self._tokenize_line(filename, line, line_number) |
| 99 self._parse_line(test_expectation) | 100 self._parse_line(test_expectation) |
| 100 expectation_lines.append(test_expectation) | 101 expectation_lines.append(test_expectation) |
| 101 return expectation_lines | 102 return expectation_lines |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 112 def expectation_line_for_test(self, test_name, expectations): | 113 def expectation_line_for_test(self, test_name, expectations): |
| 113 expectation_line = self._create_expectation_line(test_name, expectations , '<Bot TestExpectations>') | 114 expectation_line = self._create_expectation_line(test_name, expectations , '<Bot TestExpectations>') |
| 114 self._parse_line(expectation_line) | 115 self._parse_line(expectation_line) |
| 115 return expectation_line | 116 return expectation_line |
| 116 | 117 |
| 117 | 118 |
| 118 def expectation_for_skipped_test(self, test_name): | 119 def expectation_for_skipped_test(self, test_name): |
| 119 if not self._port.test_exists(test_name): | 120 if not self._port.test_exists(test_name): |
| 120 _log.warning('The following test %s from the Skipped list doesn\'t e xist' % test_name) | 121 _log.warning('The following test %s from the Skipped list doesn\'t e xist' % test_name) |
| 121 expectation_line = self._create_expectation_line(test_name, [TestExpecta tionParser.PASS_EXPECTATION], '<Skipped file>') | 122 expectation_line = self._create_expectation_line(test_name, [TestExpecta tionParser.PASS_EXPECTATION], '<Skipped file>') |
| 122 # FIXME: It's not clear what the expectations for a skipped test should be; the expectations | 123 expectation_line.expectations = [TestExpectationParser.SKIP_MODIFIER, Te stExpectationParser.WONTFIX_MODIFIER] |
| 123 # might be different for different entries in a Skipped file, or from th e command line, or from | |
| 124 # only running parts of the tests. It's also not clear if it matters muc h. | |
| 125 expectation_line.modifiers = [TestExpectationParser.SKIP_MODIFIER, TestE xpectationParser.WONTFIX_MODIFIER] | |
| 126 expectation_line.is_skipped_outside_expectations_file = True | 124 expectation_line.is_skipped_outside_expectations_file = True |
| 127 self._parse_line(expectation_line) | 125 self._parse_line(expectation_line) |
| 128 return expectation_line | 126 return expectation_line |
| 129 | 127 |
| 130 def _parse_line(self, expectation_line): | 128 def _parse_line(self, expectation_line): |
| 131 if not expectation_line.name: | 129 if not expectation_line.name: |
| 132 return | 130 return |
| 133 | 131 |
| 134 if not self._check_test_exists(expectation_line): | 132 if not self._check_test_exists(expectation_line): |
| 135 return | 133 return |
| 136 | 134 |
| 137 expectation_line.is_file = self._port.test_isfile(expectation_line.name) | 135 expectation_line.is_file = self._port.test_isfile(expectation_line.name) |
| 138 if expectation_line.is_file: | 136 if expectation_line.is_file: |
| 139 expectation_line.path = expectation_line.name | 137 expectation_line.path = expectation_line.name |
| 140 else: | 138 else: |
| 141 expectation_line.path = self._port.normalize_test_name(expectation_l ine.name) | 139 expectation_line.path = self._port.normalize_test_name(expectation_l ine.name) |
| 142 | 140 |
| 143 self._collect_matching_tests(expectation_line) | 141 self._collect_matching_tests(expectation_line) |
| 144 | 142 |
| 145 self._parse_modifiers(expectation_line) | 143 self._parse_specifiers(expectation_line) |
| 146 self._parse_expectations(expectation_line) | 144 self._parse_expectations(expectation_line) |
| 147 | 145 |
| 148 def _parse_modifiers(self, expectation_line): | 146 def _parse_specifiers(self, expectation_line): |
| 149 has_wontfix = False | 147 parsed_specifiers = set([specifier.lower() for specifier in expectation_ line.specifiers]) |
| 150 parsed_specifiers = set() | |
| 151 | |
| 152 modifiers = [modifier.lower() for modifier in expectation_line.modifiers ] | |
| 153 expectations = [expectation.lower() for expectation in expectation_line. expectations] | 148 expectations = [expectation.lower() for expectation in expectation_line. expectations] |
| 154 | 149 |
| 155 if self.SLOW_MODIFIER in modifiers and self.TIMEOUT_EXPECTATION in expec tations: | 150 if self.SLOW_MODIFIER in expectations and self.TIMEOUT_EXPECTATION in ex pectations: |
| 156 expectation_line.warnings.append('A test can not be both SLOW and TI MEOUT. If it times out indefinitely, then it should be just TIMEOUT.') | 151 expectation_line.warnings.append('A test can not be both SLOW and TI MEOUT. If it times out indefinitely, then it should be just TIMEOUT.') |
| 157 | 152 |
| 158 for modifier in expectation_line.modifiers: | 153 if not expectation_line.bugs and self.WONTFIX_MODIFIER not in expectatio ns and self._port.warn_if_bug_missing_in_test_expectations(): |
| 159 # FIXME: Store the unmodified modifier. | |
| 160 modifier = modifier.lower() | |
| 161 if modifier in TestExpectations.MODIFIERS: | |
| 162 expectation_line.parsed_modifiers.append(modifier) | |
| 163 if modifier == self.WONTFIX_MODIFIER: | |
| 164 has_wontfix = True | |
| 165 else: | |
| 166 parsed_specifiers.add(modifier) | |
| 167 | |
| 168 if not expectation_line.bugs and not has_wontfix and self._port.warn_if_ bug_missing_in_test_expectations(): | |
| 169 expectation_line.warnings.append(self.MISSING_BUG_WARNING) | 154 expectation_line.warnings.append(self.MISSING_BUG_WARNING) |
| 170 | 155 |
| 171 if self._allow_rebaseline_modifier and self.REBASELINE_MODIFIER in modif iers: | 156 if self._allow_rebaseline and self.REBASELINE_MODIFIER in expectations: |
| 172 expectation_line.warnings.append('REBASELINE should only be used for running rebaseline.py. Cannot be checked in.') | 157 expectation_line.warnings.append('REBASELINE should only be used for running rebaseline.py. Cannot be checked in.') |
| 173 | 158 |
| 174 expectation_line.matching_configurations = self._test_configuration_conv erter.to_config_set(parsed_specifiers, expectation_line.warnings) | 159 expectation_line.matching_configurations = self._test_configuration_conv erter.to_config_set(parsed_specifiers, expectation_line.warnings) |
| 175 | 160 |
| 176 def _parse_expectations(self, expectation_line): | 161 def _parse_expectations(self, expectation_line): |
| 177 result = set() | 162 result = set() |
| 178 for part in expectation_line.expectations: | 163 for part in expectation_line.expectations: |
| 179 expectation = TestExpectations.expectation_from_string(part) | 164 expectation = TestExpectations.expectation_from_string(part) |
| 180 if expectation is None: # Careful, PASS is currently 0. | 165 if expectation is None: # Careful, PASS is currently 0. |
| 181 expectation_line.warnings.append('Unsupported expectation: %s' % part) | 166 expectation_line.warnings.append('Unsupported expectation: %s' % part) |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 211 if not expectation_line.is_file: | 196 if not expectation_line.is_file: |
| 212 # this is a test category, return all the tests of the category. | 197 # this is a test category, return all the tests of the category. |
| 213 expectation_line.matching_tests = [test for test in self._full_test_ list if test.startswith(expectation_line.path)] | 198 expectation_line.matching_tests = [test for test in self._full_test_ list if test.startswith(expectation_line.path)] |
| 214 return | 199 return |
| 215 | 200 |
| 216 # this is a test file, do a quick check if it's in the | 201 # this is a test file, do a quick check if it's in the |
| 217 # full test suite. | 202 # full test suite. |
| 218 if expectation_line.path in self._full_test_list: | 203 if expectation_line.path in self._full_test_list: |
| 219 expectation_line.matching_tests.append(expectation_line.path) | 204 expectation_line.matching_tests.append(expectation_line.path) |
| 220 | 205 |
| 221 # FIXME: Update the original modifiers and remove this once the old syntax i s gone. | 206 # FIXME: Update the original specifiers and remove this once the old syntax is gone. |
| 222 _configuration_tokens_list = [ | 207 _configuration_tokens_list = [ |
| 223 'Mac', 'SnowLeopard', 'Lion', 'MountainLion', | 208 'Mac', 'SnowLeopard', 'Lion', 'MountainLion', |
| 224 'Win', 'XP', 'Win7', | 209 'Win', 'XP', 'Win7', |
| 225 'Linux', | 210 'Linux', |
| 226 'Android', | 211 'Android', |
| 227 'Release', | 212 'Release', |
| 228 'Debug', | 213 'Debug', |
| 229 ] | 214 ] |
| 230 | 215 |
| 231 _configuration_tokens = dict((token, token.upper()) for token in _configurat ion_tokens_list) | 216 _configuration_tokens = dict((token, token.upper()) for token in _configurat ion_tokens_list) |
| 232 _inverted_configuration_tokens = dict((value, name) for name, value in _conf iguration_tokens.iteritems()) | 217 _inverted_configuration_tokens = dict((value, name) for name, value in _conf iguration_tokens.iteritems()) |
| 233 | 218 |
| 234 # FIXME: Update the original modifiers list and remove this once the old syn tax is gone. | 219 # FIXME: Update the original specifiers list and remove this once the old sy ntax is gone. |
| 235 _expectation_tokens = { | 220 _expectation_tokens = { |
| 236 'Crash': 'CRASH', | 221 'Crash': 'CRASH', |
| 237 'Failure': 'FAIL', | 222 'Failure': 'FAIL', |
| 238 'ImageOnlyFailure': 'IMAGE', | 223 'ImageOnlyFailure': 'IMAGE', |
| 239 MISSING_KEYWORD: 'MISSING', | 224 MISSING_KEYWORD: 'MISSING', |
| 240 'Pass': 'PASS', | 225 'Pass': 'PASS', |
| 241 'Rebaseline': 'REBASELINE', | 226 'Rebaseline': 'REBASELINE', |
| 242 NEEDS_REBASELINE_KEYWORD: NEEDS_REBASELINE_KEYWORD, | 227 NEEDS_REBASELINE_KEYWORD: NEEDS_REBASELINE_KEYWORD, |
| 243 NEEDS_MANUAL_REBASELINE_KEYWORD: NEEDS_MANUAL_REBASELINE_KEYWORD, | 228 NEEDS_MANUAL_REBASELINE_KEYWORD: NEEDS_MANUAL_REBASELINE_KEYWORD, |
| 244 'Skip': 'SKIP', | 229 'Skip': 'SKIP', |
| 245 'Slow': 'SLOW', | 230 'Slow': 'SLOW', |
| 246 'Timeout': 'TIMEOUT', | 231 'Timeout': 'TIMEOUT', |
| 247 'WontFix': 'WONTFIX', | 232 'WontFix': 'WONTFIX', |
| 248 } | 233 } |
| 249 | 234 |
| 250 _inverted_expectation_tokens = dict([(value, name) for name, value in _expec tation_tokens.iteritems()] + | 235 _inverted_expectation_tokens = dict([(value, name) for name, value in _expec tation_tokens.iteritems()] + |
| 251 [('TEXT', 'Failure'), ('IMAGE+TEXT', 'Fa ilure'), ('AUDIO', 'Failure')]) | 236 [('TEXT', 'Failure'), ('IMAGE+TEXT', 'Fa ilure'), ('AUDIO', 'Failure')]) |
| 252 | 237 |
| 253 # FIXME: Seems like these should be classmethods on TestExpectationLine inst ead of TestExpectationParser. | 238 # FIXME: Seems like these should be classmethods on TestExpectationLine inst ead of TestExpectationParser. |
| 254 @classmethod | 239 @classmethod |
| 255 def _tokenize_line(cls, filename, expectation_string, line_number): | 240 def _tokenize_line(cls, filename, expectation_string, line_number): |
| 256 """Tokenizes a line from TestExpectations and returns an unparsed TestEx pectationLine instance using the old format. | 241 """Tokenizes a line from TestExpectations and returns an unparsed TestEx pectationLine instance using the old format. |
| 257 | 242 |
| 258 The new format for a test expectation line is: | 243 The new format for a test expectation line is: |
| 259 | 244 |
| 260 [[bugs] [ "[" <configuration modifiers> "]" <name> [ "[" <expectations> "]" ["#" <comment>] | 245 [[bugs] [ "[" <configuration specifiers> "]" <name> [ "[" <expectations> "]" ["#" <comment>] |
| 261 | 246 |
| 262 Any errant whitespace is not preserved. | 247 Any errant whitespace is not preserved. |
| 263 | 248 |
| 264 """ | 249 """ |
| 265 expectation_line = TestExpectationLine() | 250 expectation_line = TestExpectationLine() |
| 266 expectation_line.original_string = expectation_string | 251 expectation_line.original_string = expectation_string |
| 267 expectation_line.filename = filename | 252 expectation_line.filename = filename |
| 268 expectation_line.line_numbers = str(line_number) | 253 expectation_line.line_numbers = str(line_number) |
| 269 | 254 |
| 270 comment_index = expectation_string.find("#") | 255 comment_index = expectation_string.find("#") |
| 271 if comment_index == -1: | 256 if comment_index == -1: |
| 272 comment_index = len(expectation_string) | 257 comment_index = len(expectation_string) |
| 273 else: | 258 else: |
| 274 expectation_line.comment = expectation_string[comment_index + 1:] | 259 expectation_line.comment = expectation_string[comment_index + 1:] |
| 275 | 260 |
| 276 remaining_string = re.sub(r"\s+", " ", expectation_string[:comment_index ].strip()) | 261 remaining_string = re.sub(r"\s+", " ", expectation_string[:comment_index ].strip()) |
| 277 if len(remaining_string) == 0: | 262 if len(remaining_string) == 0: |
| 278 return expectation_line | 263 return expectation_line |
| 279 | 264 |
| 280 # special-case parsing this so that we fail immediately instead of treat ing this as a test name | 265 # special-case parsing this so that we fail immediately instead of treat ing this as a test name |
| 281 if remaining_string.startswith('//'): | 266 if remaining_string.startswith('//'): |
| 282 expectation_line.warnings = ['use "#" instead of "//" for comments'] | 267 expectation_line.warnings = ['use "#" instead of "//" for comments'] |
| 283 return expectation_line | 268 return expectation_line |
| 284 | 269 |
| 285 bugs = [] | 270 bugs = [] |
| 286 modifiers = [] | 271 specifiers = [] |
| 287 name = None | 272 name = None |
| 288 expectations = [] | 273 expectations = [] |
| 289 warnings = [] | 274 warnings = [] |
| 290 has_unrecognized_expectation = False | 275 has_unrecognized_expectation = False |
| 291 | 276 |
| 292 tokens = remaining_string.split() | 277 tokens = remaining_string.split() |
| 293 state = 'start' | 278 state = 'start' |
| 294 for token in tokens: | 279 for token in tokens: |
| 295 if (token.startswith(WEBKIT_BUG_PREFIX) or | 280 if (token.startswith(WEBKIT_BUG_PREFIX) or |
| 296 token.startswith(CHROMIUM_BUG_PREFIX) or | 281 token.startswith(CHROMIUM_BUG_PREFIX) or |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 325 state = 'name' | 310 state = 'name' |
| 326 elif state == 'expectations': | 311 elif state == 'expectations': |
| 327 state = 'done' | 312 state = 'done' |
| 328 else: | 313 else: |
| 329 warnings.append('unexpected "]"') | 314 warnings.append('unexpected "]"') |
| 330 break | 315 break |
| 331 elif token in ('//', ':', '='): | 316 elif token in ('//', ':', '='): |
| 332 warnings.append('"%s" is not legal in the new TestExpectations s yntax.' % token) | 317 warnings.append('"%s" is not legal in the new TestExpectations s yntax.' % token) |
| 333 break | 318 break |
| 334 elif state == 'configuration': | 319 elif state == 'configuration': |
| 335 modifiers.append(cls._configuration_tokens.get(token, token)) | 320 specifiers.append(cls._configuration_tokens.get(token, token)) |
| 336 elif state == 'expectations': | 321 elif state == 'expectations': |
| 337 if token in ('Rebaseline', 'Skip', 'Slow', 'WontFix'): | 322 if token not in cls._expectation_tokens: |
| 338 modifiers.append(token.upper()) | |
| 339 elif token not in cls._expectation_tokens: | |
| 340 has_unrecognized_expectation = True | 323 has_unrecognized_expectation = True |
| 341 warnings.append('Unrecognized expectation "%s"' % token) | 324 warnings.append('Unrecognized expectation "%s"' % token) |
| 342 else: | 325 else: |
| 343 expectations.append(cls._expectation_tokens.get(token, token )) | 326 expectations.append(cls._expectation_tokens.get(token, token )) |
| 344 elif state == 'name_found': | 327 elif state == 'name_found': |
| 345 warnings.append('expecting "[", "#", or end of line instead of " %s"' % token) | 328 warnings.append('expecting "[", "#", or end of line instead of " %s"' % token) |
| 346 break | 329 break |
| 347 else: | 330 else: |
| 348 name = token | 331 name = token |
| 349 state = 'name_found' | 332 state = 'name_found' |
| 350 | 333 |
| 351 if not warnings: | 334 if not warnings: |
| 352 if not name: | 335 if not name: |
| 353 warnings.append('Did not find a test name.') | 336 warnings.append('Did not find a test name.') |
| 354 elif state not in ('name_found', 'done'): | 337 elif state not in ('name_found', 'done'): |
| 355 warnings.append('Missing a "]"') | 338 warnings.append('Missing a "]"') |
| 356 | 339 |
| 357 if 'WONTFIX' in modifiers and 'SKIP' not in modifiers and not expectatio ns: | 340 if 'WONTFIX' in expectations and 'SKIP' not in expectations: |
| 358 modifiers.append('SKIP') | 341 expectations.append('SKIP') |
| 359 | 342 |
| 360 if 'SKIP' in modifiers and expectations: | 343 if ('SKIP' in expectations or 'WONTFIX' in expectations) and len(set(exp ectations) - set(['SKIP', 'WONTFIX'])): |
| 361 # FIXME: This is really a semantic warning and shouldn't be here. Re move when we drop the old syntax. | 344 warnings.append('A test marked Skip or WontFix must not have other e xpectations.') |
| 362 warnings.append('A test marked Skip must not have other expectations .') | 345 |
| 363 elif not expectations: | 346 if not expectations and not has_unrecognized_expectation: |
| 364 if not has_unrecognized_expectation and 'SKIP' not in modifiers and 'REBASELINE' not in modifiers and NEEDS_REBASELINE_KEYWORD not in modifiers and NEEDS_MANUAL_REBASELINE_KEYWORD not in modifiers and 'SLOW' not in modifiers: | 347 warnings.append('Missing expectations.') |
| 365 warnings.append('Missing expectations.') | |
| 366 expectations = ['PASS'] | |
| 367 | 348 |
| 368 expectation_line.bugs = bugs | 349 expectation_line.bugs = bugs |
| 369 expectation_line.modifiers = modifiers | 350 expectation_line.specifiers = specifiers |
| 370 expectation_line.expectations = expectations | 351 expectation_line.expectations = expectations |
| 371 expectation_line.name = name | 352 expectation_line.name = name |
| 372 expectation_line.warnings = warnings | 353 expectation_line.warnings = warnings |
| 373 return expectation_line | 354 return expectation_line |
| 374 | 355 |
| 375 @classmethod | 356 @classmethod |
| 376 def _split_space_separated(cls, space_separated_string): | 357 def _split_space_separated(cls, space_separated_string): |
| 377 """Splits a space-separated string into an array.""" | 358 """Splits a space-separated string into an array.""" |
| 378 return [part.strip() for part in space_separated_string.strip().split(' ')] | 359 return [part.strip() for part in space_separated_string.strip().split(' ')] |
| 379 | 360 |
| 380 | 361 |
| 381 class TestExpectationLine(object): | 362 class TestExpectationLine(object): |
| 382 """Represents a line in test expectations file.""" | 363 """Represents a line in test expectations file.""" |
| 383 | 364 |
| 384 def __init__(self): | 365 def __init__(self): |
| 385 """Initializes a blank-line equivalent of an expectation.""" | 366 """Initializes a blank-line equivalent of an expectation.""" |
| 386 self.original_string = None | 367 self.original_string = None |
| 387 self.filename = None # this is the path to the expectations file for th is line | 368 self.filename = None # this is the path to the expectations file for th is line |
| 388 self.line_numbers = None | 369 self.line_numbers = None |
| 389 self.name = None # this is the path in the line itself | 370 self.name = None # this is the path in the line itself |
| 390 self.path = None # this is the normpath of self.name | 371 self.path = None # this is the normpath of self.name |
| 391 self.bugs = [] | 372 self.bugs = [] |
| 392 self.modifiers = [] | 373 self.specifiers = [] |
| 393 self.parsed_modifiers = [] | 374 self.parsed_specifiers = [] |
| 394 self.matching_configurations = set() | 375 self.matching_configurations = set() |
| 395 self.expectations = [] | 376 self.expectations = [] |
| 396 self.parsed_expectations = set() | 377 self.parsed_expectations = set() |
| 397 self.comment = None | 378 self.comment = None |
| 398 self.matching_tests = [] | 379 self.matching_tests = [] |
| 399 self.warnings = [] | 380 self.warnings = [] |
| 400 self.is_skipped_outside_expectations_file = False | 381 self.is_skipped_outside_expectations_file = False |
| 401 | 382 |
| 402 def __eq__(self, other): | 383 def __eq__(self, other): |
| 403 return (self.original_string == other.original_string | 384 return (self.original_string == other.original_string |
| 404 and self.filename == other.filename | 385 and self.filename == other.filename |
| 405 and self.line_numbers == other.line_numbers | 386 and self.line_numbers == other.line_numbers |
| 406 and self.name == other.name | 387 and self.name == other.name |
| 407 and self.path == other.path | 388 and self.path == other.path |
| 408 and self.bugs == other.bugs | 389 and self.bugs == other.bugs |
| 409 and self.modifiers == other.modifiers | 390 and self.specifiers == other.specifiers |
| 410 and self.parsed_modifiers == other.parsed_modifiers | 391 and self.parsed_specifiers == other.parsed_specifiers |
| 411 and self.matching_configurations == other.matching_configurations | 392 and self.matching_configurations == other.matching_configurations |
| 412 and self.expectations == other.expectations | 393 and self.expectations == other.expectations |
| 413 and self.parsed_expectations == other.parsed_expectations | 394 and self.parsed_expectations == other.parsed_expectations |
| 414 and self.comment == other.comment | 395 and self.comment == other.comment |
| 415 and self.matching_tests == other.matching_tests | 396 and self.matching_tests == other.matching_tests |
| 416 and self.warnings == other.warnings | 397 and self.warnings == other.warnings |
| 417 and self.is_skipped_outside_expectations_file == other.is_skipped_ou tside_expectations_file) | 398 and self.is_skipped_outside_expectations_file == other.is_skipped_ou tside_expectations_file) |
| 418 | 399 |
| 419 def is_invalid(self): | 400 def is_invalid(self): |
| 420 return self.warnings and self.warnings != [TestExpectationParser.MISSING _BUG_WARNING] | 401 return self.warnings and self.warnings != [TestExpectationParser.MISSING _BUG_WARNING] |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 450 # We only care about filenames when we're linting, in which case the fil enames are the same. | 431 # We only care about filenames when we're linting, in which case the fil enames are the same. |
| 451 # Not clear that there's anything better to do when not linting and the filenames are different. | 432 # Not clear that there's anything better to do when not linting and the filenames are different. |
| 452 if model_all_expectations: | 433 if model_all_expectations: |
| 453 result.filename = line2.filename | 434 result.filename = line2.filename |
| 454 result.line_numbers = line1.line_numbers + "," + line2.line_numbers | 435 result.line_numbers = line1.line_numbers + "," + line2.line_numbers |
| 455 result.name = line1.name | 436 result.name = line1.name |
| 456 result.path = line1.path | 437 result.path = line1.path |
| 457 result.parsed_expectations = set(line1.parsed_expectations) | set(line2. parsed_expectations) | 438 result.parsed_expectations = set(line1.parsed_expectations) | set(line2. parsed_expectations) |
| 458 result.expectations = list(set(line1.expectations) | set(line2.expectati ons)) | 439 result.expectations = list(set(line1.expectations) | set(line2.expectati ons)) |
| 459 result.bugs = list(set(line1.bugs) | set(line2.bugs)) | 440 result.bugs = list(set(line1.bugs) | set(line2.bugs)) |
| 460 result.modifiers = list(set(line1.modifiers) | set(line2.modifiers)) | 441 result.specifiers = list(set(line1.specifiers) | set(line2.specifiers)) |
| 461 result.parsed_modifiers = list(set(line1.parsed_modifiers) | set(line2.p arsed_modifiers)) | 442 result.parsed_specifiers = list(set(line1.parsed_specifiers) | set(line2 .parsed_specifiers)) |
| 462 result.matching_configurations = set(line1.matching_configurations) | se t(line2.matching_configurations) | 443 result.matching_configurations = set(line1.matching_configurations) | se t(line2.matching_configurations) |
| 463 result.matching_tests = list(list(set(line1.matching_tests) | set(line2. matching_tests))) | 444 result.matching_tests = list(list(set(line1.matching_tests) | set(line2. matching_tests))) |
| 464 result.warnings = list(set(line1.warnings) | set(line2.warnings)) | 445 result.warnings = list(set(line1.warnings) | set(line2.warnings)) |
| 465 result.is_skipped_outside_expectations_file = line1.is_skipped_outside_e xpectations_file or line2.is_skipped_outside_expectations_file | 446 result.is_skipped_outside_expectations_file = line1.is_skipped_outside_e xpectations_file or line2.is_skipped_outside_expectations_file |
| 466 return result | 447 return result |
| 467 | 448 |
| 468 def to_string(self, test_configuration_converter, include_modifiers=True, in clude_expectations=True, include_comment=True): | 449 def to_string(self, test_configuration_converter, include_specifiers=True, i nclude_expectations=True, include_comment=True): |
| 469 parsed_expectation_to_string = dict([[parsed_expectation, expectation_st ring] for expectation_string, parsed_expectation in TestExpectations.EXPECTATION S.items()]) | 450 parsed_expectation_to_string = dict([[parsed_expectation, expectation_st ring] for expectation_string, parsed_expectation in TestExpectations.EXPECTATION S.items()]) |
| 470 | 451 |
| 471 if self.is_invalid(): | 452 if self.is_invalid(): |
| 472 return self.original_string or '' | 453 return self.original_string or '' |
| 473 | 454 |
| 474 if self.name is None: | 455 if self.name is None: |
| 475 return '' if self.comment is None else "#%s" % self.comment | 456 return '' if self.comment is None else "#%s" % self.comment |
| 476 | 457 |
| 477 if test_configuration_converter and self.bugs: | 458 if test_configuration_converter and self.bugs: |
| 478 specifiers_list = test_configuration_converter.to_specifiers_list(se lf.matching_configurations) | 459 specifiers_list = test_configuration_converter.to_specifiers_list(se lf.matching_configurations) |
| 479 result = [] | 460 result = [] |
| 480 for specifiers in specifiers_list: | 461 for specifiers in specifiers_list: |
| 481 # FIXME: this is silly that we join the modifiers and then immed iately split them. | 462 # FIXME: this is silly that we join the specifiers and then imme diately split them. |
| 482 modifiers = self._serialize_parsed_modifiers(test_configuration_ converter, specifiers).split() | 463 specifiers = self._serialize_parsed_specifiers(test_configuratio n_converter, specifiers).split() |
| 483 expectations = self._serialize_parsed_expectations(parsed_expect ation_to_string).split() | 464 expectations = self._serialize_parsed_expectations(parsed_expect ation_to_string).split() |
| 484 result.append(self._format_line(self.bugs, modifiers, self.name, expectations, self.comment)) | 465 result.append(self._format_line(self.bugs, specifiers, self.name , expectations, self.comment)) |
| 485 return "\n".join(result) if result else None | 466 return "\n".join(result) if result else None |
| 486 | 467 |
| 487 return self._format_line(self.bugs, self.modifiers, self.name, self.expe ctations, self.comment, | 468 return self._format_line(self.bugs, self.specifiers, self.name, self.exp ectations, self.comment, |
| 488 include_modifiers, include_expectations, include_comment) | 469 include_specifiers, include_expectations, include_comment) |
| 489 | 470 |
| 490 def to_csv(self): | 471 def to_csv(self): |
| 491 # Note that this doesn't include the comments. | 472 # Note that this doesn't include the comments. |
| 492 return '%s,%s,%s,%s' % (self.name, ' '.join(self.bugs), ' '.join(self.mo difiers), ' '.join(self.expectations)) | 473 return '%s,%s,%s,%s' % (self.name, ' '.join(self.bugs), ' '.join(self.sp ecifiers), ' '.join(self.expectations)) |
| 493 | 474 |
| 494 def _serialize_parsed_expectations(self, parsed_expectation_to_string): | 475 def _serialize_parsed_expectations(self, parsed_expectation_to_string): |
| 495 result = [] | 476 result = [] |
| 496 for index in TestExpectations.EXPECTATION_ORDER: | 477 for index in TestExpectations.EXPECTATION_ORDER: |
| 497 if index in self.parsed_expectations: | 478 if index in self.parsed_expectations: |
| 498 result.append(parsed_expectation_to_string[index]) | 479 result.append(parsed_expectation_to_string[index]) |
| 499 return ' '.join(result) | 480 return ' '.join(result) |
| 500 | 481 |
| 501 def _serialize_parsed_modifiers(self, test_configuration_converter, specifie rs): | 482 def _serialize_parsed_specifiers(self, test_configuration_converter, specifi ers): |
| 502 result = [] | 483 result = [] |
| 503 result.extend(sorted(self.parsed_modifiers)) | 484 result.extend(sorted(self.parsed_specifiers)) |
| 504 result.extend(test_configuration_converter.specifier_sorter().sort_speci fiers(specifiers)) | 485 result.extend(test_configuration_converter.specifier_sorter().sort_speci fiers(specifiers)) |
| 505 return ' '.join(result) | 486 return ' '.join(result) |
| 506 | 487 |
| 507 @staticmethod | 488 @staticmethod |
| 508 def _filter_redundant_expectations(expectations): | 489 def _filter_redundant_expectations(expectations): |
| 509 if set(expectations) == set(['Pass', 'Skip']): | 490 if set(expectations) == set(['Pass', 'Skip']): |
| 510 return ['Skip'] | 491 return ['Skip'] |
| 511 if set(expectations) == set(['Pass', 'Slow']): | 492 if set(expectations) == set(['Pass', 'Slow']): |
| 512 return ['Slow'] | 493 return ['Slow'] |
| 513 return expectations | 494 return expectations |
| 514 | 495 |
| 515 @staticmethod | 496 @staticmethod |
| 516 def _format_line(bugs, modifiers, name, expectations, comment, include_modif iers=True, include_expectations=True, include_comment=True): | 497 def _format_line(bugs, specifiers, name, expectations, comment, include_spec ifiers=True, include_expectations=True, include_comment=True): |
| 517 new_modifiers = [] | 498 new_specifiers = [] |
| 518 new_expectations = [] | 499 new_expectations = [] |
| 519 for modifier in modifiers: | 500 for specifier in specifiers: |
| 520 # FIXME: Make this all work with the mixed-cased modifiers (e.g. Won tFix, Slow, etc). | 501 # FIXME: Make this all work with the mixed-cased specifiers (e.g. Wo ntFix, Slow, etc). |
| 521 modifier = modifier.upper() | 502 specifier = specifier.upper() |
| 522 if modifier in ('SLOW', 'SKIP', 'REBASELINE', NEEDS_REBASELINE_KEYWO RD, NEEDS_MANUAL_REBASELINE_KEYWORD, 'WONTFIX'): | 503 new_specifiers.append(TestExpectationParser._inverted_configuration_ tokens.get(specifier, specifier)) |
| 523 new_expectations.append(TestExpectationParser._inverted_expectat ion_tokens.get(modifier)) | |
| 524 else: | |
| 525 new_modifiers.append(TestExpectationParser._inverted_configurati on_tokens.get(modifier, modifier)) | |
| 526 | 504 |
| 527 for expectation in expectations: | 505 for expectation in expectations: |
| 528 expectation = expectation.upper() | 506 expectation = expectation.upper() |
| 529 new_expectations.append(TestExpectationParser._inverted_expectation_ tokens.get(expectation, expectation)) | 507 new_expectations.append(TestExpectationParser._inverted_expectation_ tokens.get(expectation, expectation)) |
| 530 | 508 |
| 531 result = '' | 509 result = '' |
| 532 if include_modifiers and (bugs or new_modifiers): | 510 if include_specifiers and (bugs or new_specifiers): |
| 533 if bugs: | 511 if bugs: |
| 534 result += ' '.join(bugs) + ' ' | 512 result += ' '.join(bugs) + ' ' |
| 535 if new_modifiers: | 513 if new_specifiers: |
| 536 result += '[ %s ] ' % ' '.join(new_modifiers) | 514 result += '[ %s ] ' % ' '.join(new_specifiers) |
| 537 result += name | 515 result += name |
| 538 if include_expectations and new_expectations: | 516 if include_expectations and new_expectations: |
| 539 new_expectations = TestExpectationLine._filter_redundant_expectation s(new_expectations) | 517 new_expectations = TestExpectationLine._filter_redundant_expectation s(new_expectations) |
| 540 result += ' [ %s ]' % ' '.join(sorted(set(new_expectations))) | 518 result += ' [ %s ]' % ' '.join(sorted(set(new_expectations))) |
| 541 if include_comment and comment is not None: | 519 if include_comment and comment is not None: |
| 542 result += " #%s" % comment | 520 result += " #%s" % comment |
| 543 return result | 521 return result |
| 544 | 522 |
| 545 | 523 |
| 546 # FIXME: Refactor API to be a proper CRUD. | 524 # FIXME: Refactor API to be a proper CRUD. |
| 547 class TestExpectationsModel(object): | 525 class TestExpectationsModel(object): |
| 548 """Represents relational store of all expectations and provides CRUD semanti cs to manage it.""" | 526 """Represents relational store of all expectations and provides CRUD semanti cs to manage it.""" |
| 549 | 527 |
| 550 def __init__(self, shorten_filename=None): | 528 def __init__(self, shorten_filename=None): |
| 551 # Maps a test to its list of expectations. | 529 # Maps a test to its list of expectations. |
| 552 self._test_to_expectations = {} | 530 self._test_to_expectations = {} |
| 553 | 531 |
| 554 # Maps a test to list of its modifiers (string values) | 532 # Maps a test to list of its specifiers (string values) |
| 555 self._test_to_modifiers = {} | 533 self._test_to_specifiers = {} |
| 556 | 534 |
| 557 # Maps a test to a TestExpectationLine instance. | 535 # Maps a test to a TestExpectationLine instance. |
| 558 self._test_to_expectation_line = {} | 536 self._test_to_expectation_line = {} |
| 559 | 537 |
| 560 self._modifier_to_tests = self._dict_of_sets(TestExpectations.MODIFIERS) | |
| 561 self._expectation_to_tests = self._dict_of_sets(TestExpectations.EXPECTA TIONS) | 538 self._expectation_to_tests = self._dict_of_sets(TestExpectations.EXPECTA TIONS) |
| 562 self._timeline_to_tests = self._dict_of_sets(TestExpectations.TIMELINES) | 539 self._timeline_to_tests = self._dict_of_sets(TestExpectations.TIMELINES) |
| 563 self._result_type_to_tests = self._dict_of_sets(TestExpectations.RESULT_ TYPES) | 540 self._result_type_to_tests = self._dict_of_sets(TestExpectations.RESULT_ TYPES) |
| 564 | 541 |
| 565 self._shorten_filename = shorten_filename or (lambda x: x) | 542 self._shorten_filename = shorten_filename or (lambda x: x) |
| 566 | 543 |
| 567 def _dict_of_sets(self, strings_to_constants): | 544 def _dict_of_sets(self, strings_to_constants): |
| 568 """Takes a dict of strings->constants and returns a dict mapping | 545 """Takes a dict of strings->constants and returns a dict mapping |
| 569 each constant to an empty set.""" | 546 each constant to an empty set.""" |
| 570 d = {} | 547 d = {} |
| 571 for c in strings_to_constants.values(): | 548 for c in strings_to_constants.values(): |
| 572 d[c] = set() | 549 d[c] = set() |
| 573 return d | 550 return d |
| 574 | 551 |
| 575 def get_test_set(self, modifier, expectation=None, include_skips=True): | 552 def get_test_set(self, expectation, include_skips=True): |
| 576 if expectation is None: | 553 tests = self._expectation_to_tests[expectation] |
| 577 tests = self._modifier_to_tests[modifier] | |
| 578 else: | |
| 579 tests = (self._expectation_to_tests[expectation] & | |
| 580 self._modifier_to_tests[modifier]) | |
| 581 | |
| 582 if not include_skips: | 554 if not include_skips: |
| 583 tests = tests - self.get_test_set(SKIP, expectation) | 555 tests = tests - self.get_test_set(SKIP) |
| 584 | |
| 585 return tests | 556 return tests |
| 586 | 557 |
| 587 def get_test_set_for_keyword(self, keyword): | 558 def get_test_set_for_keyword(self, keyword): |
| 588 # FIXME: get_test_set() is an awkward public interface because it requir es | |
| 589 # callers to know the difference between modifiers and expectations. We | |
| 590 # should replace that with this where possible. | |
| 591 expectation_enum = TestExpectations.EXPECTATIONS.get(keyword.lower(), No ne) | 559 expectation_enum = TestExpectations.EXPECTATIONS.get(keyword.lower(), No ne) |
| 592 if expectation_enum is not None: | 560 if expectation_enum is not None: |
| 593 return self._expectation_to_tests[expectation_enum] | 561 return self._expectation_to_tests[expectation_enum] |
| 594 modifier_enum = TestExpectations.MODIFIERS.get(keyword.lower(), None) | |
| 595 if modifier_enum is not None: | |
| 596 return self._modifier_to_tests[modifier_enum] | |
| 597 | 562 |
| 598 # We must not have an index on this modifier. | |
| 599 matching_tests = set() | 563 matching_tests = set() |
| 600 for test, modifiers in self._test_to_modifiers.iteritems(): | 564 for test, specifiers in self._test_to_specifiers.iteritems(): |
| 601 if keyword.lower() in modifiers: | 565 if keyword.lower() in specifiers: |
| 602 matching_tests.add(test) | 566 matching_tests.add(test) |
| 603 return matching_tests | 567 return matching_tests |
| 604 | 568 |
| 605 def get_tests_with_result_type(self, result_type): | 569 def get_tests_with_result_type(self, result_type): |
| 606 return self._result_type_to_tests[result_type] | 570 return self._result_type_to_tests[result_type] |
| 607 | 571 |
| 608 def get_tests_with_timeline(self, timeline): | 572 def get_tests_with_timeline(self, timeline): |
| 609 return self._timeline_to_tests[timeline] | 573 return self._timeline_to_tests[timeline] |
| 610 | 574 |
| 611 def get_modifiers(self, test): | |
| 612 """This returns modifiers for the given test (the modifiers plus the BUG XXXX identifier). This is used by the LTTF dashboard.""" | |
| 613 return self._test_to_modifiers[test] | |
| 614 | |
| 615 def has_modifier(self, test, modifier): | |
| 616 return test in self._modifier_to_tests[modifier] | |
| 617 | |
| 618 def has_keyword(self, test, keyword): | |
| 619 return (keyword.upper() in self.get_expectations_string(test) or | |
| 620 keyword.lower() in self.get_modifiers(test)) | |
| 621 | |
| 622 def has_test(self, test): | 575 def has_test(self, test): |
| 623 return test in self._test_to_expectation_line | 576 return test in self._test_to_expectation_line |
| 624 | 577 |
| 625 def get_expectation_line(self, test): | 578 def get_expectation_line(self, test): |
| 626 return self._test_to_expectation_line.get(test) | 579 return self._test_to_expectation_line.get(test) |
| 627 | 580 |
| 628 def get_expectations(self, test): | 581 def get_expectations(self, test): |
| 629 return self._test_to_expectations[test] | 582 return self._test_to_expectations[test] |
| 630 | 583 |
| 631 def get_expectations_string(self, test): | 584 def get_expectations_string(self, test): |
| 632 """Returns the expectatons for the given test as an uppercase string. | 585 """Returns the expectatons for the given test as an uppercase string. |
| 633 If there are no expectations for the test, then "PASS" is returned.""" | 586 If there are no expectations for the test, then "PASS" is returned.""" |
| 634 if self.get_expectation_line(test).is_skipped_outside_expectations_file: | 587 if self.get_expectation_line(test).is_skipped_outside_expectations_file: |
| 635 return 'NOTRUN' | 588 return 'NOTRUN' |
| 636 | 589 |
| 637 if self.has_modifier(test, WONTFIX): | |
| 638 return TestExpectationParser.WONTFIX_MODIFIER.upper() | |
| 639 | |
| 640 if self.has_modifier(test, SKIP): | |
| 641 return TestExpectationParser.SKIP_MODIFIER.upper() | |
| 642 | |
| 643 expectations = self.get_expectations(test) | 590 expectations = self.get_expectations(test) |
| 644 retval = [] | 591 retval = [] |
| 645 | 592 |
| 593 # FIXME: WontFix should cause the test to get skipped without artificial ly adding SKIP to the expectations list. | |
| 594 if WONTFIX in expectations and SKIP in expectations: | |
| 595 expectations.remove(SKIP) | |
| 596 | |
| 646 for expectation in expectations: | 597 for expectation in expectations: |
| 647 retval.append(self.expectation_to_string(expectation)) | 598 retval.append(self.expectation_to_string(expectation)) |
| 648 | 599 |
| 649 return " ".join(retval) | 600 return " ".join(retval) |
| 650 | 601 |
| 651 def expectation_to_string(self, expectation): | 602 def expectation_to_string(self, expectation): |
| 652 """Return the uppercased string equivalent of a given expectation.""" | 603 """Return the uppercased string equivalent of a given expectation.""" |
| 653 for item in TestExpectations.EXPECTATIONS.items(): | 604 for item in TestExpectations.EXPECTATIONS.items(): |
| 654 if item[1] == expectation: | 605 if item[1] == expectation: |
| 655 return item[0].upper() | 606 return item[0].upper() |
| 656 for item in TestExpectations.MODIFIERS.items(): | |
| 657 if item[1] == expectation: | |
| 658 return item[0].upper() | |
| 659 raise ValueError(expectation) | 607 raise ValueError(expectation) |
| 660 | 608 |
| 661 def remove_expectation_line(self, test): | 609 def remove_expectation_line(self, test): |
| 662 if not self.has_test(test): | 610 if not self.has_test(test): |
| 663 return | 611 return |
| 664 self._clear_expectations_for_test(test) | 612 self._clear_expectations_for_test(test) |
| 665 del self._test_to_expectation_line[test] | 613 del self._test_to_expectation_line[test] |
| 666 | 614 |
| 667 def add_expectation_line(self, expectation_line, | 615 def add_expectation_line(self, expectation_line, |
| 668 override_existing_matches=False, | 616 override_existing_matches=False, |
| 669 merge_existing_matches=False, | 617 merge_existing_matches=False, |
| 670 model_all_expectations=False): | 618 model_all_expectations=False): |
| 671 """Returns a list of warnings encountered while matching modifiers.""" | 619 """Returns a list of warnings encountered while matching specifiers.""" |
| 672 | 620 |
| 673 if expectation_line.is_invalid(): | 621 if expectation_line.is_invalid(): |
| 674 return | 622 return |
| 675 | 623 |
| 676 for test in expectation_line.matching_tests: | 624 for test in expectation_line.matching_tests: |
| 677 if (not (override_existing_matches or merge_existing_matches) | 625 if (not (override_existing_matches or merge_existing_matches) |
| 678 and self._already_seen_better_match(test, expectation_line)) : | 626 and self._already_seen_better_match(test, expectation_line)) : |
| 679 continue | 627 continue |
| 680 | 628 |
| 681 if merge_existing_matches or model_all_expectations: | 629 if merge_existing_matches or model_all_expectations: |
| 682 expectation_line = TestExpectationLine.merge_expectation_lines(s elf.get_expectation_line(test), expectation_line, model_all_expectations) | 630 expectation_line = TestExpectationLine.merge_expectation_lines(s elf.get_expectation_line(test), expectation_line, model_all_expectations) |
| 683 | 631 |
| 684 self._clear_expectations_for_test(test) | 632 self._clear_expectations_for_test(test) |
| 685 self._test_to_expectation_line[test] = expectation_line | 633 self._test_to_expectation_line[test] = expectation_line |
| 686 self._add_test(test, expectation_line) | 634 self._add_test(test, expectation_line) |
| 687 | 635 |
| 688 def _add_test(self, test, expectation_line): | 636 def _add_test(self, test, expectation_line): |
| 689 """Sets the expected state for a given test. | 637 """Sets the expected state for a given test. |
| 690 | 638 |
| 691 This routine assumes the test has not been added before. If it has, | 639 This routine assumes the test has not been added before. If it has, |
| 692 use _clear_expectations_for_test() to reset the state prior to | 640 use _clear_expectations_for_test() to reset the state prior to |
| 693 calling this.""" | 641 calling this.""" |
| 694 self._test_to_expectations[test] = expectation_line.parsed_expectations | 642 self._test_to_expectations[test] = expectation_line.parsed_expectations |
| 695 for expectation in expectation_line.parsed_expectations: | 643 for expectation in expectation_line.parsed_expectations: |
| 696 self._expectation_to_tests[expectation].add(test) | 644 self._expectation_to_tests[expectation].add(test) |
| 697 | 645 |
| 698 self._test_to_modifiers[test] = expectation_line.modifiers | 646 self._test_to_specifiers[test] = expectation_line.specifiers |
| 699 for modifier in expectation_line.parsed_modifiers: | |
| 700 mod_value = TestExpectations.MODIFIERS[modifier] | |
| 701 self._modifier_to_tests[mod_value].add(test) | |
| 702 | 647 |
| 703 if TestExpectationParser.WONTFIX_MODIFIER in expectation_line.parsed_mod ifiers: | 648 if WONTFIX in expectation_line.parsed_expectations: |
| 704 self._timeline_to_tests[WONTFIX].add(test) | 649 self._timeline_to_tests[WONTFIX].add(test) |
| 705 else: | 650 else: |
| 706 self._timeline_to_tests[NOW].add(test) | 651 self._timeline_to_tests[NOW].add(test) |
| 707 | 652 |
| 708 if TestExpectationParser.SKIP_MODIFIER in expectation_line.parsed_modifi ers: | 653 if SKIP in expectation_line.parsed_expectations: |
| 709 self._result_type_to_tests[SKIP].add(test) | 654 self._result_type_to_tests[SKIP].add(test) |
| 710 elif expectation_line.parsed_expectations == set([PASS]): | 655 elif expectation_line.parsed_expectations == set([PASS]): |
| 711 self._result_type_to_tests[PASS].add(test) | 656 self._result_type_to_tests[PASS].add(test) |
| 712 elif expectation_line.is_flaky(): | 657 elif expectation_line.is_flaky(): |
| 713 self._result_type_to_tests[FLAKY].add(test) | 658 self._result_type_to_tests[FLAKY].add(test) |
| 714 else: | 659 else: |
| 715 # FIXME: What is this? | 660 # FIXME: What is this? |
| 716 self._result_type_to_tests[FAIL].add(test) | 661 self._result_type_to_tests[FAIL].add(test) |
| 717 | 662 |
| 718 def _clear_expectations_for_test(self, test): | 663 def _clear_expectations_for_test(self, test): |
| 719 """Remove prexisting expectations for this test. | 664 """Remove prexisting expectations for this test. |
| 720 This happens if we are seeing a more precise path | 665 This happens if we are seeing a more precise path |
| 721 than a previous listing. | 666 than a previous listing. |
| 722 """ | 667 """ |
| 723 if self.has_test(test): | 668 if self.has_test(test): |
| 724 self._test_to_expectations.pop(test, '') | 669 self._test_to_expectations.pop(test, '') |
| 725 self._remove_from_sets(test, self._expectation_to_tests) | 670 self._remove_from_sets(test, self._expectation_to_tests) |
| 726 self._remove_from_sets(test, self._modifier_to_tests) | |
| 727 self._remove_from_sets(test, self._timeline_to_tests) | 671 self._remove_from_sets(test, self._timeline_to_tests) |
| 728 self._remove_from_sets(test, self._result_type_to_tests) | 672 self._remove_from_sets(test, self._result_type_to_tests) |
| 729 | 673 |
| 730 def _remove_from_sets(self, test, dict_of_sets_of_tests): | 674 def _remove_from_sets(self, test, dict_of_sets_of_tests): |
| 731 """Removes the given test from the sets in the dictionary. | 675 """Removes the given test from the sets in the dictionary. |
| 732 | 676 |
| 733 Args: | 677 Args: |
| 734 test: test to look for | 678 test: test to look for |
| 735 dict: dict of sets of files""" | 679 dict: dict of sets of files""" |
| 736 for set_of_tests in dict_of_sets_of_tests.itervalues(): | 680 for set_of_tests in dict_of_sets_of_tests.itervalues(): |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 756 | 700 |
| 757 if len(prev_expectation_line.path) > len(expectation_line.path): | 701 if len(prev_expectation_line.path) > len(expectation_line.path): |
| 758 # The previous path matched more of the test. | 702 # The previous path matched more of the test. |
| 759 return True | 703 return True |
| 760 | 704 |
| 761 if len(prev_expectation_line.path) < len(expectation_line.path): | 705 if len(prev_expectation_line.path) < len(expectation_line.path): |
| 762 # This path matches more of the test. | 706 # This path matches more of the test. |
| 763 return False | 707 return False |
| 764 | 708 |
| 765 # At this point we know we have seen a previous exact match on this | 709 # At this point we know we have seen a previous exact match on this |
| 766 # base path, so we need to check the two sets of modifiers. | 710 # base path, so we need to check the two sets of specifiers. |
| 767 | 711 |
| 768 # FIXME: This code was originally designed to allow lines that matched | 712 # FIXME: This code was originally designed to allow lines that matched |
| 769 # more modifiers to override lines that matched fewer modifiers. | 713 # more specifiers to override lines that matched fewer specifiers. |
| 770 # However, we currently view these as errors. | 714 # However, we currently view these as errors. |
| 771 # | 715 # |
| 772 # To use the "more modifiers wins" policy, change the errors for overrid es | 716 # To use the "more specifiers wins" policy, change the errors for overri des |
| 773 # to be warnings and return False". | 717 # to be warnings and return False". |
| 774 | 718 |
| 775 if prev_expectation_line.matching_configurations == expectation_line.mat ching_configurations: | 719 if prev_expectation_line.matching_configurations == expectation_line.mat ching_configurations: |
| 776 expectation_line.warnings.append('Duplicate or ambiguous entry lines %s:%s and %s:%s.' % ( | 720 expectation_line.warnings.append('Duplicate or ambiguous entry lines %s:%s and %s:%s.' % ( |
| 777 self._shorten_filename(prev_expectation_line.filename), prev_exp ectation_line.line_numbers, | 721 self._shorten_filename(prev_expectation_line.filename), prev_exp ectation_line.line_numbers, |
| 778 self._shorten_filename(expectation_line.filename), expectation_l ine.line_numbers)) | 722 self._shorten_filename(expectation_line.filename), expectation_l ine.line_numbers)) |
| 779 return True | 723 return True |
| 780 | 724 |
| 781 if prev_expectation_line.matching_configurations >= expectation_line.mat ching_configurations: | 725 if prev_expectation_line.matching_configurations >= expectation_line.mat ching_configurations: |
| 782 expectation_line.warnings.append('More specific entry for %s on line %s:%s overrides line %s:%s.' % (expectation_line.name, | 726 expectation_line.warnings.append('More specific entry for %s on line %s:%s overrides line %s:%s.' % (expectation_line.name, |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 805 """Test expectations consist of lines with specifications of what | 749 """Test expectations consist of lines with specifications of what |
| 806 to expect from layout test cases. The test cases can be directories | 750 to expect from layout test cases. The test cases can be directories |
| 807 in which case the expectations apply to all test cases in that | 751 in which case the expectations apply to all test cases in that |
| 808 directory and any subdirectory. The format is along the lines of: | 752 directory and any subdirectory. The format is along the lines of: |
| 809 | 753 |
| 810 LayoutTests/fast/js/fixme.js [ Failure ] | 754 LayoutTests/fast/js/fixme.js [ Failure ] |
| 811 LayoutTests/fast/js/flaky.js [ Failure Pass ] | 755 LayoutTests/fast/js/flaky.js [ Failure Pass ] |
| 812 LayoutTests/fast/js/crash.js [ Crash Failure Pass Timeout ] | 756 LayoutTests/fast/js/crash.js [ Crash Failure Pass Timeout ] |
| 813 ... | 757 ... |
| 814 | 758 |
| 815 To add modifiers: | 759 To add specifiers: |
| 816 LayoutTests/fast/js/no-good.js | 760 LayoutTests/fast/js/no-good.js |
| 817 [ Debug ] LayoutTests/fast/js/no-good.js [ Pass Timeout ] | 761 [ Debug ] LayoutTests/fast/js/no-good.js [ Pass Timeout ] |
| 818 [ Debug ] LayoutTests/fast/js/no-good.js [ Pass Skip Timeout ] | 762 [ Debug ] LayoutTests/fast/js/no-good.js [ Pass Skip Timeout ] |
| 819 [ Linux Debug ] LayoutTests/fast/js/no-good.js [ Pass Skip Timeout ] | 763 [ Linux Debug ] LayoutTests/fast/js/no-good.js [ Pass Skip Timeout ] |
| 820 [ Linux Win ] LayoutTests/fast/js/no-good.js [ Pass Skip Timeout ] | 764 [ Linux Win ] LayoutTests/fast/js/no-good.js [ Pass Skip Timeout ] |
| 821 | 765 |
| 822 Skip: Doesn't run the test. | 766 Skip: Doesn't run the test. |
| 823 Slow: The test takes a long time to run, but does not timeout indefinitely. | 767 Slow: The test takes a long time to run, but does not timeout indefinitely. |
| 824 WontFix: For tests that we never intend to pass on a given platform (treated like Skip). | 768 WontFix: For tests that we never intend to pass on a given platform (treated like Skip). |
| 825 | 769 |
| 826 Notes: | 770 Notes: |
| 827 -A test cannot be both SLOW and TIMEOUT | 771 -A test cannot be both SLOW and TIMEOUT |
| 828 -A test can be included twice, but not via the same path. | 772 -A test can be included twice, but not via the same path. |
| 829 -If a test is included twice, then the more precise path wins. | 773 -If a test is included twice, then the more precise path wins. |
| 830 -CRASH tests cannot be WONTFIX | 774 -CRASH tests cannot be WONTFIX |
| 831 """ | 775 """ |
| 832 | 776 |
| 833 # FIXME: Update to new syntax once the old format is no longer supported. | 777 # FIXME: Update to new syntax once the old format is no longer supported. |
| 834 EXPECTATIONS = {'pass': PASS, | 778 EXPECTATIONS = {'pass': PASS, |
| 835 'audio': AUDIO, | 779 'audio': AUDIO, |
| 836 'fail': FAIL, | 780 'fail': FAIL, |
| 837 'image': IMAGE, | 781 'image': IMAGE, |
| 838 'image+text': IMAGE_PLUS_TEXT, | 782 'image+text': IMAGE_PLUS_TEXT, |
| 839 'text': TEXT, | 783 'text': TEXT, |
| 840 'timeout': TIMEOUT, | 784 'timeout': TIMEOUT, |
| 841 'crash': CRASH, | 785 'crash': CRASH, |
| 842 'missing': MISSING, | 786 'missing': MISSING, |
| 843 'skip': SKIP, | 787 TestExpectationParser.SKIP_MODIFIER: SKIP, |
| 844 'needsrebaseline': NEEDS_REBASELINE, | 788 TestExpectationParser.NEEDS_REBASELINE_MODIFIER: NEEDS_REBAS ELINE, |
| 845 'needsmanualrebaseline': NEEDS_MANUAL_REBASELINE} | 789 TestExpectationParser.NEEDS_MANUAL_REBASELINE_MODIFIER: NEED S_MANUAL_REBASELINE, |
| 790 TestExpectationParser.WONTFIX_MODIFIER: WONTFIX, | |
| 791 TestExpectationParser.SLOW_MODIFIER: SLOW, | |
| 792 TestExpectationParser.REBASELINE_MODIFIER: REBASELINE, | |
| 793 } | |
| 846 | 794 |
| 847 EXPECTATIONS_TO_STRING = dict((k, v) for (v, k) in EXPECTATIONS.iteritems()) | 795 EXPECTATIONS_TO_STRING = dict((k, v) for (v, k) in EXPECTATIONS.iteritems()) |
| 848 | 796 |
| 849 # (aggregated by category, pass/fail/skip, type) | 797 # (aggregated by category, pass/fail/skip, type) |
| 850 EXPECTATION_DESCRIPTIONS = {SKIP: 'skipped', | 798 EXPECTATION_DESCRIPTIONS = {SKIP: 'skipped', |
| 851 PASS: 'passes', | 799 PASS: 'passes', |
| 852 FAIL: 'failures', | 800 FAIL: 'failures', |
| 853 IMAGE: 'image-only failures', | 801 IMAGE: 'image-only failures', |
| 854 TEXT: 'text-only failures', | 802 TEXT: 'text-only failures', |
| 855 IMAGE_PLUS_TEXT: 'image and text failures', | 803 IMAGE_PLUS_TEXT: 'image and text failures', |
| 856 AUDIO: 'audio failures', | 804 AUDIO: 'audio failures', |
| 857 CRASH: 'crashes', | 805 CRASH: 'crashes', |
| 858 TIMEOUT: 'timeouts', | 806 TIMEOUT: 'timeouts', |
| 859 MISSING: 'missing results'} | 807 MISSING: 'missing results'} |
| 860 | 808 |
| 861 EXPECTATION_ORDER = (PASS, CRASH, TIMEOUT, MISSING, FAIL, IMAGE, SKIP) | 809 EXPECTATION_ORDER = (PASS, CRASH, TIMEOUT, MISSING, FAIL, IMAGE, SKIP) |
| 862 | 810 |
| 811 NON_TEST_OUTCOME_EXPECTATIONS = (REBASELINE, SKIP, SLOW, WONTFIX) | |
| 812 | |
| 863 BUILD_TYPES = ('debug', 'release') | 813 BUILD_TYPES = ('debug', 'release') |
| 864 | 814 |
| 865 MODIFIERS = {TestExpectationParser.SKIP_MODIFIER: SKIP, | |
| 866 TestExpectationParser.WONTFIX_MODIFIER: WONTFIX, | |
| 867 TestExpectationParser.SLOW_MODIFIER: SLOW, | |
| 868 TestExpectationParser.REBASELINE_MODIFIER: REBASELINE, | |
| 869 TestExpectationParser.NEEDS_REBASELINE_MODIFIER: NEEDS_REBASELI NE, | |
| 870 TestExpectationParser.NEEDS_MANUAL_REBASELINE_MODIFIER: NEEDS_M ANUAL_REBASELINE, | |
| 871 'none': NONE} | |
| 872 | |
| 873 MODIFIERS_TO_STRING = dict((k, v) for (v, k) in MODIFIERS.iteritems()) | |
| 874 | |
| 875 TIMELINES = {TestExpectationParser.WONTFIX_MODIFIER: WONTFIX, | 815 TIMELINES = {TestExpectationParser.WONTFIX_MODIFIER: WONTFIX, |
| 876 'now': NOW} | 816 'now': NOW} |
| 877 | 817 |
| 878 RESULT_TYPES = {'skip': SKIP, | 818 RESULT_TYPES = {'skip': SKIP, |
| 879 'pass': PASS, | 819 'pass': PASS, |
| 880 'fail': FAIL, | 820 'fail': FAIL, |
| 881 'flaky': FLAKY} | 821 'flaky': FLAKY} |
| 882 | 822 |
| 883 @classmethod | 823 @classmethod |
| 884 def expectation_from_string(cls, string): | 824 def expectation_from_string(cls, string): |
| 885 assert(' ' not in string) # This only handles one expectation at a time . | 825 assert(' ' not in string) # This only handles one expectation at a time . |
| 886 return cls.EXPECTATIONS.get(string.lower()) | 826 return cls.EXPECTATIONS.get(string.lower()) |
| 887 | 827 |
| 888 @staticmethod | 828 @staticmethod |
| 889 def result_was_expected(result, expected_results, test_needs_rebaselining): | 829 def result_was_expected(result, expected_results, test_needs_rebaselining): |
| 890 """Returns whether we got a result we were expecting. | 830 """Returns whether we got a result we were expecting. |
| 891 Args: | 831 Args: |
| 892 result: actual result of a test execution | 832 result: actual result of a test execution |
| 893 expected_results: set of results listed in test_expectations | 833 expected_results: set of results listed in test_expectations |
| 894 test_needs_rebaselining: whether test was marked as REBASELINE""" | 834 test_needs_rebaselining: whether test was marked as REBASELINE""" |
| 835 if not (set(expected_results) - (set(TestExpectations.NON_TEST_OUTCOME_E XPECTATIONS))): | |
| 836 expected_results = set([PASS]) | |
| 837 | |
| 895 if result in expected_results: | 838 if result in expected_results: |
| 896 return True | 839 return True |
| 897 if result in (PASS, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, MISSING) and (N EEDS_REBASELINE in expected_results or NEEDS_MANUAL_REBASELINE in expected_resul ts): | 840 if result in (PASS, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, MISSING) and (N EEDS_REBASELINE in expected_results or NEEDS_MANUAL_REBASELINE in expected_resul ts): |
| 898 return True | 841 return True |
| 899 if result in (TEXT, IMAGE_PLUS_TEXT, AUDIO) and (FAIL in expected_result s): | 842 if result in (TEXT, IMAGE_PLUS_TEXT, AUDIO) and (FAIL in expected_result s): |
| 900 return True | 843 return True |
| 901 if result == MISSING and test_needs_rebaselining: | 844 if result == MISSING and test_needs_rebaselining: |
| 902 return True | 845 return True |
| 903 if result == SKIP: | 846 if result == SKIP: |
| 904 return True | 847 return True |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 985 self._has_warnings = False | 928 self._has_warnings = False |
| 986 self._report_warnings() | 929 self._report_warnings() |
| 987 self._process_tests_without_expectations() | 930 self._process_tests_without_expectations() |
| 988 | 931 |
| 989 # TODO(ojan): Allow for removing skipped tests when getting the list of | 932 # TODO(ojan): Allow for removing skipped tests when getting the list of |
| 990 # tests to run, but not when getting metrics. | 933 # tests to run, but not when getting metrics. |
| 991 def model(self): | 934 def model(self): |
| 992 return self._model | 935 return self._model |
| 993 | 936 |
| 994 def get_needs_rebaseline_failures(self): | 937 def get_needs_rebaseline_failures(self): |
| 995 return self._model.get_test_set_for_keyword(TestExpectationParser.NEEDS_ REBASELINE_MODIFIER) | 938 return self._model.get_test_set(NEEDS_REBASELINE) |
| 996 | 939 |
| 997 def get_rebaselining_failures(self): | 940 def get_rebaselining_failures(self): |
| 998 return self._model.get_test_set(REBASELINE) | 941 return self._model.get_test_set(REBASELINE) |
| 999 | 942 |
| 1000 # FIXME: Change the callsites to use TestExpectationsModel and remove. | 943 # FIXME: Change the callsites to use TestExpectationsModel and remove. |
| 1001 def get_expectations(self, test): | 944 def get_expectations(self, test): |
| 1002 return self._model.get_expectations(test) | 945 return self._model.get_expectations(test) |
| 1003 | 946 |
| 1004 # FIXME: Change the callsites to use TestExpectationsModel and remove. | 947 # FIXME: Change the callsites to use TestExpectationsModel and remove. |
| 1005 def has_modifier(self, test, modifier): | |
| 1006 return self._model.has_modifier(test, modifier) | |
| 1007 | |
| 1008 # FIXME: Change the callsites to use TestExpectationsModel and remove. | |
| 1009 def get_tests_with_result_type(self, result_type): | 948 def get_tests_with_result_type(self, result_type): |
| 1010 return self._model.get_tests_with_result_type(result_type) | 949 return self._model.get_tests_with_result_type(result_type) |
| 1011 | 950 |
| 1012 # FIXME: Change the callsites to use TestExpectationsModel and remove. | 951 # FIXME: Change the callsites to use TestExpectationsModel and remove. |
| 1013 def get_test_set(self, modifier, expectation=None, include_skips=True): | 952 def get_test_set(self, expectation, include_skips=True): |
| 1014 return self._model.get_test_set(modifier, expectation, include_skips) | 953 return self._model.get_test_set(expectation, include_skips) |
| 1015 | |
| 1016 # FIXME: Change the callsites to use TestExpectationsModel and remove. | |
| 1017 def get_modifiers(self, test): | |
| 1018 return self._model.get_modifiers(test) | |
| 1019 | 954 |
| 1020 # FIXME: Change the callsites to use TestExpectationsModel and remove. | 955 # FIXME: Change the callsites to use TestExpectationsModel and remove. |
| 1021 def get_tests_with_timeline(self, timeline): | 956 def get_tests_with_timeline(self, timeline): |
| 1022 return self._model.get_tests_with_timeline(timeline) | 957 return self._model.get_tests_with_timeline(timeline) |
| 1023 | 958 |
| 1024 def get_expectations_string(self, test): | 959 def get_expectations_string(self, test): |
| 1025 return self._model.get_expectations_string(test) | 960 return self._model.get_expectations_string(test) |
| 1026 | 961 |
| 1027 def expectation_to_string(self, expectation): | 962 def expectation_to_string(self, expectation): |
| 1028 return self._model.expectation_to_string(expectation) | 963 return self._model.expectation_to_string(expectation) |
| 1029 | 964 |
| 1030 def matches_an_expected_result(self, test, result, pixel_tests_are_enabled): | 965 def matches_an_expected_result(self, test, result, pixel_tests_are_enabled): |
| 1031 expected_results = self._model.get_expectations(test) | 966 expected_results = self._model.get_expectations(test) |
| 1032 if not pixel_tests_are_enabled: | 967 if not pixel_tests_are_enabled: |
| 1033 expected_results = self.remove_pixel_failures(expected_results) | 968 expected_results = self.remove_pixel_failures(expected_results) |
| 1034 return self.result_was_expected(result, expected_results, self.is_rebase lining(test)) | 969 return self.result_was_expected(result, expected_results, self.is_rebase lining(test)) |
| 1035 | 970 |
| 1036 def is_rebaselining(self, test): | 971 def is_rebaselining(self, test): |
| 1037 return self._model.has_modifier(test, REBASELINE) | 972 return REBASELINE in self._model.get_expectations(test) |
| 1038 | 973 |
| 1039 def _shorten_filename(self, filename): | 974 def _shorten_filename(self, filename): |
| 1040 if filename.startswith(self._port.path_from_webkit_base()): | 975 if filename.startswith(self._port.path_from_webkit_base()): |
| 1041 return self._port.host.filesystem.relpath(filename, self._port.path_ from_webkit_base()) | 976 return self._port.host.filesystem.relpath(filename, self._port.path_ from_webkit_base()) |
| 1042 return filename | 977 return filename |
| 1043 | 978 |
| 1044 def _report_warnings(self): | 979 def _report_warnings(self): |
| 1045 warnings = [] | 980 warnings = [] |
| 1046 for expectation in self._expectations: | 981 for expectation in self._expectations: |
| 1047 for warning in expectation.warnings: | 982 for warning in expectation.warnings: |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1086 index = self._expectations.index(expectation) | 1021 index = self._expectations.index(expectation) |
| 1087 self._expectations.remove(expectation) | 1022 self._expectations.remove(expectation) |
| 1088 | 1023 |
| 1089 if index == len(self._expectations) or self._expectations[index].is_ whitespace_or_comment(): | 1024 if index == len(self._expectations) or self._expectations[index].is_ whitespace_or_comment(): |
| 1090 while index and self._expectations[index - 1].is_whitespace_or_c omment(): | 1025 while index and self._expectations[index - 1].is_whitespace_or_c omment(): |
| 1091 index = index - 1 | 1026 index = index - 1 |
| 1092 self._expectations.pop(index) | 1027 self._expectations.pop(index) |
| 1093 | 1028 |
| 1094 return self.list_to_string(self._expectations, self._parser._test_config uration_converter, modified_expectations) | 1029 return self.list_to_string(self._expectations, self._parser._test_config uration_converter, modified_expectations) |
| 1095 | 1030 |
| 1096 def remove_rebaselined_tests(self, except_these_tests, filename): | |
|
Dirk Pranke
2013/07/26 23:07:28
I was a bit surprised that this was gone, but I gu
| |
| 1097 """Returns a copy of the expectations in the file with the tests removed .""" | |
| 1098 def without_rebaseline_modifier(expectation): | |
| 1099 return (expectation.filename == filename and | |
| 1100 not (not expectation.is_invalid() and | |
| 1101 expectation.name in except_these_tests and | |
| 1102 'rebaseline' in expectation.parsed_modifiers)) | |
| 1103 | |
| 1104 return self.list_to_string(filter(without_rebaseline_modifier, self._exp ectations), reconstitute_only_these=[]) | |
| 1105 | |
| 1106 def _add_expectations(self, expectation_list): | 1031 def _add_expectations(self, expectation_list): |
| 1107 for expectation_line in expectation_list: | 1032 for expectation_line in expectation_list: |
| 1108 if not expectation_line.expectations: | 1033 if not expectation_line.expectations: |
| 1109 continue | 1034 continue |
| 1110 | 1035 |
| 1111 if self._model_all_expectations or self._test_config in expectation_ line.matching_configurations: | 1036 if self._model_all_expectations or self._test_config in expectation_ line.matching_configurations: |
| 1112 self._model.add_expectation_line(expectation_line, model_all_exp ectations=self._model_all_expectations) | 1037 self._model.add_expectation_line(expectation_line, model_all_exp ectations=self._model_all_expectations) |
| 1113 | 1038 |
| 1114 def add_extra_skipped_tests(self, tests_to_skip): | 1039 def add_extra_skipped_tests(self, tests_to_skip): |
| 1115 if not tests_to_skip: | 1040 if not tests_to_skip: |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1149 # If reconstitute_only_these is an empty list, we want to return ori ginal_string. | 1074 # If reconstitute_only_these is an empty list, we want to return ori ginal_string. |
| 1150 # So we need to compare reconstitute_only_these to None, not just ch eck if it's falsey. | 1075 # So we need to compare reconstitute_only_these to None, not just ch eck if it's falsey. |
| 1151 if reconstitute_only_these is None or expectation_line in reconstitu te_only_these: | 1076 if reconstitute_only_these is None or expectation_line in reconstitu te_only_these: |
| 1152 return expectation_line.to_string(test_configuration_converter) | 1077 return expectation_line.to_string(test_configuration_converter) |
| 1153 return expectation_line.original_string | 1078 return expectation_line.original_string |
| 1154 | 1079 |
| 1155 def nones_out(expectation_line): | 1080 def nones_out(expectation_line): |
| 1156 return expectation_line is not None | 1081 return expectation_line is not None |
| 1157 | 1082 |
| 1158 return "\n".join(filter(nones_out, map(serialize, expectation_lines))) | 1083 return "\n".join(filter(nones_out, map(serialize, expectation_lines))) |
| OLD | NEW |