"""Unit-Tests für alle importierbaren Python-Kommandozeilenwerkzeuge.""" from __future__ import annotations import importlib import sys import tempfile import unittest from pathlib import Path from unittest.mock import patch ROOT = Path(__file__).resolve().parents[2] TOOLS = ROOT / "tools" / "python" sys.path.insert(0, str(TOOLS)) class RecordingClient: def __init__(self, get_result=None): self.calls = [] self.get_result = get_result or {} def request(self, method, path, **kwargs): self.calls.append((method, path, kwargs)) if method == "GET": return dict(self.get_result) return {"method": method, "path": path} class CommandTests(unittest.TestCase): def module(self, name): return importlib.import_module(name) def run_with_client(self, name, argv, *, get_result=None, extra_patches=()): module = self.module(name) client = RecordingClient(get_result) patches = [patch.object(module, "client_from_args", return_value=client)] patches.extend(extra_patches) for current in patches: current.start() self.addCleanup(current.stop) result = module.main(argv) return result, client def test_create_and_append_commands(self): with tempfile.TemporaryDirectory() as directory: gpx = Path(directory) / "route.gpx" picture = Path(directory) / "picture.png" audio = Path(directory) / "audio.mp3" for file_path in (gpx, picture, audio): file_path.write_bytes(b"content") _, client = self.run_with_client("append_route", ["--route-id", "1", "--gpx", str(gpx)]) self.assertEqual(client.calls[0][0:2], ("POST", "/api/routes/1/append")) _, client = self.run_with_client( "create_route", ["--gpx", str(gpx), "--name", "Route", "--slug", "route", "--description", "Text", "--school-name", "Schule"], ) self.assertEqual(client.calls[0][1], "/api/routes") self.assertEqual(client.calls[0][2]["fields"]["schoolName"], "Schule") _, client = self.run_with_client("create_audio", ["--route-id", "1", "--poi-id", "2", "--file", str(audio)]) self.assertIn("audio", client.calls[0][2]["files"]) _, client = self.run_with_client( "create_picture", ["--route-id", "1", "--poi-id", "2", "--file", str(picture), "--caption", "Bild", "--sequence", "3"], ) self.assertEqual(client.calls[0][2]["fields"], {"caption": "Bild", "sequence": 3}) _, client = self.run_with_client( "create_poi", ["--route-id", "1", "--title", "POI", "--description", "Text", "--lat", "50.1", "--lon", "10.2", "--trigger-radius", "25", "--sequence", "0"], ) self.assertEqual(client.calls[0][2]["json_body"]["sequence"], 0) self.assertEqual(client.calls[0][2]["json_body"]["description"], "Text") def test_delete_commands_cover_confirmation_and_requests(self): cases = [ ("delete_route", ["--route-id", "1"], "/api/routes/1"), ("delete_poi", ["--route-id", "1", "--poi-id", "2"], "/api/routes/1/pois/2"), ("delete_picture", ["--route-id", "1", "--poi-id", "2", "--picture-id", "3"], "/api/routes/1/pois/2/pictures/3"), ("delete_audio", ["--route-id", "1", "--poi-id", "2"], "/api/routes/1/pois/2/audio"), ] for name, argv, path in cases: with self.subTest(name=name, confirmed=False): module = self.module(name) result, client = self.run_with_client( name, argv, extra_patches=(patch.object(module, "confirm", return_value=False),), ) self.assertEqual(result, {"cancelled": True}) self.assertEqual(client.calls, []) with self.subTest(name=name, confirmed=True): module = self.module(name) _, client = self.run_with_client( name, argv, extra_patches=(patch.object(module, "confirm", return_value=True),), ) self.assertEqual(client.calls[0][0:2], ("DELETE", path)) def test_restore_and_update_commands(self): _, client = self.run_with_client("restore_route", ["--route-id", "7"]) self.assertEqual(client.calls[0][0:2], ("POST", "/api/routes/7/restore")) with tempfile.TemporaryDirectory() as directory: replacement = Path(directory) / "replacement.bin" replacement.write_bytes(b"content") _, client = self.run_with_client( "update_audio", ["--route-id", "1", "--poi-id", "2", "--file", str(replacement)] ) self.assertEqual(client.calls[0][0], "PUT") _, client = self.run_with_client( "update_picture", ["--route-id", "1", "--poi-id", "2", "--picture-id", "3", "--file", str(replacement)], get_result={"caption": "Alt", "sequence": 4}, extra_patches=(patch.object(self.module("update_picture"), "ask_with_default", side_effect=lambda label, current, cast=str: current),), ) self.assertEqual([call[0] for call in client.calls], ["GET", "PUT"]) self.assertIn("files", client.calls[1][2]) module = self.module("update_picture") _, client = self.run_with_client( "update_picture", ["--route-id", "1", "--poi-id", "2", "--picture-id", "3"], get_result={"caption": "Alt", "sequence": 4}, extra_patches=( patch.object(module, "ask_path", return_value=None), patch.object(module, "ask_with_default", side_effect=lambda label, current, cast=str: current), ), ) self.assertIn("json_body", client.calls[1][2]) _, client = self.run_with_client( "update_route", ["--route-id", "1", "--gpx", str(replacement)], get_result={"name": "Alt", "description": "Text", "schoolName": "Schule"}, extra_patches=(patch.object(self.module("update_route"), "ask_with_default", side_effect=lambda label, current, cast=str: current),), ) self.assertIn("files", client.calls[1][2]) module = self.module("update_route") _, client = self.run_with_client( "update_route", ["--route-id", "1"], get_result={"name": "Alt", "description": "Text", "schoolName": "Schule"}, extra_patches=( patch.object(module, "ask_path", return_value=None), patch.object(module, "ask_with_default", side_effect=lambda label, current, cast=str: current), ), ) self.assertIn("json_body", client.calls[1][2]) _, client = self.run_with_client( "update_poi", ["--route-id", "1", "--poi-id", "2"], get_result={ "title": "Alt", "description": "Text", "lat": 50.0, "lon": 10.0, "triggerRadiusM": 25.0, "sequence": 1, }, extra_patches=(patch.object(self.module("update_poi"), "ask_with_default", side_effect=lambda label, current, cast=str: current),), ) self.assertEqual(client.calls[1][2]["json_body"]["title"], "Alt") if __name__ == "__main__": unittest.main()