lint-test-expectations should be run during style checking
[WebKit-https.git] / Tools / Scripts / webkitpy / style / main_unittest.py
1 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
5 # are met:
6 # 1.  Redistributions of source code must retain the above copyright
7 #     notice, this list of conditions and the following disclaimer.
8 # 2.  Redistributions in binary form must reproduce the above copyright
9 #     notice, this list of conditions and the following disclaimer in the
10 #     documentation and/or other materials provided with the distribution.
11 #
12 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
13 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 # DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
16 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
20 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
23 import optparse
24 import unittest
25
26 import webkitpy.style.checker as checker
27
28 from main import change_directory
29 from webkitpy.common.host import Host
30 from webkitpy.common.system.filesystem_mock import MockFileSystem
31 from webkitpy.common.system.outputcapture import OutputCaptureScope
32 from webkitpy.common.system.logtesting import LogTesting
33 from webkitpy.style.checker import StyleProcessor
34 from webkitpy.style.filereader import TextFileReader
35
36
37 class ChangeDirectoryTest(unittest.TestCase):
38     _original_directory = "/original"
39     _checkout_root = "/WebKit"
40
41     def setUp(self):
42         self._log = LogTesting.setUp(self)
43         self.filesystem = MockFileSystem(dirs=[self._original_directory, self._checkout_root], cwd=self._original_directory)
44
45     def tearDown(self):
46         self._log.tearDown()
47
48     def _change_directory(self, paths, checkout_root):
49         return change_directory(self.filesystem, paths=paths, checkout_root=checkout_root)
50
51     def _assert_result(self, actual_return_value, expected_return_value,
52                        expected_log_messages, expected_current_directory):
53         self.assertEqual(actual_return_value, expected_return_value)
54         self._log.assertMessages(expected_log_messages)
55         self.assertEqual(self.filesystem.getcwd(), expected_current_directory)
56
57     def test_paths_none(self):
58         paths = self._change_directory(checkout_root=self._checkout_root, paths=None)
59         self._assert_result(paths, None, [], self._checkout_root)
60
61     def test_paths_convertible(self):
62         paths = ["/WebKit/foo1.txt", "/WebKit/foo2.txt"]
63         paths = self._change_directory(checkout_root=self._checkout_root, paths=paths)
64         self._assert_result(paths, ["foo1.txt", "foo2.txt"], [], self._checkout_root)
65
66     def test_with_scm_paths_unconvertible(self):
67         paths = ["/WebKit/foo1.txt", "/outside/foo2.txt"]
68         paths = self._change_directory(checkout_root=self._checkout_root, paths=paths)
69         log_messages = [
70 """WARNING: Path-dependent style checks may not work correctly:
71
72   One of the given paths is outside the WebKit checkout of the current
73   working directory:
74
75     Path: /outside/foo2.txt
76     Checkout root: /WebKit
77
78   Pass only files below the checkout root to ensure correct results.
79   See the help documentation for more info.
80
81 """]
82         self._assert_result(paths, paths, log_messages, self._original_directory)
83
84
85 class ExpectationLinterInStyleCheckerTest(unittest.TestCase):
86
87     def setUp(self):
88         parser = checker.check_webkit_style_parser()
89         (_, options) = parser.parse([])
90         self._style_checker_configuration = checker.check_webkit_style_configuration(options)
91
92     def _generate_file_reader(self, file_system):
93         style_processor = StyleProcessor(self._style_checker_configuration)
94         return TextFileReader(file_system, style_processor)
95
96     def _generate_testing_host(self, files={}):
97         host = Host()
98         expectation_files = files
99
100         host.filesystem = MockFileSystem(dirs=['/mock-checkout/LayoutTests'])
101         options = optparse.Values()
102         setattr(options, 'layout_tests_dir', '/mock-checkout/LayoutTests')
103
104         all_ports = [host.port_factory.get(name, options=options) for name in host.port_factory.all_port_names()]
105         for port in all_ports:
106             for path in port.expectations_files():
107                 if path not in expectation_files:
108                     expectation_files[path] = '# Empty expectation file\n'
109
110         expectation_files['/mock-checkout/LayoutTests/css1/test.html'] = 'Test'
111         expectation_files['/mock-checkout/LayoutTests/css1/test-expected.txt'] = 'Test Expectation'
112         host.filesystem = MockFileSystem(files=expectation_files)
113         return host
114
115     def test_no_linter_errors(self):
116         host = self._generate_testing_host()
117
118         scope = OutputCaptureScope()
119         with scope:
120             file_reader = self._generate_file_reader(host.filesystem)
121             file_reader.do_association_check('/mock-checkout', host)
122         self.assertEqual(scope.captured_output, ('', '', ''))
123
124     def test_linter_duplicate_line(self):
125         files = {
126             '/mock-checkout/LayoutTests/TestExpectations':
127             '# TestExpectations\ncss1/test.html [ Failure ]\ncss1/test.html [ Failure ]\n'}
128         host = self._generate_testing_host(files)
129
130         scope = OutputCaptureScope()
131         with scope:
132             file_reader = self._generate_file_reader(host.filesystem)
133             file_reader.process_paths({'/mock-checkout/LayoutTests/TestExpectations'})
134             file_reader.do_association_check('/mock-checkout', host)
135         self.assertEqual(
136             scope.captured_output,
137             ('', '', '/mock-checkout/LayoutTests/TestExpectations:3:  Duplicate or ambiguous entry lines LayoutTests/TestExpectations:2 and LayoutTests/TestExpectations:3.  [test/expectations] [5]\n'))
138
139     def test_linter_duplicate_line_no_edit(self):
140         files = {
141             '/mock-checkout/LayoutTests/TestExpectations':
142             '# TestExpectations\ncss1/test.html [ Failure ]\ncss1/test.html [ Failure ]\n'}
143         host = self._generate_testing_host(files)
144
145         scope = OutputCaptureScope()
146         with scope:
147             file_reader = self._generate_file_reader(host.filesystem)
148             file_reader.process_paths(['/mock-checkout/LayoutTests/platform/ios/TestExpectations'])
149             file_reader.do_association_check('/mock-checkout', host)
150         self.assertEqual(scope.captured_output, ('', '', ''))
151
152     def test_linter_duplicate_line_edit_in_file(self):
153         files = {
154             '/mock-checkout/LayoutTests/TestExpectations':
155             '# TestExpectations\ncss1/test.html [ Failure ]\ncss1/test.html [ Failure ]\n'}
156         host = self._generate_testing_host(files)
157
158         scope = OutputCaptureScope()
159         with scope:
160             file_reader = self._generate_file_reader(host.filesystem)
161             file_reader.process_file('/mock-checkout/LayoutTests/TestExpectations', line_numbers=[1])
162             file_reader.do_association_check('/mock-checkout', host)
163         self.assertEqual(scope.captured_output, ('', '', ''))
164
165     def test_linter_deleted_file(self):
166         files = {
167             '/mock-checkout/LayoutTests/TestExpectations':
168             '# TestExpectations\ncss1/deleted-test.html [ Failure ]\n'}
169         host = self._generate_testing_host(files)
170         host = self._generate_testing_host(files)
171
172         scope = OutputCaptureScope()
173         with scope:
174             file_reader = self._generate_file_reader(host.filesystem)
175             file_reader.delete_file('/mock-checkout/LayoutTests/css1/deleted-test.html')
176             file_reader.do_association_check('/mock-checkout', host)
177         self.assertEqual(
178             scope.captured_output,
179             ('', '', '/mock-checkout/LayoutTests/TestExpectations:2:  Path does not exist.  [test/expectations] [5]\n'))
180
181     def test_linter_deleted_file_no_edit(self):
182         files = {
183             '/mock-checkout/LayoutTests/TestExpectations':
184             '# TestExpectations\ncss1/deleted-test.html [ Failure ]\n'}
185         host = self._generate_testing_host(files)
186
187         scope = OutputCaptureScope()
188         with scope:
189             file_reader = self._generate_file_reader(host.filesystem)
190             file_reader.delete_file('/mock-checkout/LayoutTests/css1/other-deleted-test.html')
191             file_reader.do_association_check('/mock-checkout', host)
192         self.assertEqual(scope.captured_output, ('', '', ''))