mirror of
https://github.com/razzant/ouroboros.git
synced 2026-10-03 04:07:04 +00:00
Remove completed campaign records, one-time adoption/transplant machinery and incidental line floors. Keep current contracts and generated inventories with their readers, and direct optional domain reports to stdout or an explicit file. Document continuing-purpose review in the existing handbook and checklists. No version bump; ordinary release gates and runtime behavior are preserved. Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
102 lines
3.6 KiB
Python
102 lines
3.6 KiB
Python
"""The optional graph report writes only to the requested output surface."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import pathlib
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
|
|
pytestmark = pytest.mark.serial # Real Git and Python subprocesses.
|
|
|
|
REPO = pathlib.Path(__file__).resolve().parents[1]
|
|
|
|
|
|
@pytest.fixture
|
|
def report_repo(tmp_path):
|
|
root = tmp_path / "repo"
|
|
(root / "scripts").mkdir(parents=True)
|
|
(root / "ouroboros").mkdir()
|
|
for name in ("domain_report.py", "domain_graph.py"):
|
|
shutil.copyfile(REPO / "scripts" / name, root / "scripts" / name)
|
|
(root / "ouroboros/a.py").write_text("import ouroboros.b\n", encoding="utf-8")
|
|
(root / "ouroboros/b.py").write_text("import ouroboros.a\n", encoding="utf-8")
|
|
(root / "ouroboros/domains.toml").write_text(
|
|
'[domains]\nD01 = "Первый"\nD02 = "Second"\n'
|
|
'[modules]\n"ouroboros/a.py" = "D01"\n"ouroboros/b.py" = "D02"\n',
|
|
encoding="utf-8",
|
|
)
|
|
for args in (
|
|
["init"],
|
|
["add", "."],
|
|
["-c", "user.name=Test", "-c", "user.email=test@example.invalid",
|
|
"-c", "commit.gpgsign=false", "commit", "-m", "fixture"],
|
|
):
|
|
subprocess.run(["git", *args], cwd=root, check=True, capture_output=True,
|
|
encoding="utf-8")
|
|
return root
|
|
|
|
|
|
def _files(root):
|
|
return {
|
|
path.relative_to(root): path.read_bytes()
|
|
for path in root.rglob("*")
|
|
if path.is_file() and ".git" not in path.relative_to(root).parts
|
|
}
|
|
|
|
|
|
def _run(root, *args):
|
|
# The report's UTF-8 output must also survive a non-UTF-8 host default.
|
|
return subprocess.run(
|
|
[sys.executable, "-B", str(root / "scripts/domain_report.py"), *args],
|
|
cwd=root, capture_output=True, encoding="utf-8",
|
|
env={**os.environ, "PYTHONIOENCODING": "ascii"},
|
|
)
|
|
|
|
|
|
def _assert_report(text):
|
|
assert text.startswith("# Domain quotient report (report-only)\n")
|
|
assert "Generated by `scripts/domain_report.py`" in text
|
|
assert "analyzed-inputs content fingerprint: sha256" in text
|
|
assert "`ouroboros/a.py` → `ouroboros/b.py` (line 1)" in text
|
|
assert "D01 — Первый" in text
|
|
assert text.endswith("\n") and not text.endswith("\n\n")
|
|
assert "\nstrict:" not in text and "\n cycle:" not in text
|
|
|
|
|
|
def test_report_defaults_to_stdout_without_repository_writes(report_repo):
|
|
before = _files(report_repo)
|
|
result = _run(report_repo)
|
|
assert result.returncode == 0, result.stderr
|
|
_assert_report(result.stdout)
|
|
assert "strict: 2 module edges, 2 domain edges, 1 cycle groups" in result.stderr
|
|
assert "cycle: D01 ⇄ D02" in result.stderr
|
|
assert _files(report_repo) == before
|
|
|
|
|
|
def test_report_writes_only_to_explicit_output(report_repo, tmp_path):
|
|
before = _files(report_repo)
|
|
output = tmp_path / "reports" / "graph.md"
|
|
result = _run(report_repo, "--output", str(output))
|
|
assert result.returncode == 0, result.stderr
|
|
assert result.stdout == ""
|
|
_assert_report(output.read_text(encoding="utf-8"))
|
|
assert f"wrote {output}" in result.stderr
|
|
assert "strict: 2 module edges" in result.stderr
|
|
assert _files(report_repo) == before
|
|
|
|
|
|
@pytest.mark.parametrize("broken", ["manifest", "source"])
|
|
def test_untrustworthy_inputs_return_two_without_a_report(report_repo, broken):
|
|
if broken == "manifest":
|
|
(report_repo / "ouroboros/domains.toml").unlink()
|
|
else:
|
|
(report_repo / "ouroboros/a.py").write_text("def (\n", encoding="utf-8")
|
|
result = _run(report_repo)
|
|
assert result.returncode == 2, result.stderr
|
|
assert result.stdout == ""
|
|
assert ("missing manifest:" if broken == "manifest" else "cannot parse:") in result.stderr
|