"""Tests for lumina_skills.domain types.""" from __future__ import annotations import json from datetime import datetime, time import pytest import sys import pathlib sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[2] / "skills" / "_lib")) from lumina_skills.domain import ( Appointment, AppointmentStatus, DayBoard, Gap, ) # ── Appointment ──────────────────────────────────────────────────────────── def test_appointment_duration(): apt = Appointment( appointment_id="APT-001", start_time=datetime(2026, 7, 28, 9, 0), end_time=datetime(2026, 7, 28, 10, 30), client_name="Elena Rossi", service_name="Balayage + Cut", staff_name="Claire Bennett", status=AppointmentStatus.CONFIRMED, ) assert apt.duration_minutes() == 90 def test_appointment_duration_one_hour(): apt = Appointment( appointment_id="APT-002", start_time=datetime(2026, 7, 28, 13, 0), end_time=datetime(2026, 7, 28, 14, 0), client_name="Chris Nguyen", service_name="Men's Cut", staff_name="Claire Bennett", status=AppointmentStatus.PENDING, ) assert apt.duration_minutes() == 60 def test_appointment_time_only(): apt = Appointment( appointment_id="APT-003", start_time=datetime(2026, 7, 28, 11, 15), end_time=datetime(2026, 7, 28, 12, 45), client_name="Jasmine Patel", service_name="Root Touch-Up", staff_name="Maya Torres", status=AppointmentStatus.CONFIRMED, ) assert apt.start_time_only() == time(11, 15) assert apt.end_time_only() == time(12, 45) def test_appointment_frozen(): """Appointment is immutable.""" apt = Appointment( appointment_id="APT-001", start_time=datetime(2026, 7, 28, 9, 0), end_time=datetime(2026, 7, 28, 10, 0), client_name="Test", service_name="Test", staff_name="Test", status=AppointmentStatus.CONFIRMED, ) with pytest.raises(Exception): # FrozenInstanceError apt.client_name = "Hacker" def test_appointment_needs_confirmation_default(): apt = Appointment( appointment_id="APT-001", start_time=datetime(2026, 7, 28, 9, 0), end_time=datetime(2026, 7, 28, 10, 0), client_name="Test", service_name="Test", staff_name="Test", status=AppointmentStatus.PENDING, ) assert apt.needs_confirmation is False def test_appointment_status_enum(): assert AppointmentStatus.CONFIRMED.value == "confirmed" assert AppointmentStatus.PENDING.value == "pending" assert AppointmentStatus.CANCELLED.value == "cancelled" assert AppointmentStatus.COMPLETED.value == "completed" assert AppointmentStatus.NO_SHOW.value == "no_show" # ── Gap ──────────────────────────────────────────────────────────────────── def test_gap_creation(): gap = Gap( start_time=time(12, 0), end_time=time(13, 30), duration_minutes=90, staff_name="Claire Bennett", ) assert gap.duration_minutes == 90 assert gap.staff_name == "Claire Bennett" def test_gap_with_references(): gap = Gap( start_time=time(12, 0), end_time=time(13, 0), duration_minutes=60, staff_name="Claire Bennett", preceding_appointment_id="APT-001", following_appointment_id="APT-002", ) assert gap.preceding_appointment_id == "APT-001" assert gap.following_appointment_id == "APT-002" # ── DayBoard ─────────────────────────────────────────────────────────────── def test_dayboard_to_dict(): apt = Appointment( appointment_id="APT-001", start_time=datetime(2026, 7, 28, 9, 0), end_time=datetime(2026, 7, 28, 10, 0), client_name="Elena Rossi", service_name="Cut", staff_name="Claire Bennett", status=AppointmentStatus.CONFIRMED, needs_confirmation=False, ) board = DayBoard( date="2026-07-28", salon_name="Lumina Hair Studio & Spa", source="fixtures", is_offline=True, appointments=[apt], gaps=[], needs_confirmation=[], total_booked_minutes=60, total_gap_minutes=0, ) d = board.to_dict() assert d["date"] == "2026-07-28" assert d["salon_name"] == "Lumina Hair Studio & Spa" assert d["source"] == "fixtures" assert d["is_offline"] is True assert len(d["appointments"]) == 1 assert d["appointments"][0]["client"] == "Elena Rossi" assert d["total_booked_minutes"] == 60 def test_dayboard_to_dict_serializable(): """to_dict output must be JSON-serializable.""" board = DayBoard( date="2026-07-28", salon_name="Test Salon", source="fixtures", is_offline=True, ) d = board.to_dict() # Should not raise. json.dumps(d) def test_dayboard_empty(): board = DayBoard( date="2026-07-28", salon_name="Empty Salon", source="offline", is_offline=True, ) assert len(board.appointments) == 0 assert len(board.gaps) == 0 assert board.total_booked_minutes == 0