• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2024 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Tests for the buildifier formatter."""
15
16import importlib.resources
17from pathlib import Path
18from tempfile import TemporaryDirectory
19import unittest
20
21from format_testing_utils import CapturingToolRunner
22from pw_presubmit.format.bazel import BuildifierFormatter
23
24
25_TEST_DATA_FILES = importlib.resources.files('pw_presubmit.format.test_data')
26_TEST_SRC_FILE = _TEST_DATA_FILES / 'bazel_test_data.bazel'
27_TEST_GOLDEN = _TEST_DATA_FILES / 'bazel_test_data_golden.bazel'
28_TEST_MALFORMED = _TEST_DATA_FILES / 'malformed_file.txt'
29
30
31class TestBuildifierFormatter(unittest.TestCase):
32    """Tests for the BuildifierFormatter."""
33
34    def test_check_file(self):
35        """Tests that a formatting check produces the formatted result."""
36        tool_runner = CapturingToolRunner()
37        formatter = BuildifierFormatter()
38        formatter.run_tool = tool_runner
39
40        result = formatter.format_file_in_memory(
41            _TEST_SRC_FILE, _TEST_SRC_FILE.read_bytes()
42        )
43        self.assertTrue(result.ok)
44        self.assertEqual(result.error_message, None)
45        self.assertMultiLineEqual(
46            result.formatted_file_contents.decode(), _TEST_GOLDEN.read_text()
47        )
48
49        self.assertEqual(
50            tool_runner.command_history.pop(0),
51            ' '.join(
52                (
53                    'buildifier',
54                    '--type=build',
55                    '--lint=fix',
56                    '--warnings='
57                    + ','.join(
58                        (
59                            'load',
60                            'load-on-top',
61                            'native-build',
62                            'same-origin-load',
63                            'out-of-order-load',
64                            'unsorted-dict-items',
65                        )
66                    ),
67                )
68            ),
69        )
70
71    def test_check_file_error(self):
72        """Tests that a malformed build file propagates an error."""
73
74        tool_runner = CapturingToolRunner()
75        formatter = BuildifierFormatter()
76        formatter.run_tool = tool_runner
77
78        result = formatter.format_file_in_memory(
79            _TEST_MALFORMED, _TEST_MALFORMED.read_bytes()
80        )
81        self.assertFalse(result.ok)
82        self.assertEqual(result.formatted_file_contents, b'')
83        self.assertIn('syntax error', result.error_message)
84
85        self.assertEqual(
86            tool_runner.command_history.pop(0),
87            ' '.join(
88                (
89                    'buildifier',
90                    '--type=default',
91                    '--lint=fix',
92                    '--warnings='
93                    + ','.join(
94                        (
95                            'load',
96                            'load-on-top',
97                            'native-build',
98                            'same-origin-load',
99                            'out-of-order-load',
100                            'unsorted-dict-items',
101                        )
102                    ),
103                )
104            ),
105        )
106
107    def test_fix_file(self):
108        """Tests that formatting is properly applied to files."""
109
110        tool_runner = CapturingToolRunner()
111        formatter = BuildifierFormatter()
112        formatter.run_tool = tool_runner
113
114        with TemporaryDirectory() as temp_dir:
115            file_to_fix = Path(temp_dir) / _TEST_SRC_FILE.name
116            file_to_fix.write_bytes(_TEST_SRC_FILE.read_bytes())
117
118            malformed_file = Path(temp_dir) / _TEST_MALFORMED.name
119            malformed_file.write_bytes(_TEST_MALFORMED.read_bytes())
120
121            errors = list(formatter.format_files([file_to_fix, malformed_file]))
122
123            # Should see three separate commands, one where we try to format
124            # the *.bazel files together, and two where we try to format the
125            # .txt file (which is considered an unknown type).
126            self.assertEqual(
127                tool_runner.command_history.pop(0),
128                ' '.join(
129                    (
130                        'buildifier',
131                        '--type=build',
132                        '--lint=fix',
133                        '--warnings='
134                        + ','.join(
135                            (
136                                'load',
137                                'load-on-top',
138                                'native-build',
139                                'same-origin-load',
140                                'out-of-order-load',
141                                'unsorted-dict-items',
142                            )
143                        ),
144                        str(file_to_fix),
145                    )
146                ),
147            )
148
149            self.assertEqual(
150                tool_runner.command_history.pop(0),
151                ' '.join(
152                    (
153                        'buildifier',
154                        '--type=default',
155                        '--lint=fix',
156                        '--warnings='
157                        + ','.join(
158                            (
159                                'load',
160                                'load-on-top',
161                                'native-build',
162                                'same-origin-load',
163                                'out-of-order-load',
164                                'unsorted-dict-items',
165                            )
166                        ),
167                        str(malformed_file),
168                    )
169                ),
170            )
171
172            self.assertEqual(
173                tool_runner.command_history.pop(0),
174                ' '.join(
175                    (
176                        'buildifier',
177                        '--type=default',
178                        '--lint=fix',
179                        '--warnings='
180                        + ','.join(
181                            (
182                                'load',
183                                'load-on-top',
184                                'native-build',
185                                'same-origin-load',
186                                'out-of-order-load',
187                                'unsorted-dict-items',
188                            )
189                        ),
190                        str(malformed_file),
191                    )
192                ),
193            )
194
195            # Check good build file.
196            self.assertMultiLineEqual(
197                file_to_fix.read_text(), _TEST_GOLDEN.read_text()
198            )
199
200            # Check malformed file.
201            self.assertEqual(len(errors), 1)
202            malformed_files = [malformed_file]
203            for file_path, error in errors:
204                self.assertIn(file_path, malformed_files)
205                self.assertFalse(error.ok)
206                self.assertIn('syntax error', error.error_message)
207
208
209if __name__ == '__main__':
210    unittest.main()
211