OSDN Git Service

Merge WebKit at r84325: Initial merge by git.
[android-x86/external-webkit.git] / Tools / Scripts / webkitpy / layout_tests / layout_package / test_expectations_unittest.py
1 #!/usr/bin/python
2 # Copyright (C) 2010 Google Inc. All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7 #
8 #     * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 #     * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
13 # distribution.
14 #     * Neither the name of Google Inc. nor the names of its
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 """Unit tests for test_expectations.py."""
31
32 import unittest
33
34 from webkitpy.layout_tests import port
35 from webkitpy.layout_tests.port import base
36 from webkitpy.layout_tests.layout_package.test_expectations import *
37
38 class FunctionsTest(unittest.TestCase):
39     def test_result_was_expected(self):
40         # test basics
41         self.assertEquals(result_was_expected(PASS, set([PASS]),
42                                               False, False), True)
43         self.assertEquals(result_was_expected(TEXT, set([PASS]),
44                                               False, False), False)
45
46         # test handling of FAIL expectations
47         self.assertEquals(result_was_expected(IMAGE_PLUS_TEXT, set([FAIL]),
48                                               False, False), True)
49         self.assertEquals(result_was_expected(IMAGE, set([FAIL]),
50                                               False, False), True)
51         self.assertEquals(result_was_expected(TEXT, set([FAIL]),
52                                               False, False), True)
53         self.assertEquals(result_was_expected(CRASH, set([FAIL]),
54                                               False, False), False)
55
56         # test handling of SKIPped tests and results
57         self.assertEquals(result_was_expected(SKIP, set([CRASH]),
58                                               False, True), True)
59         self.assertEquals(result_was_expected(SKIP, set([CRASH]),
60                                               False, False), False)
61
62         # test handling of MISSING results and the REBASELINE modifier
63         self.assertEquals(result_was_expected(MISSING, set([PASS]),
64                                               True, False), True)
65         self.assertEquals(result_was_expected(MISSING, set([PASS]),
66                                               False, False), False)
67
68     def test_remove_pixel_failures(self):
69         self.assertEquals(remove_pixel_failures(set([TEXT])),
70                           set([TEXT]))
71         self.assertEquals(remove_pixel_failures(set([PASS])),
72                           set([PASS]))
73         self.assertEquals(remove_pixel_failures(set([IMAGE])),
74                           set([PASS]))
75         self.assertEquals(remove_pixel_failures(set([IMAGE_PLUS_TEXT])),
76                           set([TEXT]))
77         self.assertEquals(remove_pixel_failures(set([PASS, IMAGE, CRASH])),
78                           set([PASS, CRASH]))
79
80
81 class Base(unittest.TestCase):
82     # Note that all of these tests are written assuming the configuration
83     # being tested is Windows XP, Release build.
84
85     def __init__(self, testFunc, setUp=None, tearDown=None, description=None):
86         self._port = port.get('test-win-xp', None)
87         self._fs = self._port._filesystem
88         self._exp = None
89         unittest.TestCase.__init__(self, testFunc)
90
91     def get_test(self, test_name):
92         return self._fs.join(self._port.layout_tests_dir(), test_name)
93
94     def get_basic_tests(self):
95         return [self.get_test('failures/expected/text.html'),
96                 self.get_test('failures/expected/image_checksum.html'),
97                 self.get_test('failures/expected/crash.html'),
98                 self.get_test('failures/expected/missing_text.html'),
99                 self.get_test('failures/expected/image.html'),
100                 self.get_test('passes/text.html')]
101
102     def get_basic_expectations(self):
103         return """
104 BUG_TEST : failures/expected/text.html = TEXT
105 BUG_TEST WONTFIX SKIP : failures/expected/crash.html = CRASH
106 BUG_TEST REBASELINE : failures/expected/missing_image.html = MISSING
107 BUG_TEST WONTFIX : failures/expected/image_checksum.html = IMAGE
108 BUG_TEST WONTFIX MAC : failures/expected/image.html = IMAGE
109 """
110
111     def parse_exp(self, expectations, overrides=None, is_lint_mode=False):
112         test_config = self._port.test_configuration()
113         self._exp = TestExpectations(self._port,
114              tests=self.get_basic_tests(),
115              expectations=expectations,
116              test_config=test_config,
117              is_lint_mode=is_lint_mode,
118              overrides=overrides)
119
120     def assert_exp(self, test, result):
121         self.assertEquals(self._exp.get_expectations(self.get_test(test)),
122                           set([result]))
123
124
125 class BasicTests(Base):
126     def test_basic(self):
127         self.parse_exp(self.get_basic_expectations())
128         self.assert_exp('failures/expected/text.html', TEXT)
129         self.assert_exp('failures/expected/image_checksum.html', IMAGE)
130         self.assert_exp('passes/text.html', PASS)
131         self.assert_exp('failures/expected/image.html', PASS)
132
133
134 class MiscTests(Base):
135     def test_multiple_results(self):
136         self.parse_exp('BUGX : failures/expected/text.html = TEXT CRASH')
137         self.assertEqual(self._exp.get_expectations(
138             self.get_test('failures/expected/text.html')),
139             set([TEXT, CRASH]))
140
141     def test_category_expectations(self):
142         # This test checks unknown tests are not present in the
143         # expectations and that known test part of a test category is
144         # present in the expectations.
145         exp_str = """
146 BUGX WONTFIX : failures/expected = IMAGE
147 """
148         self.parse_exp(exp_str)
149         test_name = 'failures/expected/unknown-test.html'
150         unknown_test = self.get_test(test_name)
151         self.assertRaises(KeyError, self._exp.get_expectations,
152                           unknown_test)
153         self.assert_exp('failures/expected/crash.html', IMAGE)
154
155     def test_get_options(self):
156         self.parse_exp(self.get_basic_expectations())
157         self.assertEqual(self._exp.get_options(
158                          self.get_test('passes/text.html')), [])
159
160     def test_expectations_json_for_all_platforms(self):
161         self.parse_exp(self.get_basic_expectations())
162         json_str = self._exp.get_expectations_json_for_all_platforms()
163         # FIXME: test actual content?
164         self.assertTrue(json_str)
165
166     def test_get_expectations_string(self):
167         self.parse_exp(self.get_basic_expectations())
168         self.assertEquals(self._exp.get_expectations_string(
169                           self.get_test('failures/expected/text.html')),
170                           'TEXT')
171
172     def test_expectation_to_string(self):
173         # Normal cases are handled by other tests.
174         self.parse_exp(self.get_basic_expectations())
175         self.assertRaises(ValueError, self._exp.expectation_to_string,
176                           -1)
177
178     def test_get_test_set(self):
179         # Handle some corner cases for this routine not covered by other tests.
180         self.parse_exp(self.get_basic_expectations())
181         s = self._exp._expected_failures.get_test_set(WONTFIX)
182         self.assertEqual(s,
183             set([self.get_test('failures/expected/crash.html'),
184                  self.get_test('failures/expected/image_checksum.html')]))
185         s = self._exp._expected_failures.get_test_set(WONTFIX, CRASH)
186         self.assertEqual(s,
187             set([self.get_test('failures/expected/crash.html')]))
188         s = self._exp._expected_failures.get_test_set(WONTFIX, CRASH,
189                                                       include_skips=False)
190         self.assertEqual(s, set([]))
191
192     def test_parse_error_fatal(self):
193         try:
194             self.parse_exp("""FOO : failures/expected/text.html = TEXT
195 SKIP : failures/expected/image.html""")
196             self.assertFalse(True, "ParseError wasn't raised")
197         except ParseError, e:
198             self.assertTrue(e.fatal)
199             exp_errors = [u"Line:1 Unrecognized option 'foo' failures/expected/text.html",
200                           u"Line:2 Missing expectations. [' failures/expected/image.html']"]
201             self.assertEqual(str(e), '\n'.join(map(str, exp_errors)))
202             self.assertEqual(e.errors, exp_errors)
203
204     def test_parse_error_nonfatal(self):
205         try:
206             self.parse_exp('SKIP : failures/expected/text.html = TEXT',
207                            is_lint_mode=True)
208             self.assertFalse(True, "ParseError wasn't raised")
209         except ParseError, e:
210             self.assertFalse(e.fatal)
211             exp_errors = [u'Line:1 Test lacks BUG modifier. failures/expected/text.html']
212             self.assertEqual(str(e), '\n'.join(map(str, exp_errors)))
213             self.assertEqual(e.errors, exp_errors)
214
215     def test_overrides(self):
216         self.parse_exp("BUG_EXP: failures/expected/text.html = TEXT",
217                        "BUG_OVERRIDE : failures/expected/text.html = IMAGE")
218         self.assert_exp('failures/expected/text.html', IMAGE)
219
220     def test_overrides__duplicate(self):
221         self.assertRaises(ParseError, self.parse_exp,
222              "BUG_EXP: failures/expected/text.html = TEXT",
223              """
224 BUG_OVERRIDE : failures/expected/text.html = IMAGE
225 BUG_OVERRIDE : failures/expected/text.html = CRASH
226 """)
227
228     def test_pixel_tests_flag(self):
229         def match(test, result, pixel_tests_enabled):
230             return self._exp.matches_an_expected_result(
231                 self.get_test(test), result, pixel_tests_enabled)
232
233         self.parse_exp(self.get_basic_expectations())
234         self.assertTrue(match('failures/expected/text.html', TEXT, True))
235         self.assertTrue(match('failures/expected/text.html', TEXT, False))
236         self.assertFalse(match('failures/expected/text.html', CRASH, True))
237         self.assertFalse(match('failures/expected/text.html', CRASH, False))
238         self.assertTrue(match('failures/expected/image_checksum.html', IMAGE,
239                               True))
240         self.assertTrue(match('failures/expected/image_checksum.html', PASS,
241                               False))
242         self.assertTrue(match('failures/expected/crash.html', SKIP, False))
243         self.assertTrue(match('passes/text.html', PASS, False))
244
245     def test_more_specific_override_resets_skip(self):
246         self.parse_exp("BUGX SKIP : failures/expected = TEXT\n"
247                        "BUGX : failures/expected/text.html = IMAGE\n")
248         self.assert_exp('failures/expected/text.html', IMAGE)
249         self.assertFalse(self._port._filesystem.join(self._port.layout_tests_dir(),
250                                                      'failures/expected/text.html') in
251                          self._exp.get_tests_with_result_type(SKIP))
252
253 class ExpectationSyntaxTests(Base):
254     def test_missing_expectation(self):
255         # This is missing the expectation.
256         self.assertRaises(ParseError, self.parse_exp,
257                           'BUG_TEST: failures/expected/text.html')
258
259     def test_missing_colon(self):
260         # This is missing the modifiers and the ':'
261         self.assertRaises(ParseError, self.parse_exp,
262                           'failures/expected/text.html = TEXT')
263
264     def disabled_test_too_many_colons(self):
265         # FIXME: Enable this test and fix the underlying bug.
266         self.assertRaises(ParseError, self.parse_exp,
267                           'BUG_TEST: failures/expected/text.html = PASS :')
268
269     def test_too_many_equals_signs(self):
270         self.assertRaises(ParseError, self.parse_exp,
271                           'BUG_TEST: failures/expected/text.html = TEXT = IMAGE')
272
273     def test_unrecognized_expectation(self):
274         self.assertRaises(ParseError, self.parse_exp,
275                           'BUG_TEST: failures/expected/text.html = UNKNOWN')
276
277     def test_macro(self):
278         exp_str = """
279 BUG_TEST WIN-XP : failures/expected/text.html = TEXT
280 """
281         self.parse_exp(exp_str)
282         self.assert_exp('failures/expected/text.html', TEXT)
283
284
285 class SemanticTests(Base):
286     def test_bug_format(self):
287         self.assertRaises(ParseError, self.parse_exp, 'BUG1234 : failures/expected/text.html = TEXT')
288
289     def test_missing_bugid(self):
290         # This should log a non-fatal error.
291         self.parse_exp('SLOW : failures/expected/text.html = TEXT')
292         self.assertEqual(
293             len(self._exp._expected_failures.get_non_fatal_errors()), 1)
294
295     def test_slow_and_timeout(self):
296         # A test cannot be SLOW and expected to TIMEOUT.
297         self.assertRaises(ParseError, self.parse_exp,
298             'BUG_TEST SLOW : failures/expected/timeout.html = TIMEOUT')
299
300     def test_rebaseline(self):
301         # Can't lint a file w/ 'REBASELINE' in it.
302         self.assertRaises(ParseError, self.parse_exp,
303             'BUG_TEST REBASELINE : failures/expected/text.html = TEXT',
304             is_lint_mode=True)
305
306     def test_duplicates(self):
307         self.assertRaises(ParseError, self.parse_exp, """
308 BUG_EXP : failures/expected/text.html = TEXT
309 BUG_EXP : failures/expected/text.html = IMAGE""")
310
311         self.assertRaises(ParseError, self.parse_exp,
312             self.get_basic_expectations(), overrides="""
313 BUG_OVERRIDE : failures/expected/text.html = TEXT
314 BUG_OVERRIDE : failures/expected/text.html = IMAGE""", )
315
316     def test_missing_file(self):
317         # This should log a non-fatal error.
318         self.parse_exp('BUG_TEST : missing_file.html = TEXT')
319         self.assertEqual(
320             len(self._exp._expected_failures.get_non_fatal_errors()), 1)
321
322
323 class PrecedenceTests(Base):
324     def test_file_over_directory(self):
325         # This tests handling precedence of specific lines over directories
326         # and tests expectations covering entire directories.
327         exp_str = """
328 BUGX : failures/expected/text.html = TEXT
329 BUGX WONTFIX : failures/expected = IMAGE
330 """
331         self.parse_exp(exp_str)
332         self.assert_exp('failures/expected/text.html', TEXT)
333         self.assert_exp('failures/expected/crash.html', IMAGE)
334
335         exp_str = """
336 BUGX WONTFIX : failures/expected = IMAGE
337 BUGX : failures/expected/text.html = TEXT
338 """
339         self.parse_exp(exp_str)
340         self.assert_exp('failures/expected/text.html', TEXT)
341         self.assert_exp('failures/expected/crash.html', IMAGE)
342
343     def test_ambiguous(self):
344         self.assertRaises(ParseError, self.parse_exp, """
345 BUG_TEST RELEASE : passes/text.html = PASS
346 BUG_TEST WIN : passes/text.html = FAIL
347 """)
348
349     def test_more_modifiers(self):
350         exp_str = """
351 BUG_TEST RELEASE : passes/text.html = PASS
352 BUG_TEST WIN RELEASE : passes/text.html = TEXT
353 """
354         self.assertRaises(ParseError, self.parse_exp, exp_str)
355
356     def test_order_in_file(self):
357         exp_str = """
358 BUG_TEST WIN RELEASE : passes/text.html = TEXT
359 BUG_TEST RELEASE : passes/text.html = PASS
360 """
361         self.assertRaises(ParseError, self.parse_exp, exp_str)
362
363     def test_version_overrides(self):
364         exp_str = """
365 BUG_TEST WIN : passes/text.html = PASS
366 BUG_TEST WIN XP : passes/text.html = TEXT
367 """
368         self.assertRaises(ParseError, self.parse_exp, exp_str)
369
370     def test_macro_overrides(self):
371         exp_str = """
372 BUG_TEST WIN : passes/text.html = PASS
373 BUG_TEST WIN-XP : passes/text.html = TEXT
374 """
375         self.assertRaises(ParseError, self.parse_exp, exp_str)
376
377
378 class RebaseliningTest(Base):
379     """Test rebaselining-specific functionality."""
380     def assertRemove(self, input_expectations, tests, expected_expectations):
381         self.parse_exp(input_expectations)
382         actual_expectations = self._exp.remove_rebaselined_tests(tests)
383         self.assertEqual(expected_expectations, actual_expectations)
384
385     def test_remove(self):
386         self.assertRemove('BUGX REBASELINE : failures/expected/text.html = TEXT\n'
387                           'BUGY : failures/expected/image.html = IMAGE\n'
388                           'BUGZ REBASELINE : failures/expected/crash.html = CRASH\n',
389                           ['failures/expected/text.html'],
390                           'BUGY : failures/expected/image.html = IMAGE\n'
391                           'BUGZ REBASELINE : failures/expected/crash.html = CRASH\n')
392
393     def test_no_get_rebaselining_failures(self):
394         self.parse_exp(self.get_basic_expectations())
395         self.assertEqual(len(self._exp.get_rebaselining_failures()), 0)
396
397
398 class ModifierTests(unittest.TestCase):
399     def setUp(self):
400         port_obj = port.get('test-win-xp', None)
401         self.config = port_obj.test_configuration()
402         self.matcher = ModifierMatcher(self.config)
403
404     def match(self, modifiers, expected_num_matches=-1, values=None, num_errors=0):
405         matcher = self.matcher
406         if values:
407             matcher = ModifierMatcher(self.FakeTestConfiguration(values))
408         match_result = matcher.match(modifiers)
409         self.assertEqual(len(match_result.warnings), 0)
410         self.assertEqual(len(match_result.errors), num_errors)
411         self.assertEqual(match_result.num_matches, expected_num_matches,
412              'match(%s, %s) returned -> %d, expected %d' %
413              (modifiers, str(self.config.values()),
414               match_result.num_matches, expected_num_matches))
415
416     def test_bad_match_modifier(self):
417         self.match(['foo'], num_errors=1)
418
419     def test_none(self):
420         self.match([], 0)
421
422     def test_one(self):
423         self.match(['xp'], 1)
424         self.match(['win'], 1)
425         self.match(['release'], 1)
426         self.match(['cpu'], 1)
427         self.match(['x86'], 1)
428         self.match(['leopard'], -1)
429         self.match(['gpu'], -1)
430         self.match(['debug'], -1)
431
432     def test_two(self):
433         self.match(['xp', 'release'], 2)
434         self.match(['win7', 'release'], -1)
435         self.match(['win7', 'xp'], 1)
436
437     def test_three(self):
438         self.match(['win7', 'xp', 'release'], 2)
439         self.match(['xp', 'debug', 'x86'], -1)
440         self.match(['xp', 'release', 'x86'], 3)
441         self.match(['xp', 'cpu', 'release'], 3)
442
443     def test_four(self):
444         self.match(['xp', 'release', 'cpu', 'x86'], 4)
445         self.match(['win7', 'xp', 'release', 'cpu'], 3)
446         self.match(['win7', 'xp', 'debug', 'cpu'], -1)
447
448     def test_case_insensitivity(self):
449         self.match(['Win'], num_errors=1)
450         self.match(['WIN'], num_errors=1)
451         self.match(['win'], 1)
452
453     def test_duplicates(self):
454         self.match(['release', 'release'], num_errors=1)
455         self.match(['win-xp', 'xp'], num_errors=1)
456         self.match(['win-xp', 'win-xp'], num_errors=1)
457         self.match(['xp', 'release', 'xp', 'release'], num_errors=2)
458         self.match(['rebaseline', 'rebaseline'], num_errors=1)
459
460     def test_unknown_option(self):
461         self.match(['vms'], num_errors=1)
462
463     def test_duplicate_bugs(self):
464         # BUG* regexes can appear multiple times.
465         self.match(['bugfoo', 'bugbar'], 0)
466
467     def test_invalid_combinations(self):
468         # FIXME: This should probably raise an error instead of NO_MATCH.
469         self.match(['mac', 'xp'], num_errors=0)
470
471     def test_regexes_are_ignored(self):
472         self.match(['bug123xy', 'rebaseline', 'wontfix', 'slow', 'skip'], 0)
473
474     def test_none_is_invalid(self):
475         self.match(['none'], num_errors=1)
476
477
478 if __name__ == '__main__':
479     unittest.main()