"""Tests unitaires pour les modèles de parsing de l'agenda théorique. Ce module contient les tests pour les classes :class:`TheoreticalLessonEntry` et :class:`TheoreticalAgendaFile` du module :mod:`pronote_sync.sources.theoretical.model`. """ from __future__ import annotations import pytest from pydantic import ValidationError from pronote_sync.sources.theoretical.model import ( TheoreticalAgendaFile, TheoreticalLessonEntry, ) class TestTheoreticalLessonEntry: """Tests pour la classe TheoreticalLessonEntry.""" def test_valid_lesson_entry(self) -> None: """Teste la construction d'une entrée de cours valide. :assert: Tous les champs sont correctement initialisés. """ entry = TheoreticalLessonEntry( week="all", day_of_week=0, start_time="08:00", end_time="09:00", subject="Mathématiques", teachers=("Mme Martin",), rooms=("101",), id="math-1", ) assert entry.week == "all" assert entry.day_of_week == 0 assert entry.start_time == "08:00" assert entry.end_time == "09:00" assert entry.subject == "Mathématiques" assert entry.teachers == ("Mme Martin",) assert entry.rooms == ("101",) assert entry.id == "math-1" def test_invalid_time_format(self) -> None: """Teste qu'une heure invalide (25:00) lève une ValidationError. :assert: ValidationError est levée pour start_time="25:00". """ with pytest.raises(ValidationError) as exc_info: TheoreticalLessonEntry( week="all", day_of_week=0, start_time="25:00", end_time="09:00", subject="Test", ) assert "start_time" in str(exc_info.value) def test_invalid_time_format_minutes(self) -> None: """Teste qu'une minute invalide (60) lève une ValidationError. :assert: ValidationError est levée pour start_time="08:60". """ with pytest.raises(ValidationError) as exc_info: TheoreticalLessonEntry( week="all", day_of_week=0, start_time="08:60", end_time="09:00", subject="Test", ) assert "start_time" in str(exc_info.value) def test_end_before_start(self) -> None: """Teste qu'une fin avant le début lève une ValidationError. :assert: ValidationError est levée pour end_time < start_time. """ with pytest.raises(ValidationError) as exc_info: TheoreticalLessonEntry( week="all", day_of_week=0, start_time="10:00", end_time="09:00", subject="Test", ) assert "end_time" in str(exc_info.value) def test_end_equal_start(self) -> None: """Teste qu'une fin égale au début lève une ValidationError. :assert: ValidationError est levée pour end_time == start_time. """ with pytest.raises(ValidationError) as exc_info: TheoreticalLessonEntry( week="all", day_of_week=0, start_time="09:00", end_time="09:00", subject="Test", ) assert "end_time" in str(exc_info.value) def test_invalid_week(self) -> None: """Teste qu'une semaine invalide lève une ValidationError. :assert: ValidationError est levée pour week="weekly". """ with pytest.raises(ValidationError) as exc_info: TheoreticalLessonEntry( week="weekly", # type: ignore[arg-type] day_of_week=0, start_time="08:00", end_time="09:00", subject="Test", ) assert "week" in str(exc_info.value) def test_invalid_day_of_week(self) -> None: """Teste qu'un jour de semaine invalide (7) lève une ValidationError. :assert: ValidationError est levée pour day_of_week=7. """ with pytest.raises(ValidationError) as exc_info: TheoreticalLessonEntry( week="all", day_of_week=7, start_time="08:00", end_time="09:00", subject="Test", ) assert "day_of_week" in str(exc_info.value) def test_optional_fields_defaults(self) -> None: """Teste que les champs optionnels ont des valeurs par défaut. :assert: teachers et rooms valent () par défaut. """ entry = TheoreticalLessonEntry( week="all", day_of_week=0, start_time="08:00", end_time="09:00", subject="Test", ) assert entry.teachers == () assert entry.rooms == () def test_frozen_model(self) -> None: """Teste que le modèle est immuable (frozen). :assert: La tentative de mutation lève une exception. """ entry = TheoreticalLessonEntry( week="all", day_of_week=0, start_time="08:00", end_time="09:00", subject="Test", ) with pytest.raises((ValidationError, AttributeError)): entry.subject = "Nouveau" class TestTheoreticalAgendaFile: """Tests pour la classe TheoreticalAgendaFile.""" def test_agenda_file_valid(self) -> None: """Teste la construction d'un fichier d'agenda valide. :assert: version == 1 et lessons a le bon nombre d'entrées. """ lessons = [ TheoreticalLessonEntry( week="all", day_of_week=0, start_time="08:00", end_time="09:00", subject="Mathématiques", ), TheoreticalLessonEntry( week="even", day_of_week=1, start_time="10:00", end_time="11:00", subject="Anglais", ), ] agenda = TheoreticalAgendaFile(version=1, lessons=tuple(lessons)) assert agenda.version == 1 assert len(agenda.lessons) == 2 def test_agenda_file_default_version(self) -> None: """Teste que la version par défaut est 1. :assert: version vaut 1 par défaut. """ agenda = TheoreticalAgendaFile(lessons=()) assert agenda.version == 1