"""WBS-7.11(2026-06-22) — spec-코드 동기화 게이트 단위 테스트."""
from __future__ import annotations

import sys
import unittest
from pathlib import Path
from unittest.mock import patch

ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
    sys.path.insert(0, str(ROOT))

import tools.validate_specs as vs


class TestValidateSpecCodeSync(unittest.TestCase):

    def test_real_repo_has_no_missing_code_path(self):
        """현재 저장소 상태에서 1차 태깅된 파일들은 모두 code_path가 실존해야 한다."""
        errors: list[str] = []
        result = vs.validate_spec_code_sync(errors)
        self.assertEqual(result["gate"], "PASS")
        self.assertEqual(result["missing_code_path_count"], 0)
        self.assertTrue(result["checked_count"] >= 10)
        self.assertFalse(errors)

    def test_missing_code_path_fails(self):
        import tempfile
        import shutil
        tmp_dir = tempfile.mkdtemp()
        try:
            tmp_path = Path(tmp_dir)
            (tmp_path / "spec").mkdir()
            (tmp_path / "governance").mkdir()
            (tmp_path / "spec" / "fake_contract.yaml").write_text(
                "meta:\n  has_code_implementation: true\n  code_path: \"tools/does_not_exist_v1.py\"\n",
                encoding="utf-8",
            )
            with patch.object(vs, "ROOT", tmp_path):
                errors: list[str] = []
                result = vs.validate_spec_code_sync(errors)
                self.assertEqual(result["gate"], "FAIL")
                self.assertEqual(result["missing_code_path_count"], 1)
                self.assertTrue(any("does_not_exist_v1.py" in e for e in errors))
        finally:
            shutil.rmtree(tmp_dir)

    def test_redirect_only_and_has_code_is_contradiction(self):
        import tempfile
        import shutil
        tmp_dir = tempfile.mkdtemp()
        try:
            tmp_path = Path(tmp_dir)
            (tmp_path / "spec").mkdir()
            (tmp_path / "governance").mkdir()
            (tmp_path / "spec" / "contradiction.yaml").write_text(
                "meta:\n  has_code_implementation: true\n  redirect_only: true\n",
                encoding="utf-8",
            )
            with patch.object(vs, "ROOT", tmp_path):
                errors: list[str] = []
                result = vs.validate_spec_code_sync(errors)
                self.assertEqual(result["gate"], "FAIL")
                self.assertTrue(any("contradiction" in e for e in errors))
        finally:
            shutil.rmtree(tmp_dir)

    def test_files_without_the_field_are_skipped_not_failed(self):
        import tempfile
        import shutil
        tmp_dir = tempfile.mkdtemp()
        try:
            tmp_path = Path(tmp_dir)
            (tmp_path / "spec").mkdir()
            (tmp_path / "governance").mkdir()
            (tmp_path / "spec" / "untouched.yaml").write_text(
                "meta:\n  title: legacy doc with no sync field\n",
                encoding="utf-8",
            )
            with patch.object(vs, "ROOT", tmp_path):
                errors: list[str] = []
                result = vs.validate_spec_code_sync(errors)
                self.assertEqual(result["gate"], "PASS")
                self.assertEqual(result["checked_count"], 0)
                self.assertEqual(result["total_spec_files"], 1)
                self.assertFalse(errors)
        finally:
            shutil.rmtree(tmp_dir)


if __name__ == "__main__":
    unittest.main()

