Files
Plugin_SN_Verfahrensgebiet/tests/test_eigentuemer_suche.py
T

198 lines
9.2 KiB
Python
Raw Normal View History

"""Tests für die Eigentümersuche im Serienbriefexport (#56).
Alle Namen und Anschriften sind erfunden.
"""
import contextlib
import io
import types
import unittest
from unittest.mock import patch
from sn_verfahrensgebiet.functions import eigentuemer_suche as es
from sn_verfahrensgebiet.functions.eigentuemer_suche import Eigentuemer
KOPF = [
"EIG_KONTO", "PER_ID", "PER_VERSTORBEN", "PER_NR", "Anrede", "Titel", "Vorname", "Nachname",
"OT", "STRASSE", "PLZ", "WOHNORT", "Email", "PER_KONTOINHABER", "PER_RECHTSPERSON",
"EIG_GEMARKUNG", "EIG_BLATT", "LISTE_ZGBBL", "ANZAHL_PERSONEN", "EIG_ID",
]
class _Null:
"""Nachbildung von QGIS-NULL."""
def isNull(self):
return True
class _Feature(dict):
def __init__(self, fid, werte):
super().__init__(werte)
self._fid = fid
def id(self):
return self._fid
class _Layer:
def __init__(self, zeilen, kopf=KOPF, name="Serienbrief", layer_id="csv1"):
self._kopf = list(kopf)
self._name = name
self._id = layer_id
self._features = [
_Feature(i + 1, {spalte: zeile.get(spalte.lstrip(""), "") for spalte in self._kopf})
for i, zeile in enumerate(zeilen)
]
def name(self):
return self._name
def id(self):
return self._id
def fields(self):
return types.SimpleNamespace(names=lambda: list(self._kopf))
def getFeatures(self):
return iter(self._features)
def _zeile(nachname, vorname, strasse="Hauptstraße 1", plz="01234", ort="Musterstadt", **weitere):
zeile = {"Nachname": nachname, "Vorname": vorname, "STRASSE": strasse, "PLZ": plz, "WOHNORT": ort}
zeile.update(weitere)
return zeile
class TestLayererkennung(unittest.TestCase):
def test_layer_mit_name_und_vorname_ist_eigentuemerlayer(self):
"""Prüft, dass ein Layer mit den Spalten Nachname und Vorname als Eigentümerdatei erkannt wird, auch mit BOM und anderer Schreibweise."""
self.assertTrue(es.ist_eigentuemerlayer(_Layer([])))
self.assertTrue(es.ist_eigentuemerlayer(_Layer([], kopf=["NACHNAME", "vorname"])))
self.assertFalse(es.ist_eigentuemerlayer(_Layer([], kopf=["flurstueckskennzeichen"])))
self.assertFalse(es.ist_eigentuemerlayer(object()))
def test_eigentuemerlayer_im_projekt(self):
"""Prüft, dass aus dem Projekt nur passende Layer kommen, nach Namen sortiert."""
b = _Layer([], name="b-Export", layer_id="b")
a = _Layer([], name="A-Export", layer_id="a")
flst = _Layer([], kopf=["flurstueckskennzeichen"], name="Flurstücke", layer_id="f")
projekt = types.SimpleNamespace(mapLayers=lambda: {"b": b, "f": flst, "a": a})
with patch.object(es, "QgsProject", types.SimpleNamespace(instance=lambda: projekt)):
self.assertEqual(es.eigentuemerlayer_im_projekt(), [a, b])
class TestSuche(unittest.TestCase):
def test_ohne_eingabe_fehler(self):
"""Prüft, dass ohne Name und Vorname nicht die ganze Datei gelistet, sondern um eine Eingabe gebeten wird."""
with self.assertRaisesRegex(es.EigentuemerSucheFehler, "Namen"):
es.suche_eigentuemer(_Layer([_zeile("Beispiel", "Anna")]), " ", "")
def test_layer_ohne_pflichtspalten(self):
"""Prüft, dass ein Layer ohne Nachname/Vorname mit Hinweis auf den Serienbriefexport abgelehnt wird."""
with self.assertRaisesRegex(es.EigentuemerSucheFehler, "Serienbriefexport"):
es.suche_eigentuemer(_Layer([], kopf=["flurstueckskennzeichen"]), "Beispiel", "")
def test_teilstring_ohne_gross_kleinschreibung(self):
"""Prüft, dass Name und Vorname als Teilstring ohne Rücksicht auf Groß-/Kleinschreibung gesucht werden."""
layer = _Layer([
_zeile("Beispiel", "Anna"),
_zeile("Beispiel-Muster", "Bernd"),
_zeile("Anders", "Anna"),
])
self.assertEqual([e.nachname for e in es.suche_eigentuemer(layer, "beispiel", "")],
["Beispiel", "Beispiel-Muster"])
self.assertEqual([e.nachname for e in es.suche_eigentuemer(layer, "", "ANNA")], ["Anders", "Beispiel"])
self.assertEqual([e.vorname for e in es.suche_eigentuemer(layer, "beisp", "an")], ["Anna"])
def test_umlaute_und_eszett(self):
"""Prüft, dass „Müller“ auch „Mueller“ findet und „Strauss“ auch „Strauß“."""
layer = _Layer([_zeile("Mueller", "Jörg"), _zeile("Strauß", "Erika", ort="Anderswo")])
self.assertEqual(len(es.suche_eigentuemer(layer, "Müller", "Joerg")), 1)
self.assertEqual(len(es.suche_eigentuemer(layer, "Strauss", "")), 1)
def test_gleiche_person_gleiche_anschrift_zusammengefasst(self):
"""Prüft, dass Zeilen mit gleichem Namen und gleicher Anschrift ein Treffer werden und Konten, Personen-IDs und E-Mails gesammelt werden."""
layer = _Layer([
_zeile("Beispiel", "Anna", EIG_KONTO="100", PER_ID="7", Email="anna@example.org"),
_zeile("beispiel ", " Anna", strasse="Hauptstraße 1", EIG_KONTO="200", PER_ID="7",
Titel="Dr.", Email="anna@example.org"),
_zeile("Beispiel", "Anna", EIG_KONTO="300", PER_ID="8", Email="a.b@example.org"),
])
treffer = es.suche_eigentuemer(layer, "Beispiel", "Anna")
self.assertEqual(len(treffer), 1)
e = treffer[0]
self.assertEqual(e.konten, ("100", "200", "300"))
self.assertEqual(e.per_ids, ("7", "8"))
self.assertEqual(e.emails, ("anna@example.org", "a.b@example.org"))
self.assertEqual(e.feature_ids, (1, 2, 3))
self.assertEqual(e.titel, "Dr.")
def test_andere_anschrift_eigener_treffer(self):
"""Prüft, dass dieselbe Person mit anderer Anschrift ein eigener Treffer bleibt, sortiert nach Wohnort."""
layer = _Layer([
_zeile("Beispiel", "Anna", ort="Zettlitz"),
_zeile("Beispiel", "Anna", ort="Altdorf", plz="09999"),
])
treffer = es.suche_eigentuemer(layer, "Beispiel", "Anna")
self.assertEqual([e.wohnort for e in treffer], ["Altdorf", "Zettlitz"])
def test_kennzeichen_verstorben(self):
"""Prüft, dass „verstorben“ beim Exportwert 1 (auch als Zahl gelesen) gesetzt ist und bei 0, Leerem und NULL nicht."""
ja = ["1", 1]
nein = ["0", 0, "", None, _Null()]
zeilen = [_zeile(f"Ja{i}", "Test", PER_VERSTORBEN=w) for i, w in enumerate(ja)]
zeilen += [_zeile(f"Nein{i}", "Test", PER_VERSTORBEN=w) for i, w in enumerate(nein)]
for e in es.suche_eigentuemer(_Layer(zeilen), "", "Test"):
erwartet = e.nachname.startswith("Ja")
with self.subTest(name=e.nachname):
self.assertEqual(e.verstorben, erwartet)
self.assertEqual(e.hinweise, "verstorben" if erwartet else "")
def test_rechtsperson_als_rohwert(self):
"""Prüft, dass PER_RECHTSPERSON unverändert angezeigt wird (0, 1, 5, 9; noch nicht entschlüsselt) und abweichende Werte einer Person gesammelt werden."""
layer = _Layer([
_zeile("Beispiel", "Anna", PER_RECHTSPERSON="0"),
_zeile("Gemeinde Musterstadt", "", strasse="Markt 1", PER_RECHTSPERSON=5),
_zeile("Muster", "Bernd", PER_RECHTSPERSON="1"),
_zeile("Muster", "Bernd", PER_RECHTSPERSON="9"),
_zeile("Ohnewert", "Clara", PER_RECHTSPERSON=_Null()),
])
werte = {e.nachname: e.rechtsperson_text for e in es.suche_eigentuemer(layer, "e", "")}
self.assertEqual(werte, {"Beispiel": "0", "Gemeinde Musterstadt": "5", "Muster": "1, 9", "Ohnewert": ""})
def test_plz_mit_fuehrender_null(self):
"""Prüft, dass eine von QGIS als Zahl gelesene PLZ wieder fünfstellig mit führender Null erscheint und Zeilen dadurch zusammenfinden."""
layer = _Layer([
_zeile("Beispiel", "Anna", plz=1067),
_zeile("Beispiel", "Anna", plz="01067"),
_zeile("Muster", "Bernd", plz="1067.0"),
])
treffer = es.suche_eigentuemer(layer, "e", "")
self.assertEqual([(e.nachname, e.plz) for e in treffer], [("Beispiel", "01067"), ("Muster", "01067")])
def test_suche_gibt_nichts_aus(self):
"""Prüft, dass die Suche keine Personendaten auf die Konsole schreibt (Datenschutz)."""
ausgabe = io.StringIO()
with contextlib.redirect_stdout(ausgabe), contextlib.redirect_stderr(ausgabe):
es.suche_eigentuemer(_Layer([_zeile("Beispiel", "Anna")]), "Beispiel", "")
self.assertEqual(ausgabe.getvalue(), "")
class TestAnzeigeformen(unittest.TestCase):
def test_name_und_anschrift(self):
"""Prüft, dass Name mit Titel und einzeilige Anschrift mit Ortsteil lesbar zusammengesetzt werden."""
e = Eigentuemer(titel="Dr.", vorname="Anna", nachname="Beispiel", strasse="Hauptstraße 1",
plz="01234", wohnort="Musterstadt", ortsteil="Unterdorf")
self.assertEqual(e.name, "Beispiel, Dr. Anna")
self.assertEqual(e.anschrift, "Hauptstraße 1, 01234 Musterstadt, OT Unterdorf")
self.assertEqual(Eigentuemer(nachname="Beispiel", ortsteil="OT Unterdorf").anschrift, "OT Unterdorf")
self.assertEqual(Eigentuemer(nachname="Gemeinde Musterstadt").name, "Gemeinde Musterstadt")
if __name__ == "__main__":
unittest.main()