gwoe-antragspruefer/tests/test_protokoll_parsers_be.py

147 lines
5.2 KiB
Python
Raw Normal View History

"""Tests fuer app/protokoll_parsers/be.py — Berliner Plenarprotokoll-Parser (#150).
Stichprobe-getestet gegen WP19 Sitzung 50 (Berlin).
"""
from __future__ import annotations
import pytest
from app.protokoll_parsers.be import (
_normalize_fraktionen_be,
_parse_vote_block_be,
_resolve_drucksache_be,
RESULT_ANCHOR_RE,
ALLE_FRAKTIONEN_BE,
FRAKTIONEN_MAP_BE,
)
class TestNormalizeFraktionenBe:
def test_simple_cdu(self):
assert _normalize_fraktionen_be("der CDU") == ["CDU"]
def test_buendnis_90_normalizes_to_gruene(self):
assert _normalize_fraktionen_be("Bündnis 90/Die Grünen") == ["GRÜNE"]
def test_die_linke(self):
assert _normalize_fraktionen_be("der Die Linke") == ["LINKE"]
def test_combined_phrase(self):
result = _normalize_fraktionen_be(
"die Fraktionen Bündnis 90/Die Grünen und Die Linke"
)
assert set(result) == {"GRÜNE", "LINKE"}
def test_three_fraktionen(self):
result = _normalize_fraktionen_be("die Fraktionen der CDU, SPD und AfD")
assert set(result) == {"CDU", "SPD", "AfD"}
def test_empty_returns_empty(self):
assert _normalize_fraktionen_be("") == []
def test_no_double_count(self):
# 'Die Linke' und 'Linke' beide im Text → nur 1× LINKE
result = _normalize_fraktionen_be("Die Linke und der Linken")
assert result.count("LINKE") == 1
class TestParseVoteBlockBe:
def test_complete_block(self):
block = (
"Wer den Antrag auf Drucksache 19/1589 annehmen möchte, den bitte "
"ich um das Handzeichen. Das sind die Fraktionen Bündnis 90/Die "
"Grünen und Die Linke. Wer stimmt dagegen? Das sind die Fraktionen "
"der CDU, SPD und AfD. Wer enthält sich, pro forma? Das ist niemand. "
"Damit ist der Antrag abgelehnt."
)
votes = _parse_vote_block_be(block)
assert set(votes["ja"]) == {"GRÜNE", "LINKE"}
assert set(votes["nein"]) == {"CDU", "SPD", "AfD"}
assert votes["enthaltung"] == [] # 'niemand' → leer
def test_enthaltung_ignored_when_niemand(self):
block = (
"annehmen möchte, ... Das sind die CDU. "
"Wer stimmt dagegen? Das sind SPD. "
"Wer enthält sich? Das ist niemand."
)
votes = _parse_vote_block_be(block)
assert votes["enthaltung"] == []
def test_enthaltung_with_real_fraktion(self):
block = (
"annehmen möchte, ... Das sind CDU und SPD. "
"Wer stimmt dagegen? AfD. "
"Wer enthält sich? Die Linke."
)
votes = _parse_vote_block_be(block)
assert votes["enthaltung"] == ["LINKE"]
class TestResolveDrucksacheBe:
def test_finds_drucksache_before_anchor(self):
text = "Auf Drucksache 19/1234 ... Damit ist der Antrag angenommen."
anchor = text.index("Damit")
assert _resolve_drucksache_be(text, anchor) == "19/1234"
def test_with_dash_suffix(self):
"""Berliner Drucksachen koennen '-1', '-2' Suffixe haben fuer
Aenderungs-Versionen."""
text = "Aenderungsantrag auf Drucksache 19/1589-2 ... Damit ist abgelehnt."
anchor = text.index("Damit")
assert _resolve_drucksache_be(text, anchor) == "19/1589-2"
def test_returns_none_when_no_ds(self):
text = "Damit ist der Antrag abgelehnt."
assert _resolve_drucksache_be(text, 0) is None
class TestResultAnchorRegex:
def test_matches_antrag_angenommen(self):
text = "Damit ist der Antrag angenommen."
m = RESULT_ANCHOR_RE.search(text)
assert m
assert m.group("subject") == "Antrag"
assert m.group("ergebnis") == "angenommen"
def test_matches_aenderungsantrag_abgelehnt(self):
text = "Damit ist der Änderungsantrag abgelehnt."
m = RESULT_ANCHOR_RE.search(text)
assert m
assert m.group("subject") == "Änderungsantrag"
assert m.group("ergebnis") == "abgelehnt"
def test_matches_dieser_antrag_abgelehnt(self):
text = "Damit ist dieser Antrag abgelehnt."
m = RESULT_ANCHOR_RE.search(text)
assert m
def test_matches_auch_dieser_aenderungsantrag(self):
text = "Damit ist auch dieser Änderungsantrag abgelehnt."
m = RESULT_ANCHOR_RE.search(text)
assert m
def test_matches_gesetzentwurf(self):
text = "Damit ist der Gesetzentwurf angenommen."
m = RESULT_ANCHOR_RE.search(text)
assert m
def test_no_match_random_text(self):
text = "Der Bezirksbürgermeister hat eine Idee abgelehnt."
m = RESULT_ANCHOR_RE.search(text)
# 'Damit ist' fehlt — kein Match
assert m is None
class TestConstants:
def test_all_fraktionen_complete(self):
assert set(ALLE_FRAKTIONEN_BE) == {"CDU", "SPD", "GRÜNE", "LINKE", "AfD", "FDP"}
def test_mapping_covers_all_fraktionen(self):
"""Jede der 6 BE-Fraktionen sollte mindestens einen Phrase-Eintrag haben."""
all_codes = set()
for _phrase, codes in FRAKTIONEN_MAP_BE:
all_codes.update(codes)
for f in ALLE_FRAKTIONEN_BE:
assert f in all_codes, f"Fraktion {f} fehlt im FRAKTIONEN_MAP_BE"