"""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"