1 # Copyright (C) 2010 Google Inc. All rights reserved. 2 # 3 # Redistribution and use in source and binary forms, with or without 4 # modification, are permitted provided that the following conditions are 5 # met: 6 # 7 # * Redistributions of source code must retain the above copyright 8 # notice, this list of conditions and the following disclaimer. 9 # * Redistributions in binary form must reproduce the above 10 # copyright notice, this list of conditions and the following disclaimer 11 # in the documentation and/or other materials provided with the 12 # distribution. 13 # * Neither the name of Google Inc. nor the names of its 14 # contributors may be used to endorse or promote products derived from 15 # this software without specific prior written permission. 16 # 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 import webkitpy.thirdparty.unittest2 as unittest 30 31 from webkitpy.common.host_mock import MockHost 32 from webkitpy.common.system.outputcapture import OutputCapture 33 34 from webkitpy.layout_tests.models.test_configuration import * 35 from webkitpy.layout_tests.models.test_expectations import * 36 37 try: 38 from collections import OrderedDict 39 except ImportError: 40 # Needed for Python < 2.7 41 from webkitpy.thirdparty.ordered_dict import OrderedDict 42 43 44 class Base(unittest.TestCase): 45 # Note that all of these tests are written assuming the configuration 46 # being tested is Windows XP, Release build. 47 48 def __init__(self, testFunc): 49 host = MockHost() 50 self._port = host.port_factory.get('test-win-xp', None) 51 self._exp = None 52 unittest.TestCase.__init__(self, testFunc) 53 54 def get_test(self, test_name): 55 # FIXME: Remove this routine and just reference test names directly. 56 return test_name 57 58 def get_basic_tests(self): 59 return [self.get_test('failures/expected/text.html'), 60 self.get_test('failures/expected/image_checksum.html'), 61 self.get_test('failures/expected/crash.html'), 62 self.get_test('failures/expected/needsrebaseline.html'), 63 self.get_test('failures/expected/needsmanualrebaseline.html'), 64 self.get_test('failures/expected/missing_text.html'), 65 self.get_test('failures/expected/image.html'), 66 self.get_test('failures/expected/timeout.html'), 67 self.get_test('passes/text.html')] 68 69 70 def get_basic_expectations(self): 71 return """ 72 Bug(test) failures/expected/text.html [ Failure ] 73 Bug(test) failures/expected/crash.html [ WontFix ] 74 Bug(test) failures/expected/needsrebaseline.html [ NeedsRebaseline ] 75 Bug(test) failures/expected/needsmanualrebaseline.html [ NeedsManualRebaseline ] 76 Bug(test) failures/expected/missing_image.html [ Rebaseline Missing ] 77 Bug(test) failures/expected/image_checksum.html [ WontFix ] 78 Bug(test) failures/expected/image.html [ WontFix Mac ] 79 """ 80 81 def parse_exp(self, expectations, overrides=None, is_lint_mode=False): 82 expectations_dict = OrderedDict() 83 expectations_dict['expectations'] = expectations 84 if overrides: 85 expectations_dict['overrides'] = overrides 86 self._port.expectations_dict = lambda: expectations_dict 87 expectations_to_lint = expectations_dict if is_lint_mode else None 88 self._exp = TestExpectations(self._port, self.get_basic_tests(), expectations_dict=expectations_to_lint, is_lint_mode=is_lint_mode) 89 90 def assert_exp_list(self, test, results): 91 self.assertEqual(self._exp.get_expectations(self.get_test(test)), set(results)) 92 93 def assert_exp(self, test, result): 94 self.assert_exp_list(test, [result]) 95 96 def assert_bad_expectations(self, expectations, overrides=None): 97 self.assertRaises(ParseError, self.parse_exp, expectations, is_lint_mode=True, overrides=overrides) 98 99 100 class BasicTests(Base): 101 def test_basic(self): 102 self.parse_exp(self.get_basic_expectations()) 103 self.assert_exp('failures/expected/text.html', FAIL) 104 self.assert_exp_list('failures/expected/image_checksum.html', [WONTFIX, SKIP]) 105 self.assert_exp('passes/text.html', PASS) 106 self.assert_exp('failures/expected/image.html', PASS) 107 108 109 class MiscTests(Base): 110 def test_multiple_results(self): 111 self.parse_exp('Bug(x) failures/expected/text.html [ Crash Failure ]') 112 self.assertEqual(self._exp.get_expectations( 113 self.get_test('failures/expected/text.html')), 114 set([FAIL, CRASH])) 115 116 def test_result_was_expected(self): 117 # test basics 118 self.assertEqual(TestExpectations.result_was_expected(PASS, set([PASS]), test_needs_rebaselining=False), True) 119 self.assertEqual(TestExpectations.result_was_expected(FAIL, set([PASS]), test_needs_rebaselining=False), False) 120 121 # test handling of SKIPped tests and results 122 self.assertEqual(TestExpectations.result_was_expected(SKIP, set([CRASH]), test_needs_rebaselining=False), True) 123 self.assertEqual(TestExpectations.result_was_expected(SKIP, set([LEAK]), test_needs_rebaselining=False), True) 124 125 # test handling of MISSING results and the REBASELINE specifier 126 self.assertEqual(TestExpectations.result_was_expected(MISSING, set([PASS]), test_needs_rebaselining=True), True) 127 self.assertEqual(TestExpectations.result_was_expected(MISSING, set([PASS]), test_needs_rebaselining=False), False) 128 129 self.assertTrue(TestExpectations.result_was_expected(PASS, set([NEEDS_REBASELINE]), test_needs_rebaselining=False)) 130 self.assertTrue(TestExpectations.result_was_expected(MISSING, set([NEEDS_REBASELINE]), test_needs_rebaselining=False)) 131 self.assertTrue(TestExpectations.result_was_expected(TEXT, set([NEEDS_REBASELINE]), test_needs_rebaselining=False)) 132 self.assertTrue(TestExpectations.result_was_expected(IMAGE, set([NEEDS_REBASELINE]), test_needs_rebaselining=False)) 133 self.assertTrue(TestExpectations.result_was_expected(IMAGE_PLUS_TEXT, set([NEEDS_REBASELINE]), test_needs_rebaselining=False)) 134 self.assertTrue(TestExpectations.result_was_expected(AUDIO, set([NEEDS_REBASELINE]), test_needs_rebaselining=False)) 135 self.assertFalse(TestExpectations.result_was_expected(TIMEOUT, set([NEEDS_REBASELINE]), test_needs_rebaselining=False)) 136 self.assertFalse(TestExpectations.result_was_expected(CRASH, set([NEEDS_REBASELINE]), test_needs_rebaselining=False)) 137 self.assertFalse(TestExpectations.result_was_expected(LEAK, set([NEEDS_REBASELINE]), test_needs_rebaselining=False)) 138 139 def test_remove_pixel_failures(self): 140 self.assertEqual(TestExpectations.remove_pixel_failures(set([FAIL])), set([FAIL])) 141 self.assertEqual(TestExpectations.remove_pixel_failures(set([PASS])), set([PASS])) 142 self.assertEqual(TestExpectations.remove_pixel_failures(set([IMAGE])), set([PASS])) 143 self.assertEqual(TestExpectations.remove_pixel_failures(set([FAIL])), set([FAIL])) 144 self.assertEqual(TestExpectations.remove_pixel_failures(set([PASS, IMAGE, CRASH])), set([PASS, CRASH])) 145 146 def test_suffixes_for_expectations(self): 147 self.assertEqual(TestExpectations.suffixes_for_expectations(set([FAIL])), set(['txt', 'png', 'wav'])) 148 self.assertEqual(TestExpectations.suffixes_for_expectations(set([IMAGE])), set(['png'])) 149 self.assertEqual(TestExpectations.suffixes_for_expectations(set([FAIL, IMAGE, CRASH])), set(['txt', 'png', 'wav'])) 150 self.assertEqual(TestExpectations.suffixes_for_expectations(set()), set()) 151 152 def test_category_expectations(self): 153 # This test checks unknown tests are not present in the 154 # expectations and that known test part of a test category is 155 # present in the expectations. 156 exp_str = 'Bug(x) failures/expected [ WontFix ]' 157 self.parse_exp(exp_str) 158 test_name = 'failures/expected/unknown-test.html' 159 unknown_test = self.get_test(test_name) 160 self.assertRaises(KeyError, self._exp.get_expectations, 161 unknown_test) 162 self.assert_exp_list('failures/expected/crash.html', [WONTFIX, SKIP]) 163 164 def test_get_expectations_string(self): 165 self.parse_exp(self.get_basic_expectations()) 166 self.assertEqual(self._exp.get_expectations_string( 167 self.get_test('failures/expected/text.html')), 168 'FAIL') 169 170 def test_expectation_to_string(self): 171 # Normal cases are handled by other tests. 172 self.parse_exp(self.get_basic_expectations()) 173 self.assertRaises(ValueError, self._exp.expectation_to_string, 174 -1) 175 176 def test_get_test_set(self): 177 # Handle some corner cases for this routine not covered by other tests. 178 self.parse_exp(self.get_basic_expectations()) 179 s = self._exp.get_test_set(WONTFIX) 180 self.assertEqual(s, 181 set([self.get_test('failures/expected/crash.html'), 182 self.get_test('failures/expected/image_checksum.html')])) 183 184 def test_needs_rebaseline_reftest(self): 185 try: 186 filesystem = self._port.host.filesystem 187 filesystem.write_text_file(filesystem.join(self._port.layout_tests_dir(), 'failures/expected/needsrebaseline.html'), 'content') 188 filesystem.write_text_file(filesystem.join(self._port.layout_tests_dir(), 'failures/expected/needsrebaseline-expected.html'), 'content') 189 filesystem.write_text_file(filesystem.join(self._port.layout_tests_dir(), 'failures/expected/needsmanualrebaseline.html'), 'content') 190 filesystem.write_text_file(filesystem.join(self._port.layout_tests_dir(), 'failures/expected/needsmanualrebaseline-expected.html'), 'content') 191 self.parse_exp("""Bug(user) failures/expected/needsrebaseline.html [ NeedsRebaseline ] 192 Bug(user) failures/expected/needsmanualrebaseline.html [ NeedsManualRebaseline ]""", is_lint_mode=True) 193 self.assertFalse(True, "ParseError wasn't raised") 194 except ParseError, e: 195 warnings = """expectations:1 A reftest cannot be marked as NeedsRebaseline/NeedsManualRebaseline failures/expected/needsrebaseline.html 196 expectations:2 A reftest cannot be marked as NeedsRebaseline/NeedsManualRebaseline failures/expected/needsmanualrebaseline.html""" 197 self.assertEqual(str(e), warnings) 198 199 def test_parse_warning(self): 200 try: 201 filesystem = self._port.host.filesystem 202 filesystem.write_text_file(filesystem.join(self._port.layout_tests_dir(), 'disabled-test.html-disabled'), 'content') 203 self.get_test('disabled-test.html-disabled'), 204 self.parse_exp("Bug(user) [ FOO ] failures/expected/text.html [ Failure ]\n" 205 "Bug(user) non-existent-test.html [ Failure ]\n" 206 "Bug(user) disabled-test.html-disabled [ ImageOnlyFailure ]", is_lint_mode=True) 207 self.assertFalse(True, "ParseError wasn't raised") 208 except ParseError, e: 209 warnings = ("expectations:1 Unrecognized specifier 'foo' failures/expected/text.html\n" 210 "expectations:2 Path does not exist. non-existent-test.html") 211 self.assertEqual(str(e), warnings) 212 213 def test_parse_warnings_are_logged_if_not_in_lint_mode(self): 214 oc = OutputCapture() 215 try: 216 oc.capture_output() 217 self.parse_exp('-- this should be a syntax error', is_lint_mode=False) 218 finally: 219 _, _, logs = oc.restore_output() 220 self.assertNotEquals(logs, '') 221 222 def test_error_on_different_platform(self): 223 # parse_exp uses a Windows port. Assert errors on Mac show up in lint mode. 224 self.assertRaises(ParseError, self.parse_exp, 225 'Bug(test) [ Mac ] failures/expected/text.html [ Failure ]\nBug(test) [ Mac ] failures/expected/text.html [ Failure ]', 226 is_lint_mode=True) 227 228 def test_error_on_different_build_type(self): 229 # parse_exp uses a Release port. Assert errors on DEBUG show up in lint mode. 230 self.assertRaises(ParseError, self.parse_exp, 231 'Bug(test) [ Debug ] failures/expected/text.html [ Failure ]\nBug(test) [ Debug ] failures/expected/text.html [ Failure ]', 232 is_lint_mode=True) 233 234 def test_overrides(self): 235 self.parse_exp("Bug(exp) failures/expected/text.html [ Failure ]", 236 "Bug(override) failures/expected/text.html [ ImageOnlyFailure ]") 237 self.assert_exp_list('failures/expected/text.html', [FAIL, IMAGE]) 238 239 def test_overrides__directory(self): 240 self.parse_exp("Bug(exp) failures/expected/text.html [ Failure ]", 241 "Bug(override) failures/expected [ Crash ]") 242 self.assert_exp_list('failures/expected/text.html', [FAIL, CRASH]) 243 self.assert_exp_list('failures/expected/image.html', [CRASH]) 244 245 def test_overrides__duplicate(self): 246 self.assert_bad_expectations("Bug(exp) failures/expected/text.html [ Failure ]", 247 "Bug(override) failures/expected/text.html [ ImageOnlyFailure ]\n" 248 "Bug(override) failures/expected/text.html [ Crash ]\n") 249 250 def test_pixel_tests_flag(self): 251 def match(test, result, pixel_tests_enabled): 252 return self._exp.matches_an_expected_result( 253 self.get_test(test), result, pixel_tests_enabled, sanitizer_is_enabled=False) 254 255 self.parse_exp(self.get_basic_expectations()) 256 self.assertTrue(match('failures/expected/text.html', FAIL, True)) 257 self.assertTrue(match('failures/expected/text.html', FAIL, False)) 258 self.assertFalse(match('failures/expected/text.html', CRASH, True)) 259 self.assertFalse(match('failures/expected/text.html', CRASH, False)) 260 self.assertTrue(match('failures/expected/image_checksum.html', PASS, True)) 261 self.assertTrue(match('failures/expected/image_checksum.html', PASS, False)) 262 self.assertTrue(match('failures/expected/crash.html', PASS, False)) 263 self.assertTrue(match('failures/expected/needsrebaseline.html', TEXT, True)) 264 self.assertFalse(match('failures/expected/needsrebaseline.html', CRASH, True)) 265 self.assertTrue(match('failures/expected/needsmanualrebaseline.html', TEXT, True)) 266 self.assertFalse(match('failures/expected/needsmanualrebaseline.html', CRASH, True)) 267 self.assertTrue(match('passes/text.html', PASS, False)) 268 269 def test_sanitizer_flag(self): 270 def match(test, result): 271 return self._exp.matches_an_expected_result( 272 self.get_test(test), result, pixel_tests_are_enabled=False, sanitizer_is_enabled=True) 273 274 self.parse_exp(""" 275 Bug(test) failures/expected/crash.html [ Crash ] 276 Bug(test) failures/expected/image.html [ ImageOnlyFailure ] 277 Bug(test) failures/expected/text.html [ Failure ] 278 Bug(test) failures/expected/timeout.html [ Timeout ] 279 """) 280 self.assertTrue(match('failures/expected/crash.html', CRASH)) 281 self.assertTrue(match('failures/expected/image.html', PASS)) 282 self.assertTrue(match('failures/expected/text.html', PASS)) 283 self.assertTrue(match('failures/expected/timeout.html', TIMEOUT)) 284 285 def test_more_specific_override_resets_skip(self): 286 self.parse_exp("Bug(x) failures/expected [ Skip ]\n" 287 "Bug(x) failures/expected/text.html [ ImageOnlyFailure ]\n") 288 self.assert_exp('failures/expected/text.html', IMAGE) 289 self.assertFalse(self._port._filesystem.join(self._port.layout_tests_dir(), 290 'failures/expected/text.html') in 291 self._exp.get_tests_with_result_type(SKIP)) 292 293 def test_bot_test_expectations(self): 294 """Test that expectations are merged rather than overridden when using flaky option 'unexpected'.""" 295 test_name1 = 'failures/expected/text.html' 296 test_name2 = 'passes/text.html' 297 298 expectations_dict = OrderedDict() 299 expectations_dict['expectations'] = "Bug(x) %s [ ImageOnlyFailure ]\nBug(x) %s [ Slow ]\n" % (test_name1, test_name2) 300 self._port.expectations_dict = lambda: expectations_dict 301 302 expectations = TestExpectations(self._port, self.get_basic_tests()) 303 self.assertEqual(expectations.get_expectations(self.get_test(test_name1)), set([IMAGE])) 304 self.assertEqual(expectations.get_expectations(self.get_test(test_name2)), set([SLOW])) 305 306 def bot_expectations(): 307 return {test_name1: ['PASS', 'TIMEOUT'], test_name2: ['CRASH']} 308 self._port.bot_expectations = bot_expectations 309 self._port._options.ignore_flaky_tests = 'unexpected' 310 311 expectations = TestExpectations(self._port, self.get_basic_tests()) 312 self.assertEqual(expectations.get_expectations(self.get_test(test_name1)), set([PASS, IMAGE, TIMEOUT])) 313 self.assertEqual(expectations.get_expectations(self.get_test(test_name2)), set([CRASH, SLOW])) 314 315 class SkippedTests(Base): 316 def check(self, expectations, overrides, skips, lint=False, expected_results=[WONTFIX, SKIP, FAIL]): 317 port = MockHost().port_factory.get('test-win-xp') 318 port._filesystem.write_text_file(port._filesystem.join(port.layout_tests_dir(), 'failures/expected/text.html'), 'foo') 319 expectations_dict = OrderedDict() 320 expectations_dict['expectations'] = expectations 321 if overrides: 322 expectations_dict['overrides'] = overrides 323 port.expectations_dict = lambda: expectations_dict 324 port.skipped_layout_tests = lambda tests: set(skips) 325 expectations_to_lint = expectations_dict if lint else None 326 exp = TestExpectations(port, ['failures/expected/text.html'], expectations_dict=expectations_to_lint, is_lint_mode=lint) 327 self.assertEqual(exp.get_expectations('failures/expected/text.html'), set(expected_results)) 328 329 def test_skipped_tests_work(self): 330 self.check(expectations='', overrides=None, skips=['failures/expected/text.html'], expected_results=[WONTFIX, SKIP]) 331 332 def test_duplicate_skipped_test_fails_lint(self): 333 self.assertRaises(ParseError, self.check, expectations='Bug(x) failures/expected/text.html [ Failure ]\n', 334 overrides=None, skips=['failures/expected/text.html'], lint=True) 335 336 def test_skipped_file_overrides_expectations(self): 337 self.check(expectations='Bug(x) failures/expected/text.html [ Failure ]\n', overrides=None, 338 skips=['failures/expected/text.html']) 339 340 def test_skipped_dir_overrides_expectations(self): 341 self.check(expectations='Bug(x) failures/expected/text.html [ Failure ]\n', overrides=None, 342 skips=['failures/expected']) 343 344 def test_skipped_file_overrides_overrides(self): 345 self.check(expectations='', overrides='Bug(x) failures/expected/text.html [ Failure ]\n', 346 skips=['failures/expected/text.html']) 347 348 def test_skipped_dir_overrides_overrides(self): 349 self.check(expectations='', overrides='Bug(x) failures/expected/text.html [ Failure ]\n', 350 skips=['failures/expected']) 351 352 def test_skipped_entry_dont_exist(self): 353 port = MockHost().port_factory.get('test-win-xp') 354 expectations_dict = OrderedDict() 355 expectations_dict['expectations'] = '' 356 port.expectations_dict = lambda: expectations_dict 357 port.skipped_layout_tests = lambda tests: set(['foo/bar/baz.html']) 358 capture = OutputCapture() 359 capture.capture_output() 360 exp = TestExpectations(port) 361 _, _, logs = capture.restore_output() 362 self.assertEqual('The following test foo/bar/baz.html from the Skipped list doesn\'t exist\n', logs) 363 364 def test_expectations_string(self): 365 self.parse_exp(self.get_basic_expectations()) 366 notrun = 'failures/expected/text.html' 367 self._exp.add_extra_skipped_tests([notrun]) 368 self.assertEqual('NOTRUN', self._exp.get_expectations_string(notrun)) 369 370 371 class ExpectationSyntaxTests(Base): 372 def test_unrecognized_expectation(self): 373 self.assert_bad_expectations('Bug(test) failures/expected/text.html [ Unknown ]') 374 375 def test_macro(self): 376 exp_str = 'Bug(test) [ Win ] failures/expected/text.html [ Failure ]' 377 self.parse_exp(exp_str) 378 self.assert_exp('failures/expected/text.html', FAIL) 379 380 def assert_tokenize_exp(self, line, bugs=None, specifiers=None, expectations=None, warnings=None, comment=None, name='foo.html'): 381 bugs = bugs or [] 382 specifiers = specifiers or [] 383 expectations = expectations or [] 384 warnings = warnings or [] 385 filename = 'TestExpectations' 386 line_number = '1' 387 expectation_line = TestExpectationParser._tokenize_line(filename, line, line_number) 388 self.assertEqual(expectation_line.warnings, warnings) 389 self.assertEqual(expectation_line.name, name) 390 self.assertEqual(expectation_line.filename, filename) 391 self.assertEqual(expectation_line.line_numbers, line_number) 392 if not warnings: 393 self.assertEqual(expectation_line.specifiers, specifiers) 394 self.assertEqual(expectation_line.expectations, expectations) 395 396 def test_comments(self): 397 self.assert_tokenize_exp("# comment", name=None, comment="# comment") 398 self.assert_tokenize_exp("foo.html [ Pass ] # comment", comment="# comment", expectations=['PASS'], specifiers=[]) 399 400 def test_config_specifiers(self): 401 self.assert_tokenize_exp('[ Mac ] foo.html [ Failure ] ', specifiers=['MAC'], expectations=['FAIL']) 402 403 def test_unknown_config(self): 404 self.assert_tokenize_exp('[ Foo ] foo.html [ Pass ]', specifiers=['Foo'], expectations=['PASS']) 405 406 def test_unknown_expectation(self): 407 self.assert_tokenize_exp('foo.html [ Audio ]', warnings=['Unrecognized expectation "Audio"']) 408 409 def test_skip(self): 410 self.assert_tokenize_exp('foo.html [ Skip ]', specifiers=[], expectations=['SKIP']) 411 412 def test_slow(self): 413 self.assert_tokenize_exp('foo.html [ Slow ]', specifiers=[], expectations=['SLOW']) 414 415 def test_wontfix(self): 416 self.assert_tokenize_exp('foo.html [ WontFix ]', specifiers=[], expectations=['WONTFIX', 'SKIP']) 417 self.assert_tokenize_exp('foo.html [ WontFix ImageOnlyFailure ]', specifiers=[], expectations=['WONTFIX', 'SKIP'], 418 warnings=['A test marked Skip or WontFix must not have other expectations.']) 419 420 def test_blank_line(self): 421 self.assert_tokenize_exp('', name=None) 422 423 def test_warnings(self): 424 self.assert_tokenize_exp('[ Mac ]', warnings=['Did not find a test name.', 'Missing expectations.'], name=None) 425 self.assert_tokenize_exp('[ [', warnings=['unexpected "["', 'Missing expectations.'], name=None) 426 self.assert_tokenize_exp('crbug.com/12345 ]', warnings=['unexpected "]"', 'Missing expectations.'], name=None) 427 428 self.assert_tokenize_exp('foo.html crbug.com/12345 ]', warnings=['"crbug.com/12345" is not at the start of the line.', 'Missing expectations.']) 429 self.assert_tokenize_exp('foo.html', warnings=['Missing expectations.']) 430 431 432 class SemanticTests(Base): 433 def test_bug_format(self): 434 self.assertRaises(ParseError, self.parse_exp, 'BUG1234 failures/expected/text.html [ Failure ]', is_lint_mode=True) 435 436 def test_bad_bugid(self): 437 try: 438 self.parse_exp('crbug/1234 failures/expected/text.html [ Failure ]', is_lint_mode=True) 439 self.fail('should have raised an error about a bad bug identifier') 440 except ParseError, exp: 441 self.assertEqual(len(exp.warnings), 3) 442 443 def test_missing_bugid(self): 444 self.parse_exp('failures/expected/text.html [ Failure ]', is_lint_mode=False) 445 self.assertFalse(self._exp.has_warnings()) 446 447 try: 448 self.parse_exp('failures/expected/text.html [ Failure ]', is_lint_mode=True) 449 except ParseError, exp: 450 self.assertEqual(exp.warnings, ['expectations:1 Test lacks BUG specifier. failures/expected/text.html']) 451 452 def test_skip_and_wontfix(self): 453 # Skip is not allowed to have other expectations as well, because those 454 # expectations won't be exercised and may become stale . 455 self.parse_exp('failures/expected/text.html [ Failure Skip ]') 456 self.assertTrue(self._exp.has_warnings()) 457 458 self.parse_exp('failures/expected/text.html [ Crash WontFix ]') 459 self.assertTrue(self._exp.has_warnings()) 460 461 self.parse_exp('failures/expected/text.html [ Pass WontFix ]') 462 self.assertTrue(self._exp.has_warnings()) 463 464 def test_rebaseline(self): 465 # Can't lint a file w/ 'REBASELINE' in it. 466 self.assertRaises(ParseError, self.parse_exp, 467 'Bug(test) failures/expected/text.html [ Failure Rebaseline ]', 468 is_lint_mode=True) 469 470 def test_duplicates(self): 471 self.assertRaises(ParseError, self.parse_exp, """ 472 Bug(exp) failures/expected/text.html [ Failure ] 473 Bug(exp) failures/expected/text.html [ ImageOnlyFailure ]""", is_lint_mode=True) 474 475 self.assertRaises(ParseError, self.parse_exp, 476 self.get_basic_expectations(), overrides=""" 477 Bug(override) failures/expected/text.html [ Failure ] 478 Bug(override) failures/expected/text.html [ ImageOnlyFailure ]""", is_lint_mode=True) 479 480 def test_duplicate_with_line_before_preceding_line(self): 481 self.assert_bad_expectations("""Bug(exp) [ Debug ] failures/expected/text.html [ Failure ] 482 Bug(exp) [ Release ] failures/expected/text.html [ Failure ] 483 Bug(exp) [ Debug ] failures/expected/text.html [ Failure ] 484 """) 485 486 def test_missing_file(self): 487 self.parse_exp('Bug(test) missing_file.html [ Failure ]') 488 self.assertTrue(self._exp.has_warnings(), 1) 489 490 491 class PrecedenceTests(Base): 492 def test_file_over_directory(self): 493 # This tests handling precedence of specific lines over directories 494 # and tests expectations covering entire directories. 495 exp_str = """ 496 Bug(x) failures/expected/text.html [ Failure ] 497 Bug(y) failures/expected [ WontFix ] 498 """ 499 self.parse_exp(exp_str) 500 self.assert_exp('failures/expected/text.html', FAIL) 501 self.assert_exp_list('failures/expected/crash.html', [WONTFIX, SKIP]) 502 503 exp_str = """ 504 Bug(x) failures/expected [ WontFix ] 505 Bug(y) failures/expected/text.html [ Failure ] 506 """ 507 self.parse_exp(exp_str) 508 self.assert_exp('failures/expected/text.html', FAIL) 509 self.assert_exp_list('failures/expected/crash.html', [WONTFIX, SKIP]) 510 511 def test_ambiguous(self): 512 self.assert_bad_expectations("Bug(test) [ Release ] passes/text.html [ Pass ]\n" 513 "Bug(test) [ Win ] passes/text.html [ Failure ]\n") 514 515 def test_more_specifiers(self): 516 self.assert_bad_expectations("Bug(test) [ Release ] passes/text.html [ Pass ]\n" 517 "Bug(test) [ Win Release ] passes/text.html [ Failure ]\n") 518 519 def test_order_in_file(self): 520 self.assert_bad_expectations("Bug(test) [ Win Release ] : passes/text.html [ Failure ]\n" 521 "Bug(test) [ Release ] : passes/text.html [ Pass ]\n") 522 523 def test_macro_overrides(self): 524 self.assert_bad_expectations("Bug(test) [ Win ] passes/text.html [ Pass ]\n" 525 "Bug(test) [ XP ] passes/text.html [ Failure ]\n") 526 527 528 class RemoveConfigurationsTest(Base): 529 def test_remove(self): 530 host = MockHost() 531 test_port = host.port_factory.get('test-win-xp', None) 532 test_port.test_exists = lambda test: True 533 test_port.test_isfile = lambda test: True 534 535 test_config = test_port.test_configuration() 536 test_port.expectations_dict = lambda: {"expectations": """Bug(x) [ Linux Win Release ] failures/expected/foo.html [ Failure ] 537 Bug(y) [ Win Mac Debug ] failures/expected/foo.html [ Crash ] 538 """} 539 expectations = TestExpectations(test_port, self.get_basic_tests()) 540 541 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', test_config)]) 542 543 self.assertEqual("""Bug(x) [ Linux Win7 Release ] failures/expected/foo.html [ Failure ] 544 Bug(y) [ Win Mac Debug ] failures/expected/foo.html [ Crash ] 545 """, actual_expectations) 546 547 def test_remove_needs_rebaseline(self): 548 host = MockHost() 549 test_port = host.port_factory.get('test-win-xp', None) 550 test_port.test_exists = lambda test: True 551 test_port.test_isfile = lambda test: True 552 553 test_config = test_port.test_configuration() 554 test_port.expectations_dict = lambda: {"expectations": """Bug(x) [ Win ] failures/expected/foo.html [ NeedsRebaseline ] 555 """} 556 expectations = TestExpectations(test_port, self.get_basic_tests()) 557 558 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', test_config)]) 559 560 self.assertEqual("""Bug(x) [ XP Debug ] failures/expected/foo.html [ NeedsRebaseline ] 561 Bug(x) [ Win7 ] failures/expected/foo.html [ NeedsRebaseline ] 562 """, actual_expectations) 563 564 def test_remove_multiple_configurations(self): 565 host = MockHost() 566 test_port = host.port_factory.get('test-win-xp', None) 567 test_port.test_exists = lambda test: True 568 test_port.test_isfile = lambda test: True 569 570 test_config = test_port.test_configuration() 571 test_port.expectations_dict = lambda: {'expectations': """Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ] 572 Bug(x) [ Win Release ] failures/expected/foo.html [ Failure ] 573 """} 574 expectations = TestExpectations(test_port) 575 576 actual_expectations = expectations.remove_configurations([ 577 ('failures/expected/foo.html', test_config), 578 ('failures/expected/foo.html', host.port_factory.get('test-win-win7', None).test_configuration()), 579 ]) 580 581 self.assertEqual("""Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ] 582 """, actual_expectations) 583 584 def test_remove_line_with_comments(self): 585 host = MockHost() 586 test_port = host.port_factory.get('test-win-xp', None) 587 test_port.test_exists = lambda test: True 588 test_port.test_isfile = lambda test: True 589 590 test_config = test_port.test_configuration() 591 test_port.expectations_dict = lambda: {'expectations': """Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ] 592 593 # This comment line should get stripped. As should the preceding line. 594 Bug(x) [ Win Release ] failures/expected/foo.html [ Failure ] 595 """} 596 expectations = TestExpectations(test_port) 597 598 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', test_config)]) 599 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', host.port_factory.get('test-win-win7', None).test_configuration())]) 600 601 self.assertEqual("""Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ] 602 """, actual_expectations) 603 604 def test_remove_line_with_comments_at_start(self): 605 host = MockHost() 606 test_port = host.port_factory.get('test-win-xp', None) 607 test_port.test_exists = lambda test: True 608 test_port.test_isfile = lambda test: True 609 610 test_config = test_port.test_configuration() 611 test_port.expectations_dict = lambda: {'expectations': """ 612 # This comment line should get stripped. As should the preceding line. 613 Bug(x) [ Win Release ] failures/expected/foo.html [ Failure ] 614 615 Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ] 616 """} 617 expectations = TestExpectations(test_port) 618 619 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', test_config)]) 620 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', host.port_factory.get('test-win-win7', None).test_configuration())]) 621 622 self.assertEqual(""" 623 Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ] 624 """, actual_expectations) 625 626 def test_remove_line_with_comments_at_end_with_no_trailing_newline(self): 627 host = MockHost() 628 test_port = host.port_factory.get('test-win-xp', None) 629 test_port.test_exists = lambda test: True 630 test_port.test_isfile = lambda test: True 631 632 test_config = test_port.test_configuration() 633 test_port.expectations_dict = lambda: {'expectations': """Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ] 634 635 # This comment line should get stripped. As should the preceding line. 636 Bug(x) [ Win Release ] failures/expected/foo.html [ Failure ]"""} 637 expectations = TestExpectations(test_port) 638 639 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', test_config)]) 640 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', host.port_factory.get('test-win-win7', None).test_configuration())]) 641 642 self.assertEqual("""Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ]""", actual_expectations) 643 644 def test_remove_line_leaves_comments_for_next_line(self): 645 host = MockHost() 646 test_port = host.port_factory.get('test-win-xp', None) 647 test_port.test_exists = lambda test: True 648 test_port.test_isfile = lambda test: True 649 650 test_config = test_port.test_configuration() 651 test_port.expectations_dict = lambda: {'expectations': """ 652 # This comment line should not get stripped. 653 Bug(x) [ Win Release ] failures/expected/foo.html [ Failure ] 654 Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ] 655 """} 656 expectations = TestExpectations(test_port) 657 658 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', test_config)]) 659 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', host.port_factory.get('test-win-win7', None).test_configuration())]) 660 661 self.assertEqual(""" 662 # This comment line should not get stripped. 663 Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ] 664 """, actual_expectations) 665 666 def test_remove_line_no_whitespace_lines(self): 667 host = MockHost() 668 test_port = host.port_factory.get('test-win-xp', None) 669 test_port.test_exists = lambda test: True 670 test_port.test_isfile = lambda test: True 671 672 test_config = test_port.test_configuration() 673 test_port.expectations_dict = lambda: {'expectations': """ 674 # This comment line should get stripped. 675 Bug(x) [ Win Release ] failures/expected/foo.html [ Failure ] 676 # This comment line should not get stripped. 677 Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ] 678 """} 679 expectations = TestExpectations(test_port) 680 681 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', test_config)]) 682 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', host.port_factory.get('test-win-win7', None).test_configuration())]) 683 684 self.assertEqual(""" # This comment line should not get stripped. 685 Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ] 686 """, actual_expectations) 687 688 def test_remove_first_line(self): 689 host = MockHost() 690 test_port = host.port_factory.get('test-win-xp', None) 691 test_port.test_exists = lambda test: True 692 test_port.test_isfile = lambda test: True 693 694 test_config = test_port.test_configuration() 695 test_port.expectations_dict = lambda: {'expectations': """Bug(x) [ Win Release ] failures/expected/foo.html [ Failure ] 696 # This comment line should not get stripped. 697 Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ] 698 """} 699 expectations = TestExpectations(test_port) 700 701 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', test_config)]) 702 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', host.port_factory.get('test-win-win7', None).test_configuration())]) 703 704 self.assertEqual(""" # This comment line should not get stripped. 705 Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ] 706 """, actual_expectations) 707 708 def test_remove_flaky_line(self): 709 host = MockHost() 710 test_port = host.port_factory.get('test-win-xp', None) 711 test_port.test_exists = lambda test: True 712 test_port.test_isfile = lambda test: True 713 714 test_config = test_port.test_configuration() 715 test_port.expectations_dict = lambda: {'expectations': """Bug(x) [ Win ] failures/expected/foo.html [ Failure Timeout ] 716 Bug(y) [ Mac ] failures/expected/foo.html [ Crash ] 717 """} 718 expectations = TestExpectations(test_port) 719 720 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', test_config)]) 721 actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', host.port_factory.get('test-win-win7', None).test_configuration())]) 722 723 self.assertEqual("""Bug(x) [ Win Debug ] failures/expected/foo.html [ Failure Timeout ] 724 Bug(y) [ Mac ] failures/expected/foo.html [ Crash ] 725 """, actual_expectations) 726 727 728 class RebaseliningTest(Base): 729 def test_get_rebaselining_failures(self): 730 # Make sure we find a test as needing a rebaseline even if it is not marked as a failure. 731 self.parse_exp('Bug(x) failures/expected/text.html [ Rebaseline ]\n') 732 self.assertEqual(len(self._exp.get_rebaselining_failures()), 1) 733 734 self.parse_exp(self.get_basic_expectations()) 735 self.assertEqual(len(self._exp.get_rebaselining_failures()), 0) 736 737 738 class TestExpectationsParserTests(unittest.TestCase): 739 def __init__(self, testFunc): 740 host = MockHost() 741 test_port = host.port_factory.get('test-win-xp', None) 742 self._converter = TestConfigurationConverter(test_port.all_test_configurations(), test_port.configuration_specifier_macros()) 743 unittest.TestCase.__init__(self, testFunc) 744 self._parser = TestExpectationParser(host.port_factory.get('test-win-xp', None), [], is_lint_mode=False) 745 746 def test_expectation_line_for_test(self): 747 # This is kind of a silly test, but it at least ensures that we don't throw an error. 748 test_name = 'foo/test.html' 749 expectations = set(["PASS", "IMAGE"]) 750 751 expectation_line = TestExpectationLine() 752 expectation_line.original_string = test_name 753 expectation_line.name = test_name 754 expectation_line.filename = '<Bot TestExpectations>' 755 expectation_line.line_numbers = '0' 756 expectation_line.expectations = expectations 757 self._parser._parse_line(expectation_line) 758 759 self.assertEqual(self._parser.expectation_line_for_test(test_name, expectations), expectation_line) 760 761 762 class TestExpectationSerializationTests(unittest.TestCase): 763 def __init__(self, testFunc): 764 host = MockHost() 765 test_port = host.port_factory.get('test-win-xp', None) 766 self._converter = TestConfigurationConverter(test_port.all_test_configurations(), test_port.configuration_specifier_macros()) 767 unittest.TestCase.__init__(self, testFunc) 768 769 def _tokenize(self, line): 770 return TestExpectationParser._tokenize_line('path', line, 0) 771 772 def assert_round_trip(self, in_string, expected_string=None): 773 expectation = self._tokenize(in_string) 774 if expected_string is None: 775 expected_string = in_string 776 self.assertEqual(expected_string, expectation.to_string(self._converter)) 777 778 def assert_list_round_trip(self, in_string, expected_string=None): 779 host = MockHost() 780 parser = TestExpectationParser(host.port_factory.get('test-win-xp', None), [], is_lint_mode=False) 781 expectations = parser.parse('path', in_string) 782 if expected_string is None: 783 expected_string = in_string 784 self.assertEqual(expected_string, TestExpectations.list_to_string(expectations, self._converter)) 785 786 def test_unparsed_to_string(self): 787 expectation = TestExpectationLine() 788 789 self.assertEqual(expectation.to_string(self._converter), '') 790 expectation.comment = ' Qux.' 791 self.assertEqual(expectation.to_string(self._converter), '# Qux.') 792 expectation.name = 'bar' 793 self.assertEqual(expectation.to_string(self._converter), 'bar # Qux.') 794 expectation.specifiers = ['foo'] 795 # FIXME: case should be preserved here but we can't until we drop the old syntax. 796 self.assertEqual(expectation.to_string(self._converter), '[ FOO ] bar # Qux.') 797 expectation.expectations = ['bAz'] 798 self.assertEqual(expectation.to_string(self._converter), '[ FOO ] bar [ BAZ ] # Qux.') 799 expectation.expectations = ['bAz1', 'baZ2'] 800 self.assertEqual(expectation.to_string(self._converter), '[ FOO ] bar [ BAZ1 BAZ2 ] # Qux.') 801 expectation.specifiers = ['foo1', 'foO2'] 802 self.assertEqual(expectation.to_string(self._converter), '[ FOO1 FOO2 ] bar [ BAZ1 BAZ2 ] # Qux.') 803 expectation.warnings.append('Oh the horror.') 804 self.assertEqual(expectation.to_string(self._converter), '') 805 expectation.original_string = 'Yes it is!' 806 self.assertEqual(expectation.to_string(self._converter), 'Yes it is!') 807 808 def test_unparsed_list_to_string(self): 809 expectation = TestExpectationLine() 810 expectation.comment = 'Qux.' 811 expectation.name = 'bar' 812 expectation.specifiers = ['foo'] 813 expectation.expectations = ['bAz1', 'baZ2'] 814 # FIXME: case should be preserved here but we can't until we drop the old syntax. 815 self.assertEqual(TestExpectations.list_to_string([expectation]), '[ FOO ] bar [ BAZ1 BAZ2 ] #Qux.') 816 817 def test_parsed_to_string(self): 818 expectation_line = TestExpectationLine() 819 expectation_line.bugs = ['Bug(x)'] 820 expectation_line.name = 'test/name/for/realz.html' 821 expectation_line.parsed_expectations = set([IMAGE]) 822 self.assertEqual(expectation_line.to_string(self._converter), None) 823 expectation_line.matching_configurations = set([TestConfiguration('xp', 'x86', 'release')]) 824 self.assertEqual(expectation_line.to_string(self._converter), 'Bug(x) [ XP Release ] test/name/for/realz.html [ ImageOnlyFailure ]') 825 expectation_line.matching_configurations = set([TestConfiguration('xp', 'x86', 'release'), TestConfiguration('xp', 'x86', 'debug')]) 826 self.assertEqual(expectation_line.to_string(self._converter), 'Bug(x) [ XP ] test/name/for/realz.html [ ImageOnlyFailure ]') 827 828 def test_serialize_parsed_expectations(self): 829 expectation_line = TestExpectationLine() 830 expectation_line.parsed_expectations = set([]) 831 parsed_expectation_to_string = dict([[parsed_expectation, expectation_string] for expectation_string, parsed_expectation in TestExpectations.EXPECTATIONS.items()]) 832 self.assertEqual(expectation_line._serialize_parsed_expectations(parsed_expectation_to_string), '') 833 expectation_line.parsed_expectations = set([FAIL]) 834 self.assertEqual(expectation_line._serialize_parsed_expectations(parsed_expectation_to_string), 'fail') 835 expectation_line.parsed_expectations = set([PASS, IMAGE]) 836 self.assertEqual(expectation_line._serialize_parsed_expectations(parsed_expectation_to_string), 'image pass') 837 expectation_line.parsed_expectations = set([FAIL, PASS]) 838 self.assertEqual(expectation_line._serialize_parsed_expectations(parsed_expectation_to_string), 'pass fail') 839 840 def test_serialize_parsed_specifier_string(self): 841 expectation_line = TestExpectationLine() 842 expectation_line.bugs = ['garden-o-matic'] 843 expectation_line.parsed_specifiers = ['the', 'for'] 844 self.assertEqual(expectation_line._serialize_parsed_specifiers(self._converter, []), 'for the') 845 self.assertEqual(expectation_line._serialize_parsed_specifiers(self._converter, ['win']), 'for the win') 846 expectation_line.bugs = [] 847 expectation_line.parsed_specifiers = [] 848 self.assertEqual(expectation_line._serialize_parsed_specifiers(self._converter, []), '') 849 self.assertEqual(expectation_line._serialize_parsed_specifiers(self._converter, ['win']), 'win') 850 851 def test_format_line(self): 852 self.assertEqual(TestExpectationLine._format_line([], ['MODIFIERS'], 'name', ['EXPECTATIONS'], 'comment'), '[ MODIFIERS ] name [ EXPECTATIONS ] #comment') 853 self.assertEqual(TestExpectationLine._format_line([], ['MODIFIERS'], 'name', ['EXPECTATIONS'], None), '[ MODIFIERS ] name [ EXPECTATIONS ]') 854 855 def test_string_roundtrip(self): 856 self.assert_round_trip('') 857 self.assert_round_trip('[') 858 self.assert_round_trip('FOO [') 859 self.assert_round_trip('FOO ] bar') 860 self.assert_round_trip(' FOO [') 861 self.assert_round_trip(' [ FOO ] ') 862 self.assert_round_trip('[ FOO ] bar [ BAZ ]') 863 self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux.') 864 self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux.') 865 self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux. ') 866 self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux. ') 867 self.assert_round_trip('[ FOO ] ] ] bar BAZ') 868 self.assert_round_trip('[ FOO ] ] ] bar [ BAZ ]') 869 self.assert_round_trip('FOO ] ] bar ==== BAZ') 870 self.assert_round_trip('=') 871 self.assert_round_trip('#') 872 self.assert_round_trip('# ') 873 self.assert_round_trip('# Foo') 874 self.assert_round_trip('# Foo') 875 self.assert_round_trip('# Foo :') 876 self.assert_round_trip('# Foo : =') 877 878 def test_list_roundtrip(self): 879 self.assert_list_round_trip('') 880 self.assert_list_round_trip('\n') 881 self.assert_list_round_trip('\n\n') 882 self.assert_list_round_trip('bar') 883 self.assert_list_round_trip('bar\n# Qux.') 884 self.assert_list_round_trip('bar\n# Qux.\n') 885 886 def test_reconstitute_only_these(self): 887 lines = [] 888 reconstitute_only_these = [] 889 890 def add_line(matching_configurations, reconstitute): 891 expectation_line = TestExpectationLine() 892 expectation_line.original_string = "Nay" 893 expectation_line.bugs = ['Bug(x)'] 894 expectation_line.name = 'Yay' 895 expectation_line.parsed_expectations = set([IMAGE]) 896 expectation_line.matching_configurations = matching_configurations 897 lines.append(expectation_line) 898 if reconstitute: 899 reconstitute_only_these.append(expectation_line) 900 901 add_line(set([TestConfiguration('xp', 'x86', 'release')]), True) 902 add_line(set([TestConfiguration('xp', 'x86', 'release'), TestConfiguration('xp', 'x86', 'debug')]), False) 903 serialized = TestExpectations.list_to_string(lines, self._converter) 904 self.assertEqual(serialized, "Bug(x) [ XP Release ] Yay [ ImageOnlyFailure ]\nBug(x) [ XP ] Yay [ ImageOnlyFailure ]") 905 serialized = TestExpectations.list_to_string(lines, self._converter, reconstitute_only_these=reconstitute_only_these) 906 self.assertEqual(serialized, "Bug(x) [ XP Release ] Yay [ ImageOnlyFailure ]\nNay") 907 908 def disabled_test_string_whitespace_stripping(self): 909 # FIXME: Re-enable this test once we rework the code to no longer support the old syntax. 910 self.assert_round_trip('\n', '') 911 self.assert_round_trip(' [ FOO ] bar [ BAZ ]', '[ FOO ] bar [ BAZ ]') 912 self.assert_round_trip('[ FOO ] bar [ BAZ ]', '[ FOO ] bar [ BAZ ]') 913 self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux.', '[ FOO ] bar [ BAZ ] # Qux.') 914 self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux.', '[ FOO ] bar [ BAZ ] # Qux.') 915 self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux.', '[ FOO ] bar [ BAZ ] # Qux.') 916 self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux.', '[ FOO ] bar [ BAZ ] # Qux.') 917