gwoe-antragspruefer/tests/test_protokoll_parsers_stubs.py
Dotty Dotter c7d6ac7f5f feat(#150): BE-Parser produktiv — Berliner Abgeordnetenhaus-Plenarprotokolle
Dritter vollwertiger Plenarprotokoll-Parser nach NRW + BUND.

URL-Pattern verifiziert (WP19 Sitzungen 1, 10, 50, 80, 100):
  https://www.parlament-berlin.de/ados/{wp}/IIIPlen/protokoll/plen{wp}-{n:03}-pp.pdf

Anchor-Sprache (NRW-aehnlich, mit Berliner-Eigenheit 'pro forma'):
  Wer den Antrag auf Drucksache 19/X annehmen moechte, ... – Das sind
    die Fraktionen Buendnis 90/Die Gruenen und Die Linke.
  Wer stimmt dagegen? – Das sind die Fraktionen der CDU, SPD und AfD.
  Wer enthaelt sich, pro forma? – Das ist niemand.
  Damit ist der Antrag abgelehnt.

Pattern:
- Result-Anchor: Damit ist [Antrag/Aenderungsantrag/Gesetzentwurf/...]
  (angenommen|abgelehnt)
- Vote-Block: 3 Q+A-Paare im Reden-Stil (annehmen moechte / dagegen /
  enthaelt sich)
- Drucksachen-Lookup: 'Drucksache 19/N(-suffix)' rueckwaerts (1500-char Fenster)

Fraktions-Mapping WP19:
- Buendnis 90/Die Gruenen → GRÜNE
- Die Linke → LINKE
- CDU, SPD, AfD, FDP

21 Tests in test_protokoll_parsers_be.py.
Cron-PROTO_TARGETS erweitert um BE WP19 (~80 Sitzungen).
Stub-Test angepasst.

905 Tests gruen (889 → 905, +16 fuer BE).
2026-04-29 00:37:47 +02:00

114 lines
4.4 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 raus, weil seit 2026-04-28 produktiver Parser (#148)
# BE raus, weil seit 2026-04-29 produktiver Parser (#150)
"BB", "BW", "BY", "HB", "HE", "HH",
"LSA", "MV", "NI", "RP", "SH", "SL", "SN", "TH",
]
@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 produktiv
assert registered == {"NRW", "BUND", "BE"}, (
"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."
)