"""Tests unitaires pour l'usine de construction du fournisseur d'agenda théorique. Ce module contient les tests pour la fonction :func:`get_theoretical_provider` du module :mod:`pronote_sync.sources.theoretical`. """ from __future__ import annotations import json from datetime import date from pathlib import Path import pytest from pronote_sync.errors import PronoteSyncError from pronote_sync.sources.theoretical import ( TheoreticalAgendaProvider, get_theoretical_provider, ) class TestGetTheoreticalProvider: """Tests pour la fonction get_theoretical_provider.""" @pytest.fixture def fixture_path(self) -> Path: """Retourne le chemin du fichier de fixture theoretical.json.""" return Path(__file__).parent.parent / "fixtures" / "theoretical.json" @pytest.fixture def holidays_path(self) -> Path: """Retourne le chemin du fichier de fixture school_holidays.json.""" return Path(__file__).parent.parent / "fixtures" / "school_holidays.json" @pytest.fixture def all_only_path(self, tmp_path: Path) -> Path: """Crée un fichier JSON avec uniquement des cours "all".""" data = { "version": 1, "lessons": [ { "week": "all", "day_of_week": 0, "start_time": "08:00", "end_time": "09:00", "subject": "Test", } ], } file_path = tmp_path / "all_only.json" file_path.write_text(json.dumps(data), encoding="utf-8") return file_path def test_factory_returns_none_when_path_none(self) -> None: """Teste que l'usine retourne None quand agenda_path est None. :assert: get_theoretical_provider(None, None, None, None) retourne None. """ result = get_theoretical_provider(None, None, None, None) assert result is None def test_factory_returns_provider_with_full_config( self, fixture_path: Path, holidays_path: Path ) -> None: """Teste que l'usine retourne un fournisseur avec une configuration complète. :assert: Un fournisseur est retourné avec tous les paramètres. """ result = get_theoretical_provider( agenda_path=str(fixture_path), holidays_path=str(holidays_path), anchor_date=date(2026, 9, 1), anchor_type="even", ) assert result is not None assert isinstance(result, TheoreticalAgendaProvider) def test_factory_partial_parity_config_error(self, fixture_path: Path) -> None: """Teste qu'une configuration de parité partielle lève une PronoteSyncError. :assert: PronoteSyncError est levée quand anchor_date est fourni sans anchor_type. """ with pytest.raises(PronoteSyncError) as exc_info: get_theoretical_provider( agenda_path=str(fixture_path), holidays_path=None, anchor_date=date(2026, 9, 1), anchor_type=None, ) assert "incomplète" in str(exc_info.value) def test_factory_partial_parity_config_error_type_only(self, fixture_path: Path) -> None: """Teste qu'une configuration de parité partielle (type seulement) lève une PronoteSyncError. :assert: PronoteSyncError est levée quand anchor_type est fourni sans anchor_date. """ with pytest.raises(PronoteSyncError) as exc_info: get_theoretical_provider( agenda_path=str(fixture_path), holidays_path=None, anchor_date=None, anchor_type="even", ) assert "incomplète" in str(exc_info.value) def test_factory_no_holidays(self, fixture_path: Path) -> None: """Teste que l'usine retourne un fournisseur sans calendrier de vacances. :assert: Un fournisseur est retourné sans calendrier de vacances. """ result = get_theoretical_provider( agenda_path=str(fixture_path), holidays_path=None, anchor_date=date(2026, 9, 1), anchor_type="even", ) assert result is not None assert isinstance(result, TheoreticalAgendaProvider) def test_factory_no_parity(self, all_only_path: Path) -> None: """Teste que l'usine retourne un fournisseur sans service de parité pour des cours "all". :assert: Un fournisseur est retourné sans service de parité. """ result = get_theoretical_provider( agenda_path=str(all_only_path), holidays_path=None, anchor_date=None, anchor_type=None, ) assert result is not None assert isinstance(result, TheoreticalAgendaProvider) def test_factory_protocol_compliance(self, fixture_path: Path, holidays_path: Path) -> None: """Teste que le fournisseur retourné respecte le protocole TheoreticalAgendaProvider. :assert: Le fournisseur satisfait isinstance(provider, TheoreticalAgendaProvider). """ result = get_theoretical_provider( agenda_path=str(fixture_path), holidays_path=str(holidays_path), anchor_date=date(2026, 9, 1), anchor_type="even", ) assert result is not None assert isinstance(result, TheoreticalAgendaProvider)