99 lines
3.0 KiB
Python
99 lines
3.0 KiB
Python
from pathlib import Path
|
|
|
|
import textwrap
|
|
|
|
import pytest
|
|
|
|
from automation.config import RulesConfig
|
|
|
|
|
|
def write_yaml(path: Path, content: str) -> None:
|
|
path.write_text(textwrap.dedent(content).strip() + "\n", encoding="utf-8")
|
|
|
|
|
|
@pytest.fixture()
|
|
def sample_repo(tmp_path: Path) -> Path:
|
|
root = tmp_path / "repo"
|
|
(root / "Docs" / "features" / "FR_123" / "discussions").mkdir(parents=True, exist_ok=True)
|
|
|
|
write_yaml(
|
|
root / ".ai-rules.yml",
|
|
"""
|
|
file_associations:
|
|
feature_request.md: feature_request
|
|
rules:
|
|
feature_request:
|
|
outputs:
|
|
summary:
|
|
path: "{feature_id}/summary.md"
|
|
""",
|
|
)
|
|
|
|
write_yaml(
|
|
root / "Docs" / "features" / ".ai-rules.yml",
|
|
"""
|
|
file_associations:
|
|
design.md: design_rule
|
|
rules:
|
|
design_rule:
|
|
outputs:
|
|
diagram:
|
|
path: "diagrams/{stage}.puml"
|
|
""",
|
|
)
|
|
|
|
write_yaml(
|
|
root / "Docs" / "features" / "FR_123" / ".ai-rules.yml",
|
|
"""
|
|
rules:
|
|
design_rule:
|
|
outputs:
|
|
diagram:
|
|
instruction: "Draw updated design diagram"
|
|
""",
|
|
)
|
|
|
|
return root
|
|
|
|
|
|
def test_get_rule_name_cascades(sample_repo: Path) -> None:
|
|
cfg = RulesConfig.load(sample_repo)
|
|
assert cfg.get_rule_name(Path("feature_request.md")) == "feature_request"
|
|
assert cfg.get_rule_name(Path("Docs/features/design.md")) == "design_rule"
|
|
assert cfg.get_rule_name(Path("unknown.md")) is None
|
|
|
|
|
|
def test_cascade_for_merges_overrides(sample_repo: Path) -> None:
|
|
cfg = RulesConfig.load(sample_repo)
|
|
rel = Path("Docs/features/FR_123/discussions/design.discussion.md")
|
|
merged = cfg.cascade_for(rel, "design_rule")
|
|
|
|
outputs = merged["outputs"]
|
|
assert "diagram" in outputs
|
|
diagram_cfg = outputs["diagram"]
|
|
assert diagram_cfg["path"] == "diagrams/{stage}.puml"
|
|
assert diagram_cfg["instruction"] == "Draw updated design diagram"
|
|
|
|
|
|
def test_template_rendering(sample_repo: Path) -> None:
|
|
cfg = RulesConfig.load(sample_repo)
|
|
rel = Path("Docs/features/FR_123/discussions/design.discussion.md")
|
|
rendered = cfg.resolve_template("{feature_id}/{stage}.sum.md", rel)
|
|
assert rendered == "FR_123/design.sum.md"
|
|
|
|
rendered_dir = cfg.resolve_template("{dir}/generated.md", Path("Docs/features/FR_123/request.md"))
|
|
assert rendered_dir == "Docs/features/FR_123/generated.md"
|
|
|
|
rendered_repo = cfg.resolve_template("{repo}/README.md", Path("Docs/features/FR_123/request.md"))
|
|
assert rendered_repo == "./README.md"
|
|
|
|
rendered_path = cfg.resolve_template("copy-of-{path}", Path("Docs/features/FR_123/request.md"))
|
|
assert rendered_path == "copy-of-Docs/features/FR_123/request.md"
|
|
|
|
|
|
def test_normalize_repo_rel_blocks_escape(sample_repo: Path) -> None:
|
|
cfg = RulesConfig.load(sample_repo)
|
|
with pytest.raises(ValueError):
|
|
cfg.normalize_repo_rel("../outside.md")
|
|
assert cfg.normalize_repo_rel("Docs/features/file.md").as_posix() == "Docs/features/file.md"
|