test_expectations_unittest.py 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  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. import unittest2 as unittest
  29. from webkitpy.common.host_mock import MockHost
  30. from webkitpy.common.system.outputcapture import OutputCapture
  31. from webkitpy.layout_tests.models.test_configuration import *
  32. from webkitpy.layout_tests.models.test_expectations import *
  33. from webkitpy.layout_tests.models.test_configuration import *
  34. try:
  35. from collections import OrderedDict
  36. except ImportError:
  37. # Needed for Python < 2.7
  38. from webkitpy.thirdparty.ordered_dict import OrderedDict
  39. class Base(unittest.TestCase):
  40. # Note that all of these tests are written assuming the configuration
  41. # being tested is Windows XP, Release build.
  42. def __init__(self, testFunc):
  43. host = MockHost()
  44. self._port = host.port_factory.get('test-win-xp', None)
  45. self._exp = None
  46. unittest.TestCase.__init__(self, testFunc)
  47. def get_test(self, test_name):
  48. # FIXME: Remove this routine and just reference test names directly.
  49. return test_name
  50. def get_basic_tests(self):
  51. return [self.get_test('failures/expected/text.html'),
  52. self.get_test('failures/expected/image_checksum.html'),
  53. self.get_test('failures/expected/crash.html'),
  54. self.get_test('failures/expected/missing_text.html'),
  55. self.get_test('failures/expected/image.html'),
  56. self.get_test('passes/text.html')]
  57. def get_basic_expectations(self):
  58. return """
  59. Bug(test) failures/expected/text.html [ Failure ]
  60. Bug(test) failures/expected/crash.html [ WontFix ]
  61. Bug(test) failures/expected/missing_image.html [ Rebaseline Missing ]
  62. Bug(test) failures/expected/image_checksum.html [ WontFix ]
  63. Bug(test) failures/expected/image.html [ WontFix Mac ]
  64. """
  65. def parse_exp(self, expectations, overrides=None, is_lint_mode=False):
  66. expectations_dict = OrderedDict()
  67. expectations_dict['expectations'] = expectations
  68. if overrides:
  69. expectations_dict['overrides'] = overrides
  70. self._port.expectations_dict = lambda: expectations_dict
  71. expectations_to_lint = expectations_dict if is_lint_mode else None
  72. self._exp = TestExpectations(self._port, self.get_basic_tests(), expectations_to_lint=expectations_to_lint)
  73. def assert_exp(self, test, result):
  74. self.assertEqual(self._exp.get_expectations(self.get_test(test)),
  75. set([result]))
  76. def assert_bad_expectations(self, expectations, overrides=None):
  77. self.assertRaises(ParseError, self.parse_exp, expectations, is_lint_mode=True, overrides=overrides)
  78. class BasicTests(Base):
  79. def test_basic(self):
  80. self.parse_exp(self.get_basic_expectations())
  81. self.assert_exp('failures/expected/text.html', FAIL)
  82. self.assert_exp('failures/expected/image_checksum.html', PASS)
  83. self.assert_exp('passes/text.html', PASS)
  84. self.assert_exp('failures/expected/image.html', PASS)
  85. class MiscTests(Base):
  86. def test_multiple_results(self):
  87. self.parse_exp('Bug(x) failures/expected/text.html [ Crash Failure ]')
  88. self.assertEqual(self._exp.get_expectations(
  89. self.get_test('failures/expected/text.html')),
  90. set([FAIL, CRASH]))
  91. def test_result_was_expected(self):
  92. # test basics
  93. self.assertEqual(TestExpectations.result_was_expected(PASS, set([PASS]), test_needs_rebaselining=False, test_is_skipped=False), True)
  94. self.assertEqual(TestExpectations.result_was_expected(FAIL, set([PASS]), test_needs_rebaselining=False, test_is_skipped=False), False)
  95. # test handling of SKIPped tests and results
  96. self.assertEqual(TestExpectations.result_was_expected(SKIP, set([CRASH]), test_needs_rebaselining=False, test_is_skipped=True), True)
  97. self.assertEqual(TestExpectations.result_was_expected(SKIP, set([CRASH]), test_needs_rebaselining=False, test_is_skipped=False), False)
  98. # test handling of MISSING results and the REBASELINE modifier
  99. self.assertEqual(TestExpectations.result_was_expected(MISSING, set([PASS]), test_needs_rebaselining=True, test_is_skipped=False), True)
  100. self.assertEqual(TestExpectations.result_was_expected(MISSING, set([PASS]), test_needs_rebaselining=False, test_is_skipped=False), False)
  101. def test_remove_pixel_failures(self):
  102. self.assertEqual(TestExpectations.remove_pixel_failures(set([FAIL])), set([FAIL]))
  103. self.assertEqual(TestExpectations.remove_pixel_failures(set([PASS])), set([PASS]))
  104. self.assertEqual(TestExpectations.remove_pixel_failures(set([IMAGE])), set([PASS]))
  105. self.assertEqual(TestExpectations.remove_pixel_failures(set([FAIL])), set([FAIL]))
  106. self.assertEqual(TestExpectations.remove_pixel_failures(set([PASS, IMAGE, CRASH])), set([PASS, CRASH]))
  107. def test_suffixes_for_expectations(self):
  108. self.assertEqual(TestExpectations.suffixes_for_expectations(set([FAIL])), set(['txt', 'png', 'wav']))
  109. self.assertEqual(TestExpectations.suffixes_for_expectations(set([IMAGE])), set(['png']))
  110. self.assertEqual(TestExpectations.suffixes_for_expectations(set([FAIL, IMAGE, CRASH])), set(['txt', 'png', 'wav']))
  111. self.assertEqual(TestExpectations.suffixes_for_expectations(set()), set())
  112. def test_category_expectations(self):
  113. # This test checks unknown tests are not present in the
  114. # expectations and that known test part of a test category is
  115. # present in the expectations.
  116. exp_str = 'Bug(x) failures/expected [ WontFix ]'
  117. self.parse_exp(exp_str)
  118. test_name = 'failures/expected/unknown-test.html'
  119. unknown_test = self.get_test(test_name)
  120. self.assertRaises(KeyError, self._exp.get_expectations,
  121. unknown_test)
  122. self.assert_exp('failures/expected/crash.html', PASS)
  123. def test_get_modifiers(self):
  124. self.parse_exp(self.get_basic_expectations())
  125. self.assertEqual(self._exp.get_modifiers(
  126. self.get_test('passes/text.html')), [])
  127. def test_get_expectations_string(self):
  128. self.parse_exp(self.get_basic_expectations())
  129. self.assertEqual(self._exp.get_expectations_string(
  130. self.get_test('failures/expected/text.html')),
  131. 'FAIL')
  132. def test_expectation_to_string(self):
  133. # Normal cases are handled by other tests.
  134. self.parse_exp(self.get_basic_expectations())
  135. self.assertRaises(ValueError, self._exp.expectation_to_string,
  136. -1)
  137. def test_get_test_set(self):
  138. # Handle some corner cases for this routine not covered by other tests.
  139. self.parse_exp(self.get_basic_expectations())
  140. s = self._exp.get_test_set(WONTFIX)
  141. self.assertEqual(s,
  142. set([self.get_test('failures/expected/crash.html'),
  143. self.get_test('failures/expected/image_checksum.html')]))
  144. def test_parse_warning(self):
  145. try:
  146. filesystem = self._port.host.filesystem
  147. filesystem.write_text_file(filesystem.join(self._port.layout_tests_dir(), 'disabled-test.html-disabled'), 'content')
  148. self.get_test('disabled-test.html-disabled'),
  149. self.parse_exp("[ FOO ] failures/expected/text.html [ Failure ]\n"
  150. "Bug(rniwa) non-existent-test.html [ Failure ]\n"
  151. "Bug(rniwa) disabled-test.html-disabled [ ImageOnlyFailure ]", is_lint_mode=True)
  152. self.assertFalse(True, "ParseError wasn't raised")
  153. except ParseError, e:
  154. warnings = ("expectations:1 Unrecognized modifier 'foo' failures/expected/text.html\n"
  155. "expectations:2 Path does not exist. non-existent-test.html")
  156. self.assertEqual(str(e), warnings)
  157. def test_parse_warnings_are_logged_if_not_in_lint_mode(self):
  158. oc = OutputCapture()
  159. try:
  160. oc.capture_output()
  161. self.parse_exp('-- this should be a syntax error', is_lint_mode=False)
  162. finally:
  163. _, _, logs = oc.restore_output()
  164. self.assertNotEquals(logs, '')
  165. def test_error_on_different_platform(self):
  166. # parse_exp uses a Windows port. Assert errors on Mac show up in lint mode.
  167. self.assertRaises(ParseError, self.parse_exp,
  168. 'Bug(test) [ Mac ] failures/expected/text.html [ Failure ]\nBug(test) [ Mac ] failures/expected/text.html [ Failure ]',
  169. is_lint_mode=True)
  170. def test_error_on_different_build_type(self):
  171. # parse_exp uses a Release port. Assert errors on DEBUG show up in lint mode.
  172. self.assertRaises(ParseError, self.parse_exp,
  173. 'Bug(test) [ Debug ] failures/expected/text.html [ Failure ]\nBug(test) [ Debug ] failures/expected/text.html [ Failure ]',
  174. is_lint_mode=True)
  175. def test_overrides(self):
  176. self.parse_exp("Bug(exp) failures/expected/text.html [ Failure ]",
  177. "Bug(override) failures/expected/text.html [ ImageOnlyFailure ]")
  178. self.assert_exp('failures/expected/text.html', IMAGE)
  179. def test_overrides__directory(self):
  180. self.parse_exp("Bug(exp) failures/expected/text.html [ Failure ]",
  181. "Bug(override) failures/expected [ Crash ]")
  182. self.assert_exp('failures/expected/text.html', CRASH)
  183. self.assert_exp('failures/expected/image.html', CRASH)
  184. def test_overrides__duplicate(self):
  185. self.assert_bad_expectations("Bug(exp) failures/expected/text.html [ Failure ]",
  186. "Bug(override) failures/expected/text.html [ ImageOnlyFailure ]\n"
  187. "Bug(override) failures/expected/text.html [ Crash ]\n")
  188. def test_pixel_tests_flag(self):
  189. def match(test, result, pixel_tests_enabled):
  190. return self._exp.matches_an_expected_result(
  191. self.get_test(test), result, pixel_tests_enabled)
  192. self.parse_exp(self.get_basic_expectations())
  193. self.assertTrue(match('failures/expected/text.html', FAIL, True))
  194. self.assertTrue(match('failures/expected/text.html', FAIL, False))
  195. self.assertFalse(match('failures/expected/text.html', CRASH, True))
  196. self.assertFalse(match('failures/expected/text.html', CRASH, False))
  197. self.assertTrue(match('failures/expected/image_checksum.html', PASS,
  198. True))
  199. self.assertTrue(match('failures/expected/image_checksum.html', PASS,
  200. False))
  201. self.assertTrue(match('failures/expected/crash.html', PASS, False))
  202. self.assertTrue(match('passes/text.html', PASS, False))
  203. def test_more_specific_override_resets_skip(self):
  204. self.parse_exp("Bug(x) failures/expected [ Skip ]\n"
  205. "Bug(x) failures/expected/text.html [ ImageOnlyFailure ]\n")
  206. self.assert_exp('failures/expected/text.html', IMAGE)
  207. self.assertFalse(self._port._filesystem.join(self._port.layout_tests_dir(),
  208. 'failures/expected/text.html') in
  209. self._exp.get_tests_with_result_type(SKIP))
  210. class SkippedTests(Base):
  211. def check(self, expectations, overrides, skips, lint=False):
  212. port = MockHost().port_factory.get('qt')
  213. port._filesystem.write_text_file(port._filesystem.join(port.layout_tests_dir(), 'failures/expected/text.html'), 'foo')
  214. expectations_dict = OrderedDict()
  215. expectations_dict['expectations'] = expectations
  216. if overrides:
  217. expectations_dict['overrides'] = overrides
  218. port.expectations_dict = lambda: expectations_dict
  219. port.skipped_layout_tests = lambda tests: set(skips)
  220. expectations_to_lint = expectations_dict if lint else None
  221. exp = TestExpectations(port, ['failures/expected/text.html'], expectations_to_lint=expectations_to_lint)
  222. # Check that the expectation is for BUG_DUMMY SKIP : ... [ Pass ]
  223. self.assertEqual(exp.get_modifiers('failures/expected/text.html'),
  224. [TestExpectationParser.DUMMY_BUG_MODIFIER, TestExpectationParser.SKIP_MODIFIER, TestExpectationParser.WONTFIX_MODIFIER])
  225. self.assertEqual(exp.get_expectations('failures/expected/text.html'), set([PASS]))
  226. def test_skipped_tests_work(self):
  227. self.check(expectations='', overrides=None, skips=['failures/expected/text.html'])
  228. def test_duplicate_skipped_test_fails_lint(self):
  229. self.assertRaises(ParseError, self.check, expectations='Bug(x) failures/expected/text.html [ Failure ]\n', overrides=None, skips=['failures/expected/text.html'], lint=True)
  230. def test_skipped_file_overrides_expectations(self):
  231. self.check(expectations='Bug(x) failures/expected/text.html [ Failure ]\n', overrides=None,
  232. skips=['failures/expected/text.html'])
  233. def test_skipped_dir_overrides_expectations(self):
  234. self.check(expectations='Bug(x) failures/expected/text.html [ Failure ]\n', overrides=None,
  235. skips=['failures/expected'])
  236. def test_skipped_file_overrides_overrides(self):
  237. self.check(expectations='', overrides='Bug(x) failures/expected/text.html [ Failure ]\n',
  238. skips=['failures/expected/text.html'])
  239. def test_skipped_dir_overrides_overrides(self):
  240. self.check(expectations='', overrides='Bug(x) failures/expected/text.html [ Failure ]\n',
  241. skips=['failures/expected'])
  242. def test_skipped_entry_dont_exist(self):
  243. port = MockHost().port_factory.get('qt')
  244. expectations_dict = OrderedDict()
  245. expectations_dict['expectations'] = ''
  246. port.expectations_dict = lambda: expectations_dict
  247. port.skipped_layout_tests = lambda tests: set(['foo/bar/baz.html'])
  248. capture = OutputCapture()
  249. capture.capture_output()
  250. exp = TestExpectations(port)
  251. _, _, logs = capture.restore_output()
  252. self.assertEqual('The following test foo/bar/baz.html from the Skipped list doesn\'t exist\n', logs)
  253. class ExpectationSyntaxTests(Base):
  254. def test_unrecognized_expectation(self):
  255. self.assert_bad_expectations('Bug(test) failures/expected/text.html [ Unknown ]')
  256. def test_macro(self):
  257. exp_str = 'Bug(test) [ Win ] failures/expected/text.html [ Failure ]'
  258. self.parse_exp(exp_str)
  259. self.assert_exp('failures/expected/text.html', FAIL)
  260. def assert_tokenize_exp(self, line, bugs=None, modifiers=None, expectations=None, warnings=None, comment=None, name='foo.html'):
  261. bugs = bugs or []
  262. modifiers = modifiers or []
  263. expectations = expectations or []
  264. warnings = warnings or []
  265. filename = 'TestExpectations'
  266. line_number = 1
  267. expectation_line = TestExpectationParser._tokenize_line(filename, line, line_number)
  268. self.assertEqual(expectation_line.warnings, warnings)
  269. self.assertEqual(expectation_line.name, name)
  270. self.assertEqual(expectation_line.filename, filename)
  271. self.assertEqual(expectation_line.line_number, line_number)
  272. if not warnings:
  273. self.assertEqual(expectation_line.modifiers, modifiers)
  274. self.assertEqual(expectation_line.expectations, expectations)
  275. def test_bare_name(self):
  276. self.assert_tokenize_exp('foo.html', modifiers=['SKIP'], expectations=['PASS'])
  277. def test_bare_name_and_bugs(self):
  278. self.assert_tokenize_exp('webkit.org/b/12345 foo.html', modifiers=['BUGWK12345', 'SKIP'], expectations=['PASS'])
  279. self.assert_tokenize_exp('Bug(dpranke) foo.html', modifiers=['BUGDPRANKE', 'SKIP'], expectations=['PASS'])
  280. self.assert_tokenize_exp('webkit.org/b/12345 webkit.org/b/34567 foo.html', modifiers=['BUGWK12345', 'BUGWK34567', 'SKIP'], expectations=['PASS'])
  281. def test_comments(self):
  282. self.assert_tokenize_exp("# comment", name=None, comment="# comment")
  283. self.assert_tokenize_exp("foo.html # comment", comment="# comment", expectations=['PASS'], modifiers=['SKIP'])
  284. def test_config_modifiers(self):
  285. self.assert_tokenize_exp('[ Mac ] foo.html', modifiers=['MAC', 'SKIP'], expectations=['PASS'])
  286. self.assert_tokenize_exp('[ Mac Vista ] foo.html', modifiers=['MAC', 'VISTA', 'SKIP'], expectations=['PASS'])
  287. self.assert_tokenize_exp('[ Mac ] foo.html [ Failure ] ', modifiers=['MAC'], expectations=['FAIL'])
  288. def test_unknown_config(self):
  289. self.assert_tokenize_exp('[ Foo ] foo.html ', modifiers=['Foo', 'SKIP'], expectations=['PASS'])
  290. def test_unknown_expectation(self):
  291. self.assert_tokenize_exp('foo.html [ Audio ]', warnings=['Unrecognized expectation "Audio"'])
  292. def test_skip(self):
  293. self.assert_tokenize_exp('foo.html [ Skip ]', modifiers=['SKIP'], expectations=['PASS'])
  294. def test_slow(self):
  295. self.assert_tokenize_exp('foo.html [ Slow ]', modifiers=['SLOW'], expectations=['PASS'])
  296. def test_wontfix(self):
  297. self.assert_tokenize_exp('foo.html [ WontFix ]', modifiers=['WONTFIX', 'SKIP'], expectations=['PASS'])
  298. self.assert_tokenize_exp('foo.html [ WontFix ImageOnlyFailure ]', modifiers=['WONTFIX'], expectations=['IMAGE'])
  299. self.assert_tokenize_exp('foo.html [ WontFix Pass Failure ]', modifiers=['WONTFIX'], expectations=['PASS', 'FAIL'])
  300. def test_blank_line(self):
  301. self.assert_tokenize_exp('', name=None)
  302. def test_warnings(self):
  303. self.assert_tokenize_exp('[ Mac ]', warnings=['Did not find a test name.'], name=None)
  304. self.assert_tokenize_exp('[ [', warnings=['unexpected "["'], name=None)
  305. self.assert_tokenize_exp('webkit.org/b/12345 ]', warnings=['unexpected "]"'], name=None)
  306. self.assert_tokenize_exp('foo.html webkit.org/b/12345 ]', warnings=['"webkit.org/b/12345" is not at the start of the line.'])
  307. class SemanticTests(Base):
  308. def test_bug_format(self):
  309. self.assertRaises(ParseError, self.parse_exp, 'BUG1234 failures/expected/text.html [ Failure ]', is_lint_mode=True)
  310. def test_bad_bugid(self):
  311. try:
  312. self.parse_exp('BUG1234 failures/expected/text.html [ Failure ]', is_lint_mode=True)
  313. self.fail('should have raised an error about a bad bug identifier')
  314. except ParseError, exp:
  315. self.assertEqual(len(exp.warnings), 1)
  316. def test_missing_bugid(self):
  317. self.parse_exp('failures/expected/text.html [ Failure ]')
  318. self.assertFalse(self._exp.has_warnings())
  319. self._port.warn_if_bug_missing_in_test_expectations = lambda: True
  320. self.parse_exp('failures/expected/text.html [ Failure ]')
  321. line = self._exp._model.get_expectation_line('failures/expected/text.html')
  322. self.assertFalse(line.is_invalid())
  323. self.assertEqual(line.warnings, ['Test lacks BUG modifier.'])
  324. def test_skip_and_wontfix(self):
  325. # Skip is not allowed to have other expectations as well, because those
  326. # expectations won't be exercised and may become stale .
  327. self.parse_exp('failures/expected/text.html [ Failure Skip ]')
  328. self.assertTrue(self._exp.has_warnings())
  329. self.parse_exp('failures/expected/text.html [ Crash WontFix ]')
  330. self.assertFalse(self._exp.has_warnings())
  331. self.parse_exp('failures/expected/text.html [ Pass WontFix ]')
  332. self.assertFalse(self._exp.has_warnings())
  333. def test_slow_and_timeout(self):
  334. # A test cannot be SLOW and expected to TIMEOUT.
  335. self.assertRaises(ParseError, self.parse_exp,
  336. 'Bug(test) failures/expected/timeout.html [ Slow Timeout ]', is_lint_mode=True)
  337. def test_rebaseline(self):
  338. # Can't lint a file w/ 'REBASELINE' in it.
  339. self.assertRaises(ParseError, self.parse_exp,
  340. 'Bug(test) failures/expected/text.html [ Failure Rebaseline ]',
  341. is_lint_mode=True)
  342. def test_duplicates(self):
  343. self.assertRaises(ParseError, self.parse_exp, """
  344. Bug(exp) failures/expected/text.html [ Failure ]
  345. Bug(exp) failures/expected/text.html [ ImageOnlyFailure ]""", is_lint_mode=True)
  346. self.assertRaises(ParseError, self.parse_exp,
  347. self.get_basic_expectations(), overrides="""
  348. Bug(override) failures/expected/text.html [ Failure ]
  349. Bug(override) failures/expected/text.html [ ImageOnlyFailure ]""", is_lint_mode=True)
  350. def test_missing_file(self):
  351. self.parse_exp('Bug(test) missing_file.html [ Failure ]')
  352. self.assertTrue(self._exp.has_warnings(), 1)
  353. class PrecedenceTests(Base):
  354. def test_file_over_directory(self):
  355. # This tests handling precedence of specific lines over directories
  356. # and tests expectations covering entire directories.
  357. exp_str = """
  358. Bug(x) failures/expected/text.html [ Failure ]
  359. Bug(y) failures/expected [ WontFix ]
  360. """
  361. self.parse_exp(exp_str)
  362. self.assert_exp('failures/expected/text.html', FAIL)
  363. self.assert_exp('failures/expected/crash.html', PASS)
  364. exp_str = """
  365. Bug(x) failures/expected [ WontFix ]
  366. Bug(y) failures/expected/text.html [ Failure ]
  367. """
  368. self.parse_exp(exp_str)
  369. self.assert_exp('failures/expected/text.html', FAIL)
  370. self.assert_exp('failures/expected/crash.html', PASS)
  371. def test_ambiguous(self):
  372. self.assert_bad_expectations("Bug(test) [ Release ] passes/text.html [ Pass ]\n"
  373. "Bug(test) [ Win ] passes/text.html [ Failure ]\n")
  374. def test_more_modifiers(self):
  375. self.assert_bad_expectations("Bug(test) [ Release ] passes/text.html [ Pass ]\n"
  376. "Bug(test) [ Win Release ] passes/text.html [ Failure ]\n")
  377. def test_order_in_file(self):
  378. self.assert_bad_expectations("Bug(test) [ Win Release ] : passes/text.html [ Failure ]\n"
  379. "Bug(test) [ Release ] : passes/text.html [ Pass ]\n")
  380. def test_macro_overrides(self):
  381. self.assert_bad_expectations("Bug(test) [ Win ] passes/text.html [ Pass ]\n"
  382. "Bug(test) [ XP ] passes/text.html [ Failure ]\n")
  383. class RemoveConfigurationsTest(Base):
  384. def test_remove(self):
  385. host = MockHost()
  386. test_port = host.port_factory.get('test-win-xp', None)
  387. test_port.test_exists = lambda test: True
  388. test_port.test_isfile = lambda test: True
  389. test_config = test_port.test_configuration()
  390. test_port.expectations_dict = lambda: {"expectations": """Bug(x) [ Linux Win Release ] failures/expected/foo.html [ Failure ]
  391. Bug(y) [ Win Mac Debug ] failures/expected/foo.html [ Crash ]
  392. """}
  393. expectations = TestExpectations(test_port, self.get_basic_tests())
  394. actual_expectations = expectations.remove_configuration_from_test('failures/expected/foo.html', test_config)
  395. self.assertEqual("""Bug(x) [ Linux Vista Win7 Release ] failures/expected/foo.html [ Failure ]
  396. Bug(y) [ Win Mac Debug ] failures/expected/foo.html [ Crash ]
  397. """, actual_expectations)
  398. def test_remove_line(self):
  399. host = MockHost()
  400. test_port = host.port_factory.get('test-win-xp', None)
  401. test_port.test_exists = lambda test: True
  402. test_port.test_isfile = lambda test: True
  403. test_config = test_port.test_configuration()
  404. test_port.expectations_dict = lambda: {'expectations': """Bug(x) [ Win Release ] failures/expected/foo.html [ Failure ]
  405. Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ]
  406. """}
  407. expectations = TestExpectations(test_port)
  408. actual_expectations = expectations.remove_configuration_from_test('failures/expected/foo.html', test_config)
  409. actual_expectations = expectations.remove_configuration_from_test('failures/expected/foo.html', host.port_factory.get('test-win-vista', None).test_configuration())
  410. actual_expectations = expectations.remove_configuration_from_test('failures/expected/foo.html', host.port_factory.get('test-win-win7', None).test_configuration())
  411. self.assertEqual("""Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ]
  412. """, actual_expectations)
  413. class RebaseliningTest(Base):
  414. """Test rebaselining-specific functionality."""
  415. def assertRemove(self, input_expectations, input_overrides, tests, expected_expectations, expected_overrides):
  416. self.parse_exp(input_expectations, is_lint_mode=False, overrides=input_overrides)
  417. actual_expectations = self._exp.remove_rebaselined_tests(tests, 'expectations')
  418. self.assertEqual(expected_expectations, actual_expectations)
  419. actual_overrides = self._exp.remove_rebaselined_tests(tests, 'overrides')
  420. self.assertEqual(expected_overrides, actual_overrides)
  421. def test_remove(self):
  422. self.assertRemove('Bug(x) failures/expected/text.html [ Failure Rebaseline ]\n'
  423. 'Bug(y) failures/expected/image.html [ ImageOnlyFailure Rebaseline ]\n'
  424. 'Bug(z) failures/expected/crash.html [ Crash ]\n',
  425. 'Bug(x0) failures/expected/image.html [ Crash ]\n',
  426. ['failures/expected/text.html'],
  427. 'Bug(y) failures/expected/image.html [ ImageOnlyFailure Rebaseline ]\n'
  428. 'Bug(z) failures/expected/crash.html [ Crash ]\n',
  429. 'Bug(x0) failures/expected/image.html [ Crash ]\n')
  430. # Ensure that we don't modify unrelated lines, even if we could rewrite them.
  431. # i.e., the second line doesn't get rewritten to "Bug(y) failures/expected/skip.html"
  432. self.assertRemove('Bug(x) failures/expected/text.html [ Failure Rebaseline ]\n'
  433. 'Bug(Y) failures/expected/image.html [ Skip ]\n'
  434. 'Bug(z) failures/expected/crash.html\n',
  435. '',
  436. ['failures/expected/text.html'],
  437. 'Bug(Y) failures/expected/image.html [ Skip ]\n'
  438. 'Bug(z) failures/expected/crash.html\n',
  439. '')
  440. def test_get_rebaselining_failures(self):
  441. # Make sure we find a test as needing a rebaseline even if it is not marked as a failure.
  442. self.parse_exp('Bug(x) failures/expected/text.html [ Rebaseline ]\n')
  443. self.assertEqual(len(self._exp.get_rebaselining_failures()), 1)
  444. self.parse_exp(self.get_basic_expectations())
  445. self.assertEqual(len(self._exp.get_rebaselining_failures()), 0)
  446. class TestExpectationSerializationTests(unittest.TestCase):
  447. def __init__(self, testFunc):
  448. host = MockHost()
  449. test_port = host.port_factory.get('test-win-xp', None)
  450. self._converter = TestConfigurationConverter(test_port.all_test_configurations(), test_port.configuration_specifier_macros())
  451. unittest.TestCase.__init__(self, testFunc)
  452. def _tokenize(self, line):
  453. return TestExpectationParser._tokenize_line('path', line, 0)
  454. def assert_round_trip(self, in_string, expected_string=None):
  455. expectation = self._tokenize(in_string)
  456. if expected_string is None:
  457. expected_string = in_string
  458. self.assertEqual(expected_string, expectation.to_string(self._converter))
  459. def assert_list_round_trip(self, in_string, expected_string=None):
  460. host = MockHost()
  461. parser = TestExpectationParser(host.port_factory.get('test-win-xp', None), [], allow_rebaseline_modifier=False)
  462. expectations = parser.parse('path', in_string)
  463. if expected_string is None:
  464. expected_string = in_string
  465. self.assertEqual(expected_string, TestExpectations.list_to_string(expectations, self._converter))
  466. def test_unparsed_to_string(self):
  467. expectation = TestExpectationLine()
  468. self.assertEqual(expectation.to_string(self._converter), '')
  469. expectation.comment = ' Qux.'
  470. self.assertEqual(expectation.to_string(self._converter), '# Qux.')
  471. expectation.name = 'bar'
  472. self.assertEqual(expectation.to_string(self._converter), 'bar # Qux.')
  473. expectation.modifiers = ['foo']
  474. # FIXME: case should be preserved here but we can't until we drop the old syntax.
  475. self.assertEqual(expectation.to_string(self._converter), '[ FOO ] bar # Qux.')
  476. expectation.expectations = ['bAz']
  477. self.assertEqual(expectation.to_string(self._converter), '[ FOO ] bar [ BAZ ] # Qux.')
  478. expectation.expectations = ['bAz1', 'baZ2']
  479. self.assertEqual(expectation.to_string(self._converter), '[ FOO ] bar [ BAZ1 BAZ2 ] # Qux.')
  480. expectation.modifiers = ['foo1', 'foO2']
  481. self.assertEqual(expectation.to_string(self._converter), '[ FOO1 FOO2 ] bar [ BAZ1 BAZ2 ] # Qux.')
  482. expectation.warnings.append('Oh the horror.')
  483. self.assertEqual(expectation.to_string(self._converter), '')
  484. expectation.original_string = 'Yes it is!'
  485. self.assertEqual(expectation.to_string(self._converter), 'Yes it is!')
  486. def test_unparsed_list_to_string(self):
  487. expectation = TestExpectationLine()
  488. expectation.comment = 'Qux.'
  489. expectation.name = 'bar'
  490. expectation.modifiers = ['foo']
  491. expectation.expectations = ['bAz1', 'baZ2']
  492. # FIXME: case should be preserved here but we can't until we drop the old syntax.
  493. self.assertEqual(TestExpectations.list_to_string([expectation]), '[ FOO ] bar [ BAZ1 BAZ2 ] #Qux.')
  494. def test_parsed_to_string(self):
  495. expectation_line = TestExpectationLine()
  496. expectation_line.parsed_bug_modifiers = ['BUGX']
  497. expectation_line.name = 'test/name/for/realz.html'
  498. expectation_line.parsed_expectations = set([IMAGE])
  499. self.assertEqual(expectation_line.to_string(self._converter), None)
  500. expectation_line.matching_configurations = set([TestConfiguration('xp', 'x86', 'release')])
  501. self.assertEqual(expectation_line.to_string(self._converter), 'Bug(x) [ XP Release ] test/name/for/realz.html [ ImageOnlyFailure ]')
  502. expectation_line.matching_configurations = set([TestConfiguration('xp', 'x86', 'release'), TestConfiguration('xp', 'x86', 'debug')])
  503. self.assertEqual(expectation_line.to_string(self._converter), 'Bug(x) [ XP ] test/name/for/realz.html [ ImageOnlyFailure ]')
  504. def test_serialize_parsed_expectations(self):
  505. expectation_line = TestExpectationLine()
  506. expectation_line.parsed_expectations = set([])
  507. parsed_expectation_to_string = dict([[parsed_expectation, expectation_string] for expectation_string, parsed_expectation in TestExpectations.EXPECTATIONS.items()])
  508. self.assertEqual(expectation_line._serialize_parsed_expectations(parsed_expectation_to_string), '')
  509. expectation_line.parsed_expectations = set([FAIL])
  510. self.assertEqual(expectation_line._serialize_parsed_expectations(parsed_expectation_to_string), 'fail')
  511. expectation_line.parsed_expectations = set([PASS, IMAGE])
  512. self.assertEqual(expectation_line._serialize_parsed_expectations(parsed_expectation_to_string), 'pass image')
  513. expectation_line.parsed_expectations = set([FAIL, PASS])
  514. self.assertEqual(expectation_line._serialize_parsed_expectations(parsed_expectation_to_string), 'pass fail')
  515. def test_serialize_parsed_modifier_string(self):
  516. expectation_line = TestExpectationLine()
  517. expectation_line.parsed_bug_modifiers = ['garden-o-matic']
  518. expectation_line.parsed_modifiers = ['for', 'the']
  519. self.assertEqual(expectation_line._serialize_parsed_modifiers(self._converter, []), 'garden-o-matic for the')
  520. self.assertEqual(expectation_line._serialize_parsed_modifiers(self._converter, ['win']), 'garden-o-matic for the win')
  521. expectation_line.parsed_bug_modifiers = []
  522. expectation_line.parsed_modifiers = []
  523. self.assertEqual(expectation_line._serialize_parsed_modifiers(self._converter, []), '')
  524. self.assertEqual(expectation_line._serialize_parsed_modifiers(self._converter, ['win']), 'win')
  525. expectation_line.parsed_bug_modifiers = ['garden-o-matic', 'total', 'is']
  526. self.assertEqual(expectation_line._serialize_parsed_modifiers(self._converter, ['win']), 'garden-o-matic is total win')
  527. expectation_line.parsed_bug_modifiers = []
  528. expectation_line.parsed_modifiers = ['garden-o-matic', 'total', 'is']
  529. self.assertEqual(expectation_line._serialize_parsed_modifiers(self._converter, ['win']), 'garden-o-matic is total win')
  530. def test_format_line(self):
  531. self.assertEqual(TestExpectationLine._format_line(['MODIFIERS'], 'name', ['EXPECTATIONS'], 'comment'), '[ MODIFIERS ] name [ EXPECTATIONS ] #comment')
  532. self.assertEqual(TestExpectationLine._format_line(['MODIFIERS'], 'name', ['EXPECTATIONS'], None), '[ MODIFIERS ] name [ EXPECTATIONS ]')
  533. def test_string_roundtrip(self):
  534. self.assert_round_trip('')
  535. self.assert_round_trip('FOO')
  536. self.assert_round_trip('[')
  537. self.assert_round_trip('FOO [')
  538. self.assert_round_trip('FOO ] bar')
  539. self.assert_round_trip(' FOO [')
  540. self.assert_round_trip(' [ FOO ] ')
  541. self.assert_round_trip('[ FOO ] bar [ BAZ ]')
  542. self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux.')
  543. self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux.')
  544. self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux. ')
  545. self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux. ')
  546. self.assert_round_trip('[ FOO ] ] ] bar BAZ')
  547. self.assert_round_trip('[ FOO ] ] ] bar [ BAZ ]')
  548. self.assert_round_trip('FOO ] ] bar ==== BAZ')
  549. self.assert_round_trip('=')
  550. self.assert_round_trip('#')
  551. self.assert_round_trip('# ')
  552. self.assert_round_trip('# Foo')
  553. self.assert_round_trip('# Foo')
  554. self.assert_round_trip('# Foo :')
  555. self.assert_round_trip('# Foo : =')
  556. def test_list_roundtrip(self):
  557. self.assert_list_round_trip('')
  558. self.assert_list_round_trip('\n')
  559. self.assert_list_round_trip('\n\n')
  560. self.assert_list_round_trip('bar')
  561. self.assert_list_round_trip('bar\n# Qux.')
  562. self.assert_list_round_trip('bar\n# Qux.\n')
  563. def test_reconstitute_only_these(self):
  564. lines = []
  565. reconstitute_only_these = []
  566. def add_line(matching_configurations, reconstitute):
  567. expectation_line = TestExpectationLine()
  568. expectation_line.original_string = "Nay"
  569. expectation_line.parsed_bug_modifiers = ['BUGX']
  570. expectation_line.name = 'Yay'
  571. expectation_line.parsed_expectations = set([IMAGE])
  572. expectation_line.matching_configurations = matching_configurations
  573. lines.append(expectation_line)
  574. if reconstitute:
  575. reconstitute_only_these.append(expectation_line)
  576. add_line(set([TestConfiguration('xp', 'x86', 'release')]), True)
  577. add_line(set([TestConfiguration('xp', 'x86', 'release'), TestConfiguration('xp', 'x86', 'debug')]), False)
  578. serialized = TestExpectations.list_to_string(lines, self._converter)
  579. self.assertEqual(serialized, "Bug(x) [ XP Release ] Yay [ ImageOnlyFailure ]\nBug(x) [ XP ] Yay [ ImageOnlyFailure ]")
  580. serialized = TestExpectations.list_to_string(lines, self._converter, reconstitute_only_these=reconstitute_only_these)
  581. self.assertEqual(serialized, "Bug(x) [ XP Release ] Yay [ ImageOnlyFailure ]\nNay")
  582. def disabled_test_string_whitespace_stripping(self):
  583. # FIXME: Re-enable this test once we rework the code to no longer support the old syntax.
  584. self.assert_round_trip('\n', '')
  585. self.assert_round_trip(' [ FOO ] bar [ BAZ ]', '[ FOO ] bar [ BAZ ]')
  586. self.assert_round_trip('[ FOO ] bar [ BAZ ]', '[ FOO ] bar [ BAZ ]')
  587. self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux.', '[ FOO ] bar [ BAZ ] # Qux.')
  588. self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux.', '[ FOO ] bar [ BAZ ] # Qux.')
  589. self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux.', '[ FOO ] bar [ BAZ ] # Qux.')
  590. self.assert_round_trip('[ FOO ] bar [ BAZ ] # Qux.', '[ FOO ] bar [ BAZ ] # Qux.')