Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions tests/tasks/test_arch.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,32 @@ def test_task_arch_layered_skips_when_no_layers_defined(
out = capsys.readouterr().out
assert "layered template selected" in out
assert "arch_layers" in out


# ─────────────── tool pin propagation ───────────────────────────────


def test_arch_import_linter_pin_override_flows_into_cmd(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""`[tool.interlocks.tools] import-linter` override replaces bundled pin in uvx argv."""
from interlocks.tasks import arch as arch_mod

(tmp_path / "pyproject.toml").write_text(
textwrap.dedent("""\
[project]
name = "pin-probe"
version = "0.0.0"

[tool.importlinter]
root_package = "pin_probe"

[tool.interlocks.tools]
import-linter = "9.99.0"
"""),
encoding="utf-8",
)
monkeypatch.chdir(tmp_path)
task = arch_mod.task_arch()
assert task is not None, "expected a Task (user importlinter config present)"
assert "import-linter==9.99.0" in task.cmd
24 changes: 24 additions & 0 deletions tests/tasks/test_audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,27 @@ def test_audit_network_skip_clean_run_prints_ok(
audit_mod.cmd_audit(allow_network_skip=True)

assert "no known vulnerabilities" in capsys.readouterr().out.lower()


# ─────────────── tool pin propagation ───────────────────────────────


def test_audit_pip_audit_pin_override_flows_into_cmd(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""`[tool.interlocks.tools] pip-audit` override replaces the bundled pin in uvx argv."""
(tmp_path / "pyproject.toml").write_text(
textwrap.dedent("""\
[project]
name = "pin-probe"
version = "0.0.1"
dependencies = ["requests"]

[tool.interlocks.tools]
pip-audit = "9.99.0"
"""),
encoding="utf-8",
)
monkeypatch.chdir(tmp_path)
task = audit_mod.task_audit()
assert "pip-audit==9.99.0" in task.cmd
25 changes: 25 additions & 0 deletions tests/tasks/test_complexity.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,28 @@ def test_complexity_honors_tool_interlock_overrides(
assert _flag_value(cmd, "-C") == "20"
assert _flag_value(cmd, "-a") == "5"
assert _flag_value(cmd, "-L") == "150"


# ─────────────── tool pin propagation ───────────────────────────────


def test_complexity_lizard_pin_override_flows_into_cmd(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""`[tool.interlocks.tools] lizard` override replaces the bundled pin in uvx argv."""
(tmp_path / "pyproject.toml").write_text(
textwrap.dedent("""\
[project]
name = "pin-probe"
version = "0.0.0"

[tool.interlocks.tools]
lizard = "9.99.0"
"""),
encoding="utf-8",
)
monkeypatch.chdir(tmp_path)
from interlocks.tasks.complexity import task_complexity

cmd = task_complexity().cmd
assert "lizard==9.99.0" in cmd
25 changes: 25 additions & 0 deletions tests/tasks/test_deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,28 @@ def fake_run(task: Task, **_: object) -> None:
assert "--known-first-party" in cmd
kfp_idx = cmd.index("--known-first-party")
assert cmd[kfp_idx + 1] == "interlocks"


# ─────────────── tool pin propagation ───────────────────────────────


def test_deps_deptry_pin_override_flows_into_cmd(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""`[tool.interlocks.tools] deptry` override replaces the bundled pin in uvx argv."""
from interlocks.tasks.deps import task_deps

(tmp_path / "pyproject.toml").write_text(
textwrap.dedent("""\
[project]
name = "pin-probe"
version = "0.0.0"

[tool.interlocks.tools]
deptry = "9.99.0"
"""),
encoding="utf-8",
)
monkeypatch.chdir(tmp_path)
cmd = task_deps().cmd
assert "deptry==9.99.0" in cmd
25 changes: 25 additions & 0 deletions tests/tasks/test_lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,28 @@ def test_lint_omits_config_when_project_has_ruff_sidecar(
(tmp_path / "ruff.toml").write_text("line-length = 99\n", encoding="utf-8")
monkeypatch.chdir(tmp_path)
assert "--config" not in task_lint().cmd


# ─────────────── tool pin propagation ───────────────────────────────


def test_lint_ruff_pin_override_flows_into_cmd(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""`[tool.interlocks.tools] ruff` override replaces the bundled pin in the uvx argv."""
from interlocks.tasks.lint import task_lint

(tmp_path / "pyproject.toml").write_text(
textwrap.dedent("""\
[project]
name = "pin-probe"
version = "0.0.0"

[tool.interlocks.tools]
ruff = "0.99.0"
"""),
encoding="utf-8",
)
monkeypatch.chdir(tmp_path)
cmd = task_lint().cmd
assert "ruff==0.99.0" in cmd
37 changes: 37 additions & 0 deletions tests/tasks/test_mutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,3 +593,40 @@ def test_pulse_silent_when_verbose(tmp_path: Path, monkeypatch: pytest.MonkeyPat

out = buf.getvalue()
assert "\r" not in out


# ─────────────── tool pin propagation ───────────────────────────────


def test_mutation_mutmut_pin_override_flows_into_cmd(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""`[tool.interlocks.tools] interlocks-mutmut` override replaces bundled pin in uv run argv."""
(tmp_path / "pyproject.toml").write_text(
textwrap.dedent("""\
[project]
name = "pin-probe"
version = "0.0.0"

[tool.interlocks.tools]
interlocks-mutmut = "9.99.0"
"""),
encoding="utf-8",
)
monkeypatch.chdir(tmp_path)

captured_argv: list[list[str]] = []

def _spy_run(argv: list[str], _timeout: int) -> tuple[bool, Path]:
captured_argv.append(argv)
return True, tmp_path / ".interlocks" / "mutation.log"

monkeypatch.setattr(mutation_mod, "_run_mutmut", _spy_run)
monkeypatch.setattr(mutation_mod, "coverage_line_rate", lambda: 1.0)
monkeypatch.setattr(mutation_mod, "read_mutation_summary", lambda: None)
monkeypatch.setattr(sys, "argv", ["interlocks", "mutation", "--min-coverage=0"])
Comment on lines +624 to +627

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The test mocks several attributes on mutation_mod (which is interlocks.tasks.mutation) but then calls cmd_mutation() which was imported directly at line 27. While Python's module system ensures that cmd_mutation will see the mocked globals because it resides in that module, it is generally safer and more explicit to call the function through the module object when you are monkeypatching that same module's internal functions (like _run_mutmut or coverage_line_rate).

Suggested change
monkeypatch.setattr(mutation_mod, "_run_mutmut", _spy_run)
monkeypatch.setattr(mutation_mod, "coverage_line_rate", lambda: 1.0)
monkeypatch.setattr(mutation_mod, "read_mutation_summary", lambda: None)
monkeypatch.setattr(sys, "argv", ["interlocks", "mutation", "--min-coverage=0"])
monkeypatch.setattr(mutation_mod, "_run_mutmut", _spy_run)
monkeypatch.setattr(mutation_mod, "coverage_line_rate", lambda: 1.0)
monkeypatch.setattr(mutation_mod, "read_mutation_summary", lambda: None)
monkeypatch.setattr(sys, "argv", ["interlocks", "mutation", "--min-coverage=0"])
mutation_mod.cmd_mutation()


cmd_mutation()

assert captured_argv, "_run_mutmut was not called"
assert "interlocks-mutmut==9.99.0" in captured_argv[0]
26 changes: 26 additions & 0 deletions tests/tasks/test_typecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,3 +314,29 @@ def test_typecheck_resolves_imports_from_target_venv(
out = capsys.readouterr().out
assert "[typecheck]" in out
assert "ok" in out


# ─────────────── tool pin propagation ───────────────────────────────


def test_typecheck_basedpyright_pin_override_flows_into_cmd(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""`[tool.interlocks.tools] basedpyright` override replaces the bundled pin in uvx argv."""
from interlocks.tasks.typecheck import task_typecheck

(tmp_path / "pyproject.toml").write_text(
textwrap.dedent("""\
[project]
name = "pin-probe"
version = "0.0.0"
requires-python = ">=3.11"

[tool.interlocks.tools]
basedpyright = "9.99.0"
"""),
encoding="utf-8",
)
monkeypatch.chdir(tmp_path)
cmd = task_typecheck().cmd
assert "basedpyright==9.99.0" in cmd
26 changes: 26 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,32 @@ def test_tool_version_ignores_non_string_override(
assert load_config().tool_version("ruff") == DEFAULTS["ruff"]


def test_coverage_pin_override_flows_into_invoker_prefix(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""`[tool.interlocks.tools] coverage` override flows into the uv run --with spec."""
from interlocks.config import coverage_invoker_prefix

_setup_pyproject(
tmp_path,
monkeypatch,
"""
[project]
name = "pin-probe"
version = "0.0.0"

[tool.interlocks]
test_invoker = "uv"

[tool.interlocks.tools]
coverage = "9.99.0"
""",
)
cfg = load_config()
prefix = coverage_invoker_prefix(cfg)
assert "coverage==9.99.0" in prefix


def test_skip_project_policy_resolves_labels(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
Expand Down
Loading