xref: /aosp_15_r20/external/pigweed/pw_presubmit/py/bazel_format_test.py (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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_WARNINGS = (
31    'load',
32    'native-build',
33    'unsorted-dict-items',
34)
35
36
37class TestBuildifierFormatter(unittest.TestCase):
38    """Tests for the BuildifierFormatter."""
39
40    def test_check_file(self):
41        """Tests that a formatting check produces the formatted result."""
42        tool_runner = CapturingToolRunner()
43        formatter = BuildifierFormatter()
44        formatter.run_tool = tool_runner
45
46        result = formatter.format_file_in_memory(
47            _TEST_SRC_FILE, _TEST_SRC_FILE.read_bytes()
48        )
49        self.assertTrue(result.ok)
50        self.assertEqual(result.error_message, None)
51        self.assertMultiLineEqual(
52            result.formatted_file_contents.decode(), _TEST_GOLDEN.read_text()
53        )
54
55        self.assertEqual(
56            tool_runner.command_history.pop(0),
57            ' '.join(
58                (
59                    'buildifier',
60                    '--type=build',
61                    '--lint=fix',
62                    f'--warnings={",".join(_WARNINGS)}',
63                )
64            ),
65        )
66
67    def test_check_file_error(self):
68        """Tests that a malformed build file propagates an error."""
69
70        tool_runner = CapturingToolRunner()
71        formatter = BuildifierFormatter()
72        formatter.run_tool = tool_runner
73
74        result = formatter.format_file_in_memory(
75            _TEST_MALFORMED, _TEST_MALFORMED.read_bytes()
76        )
77        self.assertFalse(result.ok)
78        # stdout may differ depending on the version of buildifier used.
79        self.assertNotIn(
80            'This is just a text file with random contents!',
81            result.formatted_file_contents.decode(),
82        )
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                    f'--warnings={",".join(_WARNINGS)}',
93                )
94            ),
95        )
96
97    def test_fix_file(self):
98        """Tests that formatting is properly applied to files."""
99
100        tool_runner = CapturingToolRunner()
101        formatter = BuildifierFormatter()
102        formatter.run_tool = tool_runner
103
104        with TemporaryDirectory() as temp_dir:
105            file_to_fix = Path(temp_dir) / _TEST_SRC_FILE.name
106            file_to_fix.write_bytes(_TEST_SRC_FILE.read_bytes())
107
108            malformed_file = Path(temp_dir) / _TEST_MALFORMED.name
109            malformed_file.write_bytes(_TEST_MALFORMED.read_bytes())
110
111            errors = list(formatter.format_files([file_to_fix, malformed_file]))
112
113            # Should see three separate commands, one where we try to format
114            # the *.bazel files together, and two where we try to format the
115            # .txt file (which is considered an unknown type).
116            self.assertEqual(
117                tool_runner.command_history.pop(0),
118                ' '.join(
119                    (
120                        'buildifier',
121                        '--type=build',
122                        '--lint=fix',
123                        '--warnings=' + ','.join(_WARNINGS),
124                        str(file_to_fix),
125                    )
126                ),
127            )
128
129            self.assertEqual(
130                tool_runner.command_history.pop(0),
131                ' '.join(
132                    (
133                        'buildifier',
134                        '--type=default',
135                        '--lint=fix',
136                        '--warnings=' + ','.join(_WARNINGS),
137                        str(malformed_file),
138                    )
139                ),
140            )
141
142            self.assertEqual(
143                tool_runner.command_history.pop(0),
144                ' '.join(
145                    (
146                        'buildifier',
147                        '--type=default',
148                        '--lint=fix',
149                        '--warnings=' + ','.join(_WARNINGS),
150                        str(malformed_file),
151                    )
152                ),
153            )
154
155            # Check good build file.
156            self.assertMultiLineEqual(
157                file_to_fix.read_text(), _TEST_GOLDEN.read_text()
158            )
159
160            # Check malformed file.
161            self.assertEqual(len(errors), 1)
162            malformed_files = [malformed_file]
163            for file_path, error in errors:
164                self.assertIn(file_path, malformed_files)
165                self.assertFalse(error.ok)
166                self.assertIn('syntax error', error.error_message)
167
168
169if __name__ == '__main__':
170    unittest.main()
171