| # pylint: disable=g-bad-file-header | |
| # Copyright 2018 The Bazel Authors. All rights reserved. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| import os | |
| import tempfile | |
| import unittest | |
| from tools.python.runfiles import runfiles | |
| class RunfilesTest(unittest.TestCase): | |
| # """Unit tests for `runfiles.Runfiles`.""" | |
| def testRlocationArgumentValidation(self): | |
| r = runfiles.Create({"RUNFILES_DIR": "whatever"}) | |
| self.assertRaises(ValueError, lambda: r.Rlocation(None)) | |
| self.assertRaises(ValueError, lambda: r.Rlocation("")) | |
| self.assertRaises(TypeError, lambda: r.Rlocation(1)) | |
| self.assertRaisesRegex(ValueError, "is not normalized", | |
| lambda: r.Rlocation("../foo")) | |
| self.assertRaisesRegex(ValueError, "is not normalized", | |
| lambda: r.Rlocation("foo/..")) | |
| self.assertRaisesRegex(ValueError, "is not normalized", | |
| lambda: r.Rlocation("foo/../bar")) | |
| self.assertRaisesRegex(ValueError, "is not normalized", | |
| lambda: r.Rlocation("./foo")) | |
| self.assertRaisesRegex(ValueError, "is not normalized", | |
| lambda: r.Rlocation("foo/.")) | |
| self.assertRaisesRegex(ValueError, "is not normalized", | |
| lambda: r.Rlocation("foo/./bar")) | |
| self.assertRaisesRegex(ValueError, "is not normalized", | |
| lambda: r.Rlocation("//foobar")) | |
| self.assertRaisesRegex(ValueError, "is not normalized", | |
| lambda: r.Rlocation("foo//")) | |
| self.assertRaisesRegex(ValueError, "is not normalized", | |
| lambda: r.Rlocation("foo//bar")) | |
| self.assertRaisesRegex(ValueError, "is absolute without a drive letter", | |
| lambda: r.Rlocation("\\foo")) | |
| def testCreatesManifestBasedRunfiles(self): | |
| with _MockFile(contents=["a/b c/d"]) as mf: | |
| r = runfiles.Create({ | |
| "RUNFILES_MANIFEST_FILE": mf.Path(), | |
| "RUNFILES_DIR": "ignored when RUNFILES_MANIFEST_FILE has a value", | |
| "TEST_SRCDIR": "always ignored", | |
| }) | |
| self.assertEqual(r.Rlocation("a/b"), "c/d") | |
| self.assertIsNone(r.Rlocation("foo")) | |
| def testManifestBasedRunfilesEnvVars(self): | |
| with _MockFile(name="MANIFEST") as mf: | |
| r = runfiles.Create({ | |
| "RUNFILES_MANIFEST_FILE": mf.Path(), | |
| "TEST_SRCDIR": "always ignored", | |
| }) | |
| self.assertDictEqual( | |
| r.EnvVars(), { | |
| "RUNFILES_MANIFEST_FILE": mf.Path(), | |
| "RUNFILES_DIR": mf.Path()[:-len("/MANIFEST")], | |
| "JAVA_RUNFILES": mf.Path()[:-len("/MANIFEST")], | |
| }) | |
| with _MockFile(name="foo.runfiles_manifest") as mf: | |
| r = runfiles.Create({ | |
| "RUNFILES_MANIFEST_FILE": mf.Path(), | |
| "TEST_SRCDIR": "always ignored", | |
| }) | |
| self.assertDictEqual( | |
| r.EnvVars(), { | |
| "RUNFILES_MANIFEST_FILE": | |
| mf.Path(), | |
| "RUNFILES_DIR": ( | |
| mf.Path()[:-len("foo.runfiles_manifest")] + "foo.runfiles"), | |
| "JAVA_RUNFILES": ( | |
| mf.Path()[:-len("foo.runfiles_manifest")] + "foo.runfiles"), | |
| }) | |
| with _MockFile(name="x_manifest") as mf: | |
| r = runfiles.Create({ | |
| "RUNFILES_MANIFEST_FILE": mf.Path(), | |
| "TEST_SRCDIR": "always ignored", | |
| }) | |
| self.assertDictEqual( | |
| r.EnvVars(), { | |
| "RUNFILES_MANIFEST_FILE": mf.Path(), | |
| "RUNFILES_DIR": "", | |
| "JAVA_RUNFILES": "", | |
| }) | |
| def testCreatesDirectoryBasedRunfiles(self): | |
| r = runfiles.Create({ | |
| "RUNFILES_DIR": "runfiles/dir", | |
| "TEST_SRCDIR": "always ignored", | |
| }) | |
| self.assertEqual(r.Rlocation("a/b"), "runfiles/dir/a/b") | |
| self.assertEqual(r.Rlocation("foo"), "runfiles/dir/foo") | |
| def testDirectoryBasedRunfilesEnvVars(self): | |
| r = runfiles.Create({ | |
| "RUNFILES_DIR": "runfiles/dir", | |
| "TEST_SRCDIR": "always ignored", | |
| }) | |
| self.assertDictEqual(r.EnvVars(), { | |
| "RUNFILES_DIR": "runfiles/dir", | |
| "JAVA_RUNFILES": "runfiles/dir", | |
| }) | |
| def testFailsToCreateManifestBasedBecauseManifestDoesNotExist(self): | |
| def _Run(): | |
| runfiles.Create({"RUNFILES_MANIFEST_FILE": "non-existing path"}) | |
| self.assertRaisesRegex(IOError, "non-existing path", _Run) | |
| def testFailsToCreateAnyRunfilesBecauseEnvvarsAreNotDefined(self): | |
| with _MockFile(contents=["a b"]) as mf: | |
| runfiles.Create({ | |
| "RUNFILES_MANIFEST_FILE": mf.Path(), | |
| "RUNFILES_DIR": "whatever", | |
| "TEST_SRCDIR": "always ignored", | |
| }) | |
| runfiles.Create({ | |
| "RUNFILES_DIR": "whatever", | |
| "TEST_SRCDIR": "always ignored", | |
| }) | |
| self.assertIsNone(runfiles.Create({"TEST_SRCDIR": "always ignored"})) | |
| self.assertIsNone(runfiles.Create({"FOO": "bar"})) | |
| def testManifestBasedRlocation(self): | |
| with _MockFile(contents=[ | |
| "Foo/runfile1", | |
| "Foo/runfile2 C:/Actual Path\\runfile2", | |
| "Foo/Bar/runfile3 D:\\the path\\run file 3.txt", | |
| "Foo/Bar/Dir E:\\Actual Path\\Directory", | |
| ]) as mf: | |
| r = runfiles.CreateManifestBased(mf.Path()) | |
| self.assertEqual(r.Rlocation("Foo/runfile1"), "Foo/runfile1") | |
| self.assertEqual(r.Rlocation("Foo/runfile2"), "C:/Actual Path\\runfile2") | |
| self.assertEqual( | |
| r.Rlocation("Foo/Bar/runfile3"), "D:\\the path\\run file 3.txt") | |
| self.assertEqual( | |
| r.Rlocation("Foo/Bar/Dir/runfile4"), | |
| "E:\\Actual Path\\Directory/runfile4") | |
| self.assertEqual( | |
| r.Rlocation("Foo/Bar/Dir/Deeply/Nested/runfile4"), | |
| "E:\\Actual Path\\Directory/Deeply/Nested/runfile4") | |
| self.assertIsNone(r.Rlocation("unknown")) | |
| if RunfilesTest.IsWindows(): | |
| self.assertEqual(r.Rlocation("c:/foo"), "c:/foo") | |
| self.assertEqual(r.Rlocation("c:\\foo"), "c:\\foo") | |
| else: | |
| self.assertEqual(r.Rlocation("/foo"), "/foo") | |
| def testDirectoryBasedRlocation(self): | |
| # The _DirectoryBased strategy simply joins the runfiles directory and the | |
| # runfile's path on a "/". This strategy does not perform any normalization, | |
| # nor does it check that the path exists. | |
| r = runfiles.CreateDirectoryBased("foo/bar baz//qux/") | |
| self.assertEqual(r.Rlocation("arg"), "foo/bar baz//qux/arg") | |
| if RunfilesTest.IsWindows(): | |
| self.assertEqual(r.Rlocation("c:/foo"), "c:/foo") | |
| self.assertEqual(r.Rlocation("c:\\foo"), "c:\\foo") | |
| else: | |
| self.assertEqual(r.Rlocation("/foo"), "/foo") | |
| def testPathsFromEnvvars(self): | |
| # Both envvars have a valid value. | |
| mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2", | |
| lambda path: path == "mock1/MANIFEST", | |
| lambda path: path == "mock2") | |
| self.assertEqual(mf, "mock1/MANIFEST") | |
| self.assertEqual(dr, "mock2") | |
| # RUNFILES_MANIFEST_FILE is invalid but RUNFILES_DIR is good and there's a | |
| # runfiles manifest in the runfiles directory. | |
| mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2", | |
| lambda path: path == "mock2/MANIFEST", | |
| lambda path: path == "mock2") | |
| self.assertEqual(mf, "mock2/MANIFEST") | |
| self.assertEqual(dr, "mock2") | |
| # RUNFILES_MANIFEST_FILE is invalid but RUNFILES_DIR is good, but there's no | |
| # runfiles manifest in the runfiles directory. | |
| mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2", | |
| lambda path: False, | |
| lambda path: path == "mock2") | |
| self.assertEqual(mf, "") | |
| self.assertEqual(dr, "mock2") | |
| # RUNFILES_DIR is invalid but RUNFILES_MANIFEST_FILE is good, and it is in | |
| # a valid-looking runfiles directory. | |
| mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2", | |
| lambda path: path == "mock1/MANIFEST", | |
| lambda path: path == "mock1") | |
| self.assertEqual(mf, "mock1/MANIFEST") | |
| self.assertEqual(dr, "mock1") | |
| # RUNFILES_DIR is invalid but RUNFILES_MANIFEST_FILE is good, but it is not | |
| # in any valid-looking runfiles directory. | |
| mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2", | |
| lambda path: path == "mock1/MANIFEST", | |
| lambda path: False) | |
| self.assertEqual(mf, "mock1/MANIFEST") | |
| self.assertEqual(dr, "") | |
| # Both envvars are invalid, but there's a manifest in a runfiles directory | |
| # next to argv0, however there's no other content in the runfiles directory. | |
| mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2", | |
| lambda path: path == "argv0.runfiles/MANIFEST", | |
| lambda path: False) | |
| self.assertEqual(mf, "argv0.runfiles/MANIFEST") | |
| self.assertEqual(dr, "") | |
| # Both envvars are invalid, but there's a manifest next to argv0. There's | |
| # no runfiles tree anywhere. | |
| mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2", | |
| lambda path: path == "argv0.runfiles_manifest", | |
| lambda path: False) | |
| self.assertEqual(mf, "argv0.runfiles_manifest") | |
| self.assertEqual(dr, "") | |
| # Both envvars are invalid, but there's a valid manifest next to argv0, and | |
| # a valid runfiles directory (without a manifest in it). | |
| mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2", | |
| lambda path: path == "argv0.runfiles_manifest", | |
| lambda path: path == "argv0.runfiles") | |
| self.assertEqual(mf, "argv0.runfiles_manifest") | |
| self.assertEqual(dr, "argv0.runfiles") | |
| # Both envvars are invalid, but there's a valid runfiles directory next to | |
| # argv0, though no manifest in it. | |
| mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2", | |
| lambda path: False, | |
| lambda path: path == "argv0.runfiles") | |
| self.assertEqual(mf, "") | |
| self.assertEqual(dr, "argv0.runfiles") | |
| # Both envvars are invalid, but there's a valid runfiles directory next to | |
| # argv0 with a valid manifest in it. | |
| mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2", | |
| lambda path: path == "argv0.runfiles/MANIFEST", | |
| lambda path: path == "argv0.runfiles") | |
| self.assertEqual(mf, "argv0.runfiles/MANIFEST") | |
| self.assertEqual(dr, "argv0.runfiles") | |
| # Both envvars are invalid and there's no runfiles directory or manifest | |
| # next to the argv0. | |
| mf, dr = runfiles._PathsFrom("argv0", "mock1/MANIFEST", "mock2", | |
| lambda path: False, lambda path: False) | |
| self.assertEqual(mf, "") | |
| self.assertEqual(dr, "") | |
| def testCurrentRepository(self): | |
| self.assertEqual( | |
| runfiles.Create({"RUNFILES_DIR": "whatever"}).CurrentRepository(), "") | |
| @staticmethod | |
| def IsWindows(): | |
| return os.name == "nt" | |
| class _MockFile(object): | |
| def __init__(self, name=None, contents=None): | |
| self._contents = contents or [] | |
| self._name = name or "x" | |
| self._path = None | |
| def __enter__(self): | |
| tmpdir = os.environ.get("TEST_TMPDIR") | |
| self._path = os.path.join(tempfile.mkdtemp(dir=tmpdir), self._name) | |
| with open(self._path, "wt") as f: | |
| f.writelines(l + "\n" for l in self._contents) | |
| return self | |
| def __exit__(self, exc_type, exc_value, traceback): | |
| os.remove(self._path) | |
| os.rmdir(os.path.dirname(self._path)) | |
| def Path(self): | |
| return self._path | |
| if __name__ == "__main__": | |
| unittest.main() |