from __future__ import annotations import subprocess import sys import tempfile import unittest from pathlib import Path from pouch.yaml_io import safe_dump, safe_load ROOT = Path(__file__).resolve().parents[1] CREATE = ROOT / "skills/ship/scripts/create_ship.py" VALIDATE = ROOT / "skills/ship/scripts/validate_ship.py" MANIFEST = ROOT / "skills/ship/scripts/validate_test_manifest.py" def run(script: Path, *args: str) -> subprocess.CompletedProcess[str]: return subprocess.run( [sys.executable, str(script), *args], cwd=ROOT, text=True, capture_output=True, check=False, ) class TestManifestTests(unittest.TestCase): def _create(self, root: Path) -> Path: result = run( CREATE, "--project-root", str(root), "--ship-id", "manifest-demo", "--kind", "short", "--title", "测试 manifest", "--stop-at", "develop_verified", ) self.assertEqual(result.returncode, 0, result.stderr) return root / ".pouch/ship/manifest-demo" def test_new_ship_creates_manifest_and_schema_validates(self) -> None: with tempfile.TemporaryDirectory() as tmp: ship = self._create(Path(tmp)) manifest = ship / "2-develop/test-manifest.yaml" self.assertTrue(manifest.is_file()) checked = run( MANIFEST, str(manifest), "--ship-id", "manifest-demo", "--mode", "schema" ) self.assertEqual(checked.returncode, 0, checked.stderr) record = run(VALIDATE, str(ship)) self.assertEqual(record.returncode, 0, record.stderr) def test_required_empty_manifest_blocks_verify(self) -> None: with tempfile.TemporaryDirectory() as tmp: ship = self._create(Path(tmp)) checked = run( MANIFEST, str(ship / "2-develop/test-manifest.yaml"), "--ship-id", "manifest-demo", "--policy", "required", "--mode", "verify", ) self.assertNotEqual(checked.returncode, 0) self.assertIn("登记至少一个测试", checked.stderr) def test_manifest_lists_exact_test_selector(self) -> None: with tempfile.TemporaryDirectory() as tmp: ship = self._create(Path(tmp)) path = ship / "2-develop/test-manifest.yaml" data = safe_load(path.read_text(encoding="utf-8")) data["tests"] = [{ "id": "go:internal/store/drafts_test.go#TestDraft", "kind": "unit", "runner": "go-test", "target": "./internal/store", "selector": "^TestDraft$", "covers": ["T-01"], "change": "added", }] path.write_text(safe_dump(data), encoding="utf-8") checked = run( MANIFEST, str(path), "--ship-id", "manifest-demo", "--policy", "required", "--mode", "verify", ) self.assertEqual(checked.returncode, 0, checked.stderr) self.assertIn("go:internal/store/drafts_test.go#TestDraft", checked.stdout) def test_ship_validation_rejects_missing_manifest(self) -> None: with tempfile.TemporaryDirectory() as tmp: ship = self._create(Path(tmp)) (ship / "2-develop/test-manifest.yaml").unlink() checked = run(VALIDATE, str(ship)) self.assertNotEqual(checked.returncode, 0) self.assertIn("manifest 不存在", checked.stderr) if __name__ == "__main__": unittest.main()