feat(M13): complete test fixtures, shared conftest, and coverage >= 90%

Finalize M13 test and coverage milestone:

tests/fixtures/pronote-6e.ics (new):
- Anonymized iCal fixture for Classe de 6e (3 VEVENTs: SVT lesson with
  homework block, Histoire-Géo modified lesson, all-day school outing)
- Same structure as pronote-4e.ics, no secrets or real data

tests/conftest.py:
- Added sample_message fixture (Message with MessageType.INFORMATION)
- Integrated sample_message into pronote_data fixture (messages=[sample_message])
- Sphinx/reST docstring with :return: and :rtype:

.gitignore:
- Fixed typo: .worktress/ -> .worktrees/ (line 56)

pyproject.toml:
- Added ".worktrees" to ruff extend-exclude to prevent ruff format --check .
  from scanning worktree files

TODO.md:
- Checked M13 items: tests/fixtures/ and tests/conftest.py

Validation: 627 tests pass, coverage 95.67% (threshold 90%), ruff/mypy/
bandit/pre-commit all green.

Co-authored-by: opencode/coder <coder@agents.invalid>
This commit is contained in:
2026-09-08 16:19:27 +02:00
parent fd9b604849
commit 000416f24e
5 changed files with 82 additions and 6 deletions

2
.gitignore vendored
View File

@@ -53,7 +53,7 @@ Thumbs.db
# --- Local scratch / WIP files --- # --- Local scratch / WIP files ---
FIXME_* FIXME_*
TEST_* TEST_*
.worktress/ .worktrees/
# --- Logs --- # --- Logs ---
*.log *.log

View File

@@ -257,8 +257,8 @@ Exposer le lancement du pipeline via une interface en ligne de commande.
Couvrir l'ensemble du code par des tests sans réseau, avec fixtures anonymisées, jusqu'à ≥ 90 %. Couvrir l'ensemble du code par des tests sans réseau, avec fixtures anonymisées, jusqu'à ≥ 90 %.
- [ ] Créer `tests/fixtures/` : `pronote-4e.ics`, `pronote-6e.ics`, `theoretical.json`, `school_holidays.json`, `blog_rss.xml` (anonymisés, sans `icalsecurise`). - [x] Créer `tests/fixtures/` : `pronote-4e.ics`, `pronote-6e.ics`, `theoretical.json`, `school_holidays.json`, `blog_rss.xml` (anonymisés, sans `icalsecurise`).
- [ ] Créer `tests/conftest.py` : fixtures partagées (sample_lesson, sample_cancelled_lesson, sample_homework, sample_school_event, sample_message, sample_pronote_data…). - [x] Créer `tests/conftest.py` : fixtures partagées (sample_lesson, sample_cancelled_lesson, sample_homework, sample_school_event, sample_message, sample_pronote_data…).
- [x] Écrire `tests/unit/` : `test_models`, `test_parsing` (iCal), `test_uid`, `test_redaction`, `test_diff`, `test_sync`. - [x] Écrire `tests/unit/` : `test_models`, `test_parsing` (iCal), `test_uid`, `test_redaction`, `test_diff`, `test_sync`.
- [x] Couvrir les régressions M4 : signature réelle de `ParentClient`, ENT autorisé/inconnu, erreur vs résultat vide, `STATUS:CANCELLED` sans catégorie, plusieurs devoirs à la même date, filtrage `pronotepy` sur la date cible et stabilité d'identité entre sources. - [x] Couvrir les régressions M4 : signature réelle de `ParentClient`, ENT autorisé/inconnu, erreur vs résultat vide, `STATUS:CANCELLED` sans catégorie, plusieurs devoirs à la même date, filtrage `pronotepy` sur la date cible et stabilité d'identité entre sources.
- [x] Écrire `tests/integration/` : `test_pipeline`, `test_caldav` (mocké), `test_xmpp` (mocké). - [x] Écrire `tests/integration/` : `test_pipeline`, `test_caldav` (mocké), `test_xmpp` (mocké).

View File

