"""Tests for the scheduling fixture provider.""" from __future__ import annotations import json import pathlib import tempfile import pytest import sys sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[2] / "skills" / "_lib")) from lumina_skills.domain import Appointment, AppointmentStatus from lumina_skills.providers.scheduling.fixture_provider import ( load_fixtures, load_fixture_metadata, ) # Path to the real fixture file. _FIXTURE_PATH = pathlib.Path(__file__).resolve().parents[2] / "data" / "fixtures" / "scheduling" / "claire_bennett_2026-07-28.json" def _make_fixture_file(tmp_path: pathlib.Path, data: dict) -> pathlib.Path: """Write a fixture dict to a temp JSON file.""" p = tmp_path / "test_fixture.json" p.write_text(json.dumps(data), encoding="utf-8") return p # ── load_fixtures ────────────────────────────────────────────────────────── def test_load_real_fixture(): """Load the Claire Bennett fixture file.""" apts = load_fixtures(_FIXTURE_PATH) assert len(apts) == 7 # 7 appointments in the fixture assert all(isinstance(a, Appointment) for a in apts) def test_load_fixture_statuses(): """Fixture statuses are correctly parsed.""" apts = load_fixtures(_FIXTURE_PATH) statuses = {a.appointment_id: a.status for a in apts} assert statuses["APT-001"] == AppointmentStatus.CONFIRMED assert statuses["APT-002"] == AppointmentStatus.PENDING assert statuses["APT-007"] == AppointmentStatus.CANCELLED def test_load_fixture_needs_confirmation(): """needs_confirmation flag is loaded from fixture.""" apts = load_fixtures(_FIXTURE_PATH) flags = {a.appointment_id: a.needs_confirmation for a in apts} assert flags["APT-001"] is False assert flags["APT-002"] is True assert flags["APT-004"] is True def test_load_fixture_notes(): """Notes are loaded from fixture.""" apts = load_fixtures(_FIXTURE_PATH) notes = {a.appointment_id: a.notes for a in apts} assert "ammonia" in notes["APT-001"].lower() assert "Wedding" in notes["APT-002"] def test_load_fixture_missing_file(tmp_path: pathlib.Path): """FileNotFoundError for missing fixture.""" with pytest.raises(FileNotFoundError): load_fixtures(tmp_path / "nonexistent.json") def test_load_fixture_empty_appointments(tmp_path: pathlib.Path): """Empty appointments list returns empty list.""" data = {"salon_name": "Test", "date": "2026-01-01", "appointments": []} path = _make_fixture_file(tmp_path, data) apts = load_fixtures(path) assert apts == [] def test_load_fixture_default_status(tmp_path: pathlib.Path): """Missing status field defaults to PENDING (via .get default).""" data = { "appointments": [{ "id": "APT-X", "start": "2026-01-01T09:00:00", "end": "2026-01-01T10:00:00", "client_name": "Test", "service_name": "Test", "staff_name": "Test", # No status field. }] } path = _make_fixture_file(tmp_path, data) apts = load_fixtures(path) assert apts[0].status == AppointmentStatus.PENDING def test_load_fixture_unknown_status_raises(tmp_path: pathlib.Path): """Unknown status string raises ValueError.""" data = { "appointments": [{ "id": "APT-X", "start": "2026-01-01T09:00:00", "end": "2026-01-01T10:00:00", "client_name": "Test", "service_name": "Test", "staff_name": "Test", "status": "typo_status", }] } path = _make_fixture_file(tmp_path, data) with pytest.raises(ValueError, match="Unknown appointment status"): load_fixtures(path) def test_load_fixture_default_needs_confirmation(tmp_path: pathlib.Path): """Missing needs_confirmation defaults to False.""" data = { "appointments": [{ "id": "APT-X", "start": "2026-01-01T09:00:00", "end": "2026-01-01T10:00:00", "client_name": "Test", "service_name": "Test", "staff_name": "Test", "status": "confirmed", # No needs_confirmation field. }] } path = _make_fixture_file(tmp_path, data) apts = load_fixtures(path) assert apts[0].needs_confirmation is False def test_load_fixture_malformed_json(tmp_path: pathlib.Path): """ValueError for invalid JSON.""" p = tmp_path / "bad.json" p.write_text("{not valid json}", encoding="utf-8") with pytest.raises(ValueError): load_fixtures(p) # ── load_fixture_metadata ───────────────────────────────────────────────── def test_load_metadata(): meta = load_fixture_metadata(_FIXTURE_PATH) assert meta["salon_name"] == "Lumina Hair Studio & Spa" assert meta["date"] == "2026-07-28" assert meta["business_hours"]["open"] == "09:00" assert meta["business_hours"]["close"] == "18:00" assert len(meta["staff"]) == 2 def test_load_metadata_missing_file(tmp_path: pathlib.Path): with pytest.raises(FileNotFoundError): load_fixture_metadata(tmp_path / "nonexistent.json")