返回 CodeWhale
test_check_command_crate_boundaries.py
根目录 / scripts / test_check_command_crate_boundaries.py
1 #!/usr/bin/env python3
2 """Hermetic tests for the FEAT-014 command-contract boundary gate."""
3
4 from __future__ import annotations
5
6 import importlib.util
7 import sys
8 import unittest
9 from pathlib import Path
10
11 ROOT = Path(__file__).resolve().parents[1]
12 SCRIPT = ROOT / "scripts" / "check-command-crate-boundaries.py"
13 SPEC = importlib.util.spec_from_file_location("command_boundary", SCRIPT)
14 assert SPEC and SPEC.loader
15 mod = importlib.util.module_from_spec(SPEC)
16 sys.modules[SPEC.name] = mod
17 SPEC.loader.exec_module(mod)
18
19
20 def valid_graph() -> dict[str, set[str]]:
21 return {
22 "codewhale-command-contract": {"codewhale-core"},
23 "codewhale-core": set(),
24 "codewhale-secrets": {"codewhale-paths"},
25 "codewhale-paths": set(),
26 "codewhale-tui": set(),
27 }
28
29
30 class DependencyTests(unittest.TestCase):
31 def test_leaf_graph_passes(self) -> None:
32 self.assertEqual(mod.check_dependency_graph(valid_graph()), [])
33
34 def test_direct_tui_edge_fails(self) -> None:
35 graph = valid_graph()
36 graph["codewhale-command-contract"].add("codewhale-tui")
37 self.assertEqual(len(mod.check_dependency_graph(graph)), 1)
38
39 def test_transitive_tui_edge_fails(self) -> None:
40 graph = valid_graph()
41 graph["codewhale-core"].add("codewhale-tui")
42 self.assertEqual(len(mod.check_dependency_graph(graph)), 1)
43
44 def test_missing_contract_fails(self) -> None:
45 graph = valid_graph()
46 del graph["codewhale-command-contract"]
47 violations = mod.check_dependency_graph(graph)
48 self.assertEqual(len(violations), 1)
49 self.assertIn("missing", str(violations[0]))
50
51 def test_missing_sanitizer_fails(self) -> None:
52 graph = valid_graph()
53 del graph["codewhale-secrets"]
54 violations = mod.check_dependency_graph(graph)
55 self.assertEqual(len(violations), 1)
56 self.assertIn("codewhale-secrets", str(violations[0]))
57
58 def test_sanitizer_reaching_tui_fails(self) -> None:
59 # The shared sanitizer is consumed by portable command helpers, so a TUI
60 # edge would pull the whole TUI into the extracted command crate.
61 graph = valid_graph()
62 graph["codewhale-paths"].add("codewhale-tui")
63 violations = mod.check_dependency_graph(graph)
64 self.assertEqual(len(violations), 1)
65 self.assertIn("codewhale-secrets", str(violations[0]))
66
67 def test_both_packages_reaching_tui_fails_twice(self) -> None:
68 graph = valid_graph()
69 graph["codewhale-core"].add("codewhale-tui")
70 graph["codewhale-paths"].add("codewhale-tui")
71 self.assertEqual(len(mod.check_dependency_graph(graph)), 2)
72
73 def test_dev_dependency_is_not_a_normal_edge(self) -> None:
74 metadata = {"packages": [
75 {"name": "codewhale-command-contract", "dependencies": [
76 {"name": "codewhale-tui", "kind": "dev"},
77 {"name": "codewhale-core", "kind": None},
78 ]},
79 {"name": "codewhale-core", "dependencies": []},
80 {"name": "codewhale-secrets", "dependencies": []},
81 {"name": "codewhale-tui", "dependencies": []},
82 ]}
83 graph = mod.dependency_graph(metadata)
84 self.assertEqual(graph["codewhale-command-contract"], {"codewhale-core"})
85 self.assertEqual(mod.check_dependency_graph(graph), [])
86
87
88 class SourceTests(unittest.TestCase):
89 def test_clean_shapes_pass(self) -> None:
90 source = "pub struct CommandContexts<'a> {}\npub trait CommandModelContext {}\n"
91 self.assertEqual(mod.check_contract_source_text(source, "clean.rs"), [])
92
93 def test_forbidden_edges_fail(self) -> None:
94 cases = [
95 "use codewhale_tui::tui::app::App;",
96 "use ratatui::widgets::Paragraph;",
97 "use crate::tui::App;",
98 "pub struct CommandContext {}",
99 "let handler: Box<dyn Fn()> = value;",
100 ]
101 for source in cases:
102 with self.subTest(source=source):
103 self.assertTrue(mod.check_contract_source_text(source, "sample.rs"))
104
105 def test_comments_and_plural_envelope_pass(self) -> None:
106 source = (
107 "// Never import codewhale_tui or define CommandContext here.\n"
108 "pub struct CommandContexts<'a> { marker: &'a str }\n"
109 )
110 self.assertEqual(mod.check_contract_source_text(source, "safe.rs"), [])
111
112
113 if __name__ == "__main__":
114 unittest.main()
115
115 lines PYTHON