test: define Guanghan topology contract

Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
2026-07-09 16:49:08 +08:00
co-authored by Codex
parent 051aadc707
commit 9f0b8310d8
+94
View File
@@ -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()