79 lines
3.4 KiB
Python
79 lines
3.4 KiB
Python
"""Maintenance tools in scripts/jev: everything except the API calls."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import gzip
|
|
import importlib.util
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
from types import ModuleType
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
JEV = ROOT / "scripts" / "jev"
|
|
|
|
|
|
def _load(name: str) -> ModuleType:
|
|
if str(JEV) not in sys.path:
|
|
sys.path.insert(0, str(JEV))
|
|
spec = importlib.util.spec_from_file_location(name, JEV / f"{name}.py")
|
|
assert spec is not None and spec.loader is not None
|
|
mod = importlib.util.module_from_spec(spec)
|
|
sys.modules[name] = mod
|
|
spec.loader.exec_module(mod)
|
|
return mod
|
|
|
|
|
|
client = _load("client")
|
|
cov = _load("spec_coverage")
|
|
voice = _load("voice_check")
|
|
tri = _load("nightly_triage")
|
|
|
|
|
|
def test_client_builders() -> None:
|
|
assert client.noul("x?", true="a", false="b") == {"type": "noul", "instructions": "x?",
|
|
"criteria": {"true": "a", "false": "b"}} # fmt: skip
|
|
assert client.choice("pick", {"a": "A"})["type"] == "choice"
|
|
assert client.score("how", ["low", "high"])["criteria"] == ["low", "high"]
|
|
|
|
|
|
def test_spec_parsing_skips_open_questions() -> None:
|
|
text = (
|
|
"## 14 CLI\n- **CLI-005** `§14 · P1` **Option precedence.**\nCLI flags beat config files.\n"
|
|
"- **OQ-001** `§20` Is this needed?\n## 15 Outputs\n- **OUT-031** `§9 · P6` VCF records are sorted.\n"
|
|
)
|
|
items = cov.parse_spec(text)
|
|
assert [i.id for i in items] == ["CLI-005", "OUT-031"]
|
|
assert items[0].tag == "§14 · P1" and "config files" in items[0].text
|
|
|
|
|
|
def test_bm25_prefers_matching_test() -> None:
|
|
bm = cov.Bm25(["def test_vcf_sorted(): records sorted by position", "def test_idat_header(): magic bytes"])
|
|
assert bm.top("VCF records are sorted by position", 1) == [0]
|
|
|
|
|
|
def test_voice_rules() -> None:
|
|
paras = voice.paragraphs(Path("x.md"), "# H\n\nA seamless — revolutionary tool.\n\n```\nnot prose\n```\n")
|
|
assert len(paras) == 1 and paras[0].heading == "H"
|
|
issues = voice.mechanical(paras[0])
|
|
assert "em or en dash in prose" in issues and any("seamless" in i for i in issues)
|
|
quoted = voice.Para("x.md", 1, "", 'Never write "revolutionary" or "seamless".')
|
|
assert voice.mechanical(quoted) == []
|
|
|
|
|
|
def test_known_findings_and_evidence(tmp_path: Path) -> None:
|
|
kf = tri.known_findings("| K-014 | 2026-09-28 | NaN sign | NaNs take the platform's sign. | resolved |\n")
|
|
assert kf == {"K-014": "NaN sign: NaNs take the platform's sign."}
|
|
(tmp_path / "s" / "compare").mkdir(parents=True)
|
|
(tmp_path / "s" / "compare" / "summary.json").write_text(
|
|
json.dumps({"fields": {"GT": {"tolerance": "exact", "discrepancies": 2}, "X": {"discrepancies": 0}}})
|
|
)
|
|
with gzip.open(tmp_path / "s" / "compare" / "discrepancies.tsv.gz", "wt") as fh:
|
|
fh.write("pair\tfield\n1\tGT\n")
|
|
(tmp_path / "run.log").write_text("pi_run: MemAvailable 500 MiB < 800 MiB -- stopping the job\n")
|
|
ev = tri.evidence(tmp_path, "s", {"verdict": "FAIL", "report": "s/compare/dashboard.html"})
|
|
assert ev["differing_fields"] == {"GT": {"tolerance": "exact", "discrepancies": 2}}
|
|
assert ev["first_rows"][1] == "1\tGT" and "log" not in ev # another step's log line must not leak in
|
|
ev2 = tri.evidence(tmp_path, "t", {"verdict": "ERROR", "error": "exit 137"})
|
|
assert ev2["log"] == ["pi_run: MemAvailable 500 MiB < 800 MiB -- stopping the job"]
|