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