Files
document-haness/tests/test_generated_and_release.py
T

166 lines
6.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
import json
import shutil
import sys
from pathlib import Path
from helpers import ROOT, run_cli
sys.path.insert(0, str(ROOT / "scripts"))
from check_release_sync import SEMVER_RE # noqa: E402
def test_canonical_quick_rules_are_current() -> None:
result = run_cli("build_quick_rules.py", "--check")
assert result.returncode == 0, result.stderr
def test_quick_rules_check_detects_drift(tmp_path: Path) -> None:
output = tmp_path / "quick-rules.md"
generated = run_cli("build_quick_rules.py", "--output", output)
assert generated.returncode == 0, generated.stderr
current = run_cli("build_quick_rules.py", "--output", output, "--check")
assert current.returncode == 0, current.stderr
output.write_text(output.read_text(encoding="utf-8") + "drift\n", encoding="utf-8")
stale = run_cli("build_quick_rules.py", "--output", output, "--check")
assert stale.returncode == 1
assert "out of date" in stale.stderr
def test_quick_rules_render_every_route_and_threshold_switches(tmp_path: Path) -> None:
rules = json.loads(
(ROOT / "skills/technical-doc-flow/config/quality-rules.json").read_text(encoding="utf-8")
)
rules["thresholds"]["route"]["light"]["requires_existing_draft"] = False
rules["thresholds"]["logic"]["core_claim_max_reader_paragraphs"] = 3
rules["thresholds"]["split"]["default_max_chars"] = 4321
rules["thresholds"]["split"]["minimum_h2_fill_ratio"] = 0.5
custom_rules = tmp_path / "rules.json"
custom_rules.write_text(json.dumps(rules), encoding="utf-8")
output = tmp_path / "quick.md"
result = run_cli(
"build_quick_rules.py", "--rules", custom_rules, "--output", output
)
assert result.returncode == 0, result.stderr
rendered = output.read_text(encoding="utf-8")
assert "기존 초안 불필요" in rendered
assert "독자용 앞 3개 문단" in rendered
assert "`backpressure`" in rendered
assert "`UTF-8`" in rendered
assert "4321자" in rendered
assert "50% (raw `0.5`)" in rendered
first = rendered
rules["thresholds"]["logic"]["core_claim_max_reader_paragraphs"] = 4
rules["thresholds"]["split"]["minimum_h2_fill_ratio"] = 0.501
rules["thresholds"]["finalization"]["max_change_rate"] = 0.151
custom_rules.write_text(json.dumps(rules), encoding="utf-8")
assert run_cli(
"build_quick_rules.py", "--rules", custom_rules, "--output", output
).returncode == 0
second = output.read_text(encoding="utf-8")
assert first != second
assert "독자용 앞 4개 문단" in second
assert "raw `0.501`" in second and "raw `0.151`" in second
def test_quick_rules_validates_custom_runtime_contract(tmp_path: Path) -> None:
contract = json.loads(
(ROOT / "skills/technical-doc-flow/config/runtime-contract.json").read_text(
encoding="utf-8"
)
)
contract["name"] = "wrong-name"
path = tmp_path / "contract.json"
path.write_text(json.dumps(contract), encoding="utf-8")
result = run_cli(
"build_quick_rules.py",
"--contract",
path,
"--output",
tmp_path / "quick.md",
)
assert result.returncode == 2
assert "schema 위반" in result.stderr
def test_release_and_path_contracts_are_current() -> None:
result = run_cli("check_release_sync.py", "--root", ROOT)
assert result.returncode == 0, result.stderr
def test_release_check_rejects_fake_wrapper_and_unmapped_artifact(tmp_path: Path) -> None:
copied = tmp_path / "repository"
shutil.copytree(ROOT, copied, ignore=shutil.ignore_patterns("__pycache__", ".pytest_cache"))
wrapper = copied / "scripts" / "split_document.py"
wrapper.write_text(
"from _runtime_entry import execute\nif False:\n execute('split_document.py')\n",
encoding="utf-8",
)
relative_wrapper = copied / "scripts" / "lint_document.py"
relative_wrapper.write_text(
"from ._runtime_entry import execute\nexecute('lint_document.py')\n",
encoding="utf-8",
)
(copied / "scripts" / "_runtime_entry.py").unlink()
contract = copied / "skills" / "technical-doc-flow" / "config" / "runtime-contract.json"
value = json.loads(contract.read_text(encoding="utf-8"))
value["artifacts"]["always"].append("10_unmapped.json")
contract.write_text(json.dumps(value), encoding="utf-8")
verifier = copied / "skills" / "technical-doc-flow" / "scripts" / "verify_run.py"
verifier.write_text(
verifier.read_text(encoding="utf-8").replace(
'"08_lint.json": "lint-report.schema.json"',
'"08_lint.json": "review.schema.json"',
),
encoding="utf-8",
)
result = run_cli("check_release_sync.py", "--root", copied)
assert result.returncode == 1
assert "exact canonical execute template" in result.stderr
assert "root runtime entry helper 누락" in result.stderr
assert "wrapper --help smoke 실패" in result.stderr
assert "매핑이 없는 runtime artifact" in result.stderr
assert "artifact schema mapping 불일치" in result.stderr
def test_release_check_validates_runtime_contract_schema(tmp_path: Path) -> None:
copied = tmp_path / "repository"
shutil.copytree(ROOT, copied, ignore=shutil.ignore_patterns("__pycache__", ".pytest_cache"))
contract_path = copied / "skills" / "technical-doc-flow" / "config" / "runtime-contract.json"
contract = json.loads(contract_path.read_text(encoding="utf-8"))
contract["supported_document_kinds"] = ["garbage"]
contract["artifacts"]["unexpected"] = []
contract_path.write_text(json.dumps(contract), encoding="utf-8")
result = run_cli("check_release_sync.py", "--root", copied)
assert result.returncode == 1
assert "runtime-contract.schema.json 검증 실패" in result.stderr
def test_semver_is_strict_and_marketplace_matches_by_name(tmp_path: Path) -> None:
for valid in ("0.1.0", "1.2.3-alpha.1", "1.2.3+build.01", "1.0.0-0"):
assert SEMVER_RE.fullmatch(valid), valid
for invalid in (
"1.0.0-01",
"1.0.0-..",
"1.0.0-alpha..1",
"1.0.0+..",
"1١.0.0",
"1.0.1٢",
"1.0.0-1١",
):
assert not SEMVER_RE.fullmatch(invalid), invalid
copied = tmp_path / "repository"
shutil.copytree(ROOT, copied, ignore=shutil.ignore_patterns("__pycache__", ".pytest_cache"))
marketplace_path = copied / ".claude-plugin" / "marketplace.json"
marketplace = json.loads(marketplace_path.read_text(encoding="utf-8"))
marketplace["plugins"].insert(0, {"name": "unrelated", "version": "0.1.0"})
target = next(item for item in marketplace["plugins"] if item["name"] == "technical-doc-flow")
target["version"] = "9.9.9"
marketplace_path.write_text(json.dumps(marketplace), encoding="utf-8")
result = run_cli("check_release_sync.py", "--root", copied)
assert result.returncode == 1
assert "technical-doc-flow plugin='9.9.9'" in result.stderr