Files
badoHair_be/tests/test_slot_service.py
belviskhoremk d2dc43b16f Initial Commit
2026-05-12 00:34:21 +00:00

115 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Unit tests for slot generation and calendar logic — no HTTP involved."""
import asyncio
from datetime import date, time, timedelta
from unittest.mock import AsyncMock, MagicMock
import pytest
from app.services.slot_service import generate_slots, _fmt_time # type: ignore
from app.exceptions import AppError
def make_mock_db(schedule=None, blocked=None):
db = AsyncMock()
db.transaction = MagicMock(return_value=_TxCtx())
db.fetch = AsyncMock(side_effect=lambda q, *a: _route_fetch(q, schedule, blocked))
db.fetchval = AsyncMock(return_value=None)
db.execute = AsyncMock(return_value="INSERT 1")
return db
def _route_fetch(query, schedule, blocked):
if "weekly_schedule" in query:
return schedule or []
if "blocked_dates" in query:
return blocked or []
return []
class _TxCtx:
async def __aenter__(self): return self
async def __aexit__(self, *a): return False
MONDAY = 0 # weekday() value for Monday
SCHED_ROW = {
"day_of_week": MONDAY,
"start_time": time(9, 0),
"end_time": time(11, 0),
"slot_duration_minutes": 60,
}
async def test_generate_slots_creates_correct_count():
"""Mon 09:0011:00 with 60-min slots → 2 slots per Monday."""
db = make_mock_db(schedule=[SCHED_ROW])
# Find the next Monday
today = date.today()
days_ahead = (7 - today.weekday()) % 7 or 7
next_monday = today + timedelta(days=days_ahead)
db.fetchval = AsyncMock(return_value=None) # no existing slots
created = await generate_slots(db, next_monday, next_monday)
assert created == 2
async def test_generate_slots_skips_blocked_dates():
"""A blocked Monday produces 0 slots."""
today = date.today()
days_ahead = (7 - today.weekday()) % 7 or 7
next_monday = today + timedelta(days=days_ahead)
blocked = [{"date": next_monday}]
db = make_mock_db(schedule=[SCHED_ROW], blocked=blocked)
db.fetchval = AsyncMock(return_value=None)
created = await generate_slots(db, next_monday, next_monday)
assert created == 0
async def test_generate_slots_skips_existing_slots():
"""If a slot already exists, it is not duplicated."""
today = date.today()
days_ahead = (7 - today.weekday()) % 7 or 7
next_monday = today + timedelta(days=days_ahead)
db = make_mock_db(schedule=[SCHED_ROW])
db.fetchval = AsyncMock(return_value=1) # all slots already exist
created = await generate_slots(db, next_monday, next_monday)
assert created == 0
async def test_generate_slots_range_over_90_days_rejected():
with pytest.raises(AppError) as exc_info:
db = AsyncMock()
await generate_slots(db, date(2026, 1, 1), date(2026, 5, 1))
assert exc_info.value.code == "RANGE_TOO_LARGE"
async def test_generate_slots_no_schedule_raises():
db = make_mock_db(schedule=[])
with pytest.raises(AppError) as exc_info:
await generate_slots(db, date(2026, 6, 1), date(2026, 6, 7))
assert exc_info.value.code == "NO_SCHEDULE"
# ── Time formatting ───────────────────────────────────────────────────────────
def test_fmt_time_strips_seconds():
from datetime import time as t
assert _fmt_time(t(10, 0, 0)) == "10:00"
assert _fmt_time(t(9, 30)) == "09:30"
def test_fmt_time_string_input():
assert _fmt_time("14:30:00") == "14:30"
assert _fmt_time("08:00") == "08:00"
def test_fmt_time_none():
assert _fmt_time(None) == ""