mirror of
https://github.com/nix-community/nix-direnv.git
synced 2025-11-08 11:36:11 +01:00
rewrite tests using pytest
this allows us to use fixtures that are more flexible
This commit is contained in:
parent
6dbc942fea
commit
748988f4b9
10 changed files with 195 additions and 113 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -1,2 +1,7 @@
|
|||
.direnv/
|
||||
/template/flake.lock
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
|
|
|||
|
|
@ -18,5 +18,5 @@ writeScript "run-tests" ''
|
|||
${mypy}/bin/mypy tests
|
||||
|
||||
echo -e "\x1b[32m## run unittest\x1b[0m"
|
||||
${python3.interpreter} -m unittest discover tests
|
||||
${python3.pkgs.pytest}/bin/pytest .
|
||||
''
|
||||
|
|
|
|||
23
setup.cfg
Normal file
23
setup.cfg
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
[wheel]
|
||||
universal = 1
|
||||
|
||||
[pycodestyle]
|
||||
max-line-length = 88
|
||||
ignore = E501,E741,W503
|
||||
|
||||
[flake8]
|
||||
max-line-length = 88
|
||||
ignore = E501,E741,W503
|
||||
exclude = .git,__pycache__,docs/source/conf.py,old,build,dist
|
||||
|
||||
[mypy]
|
||||
warn_redundant_casts = true
|
||||
disallow_untyped_calls = true
|
||||
disallow_untyped_defs = true
|
||||
no_implicit_optional = true
|
||||
|
||||
[mypy-pytest.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
[isort]
|
||||
profile = black
|
||||
|
|
@ -3,7 +3,10 @@
|
|||
with pkgs;
|
||||
mkShell {
|
||||
nativeBuildInputs = [
|
||||
python3
|
||||
python3.pkgs.pytest
|
||||
python3.pkgs.mypy
|
||||
python3.pkgs.black
|
||||
python3.pkgs.flake8
|
||||
shellcheck
|
||||
direnv
|
||||
];
|
||||
|
|
|
|||
6
tests/conftest.py
Normal file
6
tests/conftest.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
pytest_plugins = [
|
||||
"direnv_project",
|
||||
"root",
|
||||
]
|
||||
47
tests/direnv_project.py
Normal file
47
tests/direnv_project.py
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from dataclasses import dataclass
|
||||
import shutil
|
||||
from tempfile import TemporaryDirectory
|
||||
from typing import Iterator
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from procs import run
|
||||
|
||||
|
||||
@dataclass
|
||||
class DirenvProject:
|
||||
dir: Path
|
||||
nix_direnv: Path
|
||||
|
||||
@property
|
||||
def envrc(self) -> Path:
|
||||
return self.dir / ".envrc"
|
||||
|
||||
def setup_envrc(self, content: str) -> None:
|
||||
self.envrc.write_text(
|
||||
f"""
|
||||
source {self.nix_direnv}
|
||||
{content}
|
||||
"""
|
||||
)
|
||||
run(["direnv", "allow"], cwd=self.dir)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def direnv_project(test_root: Path, project_root: Path) -> Iterator[DirenvProject]:
|
||||
"""
|
||||
Setups a direnv test project
|
||||
"""
|
||||
with TemporaryDirectory() as _dir:
|
||||
dir = Path(_dir) / "proj"
|
||||
shutil.copytree(test_root / "testenv", dir)
|
||||
nix_direnv = project_root / "direnvrc"
|
||||
|
||||
c = DirenvProject(Path(dir), nix_direnv)
|
||||
try:
|
||||
yield c
|
||||
finally:
|
||||
pass
|
||||
25
tests/procs.py
Normal file
25
tests/procs.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import subprocess
|
||||
from typing import List, Union, IO, Any
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
_FILE = Union[None, int, IO[Any]]
|
||||
_DIR = Union[None, Path, str]
|
||||
|
||||
|
||||
def run(
|
||||
cmd: List[str],
|
||||
text: bool = True,
|
||||
check: bool = True,
|
||||
cwd: _DIR = None,
|
||||
stderr: _FILE = None,
|
||||
stdout: _FILE = None,
|
||||
) -> subprocess.CompletedProcess:
|
||||
if cwd is not None:
|
||||
print(f"cd {cwd}")
|
||||
print("$ " + " ".join(cmd))
|
||||
return subprocess.run(
|
||||
cmd, text=text, check=check, cwd=cwd, stderr=stderr, stdout=stdout
|
||||
)
|
||||
24
tests/root.py
Normal file
24
tests/root.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
TEST_ROOT = Path(__file__).parent.resolve()
|
||||
PROJECT_ROOT = TEST_ROOT.parent
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_root() -> Path:
|
||||
"""
|
||||
Root directory of the tests
|
||||
"""
|
||||
return TEST_ROOT
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def project_root() -> Path:
|
||||
"""
|
||||
Root directory of the tests
|
||||
"""
|
||||
return PROJECT_ROOT
|
||||
111
tests/test.py
111
tests/test.py
|
|
@ -1,111 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
from tempfile import TemporaryDirectory
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import unittest
|
||||
from typing import List
|
||||
|
||||
|
||||
TEST_ROOT = Path(__file__).resolve().parent
|
||||
RENEWED_MESSAGE = "renewed cache"
|
||||
CACHED_MESSAGE = "using cached dev shell"
|
||||
|
||||
|
||||
def run(cmd: List[str], **kwargs) -> subprocess.CompletedProcess:
|
||||
print("$ " + " ".join(cmd))
|
||||
return subprocess.run(cmd, **kwargs)
|
||||
|
||||
|
||||
class TestBaseNamespace:
|
||||
"""Nested so test discovery doesn't run the base class tests directly."""
|
||||
|
||||
class TestBase(unittest.TestCase):
|
||||
env: dict
|
||||
dir: TemporaryDirectory
|
||||
testenv: Path
|
||||
direnvrc: str
|
||||
direnvrc_command: str
|
||||
out1: subprocess.CompletedProcess
|
||||
out2: subprocess.CompletedProcess
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
cls.env = os.environ.copy()
|
||||
cls.dir = TemporaryDirectory()
|
||||
cls.env["HOME"] = str(cls.dir.name)
|
||||
cls.testenv = Path(cls.dir.name).joinpath("testenv")
|
||||
shutil.copytree(TEST_ROOT.joinpath("testenv"), cls.testenv)
|
||||
cls.direnvrc = str(TEST_ROOT.parent.joinpath("direnvrc"))
|
||||
|
||||
with open(cls.testenv.joinpath(".envrc"), "w") as f:
|
||||
f.write(f"source {cls.direnvrc}\n{cls.direnvrc_command}")
|
||||
|
||||
run(["direnv", "allow"], cwd=str(cls.testenv), env=cls.env, check=True)
|
||||
|
||||
run(["nix-collect-garbage"], check=True)
|
||||
|
||||
cls.out1 = run(
|
||||
["direnv", "exec", str(cls.testenv), "hello"],
|
||||
env=cls.env,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
sys.stderr.write(cls.out1.stderr)
|
||||
|
||||
run(["nix-collect-garbage"], check=True)
|
||||
|
||||
cls.out2 = run(
|
||||
["direnv", "exec", str(cls.testenv), "hello"],
|
||||
env=cls.env,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
sys.stderr.write(cls.out2.stderr)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls) -> None:
|
||||
cls.dir.cleanup()
|
||||
|
||||
def test_fresh_shell_message(self) -> None:
|
||||
self.assertIn(RENEWED_MESSAGE, self.out1.stderr)
|
||||
|
||||
def test_fresh_shell_shellHook_gets_executed(self) -> None:
|
||||
self.assertIn("Executing shellHook.", self.out1.stderr)
|
||||
|
||||
def test_fresh_shell_returncode(self) -> None:
|
||||
self.assertEqual(self.out1.returncode, 0)
|
||||
|
||||
def test_cached_shell_message(self) -> None:
|
||||
self.assertIn(CACHED_MESSAGE, self.out2.stderr)
|
||||
|
||||
def test_cached_shell_shellHook_gets_executed(self) -> None:
|
||||
self.assertIn("Executing shellHook.", self.out2.stderr)
|
||||
|
||||
def test_cached_shell_returncode(self) -> None:
|
||||
self.assertEqual(self.out2.returncode, 0)
|
||||
|
||||
|
||||
class NixShellTest(TestBaseNamespace.TestBase):
|
||||
direnvrc_command = "use nix"
|
||||
|
||||
|
||||
class FlakeTest(TestBaseNamespace.TestBase):
|
||||
direnvrc_command = "use flake"
|
||||
|
||||
def test_gcroot_symlink_created_and_valid(self) -> None:
|
||||
inputs = list(self.testenv.joinpath(".direnv/flake-inputs").iterdir())
|
||||
# should only contain our flake-utils flake
|
||||
if len(inputs) != 3:
|
||||
subprocess.run(["nix", "flake", "archive", "--json"], cwd=self.testenv)
|
||||
print(inputs)
|
||||
self.assertEqual(len(inputs), 3)
|
||||
for symlink in inputs:
|
||||
self.assertTrue(symlink.is_dir())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
60
tests/test_gc.py
Normal file
60
tests/test_gc.py
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
import unittest
|
||||
|
||||
from procs import run
|
||||
from direnv_project import DirenvProject
|
||||
|
||||
|
||||
def common_test(direnv_project: DirenvProject) -> None:
|
||||
run(["nix-collect-garbage"])
|
||||
|
||||
testenv = str(direnv_project.dir)
|
||||
|
||||
out1 = run(
|
||||
["direnv", "exec", testenv, "hello"],
|
||||
stderr=subprocess.PIPE,
|
||||
check=False,
|
||||
cwd=direnv_project.dir,
|
||||
)
|
||||
sys.stderr.write(out1.stderr)
|
||||
assert out1.returncode == 0
|
||||
assert "renewed cache" in out1.stderr
|
||||
assert "Executing shellHook." in out1.stderr
|
||||
|
||||
run(["nix-collect-garbage"])
|
||||
|
||||
out2 = run(
|
||||
["direnv", "exec", testenv, "hello"],
|
||||
stderr=subprocess.PIPE,
|
||||
check=False,
|
||||
cwd=direnv_project.dir,
|
||||
)
|
||||
sys.stderr.write(out2.stderr)
|
||||
assert out1.returncode == 0
|
||||
assert "using cached dev shell" in out2.stderr
|
||||
assert "Executing shellHook." in out2.stderr
|
||||
|
||||
|
||||
def test_use_nix(direnv_project: DirenvProject) -> None:
|
||||
direnv_project.setup_envrc("use nix")
|
||||
common_test(direnv_project)
|
||||
|
||||
|
||||
def test_use_flake(direnv_project: DirenvProject) -> None:
|
||||
direnv_project.setup_envrc("use flake")
|
||||
common_test(direnv_project)
|
||||
inputs = list((direnv_project.dir / ".direnv/flake-inputs").iterdir())
|
||||
# should only contain our flake-utils flake
|
||||
if len(inputs) != 3:
|
||||
run(["nix", "flake", "archive", "--json"], cwd=direnv_project.dir)
|
||||
print(inputs)
|
||||
assert len(inputs) == 3
|
||||
for symlink in inputs:
|
||||
assert symlink.is_dir()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue