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