gwoe-antragspruefer/tests/test_protokoll_parsers_stubs.py
Dotty Dotter 399dbc2639 feat(#163): TH-Parser produktiv — Thueringer Plenarprotokolle
Fuenfter produktiver Parser nach NRW + BUND + BE + HH.

URL-Pattern verifiziert (WP8 Sitzungen 1, 10, 20, 30, 40, 42):
  https://www.thueringer-landtag.de/uploads/tx_tltcalendar/protocols/Arbeitsfassung{n}.pdf

Anchor-Sprache (BE-aehnlich):
  Wer dem zustimmt, ... Das sind die Stimmen aus den Fraktionen der
  CDU, BSW, SPD und Die Linke. Wer stimmt gegen ...? Das sind die
  Stimmen aus der Fraktion der AfD. Damit ist [...] mehrheitlich
  angenommen.

Pattern:
- Result-Anchor: Damit ist [Subjekt] (mehrheitlich|einstimmig)?
  (angenommen|abgelehnt)
- Vote-Block: Wer dem zustimmt / Wer stimmt gegen / Wer enthaelt sich
- Drucksachen-Lookup: 'Drucksache 8/N' rueckwaerts

Fraktions-Mapping WP8 (ab Mai 2024): CDU, AfD, BSW, Linke, SPD
(WP7-Faktionen GRUENE/FDP fuer Backfill ebenfalls im Mapping).

Cron-PROTO_TARGETS um TH-WP8 erweitert. Stub-Test angepasst.
2026-04-29 01:11:58 +02:00

113 lines
4.3 KiB
Python

"""Tests fuer die Phase-2-Stub-Parser (#106 Folge / #148-#163).
Pro BL ein Modul `app/protokoll_parsers/<bl>.py`, das:
1. importierbar ist (Recherche-Findings im Docstring)
2. ``parse_protocol(...)`` raised ``NotImplementedError`` mit Issue-Verweis
3. **NICHT** in ``PROTOKOLL_PARSERS``-Registry registriert ist (sonst wuerde
der Auto-Ingest-Cron versuchen, sie zu nutzen und mit NotImplementedError
abbrechen)
Diese Tests sind das Safety-Net: sobald ein Stub durch einen echten Parser
ersetzt wird, MUSS gleichzeitig der Eintrag in PROTOKOLL_PARSERS gesetzt
werden — sonst greift ``test_implemented_parsers_are_registered``.
"""
from __future__ import annotations
import importlib
import pytest
from app.protokoll_parsers import PROTOKOLL_PARSERS, supported_bundeslaender
STUB_BL_CODES = [
# BUND/BE/HH/TH raus, weil seit 2026-04-28/29 produktive Parser
"BB", "BW", "BY", "HB", "HE",
"LSA", "MV", "NI", "RP", "SH", "SL", "SN",
]
@pytest.fixture(params=STUB_BL_CODES)
def stub_module(request):
code = request.param
mod_name = f"app.protokoll_parsers.{code.lower()}"
return code, importlib.import_module(mod_name)
class TestStubImportability:
def test_each_stub_imports(self, stub_module):
code, mod = stub_module
assert mod is not None
assert hasattr(mod, "parse_protocol")
def test_each_stub_has_recherche_in_docstring(self, stub_module):
"""Docstring enthaelt 'Recherche'-Marker und Status-Hinweis."""
code, mod = stub_module
doc = mod.__doc__ or ""
assert "Recherche" in doc or "Status" in doc, \
f"Stub {code}: Docstring enthaelt keine Recherche-Findings"
def test_each_stub_links_to_issue(self, stub_module):
"""Docstring verweist auf konkretes Tracking-Issue."""
code, mod = stub_module
doc = mod.__doc__ or ""
assert "issues/" in doc, f"Stub {code}: kein Issue-Link"
class TestStubBehavior:
def test_each_stub_raises_not_implemented(self, stub_module):
code, mod = stub_module
with pytest.raises(NotImplementedError) as exc:
mod.parse_protocol("/dev/null")
msg = str(exc.value)
assert "noch nicht implementiert" in msg, \
f"Stub {code}: NotImplementedError-Message ist nicht informativ"
class TestRegistryDiscipline:
"""Sicherheitsnetz: Stubs duerfen NICHT in PROTOKOLL_PARSERS sein.
Sobald ein Stub durch echten Parser ersetzt wird, MUSS der Implementer:
1. NotImplementedError aus parse_protocol entfernen
2. PROTOKOLL_PARSERS[code] = parse_protocol setzen
Dieser Test schlaegt fehl, wenn eines der beiden vergessen wird —
explizit unten ueber test_implemented_parsers_are_registered.
"""
def test_stubs_not_in_registry(self):
registered = set(supported_bundeslaender())
# Aktuell: NRW + BUND + BE + HH + TH produktiv
assert registered == {"NRW", "BUND", "BE", "HH", "TH"}, (
"Unerwartete Registry-Eintraege. Wenn neue BL implementiert sind, "
"diesen Test anpassen UND den Stub durch echten Parser ersetzen."
)
def test_implemented_parsers_are_registered(self, stub_module):
"""Wenn ein Stub-Modul KEIN NotImplementedError mehr wirft (also
implementiert wurde), muss es in PROTOKOLL_PARSERS registriert sein.
Dieser Test ist der Trigger: sobald der Implementer parse_protocol
echt implementiert (kein NotImplementedError mehr), schlaegt der
andere Test (test_each_stub_raises_not_implemented) fehl. Das ist
das richtige Signal — dann muessen Tests + Registry beide angepasst
werden.
"""
code, mod = stub_module
# Probe: wirft das Modul noch NotImplementedError?
try:
mod.parse_protocol("/dev/null")
implemented = True
except NotImplementedError:
implemented = False
except Exception:
# Anderer Fehler (z.B. fitz konnte /dev/null nicht oeffnen) →
# Modul ist implementiert (wuerde mit echtem PDF arbeiten)
implemented = True
if implemented:
assert code in PROTOKOLL_PARSERS, (
f"{code}-Parser scheint implementiert (keine NotImplementedError), "
f"aber nicht in PROTOKOLL_PARSERS registriert. Beide muessen "
f"zusammen aktualisiert werden."
)