diff --git a/tests/test_guanghan_topology_demo.py b/tests/test_guanghan_topology_demo.py new file mode 100644 index 0000000..0c9b58e --- /dev/null +++ b/tests/test_guanghan_topology_demo.py @@ -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()