gwoe-antragspruefer/tests/test_protokoll_parsers_sl.py

114 lines
3.6 KiB
Python
Raw Normal View History

"""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("<p>Hello <em>world</em></p>") == "Hello world"
def test_decodes_entities(self):
assert _strip_html("a &amp; 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 = "<ul><li>foo</li><li>bar</li></ul>"
matches = list(LI_BLOCK_RE.finditer(html))
assert len(matches) == 2
assert matches[0].group(1) == "foo"
class TestConstants:
def test_all_fraktionen_set(self):
assert ALLE_FRAKTIONEN_SL == ["SPD", "CDU", "AfD"]