from __future__ import annotations import subprocess import sys import tempfile import unittest from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[1] SCRIPTS_DIR = REPO_ROOT / "skills" / "ack" / "scripts" sys.path.insert(0, str(SCRIPTS_DIR)) import validate_knowledge # noqa: E402 import validate_delivery # noqa: E402 import validate_tasks # noqa: E402 from yaml_subset import YamlSubsetError, load_yaml_subset # noqa: E402 class AckYamlSubsetTests(unittest.TestCase): def test_real_templates_and_examples_parse_under_clean_python(self) -> None: script = """ import sys from pathlib import Path sys.path.insert(0, str(Path('skills/ack/scripts').resolve())) from yaml_subset import load_yaml_subset paths = ( Path('skills/ack/templates/tasks.template.yaml'), Path('skills/ack/examples/tasks.example.yaml'), Path('skills/ack/templates/knowledge.template.yaml'), Path('skills/ack/examples/knowledge.example.yaml'), Path('skills/ack/templates/delivery.template.yaml'), Path('skills/ack/examples/delivery.example.yaml'), ) for path in paths: value = load_yaml_subset(path.read_text(encoding='utf-8')) if not isinstance(value, dict): raise SystemExit(f'{path}: top-level value is not a mapping') print('parsed=6') """ result = subprocess.run( [sys.executable, "-S", "-c", script], cwd=REPO_ROOT, text=True, capture_output=True, check=False, ) self.assertEqual(result.returncode, 0, result.stderr) self.assertEqual(result.stdout.strip(), "parsed=6") def test_tasks_validator_runs_without_site_packages(self) -> None: result = subprocess.run( [ sys.executable, "-S", str(SCRIPTS_DIR / "validate_tasks.py"), str(REPO_ROOT / "skills" / "ack" / "examples" / "tasks.example.yaml"), ], cwd=REPO_ROOT, text=True, capture_output=True, check=False, ) self.assertEqual(result.returncode, 0, result.stderr) self.assertIn("任务板校验通过", result.stdout) def test_delivery_validator_runs_without_site_packages(self) -> None: result = subprocess.run( [ sys.executable, "-S", str(SCRIPTS_DIR / "validate_delivery.py"), str(REPO_ROOT / "skills" / "ack" / "templates" / "delivery.template.yaml"), ], cwd=REPO_ROOT, text=True, capture_output=True, check=False, ) self.assertEqual(result.returncode, 0, result.stderr) self.assertIn("交付契约校验通过", result.stdout) def test_supported_subset_types_and_block_scalars(self) -> None: document = load_yaml_subset( """ # comment root: list: - null - true - -2 - name: 'single quoted' flags: [false, "double quoted", {count: 3}] emptyList: [] emptyMap: {} folded: > first line second line next paragraph literal: | first line second line """ ) self.assertEqual(document["root"]["list"][:3], [None, True, -2]) self.assertEqual( document["root"]["list"][3], { "name": "single quoted", "flags": [False, "double quoted", {"count": 3}], }, ) self.assertEqual(document["root"]["emptyList"], []) self.assertEqual(document["root"]["emptyMap"], {}) self.assertEqual( document["root"]["folded"], "first line second line\nnext paragraph\n", ) self.assertEqual( document["root"]["literal"], "first line\nsecond line\n", ) def test_quoted_mapping_key_supports_yaml_single_quote_escape(self) -> None: self.assertEqual(load_yaml_subset("'owner''s-key': value\n"), {"owner's-key": "value"}) def test_subset_rejects_duplicate_keys_at_any_depth(self) -> None: invalid_documents = ( "name: first\nname: second\n", "outer:\n name: first\n name: second\n", "outer: {name: first, name: second}\n", ) for document in invalid_documents: with self.subTest(document=document), self.assertRaises(YamlSubsetError): load_yaml_subset(document) def test_subset_rejects_unsupported_yaml_instead_of_guessing(self) -> None: invalid_documents = ( "root: &node\n value: 1\ncopy: *node\n", "root: !custom value\n", "root: {<<: {value: 1}}\n", "---\nroot: value\n", "root: >-\n value\n", "root: 1.25\n", "root:\n\tchild: value\n", ) for document in invalid_documents: with self.subTest(document=document), self.assertRaises(YamlSubsetError): load_yaml_subset(document) class AckDocumentLoaderTests(unittest.TestCase): def test_tasks_yaml_loader_rejects_duplicate_keys_with_pyyaml(self) -> None: with tempfile.TemporaryDirectory() as temp_dir: path = Path(temp_dir) / "tasks.yaml" path.write_text("version: 1\nversion: 2\n", encoding="utf-8") with self.assertRaises(SystemExit) as raised: validate_tasks.load_document(path) self.assertEqual(raised.exception.code, 1) def test_knowledge_yaml_loader_rejects_alias_graphs(self) -> None: with self.assertRaises(SystemExit) as raised: validate_knowledge.load_yaml_text( "root: &root\n child: *root\n", "知识库", ) self.assertEqual(raised.exception.code, 1) def test_tasks_json_loader_rejects_duplicate_keys(self) -> None: with tempfile.TemporaryDirectory() as temp_dir: path = Path(temp_dir) / "tasks.json" path.write_text('{"version": 1, "version": 2}', encoding="utf-8") with self.assertRaises(SystemExit) as raised: validate_tasks.load_document(path) self.assertEqual(raised.exception.code, 1) def test_knowledge_json_loader_rejects_nested_duplicate_keys(self) -> None: with tempfile.TemporaryDirectory() as temp_dir: path = Path(temp_dir) / "knowledge.json" path.write_text( '{"project": {"name": "first", "name": "second"}}', encoding="utf-8", ) with self.assertRaises(SystemExit) as raised: validate_knowledge.load_yaml(path, "知识库") self.assertEqual(raised.exception.code, 1) if __name__ == "__main__": unittest.main()