test: define Guanghan topology contract
Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
@@ -0,0 +1,94 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
HTML_PATH = ROOT / "data" / "wiki" / "guanghan_topology_demo.html"
|
||||||
|
TIMELINE_PATH = ROOT / "user_input" / "广寒计划" / "Timeline.md"
|
||||||
|
|
||||||
|
CLICKABLE_MODULES = {
|
||||||
|
"core",
|
||||||
|
"habitat-1",
|
||||||
|
"habitat-2",
|
||||||
|
"greenhouse",
|
||||||
|
"laboratory",
|
||||||
|
"power-node",
|
||||||
|
"power-north",
|
||||||
|
"power-east",
|
||||||
|
"power-south",
|
||||||
|
"power-west",
|
||||||
|
"wugang-2",
|
||||||
|
"binglun-1",
|
||||||
|
"binglun-2",
|
||||||
|
"binglun-3",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class GuanghanTopologySourceTests(unittest.TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls) -> None:
|
||||||
|
cls.html = HTML_PATH.read_text(encoding="utf-8")
|
||||||
|
timeline = TIMELINE_PATH.read_text(encoding="utf-8")
|
||||||
|
cls.ghc05 = timeline.split("GHC-05任务", 1)[1].split("JC-02任务", 1)[0]
|
||||||
|
|
||||||
|
def test_clickable_module_inventory_is_exact(self) -> None:
|
||||||
|
found = set(re.findall(r'data-module="([^"]+)"', self.html))
|
||||||
|
self.assertEqual(found, CLICKABLE_MODULES)
|
||||||
|
|
||||||
|
def test_connection_inventory_matches_approved_topology(self) -> None:
|
||||||
|
self.assertEqual(self.html.count('data-connection="pressurized"'), 2)
|
||||||
|
self.assertIn('data-link="wugang-2--greenhouse"', self.html)
|
||||||
|
self.assertIn('data-link="habitat-1--power-north"', self.html)
|
||||||
|
self.assertNotIn("perimeter-corridor", self.html)
|
||||||
|
|
||||||
|
def test_walkways_and_radiators_are_not_clickable(self) -> None:
|
||||||
|
self.assertNotRegex(
|
||||||
|
self.html,
|
||||||
|
r'<(?:line|path|rect)[^>]+data-connection="pressurized"[^>]+data-module=',
|
||||||
|
)
|
||||||
|
self.assertNotRegex(
|
||||||
|
self.html,
|
||||||
|
r'<(?:g|rect)[^>]+class="[^"]*radiator[^"]*"[^>]+data-module=',
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_future_extensions_exist_only_as_source_comments(self) -> None:
|
||||||
|
comments = "\n".join(re.findall(r"<!--(.*?)-->", self.html, flags=re.S))
|
||||||
|
visible_source = re.sub(r"<!--.*?-->", "", self.html, flags=re.S)
|
||||||
|
for direction in ("north", "east", "west"):
|
||||||
|
self.assertIn(f"FUTURE_EXPANSION_ANCHOR:{direction}", comments)
|
||||||
|
self.assertNotIn("未来北部十字结构", visible_source)
|
||||||
|
self.assertNotIn("未来东部十字结构", visible_source)
|
||||||
|
self.assertNotIn("未来西部十字结构", visible_source)
|
||||||
|
|
||||||
|
def test_every_clickable_module_has_dimensions_field(self) -> None:
|
||||||
|
for module_id in CLICKABLE_MODULES:
|
||||||
|
self.assertRegex(
|
||||||
|
self.html,
|
||||||
|
rf'"{re.escape(module_id)}"\s*:\s*\{{.*?dimensions\s*:',
|
||||||
|
msg=f"{module_id} is missing dimensions",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_timeline_contains_only_the_two_real_corridors(self) -> None:
|
||||||
|
for incorrect in (
|
||||||
|
"4段加压走道",
|
||||||
|
"居住舱#1↔居住舱#2",
|
||||||
|
"居住舱#2↔实验舱",
|
||||||
|
"实验舱↔温室",
|
||||||
|
"温室↔居住舱#1",
|
||||||
|
"环形加压通路",
|
||||||
|
"8个对接面",
|
||||||
|
"4段加压走道48小时",
|
||||||
|
):
|
||||||
|
self.assertNotIn(incorrect, self.ghc05)
|
||||||
|
self.assertIn("居住舱#1远端对接口", self.ghc05)
|
||||||
|
self.assertIn("电力模块北部", self.ghc05)
|
||||||
|
self.assertIn("温室远端对接口", self.ghc05)
|
||||||
|
self.assertIn("吴刚#2", self.ghc05)
|
||||||
|
self.assertIn("从温室模块远端接口断开", self.ghc05)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user