fix(M8): corrections d'audit FIXME_M8 — appariement, date, déterminisme, validateur
Quatre corrections bloquantes/majeures de l'audit FIXME_M8 : - Appariement un-à-un déterministe (consommation du candidat sélectionné) ; 1 réel / 2 théoriques → 1 REMOVED, 2 réels / 1 théorique → 1 ADDED. - Filtrage strict par date : les cours réels hors target_date sont exclus du matching avec un warning logé (décision architecte : pas d'exception). - Déterminisme des détails : formatage via sorted(set(...)) au lieu de set(...) brut, indépendant de PYTHONHASHSEED. - Validateur AgendaChange strict : ADDED = lesson seule, REMOVED = theoretical_lesson seule, MODIFIED = les deux requis. - Comparaison à la minute près dans _is_modified (cohérent avec _matches). - Documentation §8.4/§8.5 alignée avec l'implémentation (tolérance 15 min, API compare(), normalize_subject référencé, appariement consommé). Co-authored-by: opencode/coder <coder@agents.invalid> Co-authored-by: opencode/tech-writer <tech-writer@agents.invalid>
This commit is contained in:
@@ -240,7 +240,7 @@ class TestAgendaChangeConsistency:
|
||||
assert instance.theoretical_lesson is not None
|
||||
|
||||
def test_agenda_change_modified_with_lesson_valid(self) -> None:
|
||||
"""Vérifie que type=MODIFIED avec lesson=<valide> est valide."""
|
||||
"""Vérifie que type=MODIFIED avec lesson et theoretical_lesson est valide."""
|
||||
lesson = Lesson(
|
||||
id="lesson-valid-mod",
|
||||
start=datetime(2024, 9, 6, 10, 0, 0),
|
||||
@@ -249,13 +249,97 @@ class TestAgendaChangeConsistency:
|
||||
group=None,
|
||||
content=None,
|
||||
)
|
||||
theoretical_lesson = TheoreticalLesson(
|
||||
id="theo-lesson-valid-mod",
|
||||
day_of_week=0,
|
||||
start_time=time(10, 0, 0),
|
||||
end_time=time(11, 30, 0),
|
||||
subject="Physique",
|
||||
)
|
||||
instance = AgendaChange(
|
||||
type=AgendaChangeType.MODIFIED,
|
||||
lesson=lesson,
|
||||
theoretical_lesson=None,
|
||||
theoretical_lesson=theoretical_lesson,
|
||||
)
|
||||
assert instance.type == AgendaChangeType.MODIFIED
|
||||
assert instance.lesson is not None
|
||||
assert instance.theoretical_lesson is not None
|
||||
|
||||
def test_agenda_change_added_with_theoretical_lesson_invalid(self) -> None:
|
||||
"""Vérifie que type=ADDED avec theoretical_lesson non-None lève une ValidationError."""
|
||||
lesson = Lesson(
|
||||
id="lesson-added-theo",
|
||||
start=datetime(2024, 9, 6, 8, 0, 0),
|
||||
end=datetime(2024, 9, 6, 9, 30, 0),
|
||||
subject="Mathématiques",
|
||||
group=None,
|
||||
content=None,
|
||||
)
|
||||
theoretical_lesson = TheoreticalLesson(
|
||||
id="theo-lesson-added",
|
||||
day_of_week=0,
|
||||
start_time=time(8, 0, 0),
|
||||
end_time=time(9, 30, 0),
|
||||
subject="Mathématiques",
|
||||
)
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
AgendaChange(
|
||||
type=AgendaChangeType.ADDED,
|
||||
lesson=lesson,
|
||||
theoretical_lesson=theoretical_lesson,
|
||||
)
|
||||
assert any(
|
||||
"theoretical_lesson doit être None pour le type" in str(error)
|
||||
for error in exc_info.value.errors()
|
||||
)
|
||||
|
||||
def test_agenda_change_removed_with_lesson_invalid(self) -> None:
|
||||
"""Vérifie que type=REMOVED avec lesson non-None lève une ValidationError."""
|
||||
lesson = Lesson(
|
||||
id="lesson-removed",
|
||||
start=datetime(2024, 9, 6, 8, 0, 0),
|
||||
end=datetime(2024, 9, 6, 9, 30, 0),
|
||||
subject="Mathématiques",
|
||||
group=None,
|
||||
content=None,
|
||||
)
|
||||
theoretical_lesson = TheoreticalLesson(
|
||||
id="theo-lesson-removed",
|
||||
day_of_week=0,
|
||||
start_time=time(8, 0, 0),
|
||||
end_time=time(9, 30, 0),
|
||||
subject="Mathématiques",
|
||||
)
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
AgendaChange(
|
||||
type=AgendaChangeType.REMOVED,
|
||||
lesson=lesson,
|
||||
theoretical_lesson=theoretical_lesson,
|
||||
)
|
||||
assert any(
|
||||
"lesson doit être None pour le type" in str(error) for error in exc_info.value.errors()
|
||||
)
|
||||
|
||||
def test_agenda_change_modified_without_theoretical_lesson_invalid(self) -> None:
|
||||
"""Vérifie que type=MODIFIED sans theoretical_lesson lève une ValidationError."""
|
||||
lesson = Lesson(
|
||||
id="lesson-mod-no-theo",
|
||||
start=datetime(2024, 9, 6, 10, 0, 0),
|
||||
end=datetime(2024, 9, 6, 11, 30, 0),
|
||||
subject="Physique",
|
||||
group=None,
|
||||
content=None,
|
||||
)
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
AgendaChange(
|
||||
type=AgendaChangeType.MODIFIED,
|
||||
lesson=lesson,
|
||||
theoretical_lesson=None,
|
||||
)
|
||||
assert any(
|
||||
"theoretical_lesson est requis pour le type" in str(error)
|
||||
for error in exc_info.value.errors()
|
||||
)
|
||||
|
||||
|
||||
class TestCalDAVSyncResultInvariants:
|
||||
|
||||
Reference in New Issue
Block a user