Skip to content

Commit 505c334

Browse files
committed
Fix pytest with mixed up filename casing.
1 parent 0215bcd commit 505c334

File tree

2 files changed

+37
-11
lines changed

2 files changed

+37
-11
lines changed

src/_pytest/config/__init__.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
hookspec = HookspecMarker("pytest")
3737

3838

39+
def _uniquepath(path):
40+
return type(path)(os.path.normcase(str(path.realpath())))
41+
42+
3943
class ConftestImportFailure(Exception):
4044
def __init__(self, path, excinfo):
4145
Exception.__init__(self, path, excinfo)
@@ -366,7 +370,7 @@ def _set_initial_conftests(self, namespace):
366370
"""
367371
current = py.path.local()
368372
self._confcutdir = (
369-
current.join(namespace.confcutdir, abs=True)
373+
_uniquepath(current.join(namespace.confcutdir, abs=True))
370374
if namespace.confcutdir
371375
else None
372376
)
@@ -405,19 +409,18 @@ def _getconftestmodules(self, path):
405409
else:
406410
directory = path
407411

412+
directory = _uniquepath(directory)
413+
408414
# XXX these days we may rather want to use config.rootdir
409415
# and allow users to opt into looking into the rootdir parent
410416
# directories instead of requiring to specify confcutdir
411417
clist = []
412-
for parent in directory.realpath().parts():
418+
for parent in directory.parts():
413419
if self._confcutdir and self._confcutdir.relto(parent):
414420
continue
415421
conftestpath = parent.join("conftest.py")
416422
if conftestpath.isfile():
417-
# Use realpath to avoid loading the same conftest twice
418-
# with build systems that create build directories containing
419-
# symlinks to actual files.
420-
mod = self._importconftest(conftestpath.realpath())
423+
mod = self._importconftest(conftestpath)
421424
clist.append(mod)
422425
self._dirpath2confmods[directory] = clist
423426
return clist
@@ -432,6 +435,10 @@ def _rget_with_confmod(self, name, path):
432435
raise KeyError(name)
433436

434437
def _importconftest(self, conftestpath):
438+
# Use realpath to avoid loading the same conftest twice
439+
# with build systems that create build directories containing
440+
# symlinks to actual files.
441+
conftestpath = _uniquepath(conftestpath)
435442
try:
436443
return self._conftestpath2mod[conftestpath]
437444
except KeyError:

testing/test_conftest.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
import py
44

55
import pytest
6-
from _pytest.config import PytestPluginManager
6+
from _pytest.config import PytestPluginManager, _uniquepath
77
from _pytest.main import ExitCode
8+
import os.path
89

910

1011
def ConftestWithSetinitial(path):
@@ -141,11 +142,11 @@ def test_conftestcutdir(testdir):
141142
# but we can still import a conftest directly
142143
conftest._importconftest(conf)
143144
values = conftest._getconftestmodules(conf.dirpath())
144-
assert values[0].__file__.startswith(str(conf))
145+
assert values[0].__file__.startswith(str(_uniquepath(conf)))
145146
# and all sub paths get updated properly
146147
values = conftest._getconftestmodules(p)
147148
assert len(values) == 1
148-
assert values[0].__file__.startswith(str(conf))
149+
assert values[0].__file__.startswith(str(_uniquepath(conf)))
149150

150151

151152
def test_conftestcutdir_inplace_considered(testdir):
@@ -154,7 +155,7 @@ def test_conftestcutdir_inplace_considered(testdir):
154155
conftest_setinitial(conftest, [conf.dirpath()], confcutdir=conf.dirpath())
155156
values = conftest._getconftestmodules(conf.dirpath())
156157
assert len(values) == 1
157-
assert values[0].__file__.startswith(str(conf))
158+
assert values[0].__file__.startswith(str(_uniquepath(conf)))
158159

159160

160161
@pytest.mark.parametrize("name", "test tests whatever .dotdir".split())
@@ -164,7 +165,7 @@ def test_setinitial_conftest_subdirs(testdir, name):
164165
conftest = PytestPluginManager()
165166
conftest_setinitial(conftest, [sub.dirpath()], confcutdir=testdir.tmpdir)
166167
if name not in ("whatever", ".dotdir"):
167-
assert subconftest in conftest._conftestpath2mod
168+
assert _uniquepath(subconftest) in conftest._conftestpath2mod
168169
assert len(conftest._conftestpath2mod) == 1
169170
else:
170171
assert subconftest not in conftest._conftestpath2mod
@@ -274,6 +275,24 @@ def fixture():
274275
result.stdout.fnmatch_lines(["*conftest_loaded*", "PASSED"])
275276
assert result.ret == ExitCode.OK
276277

278+
@pytest.mark.skipif(
279+
os.path.normcase('x') != os.path.normcase('X'),
280+
reason="only relevant for case insensitive file systems",
281+
)
282+
def test_conftest_badcase(testdir):
283+
"""Check conftest.py loading when directory casing is wrong."""
284+
testdir.tmpdir.mkdir("JenkinsRoot").mkdir("test")
285+
source = {
286+
"setup.py": "",
287+
"test/__init__.py": "",
288+
"test/conftest.py": ""
289+
}
290+
testdir.makepyfile(**{"JenkinsRoot/%s" % k: v for k, v in source.items()})
291+
292+
testdir.tmpdir.join("jenkinsroot/test").chdir()
293+
result = testdir.runpytest()
294+
assert result.ret == ExitCode.NO_TESTS_COLLECTED
295+
277296

278297
def test_no_conftest(testdir):
279298
testdir.makeconftest("assert 0")

0 commit comments

Comments
 (0)