"""Tests for Tools/ue_placement.py — the single source of truth for placement. A regression test for a real bug: `ue_hero_facade_import.py` carried its own hero position (the pre-0.1.0 one) while `ue_build_demo_map.py` staged the verified one. Running the importer moved the hero 13 m east and onto the north side of the boulevard, and nothing complained because a displaced building still renders. """ import os import sys _TOOLS = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, _TOOLS) for _sub in ("review", "gen", "unreal", "blender", "input"): sys.path.insert(0, os.path.join(_TOOLS, _sub)) import os import sys import unittest ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) sys.path.insert(0, os.path.join(ROOT, "Tools")) import ue_placement # noqa: E402 class HeroPlacementTest(unittest.TestCase): def test_hero_actor_name(self): self.assertEqual(ue_placement.HERO_ACTOR, "Hero_Facade") def test_hero_location_is_the_verified_building_line(self): x, y, z = ue_placement.HERO_LOCATION_CM self.assertEqual((x, y, z), (-13336.0, 1307.0, 0.0)) # North is -Y in Unreal, so the hero on the south side must have Y > 0. self.assertGreater(y, 0.0, "hero must be on the south side (Y > 0)") def test_hero_span_is_verified(self): # The mesh spans -1308..+1308 cm in X about its origin. lo = ue_placement.HERO_LOCATION_CM[0] - 1308.0 hi = ue_placement.HERO_LOCATION_CM[0] + 1308.0 exp_min, exp_max, ok = ue_placement.span_error("hero", lo, hi) self.assertTrue(ok) # The mesh spans exactly the verified footprint, so the two agree. self.assertAlmostEqual(exp_min, lo, delta=ue_placement.SPAN_TOLERANCE_CM) self.assertAlmostEqual(exp_max, hi, delta=ue_placement.SPAN_TOLERANCE_CM) class SpanValidatorTest(unittest.TestCase): def test_misplaced_hero_is_reported(self): # The exact failure observed: the stale import position put the hero here. lo, hi = -13332.0, -10716.0 exp_min, exp_max, ok = ue_placement.span_error("hero", lo, hi) self.assertFalse(ok) message = ue_placement.describe_span_failure("hero", lo, hi) self.assertIn("does not match the verified", message) self.assertIn(f"{exp_min:.0f}", message) def test_correct_span_reports_nothing(self): self.assertEqual(ue_placement.describe_span_failure("hero", -14644, -12028), "") def test_within_tolerance_passes(self): # 99 cm off is inside the ±100 cm tolerance. self.assertTrue(ue_placement.span_error("6922", -24276 + 99, -17700 - 99)[2]) def test_outside_tolerance_fails(self): self.assertFalse(ue_placement.span_error("6922", -24276 + 101, -17700)[2]) def test_unknown_building_raises(self): with self.assertRaises(KeyError): ue_placement.span_error("no-such-building", 0, 0) def test_every_frontage_span_is_ordered(self): for name, (lo, hi) in ue_placement.FRONTAGE_SPANS_CM.items(): self.assertLess(lo, hi, f"{name} span is inverted") class SingleSourceOfTruthTest(unittest.TestCase): """The import script and the demo builder must not carry their own literals.""" def test_import_script_uses_the_shared_constant(self): src = open(os.path.join(ROOT, "Tools", "unreal", "ue_hero_facade_import.py"), encoding="utf-8").read() self.assertIn("ue_placement.HERO_LOCATION_CM", src) self.assertNotIn("(-12024.5, -1450.0, 0.0)", src, "the stale pre-0.1.0 hero position must not come back") def test_demo_builder_uses_the_shared_constant(self): src = open(os.path.join(ROOT, "Tools", "unreal", "ue_build_demo_map.py"), encoding="utf-8").read() self.assertIn("ue_placement.HERO_LOCATION_CM", src) if __name__ == "__main__": unittest.main()