Skip to content

Commit fc4792b

Browse files
committed
fix testrunner to handle relative entries in sys.path
1 parent 2e37ca3 commit fc4792b

File tree

4 files changed

+49
-5
lines changed

4 files changed

+49
-5
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
### Fixed
10+
* Fixed a regression introduced in #1176 where the testrunner couldn't handle relative paths in `sys.path`, causing `basilisp test` to fail when no arugments were provided (#1204)
11+
912
## [v0.3.6]
1013
### Added
1114
* Added support for the `:decorators` meta key in anonymous `fn`s (#1178)

src/basilisp/cli.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,7 @@ def test(
745745
"Cannot run tests without dependency PyTest. Please install PyTest and try again.",
746746
)
747747
else:
748-
pytest.main(args=list(extra))
748+
sys.exit(pytest.main(args=list(extra)))
749749

750750

751751
@_subcommand(
@@ -768,7 +768,9 @@ def test(
768768
If all options are unambiguous (e.g. they are only either used by Basilisp
769769
or by PyTest), then you can omit the `--`:
770770
771-
`basilisp test -k vector -p other_dir`"""
771+
`basilisp test -k vector -p other_dir`
772+
773+
Returns the PyTest exit code as the exit code."""
772774
),
773775
handler=test,
774776
allows_extra=True,

src/basilisp/contrib/pytest/testrunner.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from basilisp.lang import symbol as sym
1818
from basilisp.lang import vector as vec
1919
from basilisp.lang.obj import lrepr
20+
from basilisp.lang.util import munge
2021
from basilisp.util import Maybe
2122

2223
_EACH_FIXTURES_META_KW = kw.keyword("each-fixtures", "basilisp.test")
@@ -183,9 +184,10 @@ def _get_fully_qualified_module_names(file: Path) -> list[str]:
183184
there, we derive a Python module name referring to the given module path."""
184185
paths = []
185186
for pth in sys.path:
186-
root = Path(pth)
187+
root = Path(pth).resolve()
187188
if file.is_relative_to(root):
188-
elems = list(file.with_suffix("").relative_to(pth).parts)
189+
elems = list(file.with_suffix("").relative_to(root).parts)
190+
189191
if elems[-1] == "__init__":
190192
elems.pop()
191193
paths.append(".".join(elems))
@@ -269,6 +271,12 @@ def collect(self):
269271
filename = self.path.name
270272
module = self._import_module()
271273
ns = module.__basilisp_namespace__
274+
275+
# Ensure the test module was loaded because it was directly
276+
# relative to an entry in `sys.path`.
277+
if module.__name__ != munge(str(ns)):
278+
raise ModuleNotFoundError(f"Module named '{ns}' is not in sys.path")
279+
272280
once_fixtures, each_fixtures = self._collected_fixtures(ns)
273281
self._fixture_manager = FixtureManager(once_fixtures)
274282
for test in self._collected_tests(ns):

tests/basilisp/testrunner_test.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import platform
2+
import shutil
3+
import subprocess
24
import sys
35

46
import pytest
@@ -263,6 +265,33 @@ def test_fixtures_with_errors(
263265
result.assert_outcomes(passed=passes, failed=failures, errors=errors)
264266

265267

268+
def test_basilisp_test_noargs(pytester: pytest.Pytester):
269+
runtime.Namespace.remove(sym.symbol("a.test-path"))
270+
271+
code = """
272+
(ns tests.test-path
273+
(:require
274+
[basilisp.test :refer [deftest is]]))
275+
(deftest passing-test
276+
(is true))
277+
"""
278+
pytester.makefile(".lpy", **{"./tests/test_path": code})
279+
280+
# I couldn't find a way to directly manipulate the pytester's
281+
# `sys.path` with the precise control needed by this test, so I'm
282+
# invoking `basilisp test` directly as a subprocess instead ...
283+
basilisp = shutil.which("basilisp")
284+
cmd = [basilisp, "test"]
285+
result = subprocess.run(cmd, capture_output=True, text=True, cwd=pytester.path)
286+
287+
print(f"\n\n--cmd--start: {' '.join(cmd)}")
288+
print(f"\n\n--stdout--\n\n {result.stdout.strip()}")
289+
print(f"\n\n--stderr--:\n\n {result.stderr.strip()}")
290+
print(f"\n\n--cmd--end--: {' '.join(cmd)}\n\n")
291+
292+
assert result.returncode == 0
293+
294+
266295
def test_ns_in_syspath(pytester: pytest.Pytester, monkeypatch: pytest.MonkeyPatch):
267296
runtime.Namespace.remove(sym.symbol("a.test-path"))
268297

@@ -328,7 +357,9 @@ def test_ns_not_in_syspath(pytester: pytest.Pytester):
328357
pytester.syspathinsert()
329358
result: pytest.RunResult = pytester.runpytest("test")
330359
assert result.ret != 0
331-
result.stdout.fnmatch_lines(["*ModuleNotFoundError: No module named 'test.a'"])
360+
result.stdout.fnmatch_lines(
361+
["*ModuleNotFoundError: Module named 'a.test-path' is not in sys.path"]
362+
)
332363

333364

334365
def test_ns_with_underscore(pytester: pytest.Pytester):

0 commit comments

Comments
 (0)