From f0f7692f141ec902000cb2f05412ee0cae81be9b Mon Sep 17 00:00:00 2001 From: KNSO Date: Sun, 13 Sep 2026 09:49:53 +0200 Subject: [PATCH] =?UTF-8?q?fix(coords):=20Chunk-Namen=20korrekt=20f=C3=BCr?= =?UTF-8?q?=20Float-Indizes=20und=20Newlines?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - chunk_name: Reject float/bool indices like JavaScript (Number.isInteger) - parse_chunk_name: Use fullmatch instead of match($) to reject strings with trailing newlines - Add invalidIndices fixture cases to catch these edge cases in both languages Co-Authored-By: Claude Haiku 4.5 --- tests/coords.test.js | 6 ++++++ tests/fixtures/chunk-names.json | 3 ++- tools/extract/leonida/coords.py | 10 +++++++--- tools/extract/tests/test_coords.py | 5 +++++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/tests/coords.test.js b/tests/coords.test.js index b24ab34..6ab07c0 100644 --- a/tests/coords.test.js +++ b/tests/coords.test.js @@ -49,6 +49,12 @@ describe("Chunk-Namen", () => { expect(chunkName(1.5, 3)).toBeNull(); }); + it("lehnt ungültige Indextypen ab", () => { + for (const [i, j] of NAMES.invalidIndices) { + expect(chunkName(i, j)).toBeNull(); + } + }); + it("kommt für alle 144 Chunks hin und zurück", () => { for (let i = 0; i < 12; i++) { for (let j = 0; j < 12; j++) expect(parseChunkName(chunkName(i, j))).toEqual({ i, j }); diff --git a/tests/fixtures/chunk-names.json b/tests/fixtures/chunk-names.json index 648ce3a..4fe6554 100644 --- a/tests/fixtures/chunk-names.json +++ b/tests/fixtures/chunk-names.json @@ -1,5 +1,6 @@ { "pairs": [["A1", 0, 0], ["L1", 11, 0], ["A12", 0, 11], ["L12", 11, 11], ["C10", 2, 9]], "lowercase": [["c10", 2, 9], ["l12", 11, 11]], - "invalid": ["M1", "A0", "A13", "A", "10", "", "A01", "B-3", " "] + "invalid": ["M1", "A0", "A13", "A", "10", "", "A01", "B-3", " ", "A1\n"], + "invalidIndices": [[1.5, 3], [3, 2.5], [true, 0], [0, false]] } diff --git a/tools/extract/leonida/coords.py b/tools/extract/leonida/coords.py index 051a62e..51ab974 100644 --- a/tools/extract/leonida/coords.py +++ b/tools/extract/leonida/coords.py @@ -32,19 +32,23 @@ def pixel_to_world(px: int, py: int) -> tuple[float, float]: CHUNKS_PER_SIDE = (SLICE["x1"] - SLICE["x0"]) // CHUNK_SIZE # 12 CHUNK_COLUMNS = "ABCDEFGHIJKL" -_CHUNK_NAME = re.compile(r"^([A-La-l])([1-9]\d?)$") +_CHUNK_NAME = re.compile(r"([A-La-l])([1-9]\d?)") + + +def _is_index(k) -> bool: + return isinstance(k, int) and not isinstance(k, bool) and 0 <= k < CHUNKS_PER_SIDE def chunk_name(i: int, j: int) -> str | None: """Planquadrat-Name wie src/world/coords.js: Spalte A–L aus i, Zeile 1–12 aus j. A1 = Nordwest.""" - if not (0 <= i < CHUNKS_PER_SIDE and 0 <= j < CHUNKS_PER_SIDE): + if not (_is_index(i) and _is_index(j)): return None return f"{CHUNK_COLUMNS[i]}{j + 1}" def parse_chunk_name(name: str) -> tuple[int, int] | None: """Umkehrung von chunk_name. Akzeptiert Kleinschreibung, None außerhalb A1–L12.""" - match = _CHUNK_NAME.match(str(name)) + match = _CHUNK_NAME.fullmatch(str(name)) if not match or int(match.group(2)) > CHUNKS_PER_SIDE: return None return CHUNK_COLUMNS.index(match.group(1).upper()), int(match.group(2)) - 1 diff --git a/tools/extract/tests/test_coords.py b/tools/extract/tests/test_coords.py index be690fe..5455994 100644 --- a/tools/extract/tests/test_coords.py +++ b/tools/extract/tests/test_coords.py @@ -43,3 +43,8 @@ def test_chunk_names_round_trip_for_all_144_chunks(): for i in range(12): for j in range(12): assert parse_chunk_name(chunk_name(i, j)) == (i, j) + + +def test_chunk_names_reject_invalid_index_types(): + for i, j in NAMES["invalidIndices"]: + assert chunk_name(i, j) is None