# 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.assertRaisesRegexp(ValueError, "is not normalized", lambda: r.Rlocation("../foo")) self.assertRaisesRegexp(ValueError, "is not normalized", lambda: r.Rlocation("foo/..")) self.assertRaisesRegexp(ValueError, "is not normalized", lambda: r.Rlocation("foo/../bar")) self.assertRaisesRegexp(ValueError, "is not normalized", lambda: r.Rlocation("./foo")) self.assertRaisesRegexp(ValueError, "is not normalized", lambda: r.Rlocation("foo/.")) self.assertRaisesRegexp(ValueError, "is not normalized", lambda: r.Rlocation("foo/./bar")) self.assertRaisesRegexp(ValueError, "is not normalized", lambda: r.Rlocation("//foobar")) self.assertRaisesRegexp(ValueError, "is not normalized", lambda: r.Rlocation("foo//")) self.assertRaisesRegexp(ValueError, "is not normalized", lambda: r.Rlocation("foo//bar")) self.assertRaisesRegexp(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.assertRaisesRegexp(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" ]) 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.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, "") @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()