From 330c45f9ec0d5dbbdafd1c8bc3a6e95c254a6973 Mon Sep 17 00:00:00 2001 From: Fabio Zadrozny Date: Tue, 21 Jan 2020 09:14:57 -0300 Subject: [PATCH] Fix issue where working dir becomes wrong on subst drive on Windows. Fixes #5965 --- changelog/5965.bugfix.rst | 1 + src/_pytest/config/__init__.py | 4 +- testing/test_windows_subst.py | 95 ++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 changelog/5965.bugfix.rst create mode 100644 testing/test_windows_subst.py diff --git a/changelog/5965.bugfix.rst b/changelog/5965.bugfix.rst new file mode 100644 index 00000000000..15f43b51d00 --- /dev/null +++ b/changelog/5965.bugfix.rst @@ -0,0 +1 @@ +No longer resolve symlinks so that the current directory remains correct even with drives mapped with subst on Windows. diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 2677c2bec57..702658c1822 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -177,7 +177,7 @@ def get_config(args=None, plugins=None): config = Config( pluginmanager, invocation_params=Config.InvocationParams( - args=args or (), plugins=plugins, dir=Path().resolve() + args=args or (), plugins=plugins, dir=Path().absolute() ), ) @@ -736,7 +736,7 @@ def __init__(self, pluginmanager, *, invocation_params=None): if invocation_params is None: invocation_params = self.InvocationParams( - args=(), plugins=None, dir=Path().resolve() + args=(), plugins=None, dir=Path().absolute() ) self.option = argparse.Namespace() diff --git a/testing/test_windows_subst.py b/testing/test_windows_subst.py new file mode 100644 index 00000000000..6700494914e --- /dev/null +++ b/testing/test_windows_subst.py @@ -0,0 +1,95 @@ +import os.path +import subprocess +import sys +from string import ascii_lowercase + +from py._path.local import LocalPath + +import pytest +from _pytest import pytester +from _pytest.fixtures import FixtureRequest + + +class _SubstTmpdirFactory: + """ + A temp dir factory which may do a subst on Windows drives. + """ + + def __init__(self, tmpdir, tmpdir_factory, subst): + self.tmpdir = tmpdir + self.tmpdir_factory = tmpdir_factory + self.subst = subst + self.subst_drives = {} + + def _subst_path(self, filename): + + if self.subst: + for c in ascii_lowercase[7:]: # Create a subst drive from H-Z. + c += ":" + if not os.path.exists(c): + drive = c + break + else: + raise AssertionError("Unable to find suitable drive letter for subst.") + + directory = os.path.dirname(filename) + basename = os.path.basename(filename) + + args = ["subst", drive, directory] + subprocess.check_call(args) + assert os.path.exists(drive) + self.subst_drives[drive] = directory + + filename = LocalPath(os.path.join(drive, basename)) + + return filename + + def mktemp(self, name, numbered): + filename = self.tmpdir_factory.mktemp(name, numbered=numbered) + filename = self._subst_path(filename) + return filename + + def unsubst(self): + for drive in self.subst_drives: + args = ["subst", "/D", drive] + subprocess.check_call(args) + + +@pytest.fixture(params=[{"subst": True}, {"subst": False}]) +def _subst_tmpdir_factory(request: FixtureRequest, tmpdir, tmpdir_factory): + if sys.platform != "win32": + pytest.skip("Windows only test.") + factory = _SubstTmpdirFactory(tmpdir, tmpdir_factory, **request.param) + yield factory + factory.unsubst() + + +@pytest.fixture +def _custom_testdir( + request: FixtureRequest, _subst_tmpdir_factory +) -> "pytester.Testdir": + return pytester.Testdir(request, _subst_tmpdir_factory) + + +def test_windows_subst_resolve(_custom_testdir, _subst_tmpdir_factory) -> None: + """ + Check that when we have a subst on Windows the errors reported are not + in the subst target. + See: https://github.com/pytest-dev/pytest/issues/5965 + """ + testdir = _custom_testdir + testdir.makepyfile( + """ + import pytest + def test_foo(): + raise AssertionError() + """ + ) + result = testdir.runpytest() + + # i.e.: Make sure that the error is reported as a relative path, not as an + # absolute (resolved) path. + # See: https://github.com/pytest-dev/pytest/issues/5965 + for _drive, directory in _subst_tmpdir_factory.subst_drives.items(): + for line in result.stdout.lines: + assert directory.lower() not in line.lower()