test(#155): 19 Tests fuer HH-Parser
- TestNormalizeFraktionenHh: SPD, GRUENEN-Form, Linken-Form, kombinierte Phrasen, Doppelzaehl-Schutz - TestParseVoteBlockHh: voller Vote-Block, ja+nein ohne enth, leerer Block, nur ja - TestResolveDrucksacheHh: 'Drucksache 23/N', bare '23/N', closest-match, None bei keinem Treffer - TestResultAnchorRegex: einstimmig vs. mehrheitlich, angenommen/abgelehnt - Konstanten-Sanity: alle 5 HH-Fraktionen im Mapping abgedeckt 919 Tests gruen (+19).
This commit is contained in:
parent
d39f9ef0e9
commit
edbce27c49
135
tests/test_protokoll_parsers_hh.py
Normal file
135
tests/test_protokoll_parsers_hh.py
Normal file
@ -0,0 +1,135 @@
|
||||
"""Tests fuer app/protokoll_parsers/hh.py — Hamburger Beschlussprotokoll-Parser (#155).
|
||||
|
||||
Stichprobe-getestet gegen WP23 Sitzung 22 (Hamburg).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from app.protokoll_parsers.hh import (
|
||||
_normalize_fraktionen_hh,
|
||||
_parse_vote_block_hh,
|
||||
_resolve_drucksache_hh,
|
||||
RESULT_ANCHOR_RE,
|
||||
ALLE_FRAKTIONEN_HH,
|
||||
FRAKTIONEN_MAP_HH,
|
||||
)
|
||||
|
||||
|
||||
class TestNormalizeFraktionenHh:
|
||||
def test_simple_spd(self):
|
||||
assert _normalize_fraktionen_hh("der SPD") == ["SPD"]
|
||||
|
||||
def test_gruene_n_form(self):
|
||||
assert _normalize_fraktionen_hh("der GRÜNEN") == ["GRÜNE"]
|
||||
|
||||
def test_die_linke(self):
|
||||
assert _normalize_fraktionen_hh("der Linken") == ["LINKE"]
|
||||
|
||||
def test_combined_phrase(self):
|
||||
result = _normalize_fraktionen_hh(
|
||||
"der SPD und GRÜNEN gegen die Stimmen der CDU und AfD"
|
||||
)
|
||||
assert set(result) == {"SPD", "GRÜNE", "CDU", "AfD"}
|
||||
|
||||
def test_empty_returns_empty(self):
|
||||
assert _normalize_fraktionen_hh("") == []
|
||||
|
||||
def test_no_double_count(self):
|
||||
# 'GRÜNEN' und 'GRÜNE' beide → nur 1× GRÜNE
|
||||
result = _normalize_fraktionen_hh("der GRÜNE und der GRÜNEN")
|
||||
assert result.count("GRÜNE") == 1
|
||||
|
||||
|
||||
class TestParseVoteBlockHh:
|
||||
def test_full_block(self):
|
||||
block = (
|
||||
" mit den Stimmen der SPD und GRÜNEN "
|
||||
"gegen die Stimmen der CDU und AfD "
|
||||
"bei Enthaltung der Linken"
|
||||
)
|
||||
votes = _parse_vote_block_hh(block)
|
||||
assert set(votes["ja"]) == {"SPD", "GRÜNE"}
|
||||
assert set(votes["nein"]) == {"CDU", "AfD"}
|
||||
assert votes["enthaltung"] == ["LINKE"]
|
||||
|
||||
def test_only_ja_and_nein(self):
|
||||
block = (
|
||||
" mit den Stimmen der SPD, GRÜNEN, CDU und Linken "
|
||||
"gegen die Stimmen der AfD"
|
||||
)
|
||||
votes = _parse_vote_block_hh(block)
|
||||
assert set(votes["ja"]) == {"SPD", "GRÜNE", "CDU", "LINKE"}
|
||||
assert votes["nein"] == ["AfD"]
|
||||
assert votes["enthaltung"] == []
|
||||
|
||||
def test_empty_block_returns_empty_lists(self):
|
||||
votes = _parse_vote_block_hh("")
|
||||
assert votes == {"ja": [], "nein": [], "enthaltung": []}
|
||||
|
||||
def test_only_ja(self):
|
||||
block = " mit den Stimmen der SPD und GRÜNEN"
|
||||
votes = _parse_vote_block_hh(block)
|
||||
assert set(votes["ja"]) == {"SPD", "GRÜNE"}
|
||||
|
||||
|
||||
class TestResolveDrucksacheHh:
|
||||
def test_finds_ds_with_full_prefix(self):
|
||||
text = "Drucksache 23/1234 ... mehrheitlich angenommen"
|
||||
anchor = text.index("mehrheitlich")
|
||||
assert _resolve_drucksache_hh(text, anchor) == "23/1234"
|
||||
|
||||
def test_finds_bare_ds_format(self):
|
||||
text = "Bericht 23/3666 ... einstimmig angenommen"
|
||||
anchor = text.index("einstimmig")
|
||||
assert _resolve_drucksache_hh(text, anchor) == "23/3666"
|
||||
|
||||
def test_picks_closest(self):
|
||||
text = "Drucksache 23/100 ... Drucksache 23/200 ... einstimmig angenommen"
|
||||
anchor = text.index("einstimmig")
|
||||
assert _resolve_drucksache_hh(text, anchor) == "23/200"
|
||||
|
||||
def test_returns_none_when_no_ds(self):
|
||||
text = "irgendwas ... einstimmig angenommen"
|
||||
anchor = text.index("einstimmig")
|
||||
assert _resolve_drucksache_hh(text, anchor) is None
|
||||
|
||||
|
||||
class TestResultAnchorRegex:
|
||||
def test_einstimmig_angenommen(self):
|
||||
text = "alle Empfehlungen einstimmig angenommen"
|
||||
m = RESULT_ANCHOR_RE.search(text)
|
||||
assert m
|
||||
assert m.group("modus") == "einstimmig"
|
||||
assert m.group("ergebnis") == "angenommen"
|
||||
|
||||
def test_mehrheitlich_with_block(self):
|
||||
text = (
|
||||
"Antrag mehrheitlich mit den Stimmen der SPD und GRÜNEN "
|
||||
"gegen die Stimmen der CDU und AfD angenommen"
|
||||
)
|
||||
m = RESULT_ANCHOR_RE.search(text)
|
||||
assert m
|
||||
assert m.group("modus") == "mehrheitlich"
|
||||
assert m.group("ergebnis") == "angenommen"
|
||||
|
||||
def test_mehrheitlich_abgelehnt(self):
|
||||
text = (
|
||||
"Antrag mehrheitlich mit den Stimmen der SPD, GRÜNEN gegen die "
|
||||
"Stimmen der AfD abgelehnt"
|
||||
)
|
||||
m = RESULT_ANCHOR_RE.search(text)
|
||||
assert m
|
||||
assert m.group("ergebnis") == "abgelehnt"
|
||||
|
||||
|
||||
class TestConstants:
|
||||
def test_all_fraktionen_complete(self):
|
||||
assert set(ALLE_FRAKTIONEN_HH) == {"SPD", "GRÜNE", "CDU", "AfD", "LINKE"}
|
||||
|
||||
def test_mapping_covers_all_fraktionen(self):
|
||||
all_codes = set()
|
||||
for _phrase, codes in FRAKTIONEN_MAP_HH:
|
||||
all_codes.update(codes)
|
||||
for f in ALLE_FRAKTIONEN_HH:
|
||||
assert f in all_codes
|
||||
Loading…
Reference in New Issue
Block a user