"""Pytest fixtures. Each test gets a fresh in-memory SQLite connection with the FULL schema applied (all 9 tables), so all entities can be tested in isolation without Alembic. Follow the `vacation_repo` / `vacation_service` pattern to add fixtures for other entities. """ from collections.abc import AsyncIterator from dataclasses import dataclass from datetime import date, datetime from uuid import UUID, uuid4 import aiosqlite import pytest_asyncio from app.db.connection import ensure_schema from app.entities.child import Child from app.entities.personal_data import PersonalData from app.entities.workspace import Workspace from app.repositories_impl.sqlite.break_period_repository import SQLiteBreakPeriodRepository from app.repositories_impl.sqlite.child_repository import SQLiteChildRepository from app.repositories_impl.sqlite.parental_leave_repository import SQLiteParentalLeaveRepository from app.repositories_impl.sqlite.personal_data_repository import SQLitePersonalDataRepository from app.repositories_impl.sqlite.planned_leave_repository import SQLitePlannedLeaveRepository from app.repositories_impl.sqlite.user_repository import SQLiteUserRepository from app.repositories_impl.sqlite.vacation_days_repository import ( SQLiteVacationDaysRepository, ) from app.repositories_impl.sqlite.workspace_repository import ( SQLiteWorkspaceInvitationRepository, SQLiteWorkspaceRepository, ) from app.services.analytics_service import AnalyticsService from app.services.auth_service import AuthService from app.services.break_period_service import BreakPeriodService from app.services.child_service import ChildService from app.services.planning_service import PlanningService from app.services.vacation_days_service import VacationDaysService from app.services.workspace_service import WorkspaceService @dataclass class SeededIds: workspace_id: UUID personal_data_uuid: UUID child_id: UUID @pytest_asyncio.fixture async def connection() -> AsyncIterator[aiosqlite.Connection]: conn = await aiosqlite.connect(":memory:") conn.row_factory = aiosqlite.Row await conn.execute("PRAGMA foreign_keys = ON;") await ensure_schema(conn) try: yield conn finally: await conn.close() # --------------------------------------------------------------------------- # VacationDays (reference slice — keep unchanged) # --------------------------------------------------------------------------- @pytest_asyncio.fixture async def vacation_repo( connection: aiosqlite.Connection, ) -> SQLiteVacationDaysRepository: return SQLiteVacationDaysRepository(connection) @pytest_asyncio.fixture async def vacation_service( vacation_repo: SQLiteVacationDaysRepository, ) -> VacationDaysService: return VacationDaysService(vacation_repo) # --------------------------------------------------------------------------- # Auth # --------------------------------------------------------------------------- @pytest_asyncio.fixture async def user_repo(connection: aiosqlite.Connection) -> SQLiteUserRepository: return SQLiteUserRepository(connection) @pytest_asyncio.fixture async def personal_data_repo( connection: aiosqlite.Connection, ) -> SQLitePersonalDataRepository: return SQLitePersonalDataRepository(connection) @pytest_asyncio.fixture async def auth_service( user_repo: SQLiteUserRepository, personal_data_repo: SQLitePersonalDataRepository, workspace_repo: SQLiteWorkspaceRepository, ) -> AuthService: return AuthService(user_repo, personal_data_repo, workspace_repo) # --------------------------------------------------------------------------- # Workspace # --------------------------------------------------------------------------- @pytest_asyncio.fixture async def workspace_repo( connection: aiosqlite.Connection, ) -> SQLiteWorkspaceRepository: return SQLiteWorkspaceRepository(connection) @pytest_asyncio.fixture async def invitation_repo( connection: aiosqlite.Connection, ) -> SQLiteWorkspaceInvitationRepository: return SQLiteWorkspaceInvitationRepository(connection) @pytest_asyncio.fixture async def workspace_service( workspace_repo: SQLiteWorkspaceRepository, invitation_repo: SQLiteWorkspaceInvitationRepository, personal_data_repo: SQLitePersonalDataRepository, ) -> WorkspaceService: return WorkspaceService(workspace_repo, invitation_repo, personal_data_repo) # --------------------------------------------------------------------------- # Shared FK seed — used by any test that needs real workspace + personal_data rows # --------------------------------------------------------------------------- @pytest_asyncio.fixture async def seeded_ids( workspace_repo: SQLiteWorkspaceRepository, personal_data_repo: SQLitePersonalDataRepository, child_repo: SQLiteChildRepository, ) -> SeededIds: """Pre-create a workspace + personal_data + child row so FK constraints pass.""" ws = await workspace_repo.create( Workspace(id=uuid4(), name="Test WS", created_at=datetime.now()) ) pd = await personal_data_repo.create( PersonalData( uuid=uuid4(), workspace_id=ws.id, name="Test Parent", created_at=datetime.now() ) ) child = await child_repo.create( Child( id=uuid4(), workspace_id=ws.id, name="Test Child", birth_date=date(2024, 1, 1), created_at=datetime.now(), ) ) return SeededIds(workspace_id=ws.id, personal_data_uuid=pd.uuid, child_id=child.id) # --------------------------------------------------------------------------- # Child & leave # --------------------------------------------------------------------------- @pytest_asyncio.fixture async def child_repo(connection: aiosqlite.Connection) -> SQLiteChildRepository: return SQLiteChildRepository(connection) @pytest_asyncio.fixture async def parental_leave_repo( connection: aiosqlite.Connection, ) -> SQLiteParentalLeaveRepository: return SQLiteParentalLeaveRepository(connection) @pytest_asyncio.fixture async def planned_leave_repo( connection: aiosqlite.Connection, ) -> SQLitePlannedLeaveRepository: return SQLitePlannedLeaveRepository(connection) # --------------------------------------------------------------------------- # BreakPeriod # --------------------------------------------------------------------------- @pytest_asyncio.fixture async def break_period_repo( connection: aiosqlite.Connection, ) -> SQLiteBreakPeriodRepository: return SQLiteBreakPeriodRepository(connection) @pytest_asyncio.fixture async def break_period_service( break_period_repo: SQLiteBreakPeriodRepository, ) -> BreakPeriodService: return BreakPeriodService(break_period_repo) @pytest_asyncio.fixture async def child_service( child_repo: SQLiteChildRepository, ) -> ChildService: return ChildService(child_repo) @pytest_asyncio.fixture async def analytics_service( parental_leave_repo: SQLiteParentalLeaveRepository, planned_leave_repo: SQLitePlannedLeaveRepository, child_repo: SQLiteChildRepository, personal_data_repo: SQLitePersonalDataRepository, ) -> AnalyticsService: return AnalyticsService(parental_leave_repo, planned_leave_repo, child_repo, personal_data_repo) @pytest_asyncio.fixture async def planning_service( planned_leave_repo: SQLitePlannedLeaveRepository, analytics_service: AnalyticsService, ) -> PlanningService: return PlanningService(planned_leave_repo, analytics_service)