Befund aus dem QGIS-Test: Die Bildschirmwahl wirkte nicht, das Fenster erschien immer auf dem Hauptbildschirm. Im Vollbild ließ es sich weder verschieben noch schließen und verdeckte QGIS; nur ein hartes Beenden von QGIS half. Bildschirmwahl und Vollbild entfallen. Das Anzeigefenster öffnet als normales Fenster mit Rahmen; der Bearbeiter schiebt es auf den Bildschirm des Eigentümers und kann es dort maximieren. Größe und Lage werden beim Beenden gemerkt und in der nächsten Sitzung wiederhergestellt (bis zum Neustart von QGIS). Unter den Knöpfen steht jetzt Pfad und Name der Korrektur-Datei, mit Hinweis, solange sie noch nicht angelegt ist oder erst abgefragt wird. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
434 lines
22 KiB
Python
434 lines
22 KiB
Python
"""Tests für den Tab „Eigentümer“ – Flurstückssuche, Eigentümersuche, Anzeige und Korrektur (#56).
|
||
|
||
Alle Namen und Anschriften sind erfunden.
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
import tempfile
|
||
import types
|
||
import unittest
|
||
from datetime import datetime
|
||
from unittest.mock import MagicMock, patch
|
||
|
||
if "qgis" not in sys.modules:
|
||
qgis_mod = types.ModuleType("qgis")
|
||
qgis_utils = types.ModuleType("qgis.utils")
|
||
qgis_utils.iface = types.SimpleNamespace()
|
||
qgis_utils.plugins = {}
|
||
qgis_mod.utils = qgis_utils
|
||
sys.modules["qgis"] = qgis_mod
|
||
sys.modules["qgis.utils"] = qgis_utils
|
||
|
||
from sn_verfahrensgebiet.ui.tabs import eigentuemer_tab as et
|
||
from sn_verfahrensgebiet.ui.tabs.eigentuemer_tab import EigentuemerTab
|
||
from sn_verfahrensgebiet.functions.flurstueck_suche import (
|
||
FlurstueckSucheFehler,
|
||
KeinFlurstueckslayer,
|
||
SuchErgebnis,
|
||
)
|
||
from sn_verfahrensgebiet.functions.eigentuemer_suche import Eigentuemer, EigentuemerSucheFehler
|
||
from sn_verfahrensgebiet.ui import eigentuemer_treffer as treffer_modul
|
||
from sn_verfahrensgebiet.ui.eigentuemer_treffer import EigentuemerTrefferFenster, trefferzeile
|
||
|
||
|
||
def _tab(gemarkung="0268", flurstueck="562"):
|
||
tab = EigentuemerTab.__new__(EigentuemerTab)
|
||
tab.gemarkung_edit = types.SimpleNamespace(text=lambda: gemarkung)
|
||
tab.flurstueck_edit = types.SimpleNamespace(text=lambda: flurstueck)
|
||
return tab
|
||
|
||
|
||
@patch.object(et, "success")
|
||
@patch.object(et, "info")
|
||
@patch.object(et, "warning")
|
||
@patch.object(et, "show_info_dialog")
|
||
class TestFlurstueckSuchen(unittest.TestCase):
|
||
|
||
def test_ohne_flurstueckslayer_erscheint_hinweisdialog(self, dialog, warnung, hinweis, erfolg):
|
||
"""Prüft, dass ohne Layer „Flurstücke“ ein Dialog zum Laden von Verfahrensgebiet und Flurstücken erscheint."""
|
||
with patch.object(et, "flurstueck_suchen", side_effect=KeinFlurstueckslayer()):
|
||
_tab()._on_flurstueck_suchen()
|
||
dialog.assert_called_once()
|
||
self.assertIn("Flurstücke aus ALKIS laden", dialog.call_args[0][1])
|
||
warnung.assert_not_called()
|
||
erfolg.assert_not_called()
|
||
|
||
def test_eingabefehler_als_warnung(self, dialog, warnung, hinweis, erfolg):
|
||
"""Prüft, dass eine ungültige Eingabe als Warnung in der Meldungsleiste erscheint, nicht als Dialog."""
|
||
with patch.object(et, "flurstueck_suchen", side_effect=FlurstueckSucheFehler("falsch")):
|
||
_tab()._on_flurstueck_suchen()
|
||
warnung.assert_called_once_with("Flurstückssuche", "falsch")
|
||
dialog.assert_not_called()
|
||
|
||
def test_kein_treffer(self, dialog, warnung, hinweis, erfolg):
|
||
"""Prüft, dass ohne Treffer ein Hinweis erscheint und keine Auswahl gesetzt wird."""
|
||
layer = MagicMock()
|
||
with patch.object(et, "flurstueck_suchen", return_value=SuchErgebnis(layer, [])):
|
||
_tab(flurstueck="999")._on_flurstueck_suchen()
|
||
hinweis.assert_called_once()
|
||
self.assertIn("999", hinweis.call_args[0][1])
|
||
layer.selectByIds.assert_not_called()
|
||
|
||
def test_treffer_werden_ausgewaehlt_und_angezoomt(self, dialog, warnung, hinweis, erfolg):
|
||
"""Prüft, dass Treffer im Flurstückslayer ausgewählt, angezoomt und gemeldet werden."""
|
||
layer = MagicMock()
|
||
layer.name.return_value = "Flurstücke"
|
||
canvas = MagicMock()
|
||
with patch.object(et, "flurstueck_suchen", return_value=SuchErgebnis(layer, [1, 2])) as suche, \
|
||
patch.object(et, "iface", types.SimpleNamespace(mapCanvas=lambda: canvas)):
|
||
_tab(gemarkung=" Beispielhausen ", flurstueck=" 562 ")._on_flurstueck_suchen()
|
||
suche.assert_called_once_with("Beispielhausen", "562")
|
||
layer.selectByIds.assert_called_once_with([1, 2])
|
||
canvas.zoomToSelected.assert_called_once_with(layer)
|
||
canvas.flashFeatureIds.assert_called_once_with(layer, [1, 2])
|
||
erfolg.assert_called_once()
|
||
self.assertIn("2 Flurstücke", erfolg.call_args[0][1])
|
||
|
||
def test_ohne_kartenansicht_bleibt_auswahl(self, dialog, warnung, hinweis, erfolg):
|
||
"""Prüft, dass die Auswahl auch ohne Kartenansicht gesetzt und gemeldet wird."""
|
||
layer = MagicMock()
|
||
with patch.object(et, "flurstueck_suchen", return_value=SuchErgebnis(layer, [7])), \
|
||
patch.object(et, "iface", types.SimpleNamespace()):
|
||
_tab()._on_flurstueck_suchen()
|
||
layer.selectByIds.assert_called_once_with([7])
|
||
self.assertIn("1 Flurstück", erfolg.call_args[0][1])
|
||
|
||
|
||
def _eig_tab(nachname="Beispiel", vorname="", layer_id="csv1"):
|
||
tab = EigentuemerTab.__new__(EigentuemerTab)
|
||
tab.nachname_edit = types.SimpleNamespace(text=lambda: nachname)
|
||
tab.vorname_edit = types.SimpleNamespace(text=lambda: vorname)
|
||
tab.eigentuemer_layer_combo = MagicMock()
|
||
tab.eigentuemer_layer_combo.currentData.return_value = layer_id
|
||
tab._trefferfenster = None
|
||
return tab
|
||
|
||
|
||
_ANNA = Eigentuemer(vorname="Anna", nachname="Beispiel", strasse="Hauptstraße 1", plz="01234",
|
||
wohnort="Musterstadt", emails=("anna@example.org",), verstorben=True,
|
||
rechtsperson=("0",))
|
||
|
||
|
||
@patch.object(et, "info")
|
||
@patch.object(et, "warning")
|
||
class TestEigentuemerSuchen(unittest.TestCase):
|
||
|
||
def test_ohne_eigentuemerdatei_warnung(self, warnung, hinweis):
|
||
"""Prüft, dass ohne gewählte Eigentümerdatei die Liste aufgefrischt und dann auf das Laden der CSV hingewiesen wird."""
|
||
tab = _eig_tab(layer_id=None)
|
||
with patch.object(et, "hole_layer", return_value=None), \
|
||
patch.object(et, "suche_eigentuemer") as suche:
|
||
tab._on_eigentuemer_suchen()
|
||
tab.eigentuemer_layer_combo.aktualisieren.assert_called_once()
|
||
warnung.assert_called_once()
|
||
self.assertIn("CSV", warnung.call_args[0][1])
|
||
suche.assert_not_called()
|
||
|
||
def test_suchfehler_als_warnung(self, warnung, hinweis):
|
||
"""Prüft, dass ein Fehler der Suche (z. B. leere Eingabe) als Warnung erscheint."""
|
||
with patch.object(et, "hole_layer", return_value=object()), \
|
||
patch.object(et, "suche_eigentuemer", side_effect=EigentuemerSucheFehler("Bitte eingeben")):
|
||
_eig_tab()._on_eigentuemer_suchen()
|
||
warnung.assert_called_once_with("Eigentümersuche", "Bitte eingeben")
|
||
|
||
def test_kein_treffer_ohne_namen_in_meldung(self, warnung, hinweis):
|
||
"""Prüft, dass ohne Treffer ein Hinweis erscheint, der den gesuchten Namen nicht wiederholt (Datenschutz)."""
|
||
with patch.object(et, "hole_layer", return_value=object()), \
|
||
patch.object(et, "suche_eigentuemer", return_value=[]), \
|
||
patch.object(et, "EigentuemerTrefferFenster") as fenster:
|
||
_eig_tab(nachname="Beispiel")._on_eigentuemer_suchen()
|
||
hinweis.assert_called_once()
|
||
self.assertNotIn("Beispiel", hinweis.call_args[0][1])
|
||
fenster.assert_not_called()
|
||
|
||
def test_treffer_oeffnen_trefferliste_und_ersetzen_die_alte(self, warnung, hinweis):
|
||
"""Prüft, dass Treffer in einer neuen Trefferliste mit Anzeige-Rückruf erscheinen, eine offene alte Liste geschlossen wird und die Eingaben an die Suche gehen."""
|
||
layer = MagicMock()
|
||
layer.id.return_value = "csv1"
|
||
tab = _eig_tab(nachname="Beisp", vorname="An")
|
||
altes_fenster = MagicMock()
|
||
tab._trefferfenster = altes_fenster
|
||
with patch.object(et, "hole_layer", return_value=layer), \
|
||
patch.object(et, "suche_eigentuemer", return_value=[_ANNA]) as suche, patch.object(et, "EigentuemerTrefferFenster") as fenster:
|
||
tab._on_eigentuemer_suchen()
|
||
suche.assert_called_once_with(layer, "Beisp", "An")
|
||
altes_fenster.close.assert_called_once()
|
||
fenster.assert_called_once_with([_ANNA], tab, beim_anzeigen=tab._daten_anzeigen)
|
||
fenster.return_value.show.assert_called_once()
|
||
self.assertIs(tab._trefferfenster, fenster.return_value)
|
||
self.assertEqual(tab._treffer_layer_id, "csv1")
|
||
|
||
|
||
class TestTrefferliste(unittest.TestCase):
|
||
|
||
def test_trefferzeile_mit_hinweis(self):
|
||
"""Prüft, dass die Trefferliste Name, Anschrift, E-Mail, den Rohwert von PER_RECHTSPERSON und das Kennzeichen „verstorben“ zeigt."""
|
||
self.assertEqual(
|
||
trefferzeile(_ANNA),
|
||
("Beispiel, Anna", "Hauptstraße 1, 01234 Musterstadt", "anna@example.org", "0", "verstorben"),
|
||
)
|
||
|
||
def test_ausgewaehlte_eigentuemer(self):
|
||
"""Prüft, dass das Trefferfenster die in der Tabelle gewählten Einträge zurückgibt."""
|
||
bernd = Eigentuemer(vorname="Bernd", nachname="Muster")
|
||
fenster = EigentuemerTrefferFenster.__new__(EigentuemerTrefferFenster)
|
||
fenster.treffer = [_ANNA, bernd]
|
||
fenster.tabelle = object()
|
||
with patch.object(treffer_modul, "ausgewaehlte_indizes", return_value=[1]) as indizes:
|
||
self.assertEqual(fenster.ausgewaehlte_eigentuemer(), [bernd])
|
||
indizes.assert_called_once_with(fenster.tabelle)
|
||
|
||
def test_daten_anzeigen_gibt_auswahl_weiter(self):
|
||
"""Prüft, dass „Daten anzeigen“ die Auswahl der Trefferliste an den Tab übergibt."""
|
||
fenster = EigentuemerTrefferFenster.__new__(EigentuemerTrefferFenster)
|
||
fenster.treffer = [_ANNA]
|
||
fenster.tabelle = object()
|
||
fenster.beim_anzeigen = MagicMock()
|
||
with patch.object(treffer_modul, "ausgewaehlte_indizes", return_value=[0]):
|
||
fenster._on_anzeigen()
|
||
fenster.beim_anzeigen.assert_called_once_with([_ANNA])
|
||
|
||
|
||
def _anz_tab(angezeigt=None, anzeige=None, layer_id="csv1"):
|
||
tab = EigentuemerTab.__new__(EigentuemerTab)
|
||
for name in ("btn_sitzung", "btn_anzeige_leeren", "btn_korrigieren", "sitzung_label", "korrektur_label",
|
||
"eigentuemer_layer_combo"):
|
||
setattr(tab, name, MagicMock())
|
||
tab.eigentuemer_layer_combo.currentData.return_value = layer_id
|
||
tab._anzeige = anzeige
|
||
tab._anzeige_geometrie = None
|
||
tab._sitzung_seit = datetime(2026, 10, 6, 9, 5) if anzeige is not None else None
|
||
tab._angezeigt = list(angezeigt or [])
|
||
tab._treffer_layer_id = layer_id
|
||
tab._anzeige_layer_id = layer_id
|
||
tab._korrektur_pfade = {}
|
||
return tab
|
||
|
||
|
||
_BERND = Eigentuemer(vorname="Bernd", nachname="Muster", konten=("300",), per_ids=("8",))
|
||
|
||
|
||
@patch.object(et, "hole_layer", return_value=None)
|
||
@patch.object(et, "zeige_anzeigefenster")
|
||
@patch.object(et, "EigentuemerAnzeige")
|
||
class TestSitzung(unittest.TestCase):
|
||
|
||
def test_sitzung_beginnen_oeffnet_leeres_fenster_mit_rahmen(self, anzeige_klasse, zeige, _layer):
|
||
"""Prüft, dass „Sitzung beginnen“ ein leeres Anzeigefenster als normales Fenster öffnet (ohne gemerkte Lage beim ersten Mal)."""
|
||
tab = _anz_tab()
|
||
tab._on_sitzung_umschalten()
|
||
anzeige_klasse.assert_called_once_with(tab)
|
||
zeige.assert_called_once_with(anzeige_klasse.return_value, None)
|
||
self.assertIs(tab._anzeige, anzeige_klasse.return_value)
|
||
self.assertEqual(tab._angezeigt, [])
|
||
tab.btn_sitzung.setText.assert_called_with("Sitzung beenden")
|
||
self.assertIn("leer", tab.sitzung_label.setText.call_args[0][0])
|
||
|
||
def test_lage_gilt_fuer_naechste_sitzung(self, anzeige_klasse, zeige, _layer):
|
||
"""Prüft, dass Größe und Lage des Fensters beim Beenden gemerkt und in der nächsten Sitzung wiederverwendet werden."""
|
||
tab = _anz_tab()
|
||
tab._sitzung_beginnen()
|
||
anzeige_klasse.return_value.saveGeometry.return_value = b"zweiter-bildschirm"
|
||
tab._sitzung_beenden()
|
||
tab._sitzung_beginnen()
|
||
self.assertEqual(zeige.call_args_list[-1][0][1], b"zweiter-bildschirm")
|
||
|
||
def test_daten_anzeigen_beginnt_sitzung_bei_bedarf(self, anzeige_klasse, zeige, _layer):
|
||
"""Prüft, dass „Daten anzeigen“ ohne laufende Sitzung diese beginnt und die Einträge zeigt; die Statuszeile nennt nur die Anzahl."""
|
||
tab = _anz_tab()
|
||
tab._daten_anzeigen([_ANNA, _BERND])
|
||
anzeige_klasse.return_value.zeige.assert_called_once_with([_ANNA, _BERND])
|
||
self.assertEqual(tab._angezeigt, [_ANNA, _BERND])
|
||
status = tab.sitzung_label.setText.call_args[0][0]
|
||
self.assertIn("2 Einträge", status)
|
||
self.assertNotIn("Beispiel", status)
|
||
|
||
def test_daten_anzeigen_ohne_auswahl(self, anzeige_klasse, zeige, _layer):
|
||
"""Prüft, dass „Daten anzeigen“ ohne Auswahl nur einen Hinweis gibt und keine Sitzung beginnt."""
|
||
tab = _anz_tab()
|
||
with patch.object(et, "warning") as warnung:
|
||
tab._daten_anzeigen([])
|
||
warnung.assert_called_once()
|
||
anzeige_klasse.assert_not_called()
|
||
|
||
def test_anzeige_leeren_laesst_fenster_offen(self, anzeige_klasse, zeige, _layer):
|
||
"""Prüft, dass „Anzeige leeren“ die Daten entfernt, das Fenster aber nicht schließt."""
|
||
anzeige = MagicMock()
|
||
tab = _anz_tab(angezeigt=[_ANNA], anzeige=anzeige)
|
||
tab._on_anzeige_leeren()
|
||
anzeige.leeren.assert_called_once()
|
||
anzeige.close.assert_not_called()
|
||
self.assertEqual(tab._angezeigt, [])
|
||
self.assertIs(tab._anzeige, anzeige)
|
||
tab.btn_anzeige_leeren.setEnabled.assert_called_with(False)
|
||
|
||
def test_sitzung_beenden_schliesst_fenster(self, anzeige_klasse, zeige, _layer):
|
||
"""Prüft, dass „Sitzung beenden“ das Anzeigefenster schließt und die angezeigten Daten vergisst."""
|
||
anzeige = MagicMock()
|
||
tab = _anz_tab(angezeigt=[_ANNA], anzeige=anzeige)
|
||
tab._on_sitzung_umschalten()
|
||
anzeige.close.assert_called_once()
|
||
self.assertIsNone(anzeige.beim_schliessen)
|
||
self.assertIsNone(tab._anzeige)
|
||
self.assertEqual(tab._angezeigt, [])
|
||
tab.btn_sitzung.setText.assert_called_with("Sitzung beginnen")
|
||
|
||
def test_von_aussen_geschlossen_beendet_sitzung(self, anzeige_klasse, zeige, _layer):
|
||
"""Prüft, dass ein über den Fensterrahmen geschlossenes Anzeigefenster die Sitzung beendet und seine Lage gemerkt wird."""
|
||
tab = _anz_tab()
|
||
tab._sitzung_beginnen()
|
||
anzeige_klasse.return_value.saveGeometry.return_value = b"lage"
|
||
anzeige_klasse.return_value.beim_schliessen()
|
||
self.assertIsNone(tab._anzeige)
|
||
self.assertEqual(tab._anzeige_geometrie, b"lage")
|
||
|
||
|
||
class TestKorrekturLabel(unittest.TestCase):
|
||
|
||
def _text(self, tab):
|
||
return tab.korrektur_label.setText.call_args[0][0]
|
||
|
||
def test_ohne_eigentuemerdatei(self):
|
||
"""Prüft, dass ohne Eigentümerdatei unter den Knöpfen steht, dass keine gewählt ist."""
|
||
tab = _anz_tab(layer_id=None)
|
||
tab._aktualisiere_korrektur_label()
|
||
self.assertIn("keine Eigentümerdatei", self._text(tab))
|
||
|
||
def test_pfad_neben_der_eigentuemerdatei(self):
|
||
"""Prüft, dass der Pfad der Korrektur-CSV angezeigt wird, mit Hinweis, solange sie noch nicht angelegt ist."""
|
||
with tempfile.TemporaryDirectory() as ordner:
|
||
quelle = "file:///" + os.path.join(ordner, "export.csv").replace(os.sep, "/") + "?type=csv"
|
||
erwartet = os.path.normpath(os.path.join(ordner, "export_korrekturen.csv"))
|
||
tab = _anz_tab()
|
||
with patch.object(et, "hole_layer", return_value=types.SimpleNamespace(source=lambda: quelle)):
|
||
tab._aktualisiere_korrektur_label()
|
||
self.assertEqual(os.path.normcase(self._text(tab)),
|
||
os.path.normcase(f"Korrektur-Datei: {erwartet} (wird beim ersten Speichern angelegt)"))
|
||
open(erwartet, "w").close()
|
||
tab._aktualisiere_korrektur_label()
|
||
self.assertEqual(os.path.normcase(self._text(tab)), os.path.normcase(f"Korrektur-Datei: {erwartet}"))
|
||
|
||
def test_ohne_csv_quelle_wird_abgefragt(self):
|
||
"""Prüft, dass bei einer Quelle ohne CSV angekündigt wird, dass der Speicherort beim ersten Speichern abgefragt wird."""
|
||
tab = _anz_tab()
|
||
with patch.object(et, "hole_layer", return_value=types.SimpleNamespace(source=lambda: "memory?geometry=None")):
|
||
tab._aktualisiere_korrektur_label()
|
||
self.assertIn("abgefragt", self._text(tab))
|
||
|
||
def test_gewaehlter_pfad_wird_angezeigt(self):
|
||
"""Prüft, dass ein einmal gewählter Speicherort angezeigt wird."""
|
||
tab = _anz_tab()
|
||
tab._korrektur_pfade["csv1"] = "D:/Termine/korrekturen.csv"
|
||
with patch.object(et, "hole_layer", return_value=None):
|
||
tab._aktualisiere_korrektur_label()
|
||
self.assertIn(os.path.normpath("D:/Termine/korrekturen.csv"), self._text(tab))
|
||
|
||
|
||
@patch.object(et, "hole_layer", return_value=None)
|
||
@patch.object(et, "success")
|
||
@patch.object(et, "info")
|
||
@patch.object(et, "warning")
|
||
class TestKorrektur(unittest.TestCase):
|
||
|
||
def test_korrektur_wird_festgehalten_und_angezeigt(self, warnung, hinweis, erfolg, _layer):
|
||
"""Prüft, dass eine Korrektur in die Korrektur-CSV geschrieben, sofort angezeigt und ohne Namen gemeldet wird."""
|
||
anzeige = MagicMock()
|
||
tab = _anz_tab(angezeigt=[_ANNA, _BERND], anzeige=anzeige)
|
||
tab._korrektur_pfade["csv1"] = "D:/Verfahren/export_korrekturen.csv"
|
||
with patch.object(et, "frage_korrektur", return_value=(1, {"wohnort": "Neustadt"})), \
|
||
patch.object(et, "schreibe_korrekturen") as schreiben:
|
||
tab._on_korrigieren()
|
||
schreiben.assert_called_once_with("D:/Verfahren/export_korrekturen.csv", _BERND,
|
||
[("wohnort", "", "Neustadt")])
|
||
self.assertEqual(tab._angezeigt[1].wohnort, "Neustadt")
|
||
self.assertIs(tab._angezeigt[0], _ANNA)
|
||
anzeige.zeige.assert_called_once_with(tab._angezeigt)
|
||
meldung = erfolg.call_args[0][1]
|
||
self.assertIn("export_korrekturen.csv", meldung)
|
||
self.assertNotIn("Muster", meldung)
|
||
|
||
def test_ohne_aenderung_nichts_schreiben(self, warnung, hinweis, erfolg, _layer):
|
||
"""Prüft, dass ein unverändert gespeicherter Dialog nichts schreibt."""
|
||
tab = _anz_tab(angezeigt=[_ANNA], anzeige=MagicMock())
|
||
with patch.object(et, "frage_korrektur", return_value=(0, {"nachname": "Beispiel"})), \
|
||
patch.object(et, "schreibe_korrekturen") as schreiben:
|
||
tab._on_korrigieren()
|
||
schreiben.assert_not_called()
|
||
hinweis.assert_called_once()
|
||
|
||
def test_abbruch_nichts_schreiben(self, warnung, hinweis, erfolg, _layer):
|
||
"""Prüft, dass ein abgebrochener Korrekturdialog nichts schreibt."""
|
||
tab = _anz_tab(angezeigt=[_ANNA], anzeige=MagicMock())
|
||
with patch.object(et, "frage_korrektur", return_value=None), \
|
||
patch.object(et, "schreibe_korrekturen") as schreiben:
|
||
tab._on_korrigieren()
|
||
schreiben.assert_not_called()
|
||
|
||
def test_schreibfehler_warnung_und_anzeige_unveraendert(self, warnung, hinweis, erfolg, _layer):
|
||
"""Prüft, dass bei einem Schreibfehler gewarnt, die Anzeige nicht geändert und der Pfad beim nächsten Mal neu bestimmt wird."""
|
||
anzeige = MagicMock()
|
||
tab = _anz_tab(angezeigt=[_ANNA], anzeige=anzeige)
|
||
tab._korrektur_pfade["csv1"] = "X:/gesperrt.csv"
|
||
with patch.object(et, "frage_korrektur", return_value=(0, {"wohnort": "Neustadt"})), \
|
||
patch.object(et, "schreibe_korrekturen", side_effect=PermissionError(13, "Zugriff verweigert")):
|
||
tab._on_korrigieren()
|
||
warnung.assert_called_once()
|
||
anzeige.zeige.assert_not_called()
|
||
self.assertIs(tab._angezeigt[0], _ANNA)
|
||
self.assertNotIn("csv1", tab._korrektur_pfade)
|
||
|
||
def test_ohne_anzeige_keine_korrektur(self, warnung, hinweis, erfolg, _layer):
|
||
"""Prüft, dass ohne angezeigte Daten kein Korrekturdialog erscheint."""
|
||
tab = _anz_tab()
|
||
with patch.object(et, "frage_korrektur") as dialog:
|
||
tab._on_korrigieren()
|
||
dialog.assert_not_called()
|
||
warnung.assert_called_once()
|
||
|
||
|
||
class TestKorrekturDatei(unittest.TestCase):
|
||
|
||
def test_vorschlag_neben_der_eigentuemerdatei(self):
|
||
"""Prüft, dass die Korrektur-CSV ohne Rückfrage neben der Eigentümerdatei liegt, wenn der Ordner beschreibbar ist, und gemerkt wird."""
|
||
with tempfile.TemporaryDirectory() as ordner:
|
||
quelle = "file:///" + os.path.join(ordner, "export.csv").replace(os.sep, "/") + "?type=csv"
|
||
layer = types.SimpleNamespace(source=lambda: quelle)
|
||
tab = _anz_tab()
|
||
with patch.object(et, "hole_layer", return_value=layer), \
|
||
patch.object(et.QFileDialog, "getSaveFileName") as dialog:
|
||
pfad = tab._korrektur_datei()
|
||
dialog.assert_not_called()
|
||
self.assertEqual(os.path.normcase(os.path.normpath(pfad)),
|
||
os.path.normcase(os.path.join(ordner, "export_korrekturen.csv")))
|
||
self.assertEqual(tab._korrektur_pfade["csv1"], pfad)
|
||
|
||
def test_ohne_csv_quelle_wird_gefragt(self):
|
||
"""Prüft, dass ohne verwertbare CSV-Quelle nach dem Speicherort gefragt wird; Abbrechen liefert keinen Pfad."""
|
||
tab = _anz_tab()
|
||
layer = types.SimpleNamespace(source=lambda: "memory?geometry=None")
|
||
with patch.object(et, "hole_layer", return_value=layer), \
|
||
patch.object(et.QFileDialog, "getSaveFileName", return_value=("", "")) as dialog:
|
||
self.assertIsNone(tab._korrektur_datei())
|
||
dialog.assert_called_once()
|
||
self.assertEqual(tab._korrektur_pfade, {})
|
||
|
||
with patch.object(et, "hole_layer", return_value=layer), \
|
||
patch.object(et.QFileDialog, "getSaveFileName", return_value=("D:/k.csv", "")):
|
||
self.assertEqual(tab._korrektur_datei(), "D:/k.csv")
|
||
|
||
|
||
class TestDockWidgetTabs(unittest.TestCase):
|
||
|
||
def test_tab_ist_im_dockwidget_eingetragen(self):
|
||
"""Prüft, dass der Tab „Eigentümer“ im DockWidget direkt nach dem Bearbeitungs-Tab steht."""
|
||
from sn_verfahrensgebiet.ui.dockwidget import DockWidget
|
||
from sn_verfahrensgebiet.ui.tabs.working_tab import WorkingTab
|
||
|
||
self.assertEqual(DockWidget.tabs[:2], [WorkingTab, EigentuemerTab])
|
||
self.assertEqual(EigentuemerTab.tab_title, "Eigentümer")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
unittest.main()
|