"""Tests fuer app/protokoll_parsers/sl.py — SL Abstimmungsergebnisse-Parser (#161). SL ist HTML-basiert (nicht PDF) — eigene Abstimmungsergebnisse-Seite pro Sitzung mit strukturiertem [SPD: dafür; CDU und AfD: dagegen]-Format. """ from __future__ import annotations import pytest from app.protokoll_parsers.sl import ( _normalize_fraktionen_sl, _parse_vote_bracket, _strip_html, DS_RE_SL, STATUS_RE, VOTE_BRACKET_RE, LI_BLOCK_RE, ALLE_FRAKTIONEN_SL, ) class TestNormalizeFraktionenSl: def test_simple_spd(self): assert _normalize_fraktionen_sl("SPD") == ["SPD"] def test_spd_und_cdu(self): assert _normalize_fraktionen_sl("SPD und CDU") == ["CDU", "SPD"] def test_alle_drei(self): assert _normalize_fraktionen_sl("SPD, CDU und AfD") == ["AfD", "CDU", "SPD"] def test_empty(self): assert _normalize_fraktionen_sl("") == [] def test_word_boundary(self): # Kein Match auf 'SP' oder Substrings assert _normalize_fraktionen_sl("SP-Partei") == [] class TestParseVoteBracket: def test_klassisches_pattern(self): votes = _parse_vote_bracket("SPD: dafür; CDU und AfD: dagegen") assert set(votes["ja"]) == {"SPD"} assert set(votes["nein"]) == {"CDU", "AfD"} assert votes["enthaltung"] == [] def test_mit_enthaltung(self): votes = _parse_vote_bracket("SPD: dafür; CDU: dagegen; AfD: Enthaltung") assert set(votes["ja"]) == {"SPD"} assert set(votes["nein"]) == {"CDU"} assert set(votes["enthaltung"]) == {"AfD"} def test_alle_dafuer(self): votes = _parse_vote_bracket("SPD und CDU: dafür; AfD: Enthaltung") assert set(votes["ja"]) == {"SPD", "CDU"} assert votes["nein"] == [] assert set(votes["enthaltung"]) == {"AfD"} def test_alle_dagegen(self): votes = _parse_vote_bracket("AfD: dafür; SPD und CDU: dagegen") assert set(votes["ja"]) == {"AfD"} assert set(votes["nein"]) == {"SPD", "CDU"} class TestStripHtml: def test_removes_tags(self): assert _strip_html("
Hello world
") == "Hello world" def test_decodes_entities(self): assert _strip_html("a & b") == "a & b" class TestDrucksacheRegex: def test_matches_drucksache(self): m = DS_RE_SL.search("Drucksache 17/2076") assert m and m.group(1) == "17/2076" def test_matches_with_spaces(self): m = DS_RE_SL.search("(Drucksache 17/2074)") assert m and m.group(1) == "17/2074" class TestStatusRegex: def test_matches_einstimmig_angenommen(self): m = STATUS_RE.search("in Erster Lesung einstimmig angenommen") assert m and m.group("ergebnis").lower() == "angenommen" def test_matches_mit_stimmenmehrheit(self): m = STATUS_RE.search("mit Stimmenmehrheit angenommen") assert m and m.group("ergebnis").lower() == "angenommen" def test_matches_abgelehnt(self): m = STATUS_RE.search("in Erster Lesung abgelehnt") assert m and m.group("ergebnis").lower() == "abgelehnt" class TestVoteBracketRegex: def test_matches_full_bracket(self): m = VOTE_BRACKET_RE.search("[SPD: dafür; CDU und AfD: dagegen]") assert m and "SPD" in m.group("inner") class TestLiBlockRegex: def test_extracts_li_content(self): html = "