@@ -94,7 +94,7 @@ skips = ["B101"] # Ignorer les assertions (utilisées dans les tests)
line-length = 100 line-length = 100
target-version = "py313" target-version = "py313"
# Exclure la documentation markdown (ruff format ne doit pas toucher aux blocs de code Python inclus) # Exclure la documentation markdown (ruff format ne doit pas toucher aux blocs de code Python inclus)
extend-exclude = ["GUIDE_DEV_PYTHON.md"] extend-exclude = ["GUIDE_DEV_PYTHON.md", ".worktrees"]
[tool.ruff.lint] [tool.ruff.lint]
select = [ select = [

View File

@@ -14,6 +14,7 @@ from pydantic import SecretStr
from pronote_sync.config.settings import CalDAVSettings from pronote_sync.config.settings import CalDAVSettings
from pronote_sync.models.agenda import Lesson, LessonStatus, SchoolEvent, SchoolEventKind from pronote_sync.models.agenda import Lesson, LessonStatus, SchoolEvent, SchoolEventKind
from pronote_sync.models.homework import Homework from pronote_sync.models.homework import Homework
from pronote_sync.models.message import Message, MessageType
from pronote_sync.models.pronote import PronoteData from pronote_sync.models.pronote import PronoteData
@@ -85,19 +86,38 @@ def caldav_settings() -> CalDAVSettings:
) )
@pytest.fixture
def sample_message() -> Message:
"""Message Pronote pour les tests.
:return: Message Pronote de test.
:rtype: Message
"""
return Message(
id="msg-001",
type=MessageType.INFORMATION,
title="Information de rentrée",
content="La rentrée est prévue le 1er septembre.",
author="Administration",
date=datetime(2026, 1, 15, 9, 0),
read=False,
)
@pytest.fixture @pytest.fixture
def pronote_data( def pronote_data(
sample_lesson: Lesson, sample_lesson: Lesson,
sample_cancelled_lesson: Lesson, sample_cancelled_lesson: Lesson,
sample_homework: Homework, sample_homework: Homework,
sample_school_event: SchoolEvent, sample_school_event: SchoolEvent,
sample_message: Message,
) -> PronoteData: ) -> PronoteData:
"""Données Pronote de test avec des cours, devoirs et événements.""" """Données Pronote de test avec des cours, devoirs, événements et messages."""
return PronoteData( return PronoteData(
lessons=[sample_lesson, sample_cancelled_lesson], lessons=[sample_lesson, sample_cancelled_lesson],
homeworks=[sample_homework], homeworks=[sample_homework],
school_events=[sample_school_event], school_events=[sample_school_event],
messages=[], messages=[sample_message],
target_date=date(2026, 1, 15), target_date=date(2026, 1, 15),
generated_at=datetime(2026, 1, 15, 0, 0), generated_at=datetime(2026, 1, 15, 0, 0),
) )

56
tests/fixtures/pronote-6e.ics vendored Normal file
View File

@@ -0,0 +1,56 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Index Education//Pronote//FR
X-WR-CALNAME:Classe de 6e
BEGIN:VEVENT
UID:Edt_22222@index-education.net-20260908T140000Z-Index-Education
DTSTAMP:20260908T140000Z
DTSTART:20260908T140000Z
DTEND:20260908T150000Z
SUMMARY:SVT
CATEGORIES:Cours
DESCRIPTION:<div>
Matière : SVT
Professeur : M. Dubois
Salle : 104
Groupe : Classe entière
<strong>Contenu pédagogique :
</strong>
Découverte de la cellule et de ses constituants.
<strong>Pour le 15/09/2026 :
</strong>
Lire le chapitre 2 et schématiser une cellule végétale.
<strong>Donné le 08/09/2026 :
</strong>
Lire le chapitre 2 et schématiser une cellule végétale.
</div>
END:VEVENT
BEGIN:VEVENT
UID:Edt_33333@index-education.net-20260908T140000Z-Index-Education
DTSTAMP:20260908T140000Z
DTSTART:20260909T100000Z
DTEND:20260909T110000Z
SUMMARY:Histoire-Géographie
CATEGORIES:Cours - Cours modifié
DESCRIPTION:<div>
Matière : Histoire-Géographie
Professeur : Mme Lefevre
Salle : 203
Groupe : Classe entière
<strong>Contenu pédagogique :
</strong>
Les grands repères du temps long : la Préhistoire.
</div>
END:VEVENT
BEGIN:VEVENT
UID:Edt_44444@index-education.net-20260908T140000Z-Index-Education
DTSTAMP:20260908T140000Z
DTSTART;VALUE=DATE:20260928
DTEND;VALUE=DATE:20260929
SUMMARY:Sortie pédagogique
CATEGORIES:Sortie scolaire
DESCRIPTION:Journée de sortie pédagogique au musée d'histoire naturelle.
END:VEVENT
END:VCALENDAR