"""Unit tests for JsonRepositoryInterface.""" from collections.abc import Iterator from typing import Any import pytest from python_repositories.interfaces.json_repository_interface import ( JsonRepositoryInterface, ) class InMemoryJsonRepo: """Plain class that satisfies JsonRepositoryInterface without inheritance.""" def get(self, key: str) -> dict[str, Any] | None: return None def set(self, key: str, data: dict[str, Any]) -> None: pass def delete(self, key: str) -> None: pass def list_keys(self, pattern: str) -> list[str]: return [] def scan_keys( self, pattern: str, *, count: int | None = None, ) -> Iterator[str]: del count yield from self.list_keys(pattern) def accepts_json_repo(repo: JsonRepositoryInterface) -> None: """Type-checking hook for JsonRepositoryInterface structural subtyping.""" repo.get("key") def test_instantiation_fails_when_get_not_implemented() -> None: """Test that instantiation fails if get is not implemented.""" class Incomplete(JsonRepositoryInterface): """A class that does not implement get.""" def set(self, key: str, data: dict[str, Any]) -> None: pass def delete(self, key: str) -> None: pass def list_keys(self, pattern: str) -> list[str]: return [] with pytest.raises(TypeError): _ = Incomplete() # type: ignore def test_instantiation_fails_when_set_not_implemented() -> None: """Test that instantiation fails if set is not implemented.""" class Incomplete(JsonRepositoryInterface): """A class that does not implement set.""" def get(self, key: str) -> dict[str, Any] | None: return None def delete(self, key: str) -> None: pass def list_keys(self, pattern: str) -> list[str]: return [] with pytest.raises(TypeError): _ = Incomplete() # type: ignore def test_instantiation_fails_when_delete_not_implemented() -> None: """Test that instantiation fails if delete is not implemented.""" class Incomplete(JsonRepositoryInterface): """A class that does not implement delete.""" def get(self, key: str) -> dict[str, Any] | None: return None def set(self, key: str, data: dict[str, Any]) -> None: pass def list_keys(self, pattern: str) -> list[str]: return [] with pytest.raises(TypeError): _ = Incomplete() # type: ignore def test_instantiation_fails_when_list_keys_not_implemented() -> None: """Test that instantiation fails if list_keys is not implemented.""" class Incomplete(JsonRepositoryInterface): """A class that does not implement list_keys.""" def get(self, key: str) -> dict[str, Any] | None: return None def set(self, key: str, data: dict[str, Any]) -> None: pass def delete(self, key: str) -> None: pass with pytest.raises(TypeError): _ = Incomplete() # type: ignore def test_scan_keys_defaults_to_list_keys() -> None: """Test that the default scan_keys implementation delegates to list_keys.""" class Complete(JsonRepositoryInterface): def get(self, key: str) -> dict[str, Any] | None: return None def set(self, key: str, data: dict[str, Any]) -> None: pass def delete(self, key: str) -> None: pass def list_keys(self, pattern: str) -> list[str]: return [f"{pattern}-1", f"{pattern}-2"] repository = Complete() assert list(repository.scan_keys("user")) == ["user-1", "user-2"] def test_structural_subtyping() -> None: """Test that a plain class satisfies JsonRepositoryInterface structurally.""" repo: JsonRepositoryInterface = InMemoryJsonRepo() accepts_json_repo(repo) assert isinstance(repo, JsonRepositoryInterface)