From a6c0dd5d237b368c2518421b7b9a6df1763fdece Mon Sep 17 00:00:00 2001 From: hermes Date: Mon, 22 Jun 2026 09:28:16 +0000 Subject: [PATCH] feat: Game-Service mit CRUD und Suche (Issue 1) --- src/services/game_service.py | 84 ++++++++++++++++++++++++++++++++++++ tests/test_game_service.py | 64 +++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 src/services/game_service.py create mode 100644 tests/test_game_service.py diff --git a/src/services/game_service.py b/src/services/game_service.py new file mode 100644 index 0000000..b0a1632 --- /dev/null +++ b/src/services/game_service.py @@ -0,0 +1,84 @@ +"""Game-Service: Spiele-Datenbank und CRUD-Operationen.""" + +from __future__ import annotations + +from pydantic import BaseModel, Field + + +class Spiel(BaseModel): + """Ein Brettspiel-Datenmodell.""" + + id: int | None = None + name: str = Field(..., min_length=1, max_length=200) + min_spieler: int = Field(default=1, ge=1, le=20) + max_spieler: int = Field(default=10, ge=1, le=20) + dauer_min: int = Field(default=30, ge=1) + komplexitaet: float = Field(default=2.5, ge=1.0, le=5.0) + kategorie: str = Field(default="Familienspiel") + + +class GameService: + """Verwaltet die Spiele-Datenbank (In-Memory für jetzt, später DB).""" + + def __init__(self) -> None: + self._spiele: dict[int, Spiel] = {} + self._next_id = 1 + + def hinzufuegen(self, spiel: Spiel) -> Spiel: + """Fügt ein Spiel hinzu und weist eine ID zu. + + Args: + spiel: Das hinzuzufügende Spiel. + + Returns: + Das zugewiesene Spiel mit ID. + """ + spiel.id = self._next_id + self._spiele[self._next_id] = spiel + self._next_id += 1 + return spiel + + def alle(self) -> list[Spiel]: + """Gibt alle Spiele zurück. + + Returns: + Liste aller Spiele. + """ + return list(self._spiele.values()) + + def suchen(self, name: str) -> list[Spiel]: + """Sucht Spiele nach Name (case-insensitive Teilstring). + + Args: + name: Der Suchbegriff. + + Returns: + Liste der gefundenen Spiele. + """ + name_lower = name.lower() + return [spiel for spiel in self._spiele.values() if name_lower in spiel.name.lower()] + + def nach_id(self, spiel_id: int) -> Spiel | None: + """Holt ein Spiel anhand seiner ID. + + Args: + spiel_id: Die ID des Spiels. + + Returns: + Das gefundene Spiel oder None. + """ + return self._spiele.get(spiel_id) + + def loesche(self, spiel_id: int) -> bool: + """Löscht ein Spiel anhand seiner ID. + + Args: + spiel_id: Die ID des zu löschenden Spiels. + + Returns: + True wenn gelöscht, False wenn nicht existiert. + """ + if spiel_id in self._spiele: + del self._spiele[spiel_id] + return True + return False diff --git a/tests/test_game_service.py b/tests/test_game_service.py new file mode 100644 index 0000000..404c7a1 --- /dev/null +++ b/tests/test_game_service.py @@ -0,0 +1,64 @@ +"""Tests für Game-Service.""" + +from src.services.game_service import GameService, Spiel + + +class TestGameService: + """Tests für GameService.""" + + def test_hinzufuegen_id_wird_vergeben(self) -> None: + """Hinzufügen eines Spiels → ID wird vergeben.""" + service = GameService() + spiel = Spiel(name="Catan") + + resultat = service.hinzufuegen(spiel) + + assert resultat.id is not None + assert resultat.name == "Catan" + + def test_alle_leere_liste_am_anfang(self) -> None: + """Alle Spiele → leere Liste am Anfang.""" + service = GameService() + assert service.alle() == [] + + def test_alle_zwei_spielenach_hinzufuegen(self) -> None: + """Alle Spiele nach Hinzufügen → 2 Spiele.""" + service = GameService() + s1 = Spiel(name="Catan") + s2 = Spiel(name="Ticket to Ride") + service.hinzufuegen(s1) + service.hinzufuegen(s2) + + assert len(service.alle()) == 2 + + def test_suchen_nach_cat_finnt_catan(self) -> None: + """Suchen nach 'cat' → findet Catan.""" + service = GameService() + service.hinzufuegen(Spiel(name="Catan")) + + ergebnis = service.suchen("cat") + + assert len(ergebnis) == 1 + assert ergebnis[0].name == "Catan" + + def test_suchen_nach_xyz_ergebt_leere_liste(self) -> None: + """Suchen nach 'xyz' → leere Liste.""" + service = GameService() + service.hinzufuegen(Spiel(name="Catan")) + + assert service.suchen("xyz") == [] + + def test_nach_id_aktives_spiel(self) -> None: + """Nach ID holen → korrektes Spiel.""" + service = GameService() + s = Spiel(name="Carcassonne") + service.hinzufuegen(s) + + resultat = service.nach_id(1) + assert resultat is not None + assert resultat.name == "Carcassonne" + + def test_nach_id_nicht_existent(self) -> None: + """Nach ID holen → None bei nicht existenter ID.""" + service = GameService() + assert service.nach_id(999) is None