xref: /aosp_15_r20/external/pigweed/pw_build/py/project_builder_prefs_test.py (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1# Copyright 2022 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 pw_build.project_builder_prefs"""
15
16import argparse
17import copy
18from pathlib import Path
19import shutil
20import tempfile
21from typing import Any
22import unittest
23
24from parameterized import parameterized  # type: ignore
25
26from pw_build.project_builder_argparse import add_project_builder_arguments
27from pw_build.project_builder_prefs import (
28    ProjectBuilderPrefs,
29    default_config,
30    load_defaults_from_argparse,
31)
32
33_BAZEL_COMMAND = 'bazel'
34# Prefer bazelisk if available.
35if shutil.which('bazelisk'):
36    _BAZEL_COMMAND = 'bazelisk'
37
38
39def _create_tempfile(content: str) -> Path:
40    with tempfile.NamedTemporaryFile(
41        prefix=f'{__package__}', delete=False
42    ) as output_file:
43        output_file.write(content.encode('UTF-8'))
44        return Path(output_file.name)
45
46
47class TestProjectBuilderPrefs(unittest.TestCase):
48    """Tests for ProjectBuilderPrefs."""
49
50    maxDiff = None
51
52    def test_load_no_existing_files(self) -> None:
53        # Create a prefs instance with no loaded config.
54        prefs = ProjectBuilderPrefs(
55            load_argparse_arguments=add_project_builder_arguments,
56            project_file=False,
57            project_user_file=False,
58            user_file=False,
59        )
60        # Construct an expected result config.
61        expected_config: dict[Any, Any] = {}
62        # Apply default build_system_commands and build_directories.
63        expected_config.update(default_config())
64        expected_config.update(
65            load_defaults_from_argparse(add_project_builder_arguments)
66        )
67
68        self.assertEqual(
69            prefs._config, expected_config  # pylint: disable=protected-access
70        )
71
72    @parameterized.expand(
73        [
74            (
75                'Manual --build-system-commands on the command line',
76                # Argparse input
77                [
78                    '--build-system-command',
79                    'out',
80                    'bazel build',
81                    '--build-system-command',
82                    'out',
83                    'bazel test',
84                ],
85                # Expected changed config
86                {
87                    'default_build_targets': [],
88                    'build_directories': [],
89                    'build_system_commands': {
90                        'out': {
91                            'commands': [
92                                {
93                                    'command': 'bazel',
94                                    'extra_args': ['build'],
95                                },
96                                {
97                                    'command': 'bazel',
98                                    'extra_args': ['test'],
99                                },
100                            ],
101                        },
102                    },
103                },
104            ),
105            (
106                'Empty build directory (no -C) with targets. '
107                'Ninja manually specified.',
108                # Argparse input
109                '--default-build-system ninja docs python.lint'.split(),
110                # Expected changed config
111                {
112                    'default_build_system': 'ninja',
113                    'default_build_targets': ['docs', 'python.lint'],
114                    'build_directories': [],
115                    'build_system_commands': {
116                        'default': {
117                            'commands': [{'command': 'ninja', 'extra_args': []}]
118                        }
119                    },
120                },
121            ),
122            (
123                'Empty build directory (no -C) with targets. '
124                'Ninja not specified.',
125                # Argparse input
126                'docs python.lint'.split(),
127                # Expected changed config
128                {
129                    'default_build_targets': ['docs', 'python.lint'],
130                    'build_directories': [],
131                    'build_system_commands': {
132                        'default': {
133                            'commands': [{'command': 'ninja', 'extra_args': []}]
134                        }
135                    },
136                },
137            ),
138            (
139                'Empty build directory (no -C) with targets (bazel).',
140                # Argparse input
141                (
142                    '--default-build-system bazel //pw_watch/... //pw_build/...'
143                ).split(),
144                # Expected changed config
145                {
146                    'default_build_system': 'bazel',
147                    'default_build_targets': [
148                        '//pw_watch/...',
149                        '//pw_build/...',
150                    ],
151                    'build_directories': [],
152                    'build_system_commands': {
153                        'default': {
154                            'commands': [
155                                {
156                                    'command': _BAZEL_COMMAND,
157                                    'extra_args': ['build'],
158                                },
159                                {
160                                    'command': _BAZEL_COMMAND,
161                                    'extra_args': ['test'],
162                                },
163                            ]
164                        }
165                    },
166                },
167            ),
168            (
169                'Targets with no build directory and an additional build '
170                'directory with targets.',
171                # Argparse input
172                'docs python.lint -C out2 python.tests'.split(),
173                # Expected changed config
174                {
175                    'default_build_targets': ['docs', 'python.lint'],
176                    'build_directories': [['out2', 'python.tests']],
177                    'build_system_commands': {
178                        'default': {
179                            'commands': [{'command': 'ninja', 'extra_args': []}]
180                        }
181                    },
182                },
183            ),
184            (
185                '',
186                # Argparse input
187                'docs python.lint -C out2 python.tests'.split(),
188                # Expected changed config
189                {
190                    'default_build_targets': ['docs', 'python.lint'],
191                    'build_directories': [['out2', 'python.tests']],
192                    'build_system_commands': {
193                        'default': {
194                            'commands': [{'command': 'ninja', 'extra_args': []}]
195                        }
196                    },
197                },
198            ),
199            (
200                'Two build directories; one with build system commands the '
201                'other with none defined.',
202                # Argparse input
203                [
204                    '-C',
205                    'out/gn',
206                    'python.lint',
207                    '-C',
208                    'out/bazel',
209                    '//...',
210                    '--build-system-command',
211                    'out/bazel',
212                    'bazel build',
213                    '--build-system-command',
214                    'out/bazel',
215                    'bazel test',
216                    '--logfile',
217                    'out/build.txt',
218                ],
219                # Expected changed config
220                {
221                    'default_build_targets': [],
222                    'build_directories': [
223                        ['out/gn', 'python.lint'],
224                        ['out/bazel', '//...'],
225                    ],
226                    'build_system_commands': {
227                        'default': {
228                            'commands': [{'command': 'ninja', 'extra_args': []}]
229                        },
230                        'out/bazel': {
231                            'commands': [
232                                {
233                                    'command': 'bazel',
234                                    'extra_args': ['build'],
235                                },
236                                {
237                                    'command': 'bazel',
238                                    'extra_args': ['test'],
239                                },
240                            ],
241                        },
242                    },
243                    'logfile': Path('out/build.txt'),
244                },
245            ),
246        ]
247    )
248    def test_apply_command_line_args(
249        self,
250        _name,
251        argparse_args,
252        expected_config_changes,
253    ):
254        """Check command line args are applied to ProjectBuilderPrefs."""
255        # Load default command line arg values.
256        parser = argparse.ArgumentParser(
257            formatter_class=argparse.RawDescriptionHelpFormatter,
258        )
259        parser = add_project_builder_arguments(parser)
260        argparse_output = parser.parse_args(argparse_args)
261
262        # Create a prefs instance with the test config file.
263        prefs = ProjectBuilderPrefs(
264            load_argparse_arguments=add_project_builder_arguments,
265            project_file=False,
266            project_user_file=False,
267            user_file=False,
268        )
269
270        # Save config before apply_command_line_args
271        # pylint: disable=protected-access
272        expected_config = copy.deepcopy(prefs._config)
273
274        # Run apply_command_line_args
275        prefs.apply_command_line_args(argparse_output)
276
277        # Add the expected changes to the base
278        expected_config.update(expected_config_changes)
279
280        # Check equality
281        self.assertEqual(prefs._config, expected_config)
282        # pylint: enable=protected-access
283
284
285if __name__ == '__main__':
286    unittest.main()
287