from __future__ import annotations import json from pathlib import Path import shutil import sys import tempfile import unittest RUNTIME = Path(__file__).resolve().parents[1] / "runtime" if str(RUNTIME) not in sys.path: sys.path.insert(0, str(RUNTIME)) import semantic_surface_extractor as extractor # noqa: E402 REPO_ROOT = Path(__file__).resolve().parents[2] class SemanticSurfaceExtractorTest(unittest.TestCase): def setUp(self) -> None: self.tempdir = tempfile.TemporaryDirectory() self.root = Path(self.tempdir.name) (self.root / "harness/source").mkdir(parents=True) shutil.copyfile(REPO_ROOT / extractor.DEFAULT_POLICY, self.root / extractor.DEFAULT_POLICY) (self.root / "raw/branch-notes").mkdir(parents=True) def tearDown(self) -> None: self.tempdir.cleanup() def _write(self, body: str, *, exclusions: list[str] | None = None) -> Path: excluded = "\n".join(f" - {item}" for item in exclusions or []) path = self.root / "raw/branch-notes/feature-semantic-fixture.md" path.write_text( "---\n" "title: 의미 fixture\n" "source_type: branch-note\n" "status: verified\n" + (f"semantic_surface_exclusions:\n{excluded}\n" if excluded else "") + "---\n\n" + body, encoding="utf-8", ) return path def test_alias_is_one_logical_surface_and_exclusions_close_coverage(self) -> None: path = self._write( "\n## 범위\n포함한다.\n", exclusions=[ "branch-contract-packet|fixture scope", "decision-evidence|fixture scope", "implementation|fixture scope", "edge-failure-dependency|fixture scope", "claims-to-verify|fixture scope", ], ) result = extractor.check(self.root, paths=[path]) self.assertEqual(result["status"], "PASS") self.assertEqual(result["coverage"], { "eligible_surface_blocks": 6, "extracted_surface_blocks": 1, "explicitly_excluded_blocks": 5, "uncovered_surface_blocks": 0, }) self.assertEqual(result["documents"][0]["surfaces"][0]["section_id"], "scope") self.assertNotIn("LEGACY_SEMANTIC_SURFACE", {item["code"] for item in result["findings"]}) def test_legacy_heading_warns_but_does_not_fail(self) -> None: path = self._write( "## 구현 가이드\n구현한다.\n", exclusions=[ "branch-contract-packet|legacy fixture", "scope|legacy fixture", "decision-evidence|legacy fixture", "edge-failure-dependency|legacy fixture", "claims-to-verify|legacy fixture", ], ) result = extractor.check(self.root, paths=[path]) self.assertEqual(result["status"], "PASS") self.assertIn("LEGACY_SEMANTIC_SURFACE", {item["code"] for item in result["findings"]}) def test_silent_drop_fails_closed(self) -> None: path = self._write("\n## 범위\n내용\n") result = extractor.check(self.root, paths=[path]) self.assertEqual(result["status"], "FAIL") self.assertEqual(result["coverage"]["uncovered_surface_blocks"], 5) self.assertEqual( result["coverage"]["eligible_surface_blocks"], result["coverage"]["extracted_surface_blocks"] + result["coverage"]["explicitly_excluded_blocks"] + result["coverage"]["uncovered_surface_blocks"], ) def test_project_is_always_required_and_canonical_layout_uses_vault_only(self) -> None: policy = extractor.load_policy(self.root) self.assertTrue(extractor.is_required({"source_type": "project-note", "status": "raw"}, policy)) (self.root / "harness/source/vault-layout.json").write_text( json.dumps({"schema_version": "vault-layout/v1", "mode": "canonical", "vault_root": "vault"}), encoding="utf-8", ) legacy = self._write( "\n## 범위\nlegacy\n", exclusions=[ "branch-contract-packet|fixture", "decision-evidence|fixture", "implementation|fixture", "edge-failure-dependency|fixture", "claims-to-verify|fixture", ], ) canonical = self.root / "vault/10-projects/sample/branch-notes/feature-canonical.md" canonical.parent.mkdir(parents=True) canonical.write_bytes(legacy.read_bytes()) selected = extractor.eligible_documents(self.root, policy, required_only=True, mode="local") self.assertEqual(selected, (canonical.resolve(),)) result = extractor.check(self.root, paths=selected) self.assertEqual(result["status"], "PASS") self.assertEqual(result["documents"][0]["path"], "vault/10-projects/sample/branch-notes/feature-canonical.md") legacy.unlink() legacy.symlink_to(Path("../../") / canonical.relative_to(self.root)) replay = extractor.extract_document(self.root, legacy, policy) self.assertEqual(replay["path"], "raw/branch-notes/feature-semantic-fixture.md") if __name__ == "__main__": unittest.main()