From bda7921ef08efd8eeaa970ffd5c1d00075c68ed1 Mon Sep 17 00:00:00 2001 From: David Hyrule Date: Sun, 21 Jun 2026 10:21:41 +0200 Subject: [PATCH] Validate only mutated docs in gate runner --- src/hyrule_engineering_loop/gate_runner.py | 24 +++++++++++-------- tests/test_gate_runner.py | 27 ++++++++++++++++++++++ 2 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 tests/test_gate_runner.py diff --git a/src/hyrule_engineering_loop/gate_runner.py b/src/hyrule_engineering_loop/gate_runner.py index e4cca39..b3c324b 100644 --- a/src/hyrule_engineering_loop/gate_runner.py +++ b/src/hyrule_engineering_loop/gate_runner.py @@ -2,6 +2,7 @@ from __future__ import annotations +import json import subprocess import sys from pathlib import Path @@ -90,14 +91,17 @@ def select_gate_commands_for_mutations(paths: Iterable[str]) -> list[list[str]]: if any(path.endswith(".py") for path in normalized): return [[sys.executable, "-m", "compileall", "-q", "."]] if all(path.startswith("docs/") or path.endswith((".md", ".txt", ".rst")) for path in normalized): - return [ - [ - sys.executable, - "-c", - ( - "from pathlib import Path; " - "[p.read_text(encoding='utf-8') for p in Path('.').rglob('*') if p.is_file()]" - ), - ] - ] + paths_literal = repr(json.dumps(normalized)) + script = ( + "import json\n" + "from pathlib import Path\n" + f"for raw in json.loads({paths_literal}):\n" + " path = Path(raw)\n" + " if not path.exists():\n" + " continue\n" + " if not path.is_file():\n" + " raise SystemExit(f'not a file: {raw}')\n" + " path.read_text(encoding='utf-8')\n" + ) + return [[sys.executable, "-c", script]] return [[sys.executable, "-c", "from pathlib import Path; assert any(Path('.').rglob('*'))"]] diff --git a/tests/test_gate_runner.py b/tests/test_gate_runner.py new file mode 100644 index 0000000..4384cad --- /dev/null +++ b/tests/test_gate_runner.py @@ -0,0 +1,27 @@ +from __future__ import annotations + +from hyrule_engineering_loop.gate_runner import run_gate_commands, select_gate_commands_for_mutations + + +def test_docs_gate_reads_only_mutated_text_paths(tmp_path) -> None: + (tmp_path / "docs").mkdir() + (tmp_path / "docs" / "note.md").write_text("hello\n", encoding="utf-8") + (tmp_path / "binary.bin").write_bytes(b"\xb8\x00not utf8") + + commands = select_gate_commands_for_mutations(["engineering-loop:docs/note.md"]) + results, errors = run_gate_commands(commands, cwd=tmp_path) + + assert errors == [] + assert results[0]["returncode"] == 0 + + +def test_docs_gate_reports_non_utf8_mutated_file(tmp_path) -> None: + (tmp_path / "docs").mkdir() + (tmp_path / "docs" / "note.md").write_bytes(b"\xb8\x00not utf8") + + commands = select_gate_commands_for_mutations(["docs/note.md"]) + results, errors = run_gate_commands(commands, cwd=tmp_path) + + assert results[0]["returncode"] == 1 + assert errors + assert "UnicodeDecodeError" in errors[0]["stderr"]