Files
gig-line/Tools/tests/test_mapbox_buildings.py
T
zwitschi 4d27109668 refactor(tools): group the sixty scripts by what they talk to
One directory with sixty scripts stopped being navigable, and the grouping is also the sandbox boundary:

  Tools/unreal/    commandlets and the two map builders, with ue_common.py and ue_placement.py as the
                   shared imports (they need the engine)
  Tools/blender/   builders, exporters, the FBX preset, the MPFB character pipeline, blender_screenshots
                   (they need the Blender Flatpak)
  Tools/review/    the visual loop: render_screenshots.sh, judge_screenshot.py, hero_compare.py,
                   build_comparison_md.py, e2e_asset_check.py, hero_iterate.sh, visual_loop.py,
                   visual_targets.json
  Tools/gen/       image and texture generation: the ComfyUI driver, deterministic texture writers,
                   reference fetching
  Tools/input/     OS-level input injection
  root             _common.py, check-lfs.sh, addon_compat_probe.py, sibling_asset_audit.py, tests/

Every moved script now resolves the repository root as ../.. and puts the tools root plus its siblings on
sys.path, so 'import ue_common' still works from unreal/. The test suite bootstrap does the same for the five
folders. render_screenshots.sh takes the folder as a third argument to run_cmdlet, and the e2e driver,
hero_iterate.sh and the comparison generator were repointed.

51 README rows now link to their new location, the README gains a Layout section naming each folder's
sandbox, and the architecture notes and Blender README follow the moves.

Verified: 108 tests pass, prettier is clean, judge_screenshot.py and hero_compare.py run from their new
homes, and the e2e run was aborted mid-way (it had been rebuilding an empty DemoMap for 15 minutes) and is
being rerun against the new layout.
2026-11-10 12:40:30 +01:00

127 lines
4.7 KiB
Python

"""Tests for Geo/tools/mapbox_buildings.py — the pure merge logic.
No network calls here: Tilequery responses are represented as the small dicts
the API returns, and only the selection/comparison/formatting helpers are
exercised. The live call is verified by running the tool.
"""
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 json
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, "Geo", "tools"))
import mapbox_buildings as mb # noqa: E402
def feature(distance, height=None, min_height=0, type_="building", layer="building"):
props = {"tilequery": {"distance": distance, "layer": layer}}
if height is not None:
props["height"] = height
props["min_height"] = min_height
props["type"] = type_
return {"properties": props}
class NearestBuildingTest(unittest.TestCase):
def test_picks_the_closest_building(self):
payload = {"features": [feature(6.0, 10.0), feature(1.0, 20.0)]}
best = mb.nearest_building(payload, max_distance=8.0)
self.assertEqual(best["height"], 20.0)
def test_ignores_hits_beyond_max_distance(self):
payload = {"features": [feature(20.0, 10.0)]}
self.assertIsNone(mb.nearest_building(payload, max_distance=8.0))
def test_ignores_other_layers(self):
payload = {"features": [feature(0.0, 10.0, layer="road")]}
self.assertIsNone(mb.nearest_building(payload, max_distance=8.0))
def test_no_features(self):
self.assertIsNone(mb.nearest_building({"features": []}, max_distance=8.0))
class CompareTest(unittest.TestCase):
def test_match_within_half_a_metre(self):
self.assertEqual(mb.compare(14.5, "height tag", 14.2)[0], "match")
def test_close_within_two_metres(self):
verdict, delta = mb.compare(38.4, "levels x 3.2 m", 37.2)
self.assertEqual(verdict, "close")
self.assertAlmostEqual(delta, -1.2)
def test_disagree_beyond_two_metres(self):
verdict, delta = mb.compare(6.4, "GUESS: default 2 levels x 3.2 m", 3.0)
self.assertEqual(verdict, "disagree")
self.assertAlmostEqual(delta, -3.4)
def test_mapbox_only_when_we_have_nothing(self):
self.assertEqual(mb.compare(0.0, "height tag", 12.0)[0], "mapbox-only")
def test_ours_only_when_mapbox_returns_nothing(self):
self.assertEqual(mb.compare(12.0, "height tag", None)[0], "ours-only")
def test_non_building_is_excluded_from_comparison(self):
verdict, delta = mb.compare(0.0, "not a building volume (roof)", 3.0)
self.assertEqual(verdict, "non-building")
self.assertIsNone(delta)
def test_canopy_is_non_building(self):
verdict, _ = mb.compare(0.0, "not a building volume (canopy)", 3.0)
self.assertEqual(verdict, "non-building")
class CentroidTest(unittest.TestCase):
def test_centroid_of_a_square(self):
lat, lon = mb.centroid_lat_lon(
[(34.0, -118.0), (34.0, -117.0), (35.0, -117.0), (35.0, -118.0)])
self.assertAlmostEqual(lat, 34.5)
self.assertAlmostEqual(lon, -117.5)
class RenderTest(unittest.TestCase):
ARGS = type("A", (), {"radius": 25, "max_distance": 8.0, "only_diffs": False})()
def test_disagreements_sort_first(self):
rows = [
{"verdict": "match", "delta_m": 0.1, "way": 1, "name": "", "kind": "yes",
"osm_height_m": 10.0, "osm_source": "height tag", "mapbox_height_m": 10.1,
"mapbox_min_height_m": 0, "mapbox_type": "building",
"mapbox_distance_m": 0.0, "cached": True, "lat": 0, "lon": 0},
{"verdict": "disagree", "delta_m": -3.4, "way": 2, "name": "", "kind": "yes",
"osm_height_m": 6.4, "osm_source": "GUESS", "mapbox_height_m": 3.0,
"mapbox_min_height_m": 0, "mapbox_type": "building",
"mapbox_distance_m": 0.0, "cached": True, "lat": 0, "lon": 0},
]
text = mb.render_markdown(rows, self.ARGS)
self.assertLess(text.index("way 2"), text.index("way 1"))
def test_never_contains_a_token(self):
rows = []
text = mb.render_markdown(rows, self.ARGS)
self.assertNotIn("access_token", text)
self.assertNotIn("sk.", text)
class TokenTest(unittest.TestCase):
def test_explicit_token_wins(self):
self.assertEqual(mb.load_token("abc123"), "abc123")
def test_token_is_stripped(self):
self.assertEqual(mb.load_token(" abc123\n"), "abc123")
if __name__ == "__main__":
unittest.main()