"""Tests fuer app/protokoll_parsers/hb.py — HB Beschlussprotokoll-Parser (#153). HB ist (wie HE) ein Beschlussprotokoll-Parser: Status-only, keine Vote-Detail. Stichprobe-getestet gegen WP21 Sitzung 33 (Bremen Landtag). """ from __future__ import annotations import pytest from app.protokoll_parsers.hb import ( _classify_status, _normalize_text, _resolve_drucksache_hb, ANCHOR_RE, DS_INLINE_RE, DS_BLOCK_RE, ALLE_FRAKTIONEN_HB, ) class TestClassifyStatus: def test_lehnt_ab_to_abgelehnt(self): assert _classify_status("lehnt", "den Antrag", " ab.") == "abgelehnt" def test_stimmt_zu_to_angenommen(self): assert _classify_status("stimmt", "dem Antrag", " zu.") == "angenommen" def test_beschliesst_to_angenommen(self): assert _classify_status("beschließt", "das Gesetz", ".") == "angenommen" def test_verabschiedet_to_angenommen(self): assert _classify_status("verabschiedet", "den Haushalt", ".") == "angenommen" def test_nimmt_kenntnis_skipped(self): assert _classify_status( "nimmt", "von der Mitteilung Kenntnis", "." ) == "kenntnis" def test_ueberweist_to_ueberwiesen(self): assert _classify_status("überweist", "den Antrag", ".") == "überwiesen" class TestNormalizeText: def test_collapses_whitespace(self): assert _normalize_text("a b\n\tc") == "a b c" def test_repairs_soft_hyphenation(self): assert _normalize_text("Bürger- schaft") == "Bürgerschaft" class TestAnchorRegex: def test_matches_landtag_lehnt(self): text = "Die Bürgerschaft (Landtag) lehnt den Antrag ab." m = ANCHOR_RE.search(text) assert m and m.group("verb") == "lehnt" def test_matches_stadtbuergerschaft_stimmt(self): text = "Die Bürgerschaft (Stadtbürgerschaft) stimmt dem Antrag zu." m = ANCHOR_RE.search(text) assert m and m.group("verb") == "stimmt" def test_matches_beschliesst_gesetz(self): text = "Die Bürgerschaft (Landtag) beschließt das Gesetz." m = ANCHOR_RE.search(text) assert m and m.group("verb") == "beschließt" def test_matches_nimmt_kenntnis(self): text = "Die Bürgerschaft (Landtag) nimmt von der Antwort Kenntnis." m = ANCHOR_RE.search(text) assert m and m.group("verb") == "nimmt" class TestDrucksacheRegex: def test_inline_form_with_parens(self): m = DS_INLINE_RE.search("lehnt den Änderungsantrag (21/1688) ab") assert m and m.group(1) == "21/1688" def test_block_form_with_drucksache_label(self): m = DS_BLOCK_RE.search("Antrag der Fraktion (Drucksache 21/1234)") assert m and m.group(1) == "21/1234" class TestResolveDrucksacheHb: def test_inline_takes_priority(self): text = "Drucksache 21/1000 ... Die Bürgerschaft lehnt (21/2000) ab." rest = "den Antrag (21/2000)" anchor = text.index("Die Bürgerschaft") assert _resolve_drucksache_hb(text, anchor, rest) == "21/2000" def test_block_form_used_when_no_inline(self): text = "Drucksache 21/1500. Die Bürgerschaft lehnt den Antrag ab." rest = "den Antrag" anchor = text.index("Die Bürgerschaft") assert _resolve_drucksache_hb(text, anchor, rest) == "21/1500" def test_returns_none_when_no_drucksache(self): assert _resolve_drucksache_hb( "Die Bürgerschaft lehnt den Antrag ab.", 0, "den Antrag" ) is None class TestConstants: def test_all_fraktionen_set(self): # WP21-HB Konstellation: SPD-GRÜNE-LINKE Koalition + CDU/FDP Opposition + BIW assert "SPD" in ALLE_FRAKTIONEN_HB assert "GRÜNE" in ALLE_FRAKTIONEN_HB assert "CDU" in ALLE_FRAKTIONEN_HB