| #!/usr/bin/env vpython3 |
| # Copyright 2019 The LUCI Authors. All rights reserved. |
| # Use of this source code is governed under the Apache License, Version 2.0 |
| # that can be found in the LICENSE file. |
| |
| # pylint: disable=missing-docstring |
| # pylint: disable=import-error |
| # pylint: disable=invalid-name |
| |
| import os |
| import sys |
| import tempfile |
| import unittest |
| |
| # Mutates sys.path. |
| import test_env |
| |
| # third_party/ |
| from depot_tools import auto_stub |
| |
| from utils import file_path |
| from utils import tools |
| |
| _ACTUALLY_WINDOWS = sys.platform == "win32" |
| |
| |
| class FindExecutableTest(auto_stub.TestCase): |
| """This tests the tools.find_executable function. |
| |
| All test cases and helper functions are written so that they can operate (with |
| few exceptions) on all platforms that run the test. Tests which test the |
| Windows behavior of find_executable must include the string "WIN" in their |
| test function name. |
| """ |
| |
| def setUp(self): |
| super(FindExecutableTest, self).setUp() |
| self.PATH = [] |
| self.playground = os.path.realpath(tempfile.mkdtemp('tools_test-')) |
| |
| self._orig_cwd = os.getcwd() |
| os.chdir(self.playground) |
| |
| if 'WIN' in self.id(): |
| self.mock(sys, "platform", "win32") |
| else: |
| self.mock(sys, "platform", "linux") |
| |
| # initial |
| self._touch_exe('SYSTEM', 'python') |
| self._touch_exe('SYSTEM', 'python.exe') |
| self._add_PATH_abs('SYSTEM') |
| |
| def tearDown(self): |
| super(FindExecutableTest, self).tearDown() |
| |
| # restore cwd |
| os.chdir(self._orig_cwd) |
| |
| file_path.rmtree(self.playground) |
| |
| def _add_PATH_abs(self, *path_toks): |
| self.PATH.append(self._abs(*path_toks)) |
| |
| def _abs(self, *path_toks): |
| return os.path.abspath(os.path.join(self.playground, *path_toks)) |
| |
| def _touch(self, *path_toks): |
| full = self._abs(*path_toks) |
| d = os.path.dirname(full) |
| if not os.path.isdir(d): |
| os.makedirs(d) |
| |
| with open(full, 'w') as f: |
| f.write('hi') |
| |
| return full |
| |
| def _touch_exe(self, *path_toks): |
| full = self._touch(*path_toks) |
| if not _ACTUALLY_WINDOWS: |
| os.chmod(full, 0o777) |
| return full |
| |
| def _fe(self, cmd): |
| return tools.find_executable(cmd, env={'PATH': os.pathsep.join(self.PATH)}) |
| |
| def test_missing_passthrough(self): |
| cmd = ['not_a_real_path'] |
| self.assertEqual(cmd, self._fe(cmd)) |
| |
| def test_missing_abs_passthrough(self): |
| cmd = [self._abs('not', 'real')] |
| self.assertEqual(cmd, self._fe(cmd)) |
| |
| @unittest.skipIf(sys.platform == 'win32', 'posix only') |
| def test_bad_permissions(self): |
| cmd = ['config_file'] |
| os.chmod(self._touch('something', 'dir', 'config_file'), 0) |
| os.chmod(self._abs('something', 'dir'), 0) |
| self._add_PATH_abs('something', 'dir') |
| self.assertEqual(cmd, self._fe(cmd)) |
| |
| def test_WIN_implicit_extension(self): |
| self.assertEqual([self._touch_exe('SYSTEM', 'hello.bat')], |
| self._fe(['hello'])) |
| |
| def test_implicit_cwd(self): |
| self.assertEqual([self._touch_exe('python')], self._fe(['python'])) |
| |
| def test_WIN_implicit_cwd(self): |
| self.assertEqual([self._touch_exe('python.bat')], self._fe(['python'])) |
| |
| def test_relative_PATH_entry(self): |
| self.PATH.insert(0, 'LOCAL') |
| self.assertEqual([self._touch_exe('LOCAL', 'thingy')], self._fe(['thingy'])) |
| |
| def test_skip_empty(self): |
| self.PATH.insert(0, '') |
| self.assertEqual([self._abs('SYSTEM', 'python')], self._fe(['python'])) |
| |
| def test_explicit_relative(self): |
| self.assertEqual([self._touch_exe('python')], self._fe(['./python'])) |
| |
| def test_WIN_explicit_relative(self): |
| self.assertEqual([self._touch_exe('python.exe')], self._fe(['./python'])) |
| |
| def test_explicit_relative_missing(self): |
| # slash gets flipped on windows because this is not resolved to an absolute |
| # path. |
| self.assertEqual([os.path.join('.', 'not_real')], self._fe(['./not_real'])) |
| |
| |
| if __name__ == '__main__': |
| test_env.main() |