• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2025 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 runfiles_manager."""
15
16import unittest
17
18from pw_build import runfiles_manager
19
20try:
21    # pylint: disable=unused-import
22    from python.runfiles import runfiles  # type: ignore
23
24    _IS_GN = False
25except ImportError:
26    _IS_GN = True
27
28
29class TestRunfilesManager(unittest.TestCase):
30    """Tests for RunfilesManager.
31
32    These tests should always be run in BOTH the GN and Bazel builds.
33    There are different code paths tested in each. If one of the two breaks,
34    this test should NEVER have "if gn" or "if bazel" magic, since the purpose
35    of the RunfilesManager is to make handling both builds ergonomic.
36    """
37
38    def setUp(self):
39        self.r = runfiles_manager.RunfilesManager()
40
41    def test_runfiles_from_path(self):
42        self.r.add_bazel_tool('a', 'pw_build_external_runfile_resource.black')
43        self.r.add_bootstrapped_tool('a', 'black', from_shell_path=True)
44        black_tool = self.r.get('a')
45        self.assertTrue(black_tool.is_file())
46
47    def test_runfiles_at_root(self):
48        self.r.add_bazel_file('b', 'pw_build.test_runfile')
49        self.r.add_bazel_file('c', 'pw_build.another_test_runfile')
50        self.r.add_bootstrapped_file(
51            'b', '${PW_ROOT}/pw_build/test_data/test_runfile.txt'
52        )
53        self.r.add_bootstrapped_file(
54            'c', '${PW_ROOT}/pw_build/test_data/test_runfile.txt'
55        )
56
57        b = self.r['b']
58        self.assertTrue(b.is_file())
59        self.assertEqual(b.read_text(), "OK\n")
60
61        c = self.r.get('c')
62        self.assertTrue(c.is_file())
63        self.assertEqual(c.read_text(), "OK\n")
64
65    def test_bazel_missing(self):
66        self.r.add_bootstrapped_file(
67            'b', '${PW_ROOT}/pw_build/test_data/test_runfile.txt'
68        )
69
70        with self.assertRaisesRegex(ValueError, 'Either register in'):
71            self.r.get('b')
72
73    def test_bootstrap_missing(self):
74        self.r.add_bazel_file('b', 'pw_build.test_runfile')
75
76        with self.assertRaisesRegex(ValueError, 'Either register in'):
77            self.r.get('b')
78
79    def test_both_missing(self):
80        with self.assertRaisesRegex(
81            ValueError,
82            'is not a registered tool or runfile resource',
83        ):
84            self.r.get('a')
85
86
87if _IS_GN:
88
89    class TestBootstrapRunfilesManager(unittest.TestCase):
90        """GN-only tests for RunfilesManager."""
91
92        def setUp(self):
93            self.r = runfiles_manager.RunfilesManager()
94
95        def test_forgot_bazel(self):
96            with self.assertRaisesRegex(
97                ValueError,
98                '`a` was registered for bootstrap environments, but not for '
99                r'Bazel environments\. Either register in Bazel',
100            ):
101                self.r.add_bootstrapped_tool(
102                    'a',
103                    '${PW_ROOT}/pw_build/test_data/test_runfile.txt',
104                )
105                self.r.get('a')
106
107        def test_not_a_file(self):
108            with self.assertRaisesRegex(
109                ValueError,
110                r'Runfile `a=[^`]+` does not exist',
111            ):
112                self.r.add_bootstrapped_tool(
113                    'a',
114                    '${PW_ROOT}/pw_build/test_data/not_a_test_runfile.txt',
115                )
116                self.r.get('a')
117
118        def test_unspecified_env_var(self):
119            with self.assertRaisesRegex(
120                ValueError,
121                'no environment variable name',
122            ):
123                self.r.add_bootstrapped_tool('a', '${}/nah')
124
125        def test_unknown_env_var(self):
126            with self.assertRaisesRegex(
127                ValueError,
128                'Failed to expand the following environment variables for '
129                r'runfile entry `a=\${PW_ROOT}/\${_PW_VAR_D9EC8687538}/'
130                r'\${_PW_VAR_DEF6F3B0CA7}`: _PW_VAR_D9EC8687538, '
131                '_PW_VAR_DEF6F3B0CA7',
132            ):
133                self.r.add_bootstrapped_tool(
134                    'a',
135                    '${PW_ROOT}/${_PW_VAR_D9EC8687538}/${_PW_VAR_DEF6F3B0CA7}',
136                )
137
138        def test_misused_resource(self):
139            self.r.add_bazel_file('a', 'pw_build.test_runfile', exclusive=True)
140
141            with self.assertRaisesRegex(
142                ValueError,
143                'was marked as `exclusive=True` to Bazel environments, '
144                'but was used in a bootstrap environment',
145            ):
146                self.r.get('a')
147
148else:
149
150    class TestBazelRunfilesManager(unittest.TestCase):
151        """Bazel-only tests for RunfilesManager."""
152
153        def setUp(self):
154            self.r = runfiles_manager.RunfilesManager()
155
156        def test_forgot_bootstrap(self):
157            with self.assertRaisesRegex(
158                ValueError,
159                '`a` was registered for Bazel environments, but not for '
160                r'bootstrap environments\. Either register in bootstrap',
161            ):
162                self.r.add_bazel_tool('a', 'pw_build.test_runfile')
163                self.r.get('a')
164
165        def test_bad_import_path(self):
166            with self.assertRaisesRegex(
167                ValueError,
168                'Did you forget to add a dependency',
169            ):
170                self.r.add_bazel_tool('a', 'no.ahha.lol')
171
172        def test_misused_resource(self):
173            self.r.add_bootstrapped_file(
174                'a',
175                '${PW_ROOT}/pw_build/test_data/test_runfile.txt',
176                exclusive=True,
177            )
178
179            with self.assertRaisesRegex(
180                ValueError,
181                'was marked as `exclusive=True` to bootstrap environments, '
182                'but was used in a Bazel environment',
183            ):
184                self.r.get('a')
185
186
187if __name__ == '__main__':
188    unittest.main()
189