161 lines
5.9 KiB
Python
161 lines
5.9 KiB
Python
"""Tests for the reference repository + service.
|
|
|
|
Demonstrates the testing pattern: arrange an entity, exercise the repo/service,
|
|
assert on the result. Aim for >=90% coverage on new code (ARCHITECTURE.md §10).
|
|
"""
|
|
|
|
from datetime import datetime
|
|
from uuid import uuid4
|
|
|
|
import pytest
|
|
|
|
from app.entities.personal_data import PersonalData
|
|
from app.entities.vacation_days import VacationDays
|
|
from app.entities.workspace import Workspace
|
|
from app.repositories_impl.sqlite.personal_data_repository import SQLitePersonalDataRepository
|
|
from app.repositories_impl.sqlite.vacation_days_repository import (
|
|
SQLiteVacationDaysRepository,
|
|
)
|
|
from app.repositories_impl.sqlite.workspace_repository import SQLiteWorkspaceRepository
|
|
from app.services.vacation_days_service import VacationDaysService
|
|
from app.utils.errors import NotFoundError, ValidationError
|
|
from tests.conftest import SeededIds
|
|
|
|
|
|
def _make(workspace_id=None, personal_data_uuid=None, **overrides) -> VacationDays:
|
|
base = dict(
|
|
id=uuid4(),
|
|
personal_data_uuid=personal_data_uuid or uuid4(),
|
|
workspace_id=workspace_id or uuid4(),
|
|
year=2026,
|
|
total_days=25,
|
|
saved_days_in=0,
|
|
created_at=datetime.now(),
|
|
updated_at=datetime.now(),
|
|
)
|
|
base.update(overrides)
|
|
return VacationDays(**base)
|
|
|
|
|
|
class TestSQLiteVacationDaysRepository:
|
|
async def test_create_and_get_by_id(
|
|
self,
|
|
vacation_repo: SQLiteVacationDaysRepository,
|
|
seeded_ids: SeededIds,
|
|
) -> None:
|
|
entity = _make(
|
|
workspace_id=seeded_ids.workspace_id, personal_data_uuid=seeded_ids.personal_data_uuid
|
|
)
|
|
await vacation_repo.create(entity)
|
|
|
|
fetched = await vacation_repo.get_by_id(entity.id)
|
|
assert fetched is not None
|
|
assert fetched.id == entity.id
|
|
assert fetched.total_days == 25
|
|
|
|
async def test_get_by_parent_year(
|
|
self,
|
|
vacation_repo: SQLiteVacationDaysRepository,
|
|
seeded_ids: SeededIds,
|
|
) -> None:
|
|
entity = _make(
|
|
workspace_id=seeded_ids.workspace_id, personal_data_uuid=seeded_ids.personal_data_uuid
|
|
)
|
|
await vacation_repo.create(entity)
|
|
|
|
found = await vacation_repo.get_by_parent_year(entity.personal_data_uuid, 2026)
|
|
assert found is not None
|
|
assert found.id == entity.id
|
|
|
|
missing = await vacation_repo.get_by_parent_year(uuid4(), 2026)
|
|
assert missing is None
|
|
|
|
async def test_update(
|
|
self,
|
|
vacation_repo: SQLiteVacationDaysRepository,
|
|
seeded_ids: SeededIds,
|
|
) -> None:
|
|
entity = _make(
|
|
total_days=20,
|
|
workspace_id=seeded_ids.workspace_id,
|
|
personal_data_uuid=seeded_ids.personal_data_uuid,
|
|
)
|
|
await vacation_repo.create(entity)
|
|
|
|
entity.total_days = 30
|
|
updated = await vacation_repo.update(entity.id, entity)
|
|
assert updated.total_days == 30
|
|
|
|
async def test_update_missing_raises(self, vacation_repo: SQLiteVacationDaysRepository) -> None:
|
|
with pytest.raises(NotFoundError):
|
|
await vacation_repo.update(uuid4(), _make())
|
|
|
|
async def test_delete(
|
|
self,
|
|
vacation_repo: SQLiteVacationDaysRepository,
|
|
seeded_ids: SeededIds,
|
|
) -> None:
|
|
entity = _make(
|
|
workspace_id=seeded_ids.workspace_id, personal_data_uuid=seeded_ids.personal_data_uuid
|
|
)
|
|
await vacation_repo.create(entity)
|
|
await vacation_repo.delete(entity.id)
|
|
assert await vacation_repo.get_by_id(entity.id) is None
|
|
|
|
async def test_delete_missing_raises(self, vacation_repo: SQLiteVacationDaysRepository) -> None:
|
|
with pytest.raises(NotFoundError):
|
|
await vacation_repo.delete(uuid4())
|
|
|
|
async def test_list_filters_by_workspace(
|
|
self,
|
|
vacation_repo: SQLiteVacationDaysRepository,
|
|
seeded_ids: SeededIds,
|
|
workspace_repo: SQLiteWorkspaceRepository,
|
|
personal_data_repo: SQLitePersonalDataRepository,
|
|
) -> None:
|
|
ws = seeded_ids.workspace_id
|
|
pd_uuid = seeded_ids.personal_data_uuid
|
|
|
|
# Create a second workspace + personal_data for the "different workspace" row
|
|
ws2 = await workspace_repo.create(
|
|
Workspace(id=uuid4(), name="WS2", created_at=datetime.now())
|
|
)
|
|
pd2 = await personal_data_repo.create(
|
|
PersonalData(
|
|
uuid=uuid4(), workspace_id=ws2.id, name="Parent2", created_at=datetime.now()
|
|
)
|
|
)
|
|
|
|
await vacation_repo.create(_make(workspace_id=ws, personal_data_uuid=pd_uuid, year=2025))
|
|
await vacation_repo.create(_make(workspace_id=ws, personal_data_uuid=pd_uuid, year=2026))
|
|
await vacation_repo.create(_make(workspace_id=ws2.id, personal_data_uuid=pd2.uuid))
|
|
|
|
rows = await vacation_repo.list(workspace_id=ws)
|
|
assert len(rows) == 2
|
|
assert [r.year for r in rows] == [2026, 2025] # ordered year DESC
|
|
|
|
|
|
class TestVacationDaysService:
|
|
async def test_upsert_creates_then_updates(
|
|
self,
|
|
vacation_service: VacationDaysService,
|
|
seeded_ids: SeededIds,
|
|
) -> None:
|
|
parent = seeded_ids.personal_data_uuid
|
|
ws = seeded_ids.workspace_id
|
|
created = await vacation_service.upsert(parent, ws, 2026, 25)
|
|
assert created.total_days == 25
|
|
|
|
updated = await vacation_service.upsert(parent, ws, 2026, 30, saved_days_in=5)
|
|
assert updated.id == created.id # same (parent, year) row
|
|
assert updated.total_days == 30
|
|
assert updated.saved_days_in == 5
|
|
|
|
async def test_upsert_rejects_negative(self, vacation_service: VacationDaysService) -> None:
|
|
with pytest.raises(ValidationError):
|
|
await vacation_service.upsert(uuid4(), uuid4(), 2026, -1)
|
|
|
|
async def test_get_missing_raises(self, vacation_service: VacationDaysService) -> None:
|
|
with pytest.raises(NotFoundError):
|
|
await vacation_service.get(uuid4())
|