From 205ddece0b58215586c78163b63b741f95d42b9e Mon Sep 17 00:00:00 2001 From: ctan Date: Sun, 20 Sep 2026 17:43:50 +0200 Subject: [PATCH] fix(map): require single-character legend keys --- src/pf1e_simulator/map.py | 7 +++++++ tests/test_map.py | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/pf1e_simulator/map.py b/src/pf1e_simulator/map.py index 444c888..32e9f56 100644 --- a/src/pf1e_simulator/map.py +++ b/src/pf1e_simulator/map.py @@ -183,6 +183,13 @@ def load_map(path: Path) -> MapSpec: terrain = _split_rows(raw.terrain, "terrain", path) height, width = len(terrain), len(terrain[0]) + multi_char = sorted(key for key in raw.legend if len(key) != 1) + if multi_char: + msg = ( + "legend keys must be exactly one character (one char = one " + f"square), got: {multi_char}" + ) + raise MapValidationError(path, msg) unknown = sorted({ch for row in terrain for ch in row if ch not in raw.legend}) if unknown: msg = f"terrain chars missing from legend: {unknown}" diff --git a/tests/test_map.py b/tests/test_map.py index 51a3cbc..8144379 100644 --- a/tests/test_map.py +++ b/tests/test_map.py @@ -93,6 +93,26 @@ def test_rejects_char_missing_from_legend(tmp_path: Path) -> None: load_map(_write(tmp_path, body)) +def test_rejects_multi_character_legend_key(tmp_path: Path) -> None: + """One char = one square: a legend key like "ZZ" can never match a cell + and is dead data -- reject it at load.""" + body = _minimal_map().replace( + ' ".": { type: floor, move_cost: 1 }\n', + ' ".": { type: floor, move_cost: 1 }\n "ZZ": { type: floor, move_cost: 1 }\n', + ) + with pytest.raises(MapValidationError, match="legend keys must be exactly one character"): + load_map(_write(tmp_path, body)) + + +def test_rejects_empty_legend_key(tmp_path: Path) -> None: + body = _minimal_map().replace( + ' ".": { type: floor, move_cost: 1 }\n', + ' "": { type: floor, move_cost: 1 }\n', + ) + with pytest.raises(MapValidationError, match="legend keys must be exactly one character"): + load_map(_write(tmp_path, body)) + + def test_rejects_elevation_dimension_mismatch(tmp_path: Path) -> None: body = _minimal_map() + "elevation: |\n 000\n 00\n" with pytest.raises(MapValidationError):