from __future__ import annotations from pathlib import Path import sys import unittest RUNTIME = Path(__file__).resolve().parents[1] / "runtime" sys.path.insert(0, str(RUNTIME)) import template_renderer # noqa: E402 class TemplateRendererTest(unittest.TestCase): def test_allowlist_and_missing_values_are_fail_closed(self) -> None: with self.assertRaises(template_renderer.TemplateRenderError) as unknown: template_renderer.render("{{unknown}}", {"unknown": "x"}, allowed={"known"}) self.assertEqual(unknown.exception.code, "UNKNOWN_PLACEHOLDER") with self.assertRaises(template_renderer.TemplateRenderError) as missing: template_renderer.render("{{known}}", {}, allowed={"known"}) self.assertEqual(missing.exception.code, "UNRESOLVED_PLACEHOLDER") def test_generated_hash_changes_only_with_generated_region(self) -> None: first = "before\n\nA\n\nafter\n" outside = first.replace("before", "changed") inside = first.replace("\nA\n", "\nB\n") self.assertEqual(template_renderer.generated_sha256(first), template_renderer.generated_sha256(outside)) self.assertNotEqual(template_renderer.generated_sha256(first), template_renderer.generated_sha256(inside)) def test_branch_template_has_stable_parent_goal_scope_ids_in_both_surfaces(self) -> None: template = Path(__file__).resolve().parents[2] / "templates/branch-note-template.md" text = template.read_text(encoding="utf-8") for section_id in ("branch-parent", "branch-goal", "branch-scope"): self.assertEqual(text.count(f""), 2) runtime = template_renderer.extract_region( text, template_renderer.REGION_START, template_renderer.REGION_END, ) positions = [ runtime.index("section-id: branch-parent"), runtime.index("section-id: branch-contract-packet"), runtime.index("section-id: branch-goal"), runtime.index("section-id: branch-scope"), ] self.assertEqual(positions, sorted(positions)) if __name__ == "__main__": unittest.main()