From 39dff7eec3b0b257155cf17c4a49e179738ea911 Mon Sep 17 00:00:00 2001 From: Alexander Whitestone Date: Tue, 14 Apr 2026 14:14:26 -0400 Subject: [PATCH] fix: add portals.json validation tests (closes #1440) The current portals.json on main is valid JSON. The malformed version referenced in the issue was likely from a draft that was fixed before merge. Added 4 validation tests to prevent future corruption: - test_portals_json_valid: file must parse as JSON - test_portals_json_no_duplicate_keys: no duplicate keys in any object - test_portals_json_structure: required fields (id, name, description, status, color, position) present on every portal - test_portals_json_positions_valid: x/y/z coordinates are numbers Closes #1440 --- tests/test_portals_json.py | 51 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 tests/test_portals_json.py diff --git a/tests/test_portals_json.py b/tests/test_portals_json.py new file mode 100644 index 00000000..1736409b --- /dev/null +++ b/tests/test_portals_json.py @@ -0,0 +1,51 @@ +"""Test portals.json integrity — valid JSON, no duplicate keys, expected structure.""" + +from pathlib import Path +import json + + +def test_portals_json_valid(): + """portals.json must be valid JSON.""" + path = Path(__file__).resolve().parents[1] / "portals.json" + data = json.loads(path.read_text(encoding="utf-8")) + assert isinstance(data, list), "portals.json should be a JSON array" + + +def test_portals_json_no_duplicate_keys(): + """portals.json must not contain duplicate keys in any object.""" + path = Path(__file__).resolve().parents[1] / "portals.json" + content = path.read_text(encoding="utf-8") + + def check_duplicates(pairs): + keys = [k for k, _ in pairs] + seen = set() + for k in keys: + assert k not in seen, f"Duplicate key '{k}' found in portals.json" + seen.add(k) + return dict(pairs) + + json.loads(content, object_pairs_hook=check_duplicates) + + +def test_portals_json_structure(): + """Each portal entry must have required fields.""" + path = Path(__file__).resolve().parents[1] / "portals.json" + data = json.loads(path.read_text(encoding="utf-8")) + + required = {"id", "name", "description", "status", "color", "position"} + for i, portal in enumerate(data): + assert isinstance(portal, dict), f"Portal [{i}] is not a dict" + missing = required - set(portal.keys()) + assert not missing, f"Portal [{i}] ({portal.get('id', '?')}) missing fields: {missing}" + + +def test_portals_json_positions_valid(): + """Each portal position must have x, y, z coordinates.""" + path = Path(__file__).resolve().parents[1] / "portals.json" + data = json.loads(path.read_text(encoding="utf-8")) + + for i, portal in enumerate(data): + pos = portal.get("position", {}) + for axis in ("x", "y", "z"): + assert axis in pos, f"Portal [{i}] ({portal.get('id')}) missing position.{axis}" + assert isinstance(pos[axis], (int, float)), f"Portal [{i}] position.{axis} is not a number"