Tests für Dateipruefer._ist_leer (None/Whitespace), Dateipruefer._handle_leere_eingabe (Priorität bei mehreren Flags), Datenschreiber._store_style_in_gpkg (nachgezogen aus #63, siehe #67) und Pruefmanager._handle_verfahrensgebiet_layer_existiert (entfernen/ersetzen) ergänzt. Linkpruefer._ist_url/_pruefe_url/_pruefe_dateipfad und Pruefmanager._handle_datei_existiert sind bereits über pruefe()/verarbeite() vollständig abgedeckt und bekommen den Vermerk "von Test abgesehen". Pruefmanager._ask_use_or_replace_pufferlayer ist toter Code (Bug #60) und bleibt bis zur Behebung unmarkiert getestet, nur vermerkt. sn_basis steht damit laut Prüfstand bei 0 ungeklärten Funktionen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
318 lines
16 KiB
Python
318 lines
16 KiB
Python
# sn_basis/test/test_pruefmanager.py
|
|
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from sn_basis.modules.Pruefmanager import Pruefmanager
|
|
from sn_basis.modules.pruef_ergebnis import pruef_ergebnis
|
|
|
|
|
|
class TestPruefmanager(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
self.manager = Pruefmanager()
|
|
|
|
# -----------------------------------------------------
|
|
# 1. OK-Ergebnis → keine Interaktion
|
|
# -----------------------------------------------------
|
|
def test_ok(self):
|
|
"""Prüft, dass ein bereits erfolgreiches Prüfergebnis ohne Nutzerinteraktion als 'ok' durchgereicht wird."""
|
|
ergebnis = pruef_ergebnis(True, "Alles gut", "ok", None)
|
|
entscheidung = self.manager.verarbeite(ergebnis)
|
|
|
|
self.assertTrue(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "ok")
|
|
|
|
# -----------------------------------------------------
|
|
# 2. Leere Eingabe erlaubt → Nutzer sagt JA
|
|
# -----------------------------------------------------
|
|
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=True)
|
|
def test_leereingabe_erlaubt_ja(self, mock_ask):
|
|
"""Prüft, dass bei erlaubter leerer Eingabe eine Ja-Antwort des Nutzers die Entscheidung 'ok' liefert."""
|
|
ergebnis = pruef_ergebnis(False, "Leer?", "leereingabe_erlaubt", None)
|
|
entscheidung = self.manager.verarbeite(ergebnis)
|
|
|
|
self.assertTrue(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "ok")
|
|
|
|
# -----------------------------------------------------
|
|
# 3. Leere Eingabe erlaubt → Nutzer sagt NEIN
|
|
# -----------------------------------------------------
|
|
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=False)
|
|
def test_leereingabe_erlaubt_nein(self, mock_ask):
|
|
"""Prüft, dass bei erlaubter leerer Eingabe eine Nein-Antwort die Aktion 'leereingabe_erlaubt' als abgelehnt bestehen lässt."""
|
|
ergebnis = pruef_ergebnis(False, "Leer?", "leereingabe_erlaubt", None)
|
|
entscheidung = self.manager.verarbeite(ergebnis)
|
|
|
|
self.assertFalse(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "leereingabe_erlaubt")
|
|
|
|
# -----------------------------------------------------
|
|
# 4. Standarddatei vorschlagen → Nutzer sagt JA
|
|
# -----------------------------------------------------
|
|
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=True)
|
|
def test_standarddatei_vorschlagen_ja(self, mock_ask):
|
|
"""Prüft, dass eine Ja-Antwort auf den Vorschlag der Standarddatei die Entscheidung 'ok' mit dem Standardpfad als Kontext liefert."""
|
|
ergebnis = pruef_ergebnis(
|
|
False,
|
|
"Standarddatei verwenden?",
|
|
"standarddatei_vorschlagen",
|
|
"/tmp/std.txt",
|
|
)
|
|
|
|
entscheidung = self.manager.verarbeite(ergebnis)
|
|
|
|
self.assertTrue(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "ok")
|
|
self.assertEqual(entscheidung.kontext, "/tmp/std.txt")
|
|
|
|
# -----------------------------------------------------
|
|
# 5. Standarddatei vorschlagen → Nutzer sagt NEIN
|
|
# -----------------------------------------------------
|
|
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=False)
|
|
def test_standarddatei_vorschlagen_nein(self, mock_ask):
|
|
"""Prüft, dass eine Nein-Antwort auf den Vorschlag der Standarddatei die Aktion 'standarddatei_vorschlagen' als abgelehnt bestehen lässt."""
|
|
ergebnis = pruef_ergebnis(
|
|
False,
|
|
"Standarddatei verwenden?",
|
|
"standarddatei_vorschlagen",
|
|
"/tmp/std.txt",
|
|
)
|
|
|
|
entscheidung = self.manager.verarbeite(ergebnis)
|
|
|
|
self.assertFalse(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "standarddatei_vorschlagen")
|
|
|
|
# -----------------------------------------------------
|
|
# 6. Temporäre Datei erzeugen → Nutzer sagt JA
|
|
# -----------------------------------------------------
|
|
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=True)
|
|
def test_temporaer_erlaubt_ja(self, mock_ask):
|
|
"""Prüft, dass eine Ja-Antwort auf die Rückfrage nach einer temporären Datei die Aktion 'temporaer_erzeugen' auslöst."""
|
|
ergebnis = pruef_ergebnis(False, "Temporär?", "temporaer_erlaubt", None)
|
|
entscheidung = self.manager.verarbeite(ergebnis)
|
|
|
|
self.assertTrue(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "temporaer_erzeugen")
|
|
|
|
# -----------------------------------------------------
|
|
# 7. Temporäre Datei erzeugen → Nutzer sagt NEIN
|
|
# -----------------------------------------------------
|
|
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=False)
|
|
def test_temporaer_erlaubt_nein(self, mock_ask):
|
|
"""Prüft, dass eine Nein-Antwort auf die Rückfrage nach einer temporären Datei die Aktion 'temporaer_erlaubt' als abgelehnt bestehen lässt."""
|
|
ergebnis = pruef_ergebnis(False, "Temporär?", "temporaer_erlaubt", None)
|
|
entscheidung = self.manager.verarbeite(ergebnis)
|
|
|
|
self.assertFalse(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "temporaer_erlaubt")
|
|
|
|
# -----------------------------------------------------
|
|
# 8. Layer unsichtbar → Nutzer sagt JA
|
|
# -----------------------------------------------------
|
|
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=True)
|
|
@patch("sn_basis.modules.Pruefmanager.set_layer_visible")
|
|
def test_layer_unsichtbar_ja(self, mock_set, mock_ask):
|
|
"""Prüft, dass eine Ja-Antwort bei unsichtbarem Layer den Layer sichtbar schaltet und die Entscheidung 'ok' liefert."""
|
|
fake_layer = object()
|
|
ergebnis = pruef_ergebnis(False, "Layer unsichtbar", "layer_unsichtbar", fake_layer)
|
|
|
|
entscheidung = self.manager.verarbeite(ergebnis)
|
|
|
|
mock_set.assert_called_once_with(fake_layer, True)
|
|
self.assertTrue(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "ok")
|
|
|
|
# -----------------------------------------------------
|
|
# 9. Layer unsichtbar → Nutzer sagt NEIN
|
|
# -----------------------------------------------------
|
|
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=False)
|
|
def test_layer_unsichtbar_nein(self, mock_ask):
|
|
"""Prüft, dass eine Nein-Antwort bei unsichtbarem Layer die Aktion 'layer_unsichtbar' als abgelehnt bestehen lässt."""
|
|
fake_layer = object()
|
|
ergebnis = pruef_ergebnis(False, "Layer unsichtbar", "layer_unsichtbar", fake_layer)
|
|
|
|
entscheidung = self.manager.verarbeite(ergebnis)
|
|
|
|
self.assertFalse(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "layer_unsichtbar")
|
|
|
|
# -----------------------------------------------------
|
|
# 10. Fehlerhafte Aktion → Fallback
|
|
# -----------------------------------------------------
|
|
@patch("sn_basis.modules.Pruefmanager.warning")
|
|
def test_unbekannte_aktion(self, mock_warn):
|
|
"""Prüft, dass eine unbekannte Aktion eine Warnung auslöst und unverarbeitet als Fehlschlag zurückgegeben wird."""
|
|
ergebnis = pruef_ergebnis(False, "???", "unbekannt", None)
|
|
entscheidung = self.manager.verarbeite(ergebnis)
|
|
|
|
mock_warn.assert_called_once()
|
|
self.assertFalse(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "unbekannt")
|
|
|
|
@patch("sn_basis.modules.Pruefmanager.ask_overwrite_append_cancel_custom", return_value="overwrite")
|
|
def test_datei_existiert_overwrite(self, _mock_choice):
|
|
"""Prüft, dass die Nutzerwahl 'überschreiben' bei bestehender Datei zur Aktion 'datei_existiert_ueberschreiben' führt."""
|
|
ergebnis = pruef_ergebnis(False, "Datei existiert", "datei_existiert", "C:/tmp/v.gpkg")
|
|
entscheidung = self.manager.verarbeite(ergebnis)
|
|
|
|
self.assertTrue(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "datei_existiert_ueberschreiben")
|
|
self.assertEqual(entscheidung.kontext, "C:/tmp/v.gpkg")
|
|
|
|
@patch("sn_basis.modules.Pruefmanager.ask_overwrite_append_cancel_custom", return_value="append")
|
|
def test_datei_existiert_append(self, _mock_choice):
|
|
"""Prüft, dass die Nutzerwahl 'anhängen' bei bestehender Datei zur Aktion 'datei_existiert_anhaengen' führt."""
|
|
ergebnis = pruef_ergebnis(False, "Datei existiert", "datei_existiert", "C:/tmp/v.gpkg")
|
|
entscheidung = self.manager.verarbeite(ergebnis)
|
|
|
|
self.assertTrue(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "datei_existiert_anhaengen")
|
|
|
|
@patch("sn_basis.modules.Pruefmanager.ask_overwrite_append_cancel_custom", return_value="cancel")
|
|
def test_datei_existiert_cancel(self, _mock_choice):
|
|
"""Prüft, dass die Nutzerwahl 'abbrechen' bei bestehender Datei zur Aktion 'datei_existiert_ueberspringen' führt."""
|
|
ergebnis = pruef_ergebnis(False, "Datei existiert", "datei_existiert", "C:/tmp/v.gpkg")
|
|
entscheidung = self.manager.verarbeite(ergebnis)
|
|
|
|
self.assertTrue(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "datei_existiert_ueberspringen")
|
|
|
|
def test_datei_existiert_in_non_qgis_mode_returns_input(self):
|
|
"""Prüft, dass außerhalb des QGIS-Modus bei bestehender Datei keine Rückfrage erfolgt, sondern die ursprüngliche Aktion unentschieden zurückgegeben wird."""
|
|
manager = Pruefmanager(ui_modus="test")
|
|
ergebnis = pruef_ergebnis(False, "Datei existiert", "datei_existiert", "C:/tmp/v.gpkg")
|
|
|
|
entscheidung = manager.verarbeite(ergebnis)
|
|
|
|
self.assertFalse(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "datei_existiert")
|
|
|
|
# -----------------------------------------------------
|
|
# 11. Verfahrensgebiet-Layer existiert bereits
|
|
# -----------------------------------------------------
|
|
@patch("sn_basis.modules.Pruefmanager.ask_ergaenzen_entfernen_ersetzen_abbrechen", return_value="ergaenzen")
|
|
def test_verfahrensgebiet_layer_existiert_ergaenzen(self, _mock_choice):
|
|
"""Prüft, dass die Nutzerwahl 'ergänzen' bei bestehendem Verfahrensgebiet zur Aktion 'verfahrensgebiet_ergaenzen' führt."""
|
|
ergebnis = pruef_ergebnis(False, "VG existiert", "verfahrensgebiet_layer_existiert", None)
|
|
entscheidung = self.manager.verarbeite(ergebnis)
|
|
|
|
self.assertTrue(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "verfahrensgebiet_ergaenzen")
|
|
|
|
@patch("sn_basis.modules.Pruefmanager.ask_ergaenzen_entfernen_ersetzen_abbrechen", return_value="abbrechen")
|
|
def test_verfahrensgebiet_layer_existiert_abbrechen(self, _mock_choice):
|
|
"""Prüft, dass die Nutzerwahl 'abbrechen' bei bestehendem Verfahrensgebiet ok=False mit Aktion 'verfahrensgebiet_abbrechen' liefert."""
|
|
ergebnis = pruef_ergebnis(False, "VG existiert", "verfahrensgebiet_layer_existiert", None)
|
|
entscheidung = self.manager.verarbeite(ergebnis)
|
|
|
|
self.assertFalse(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "verfahrensgebiet_abbrechen")
|
|
|
|
@patch("sn_basis.modules.Pruefmanager.ask_ergaenzen_entfernen_ersetzen_abbrechen", return_value="entfernen")
|
|
def test_verfahrensgebiet_layer_existiert_entfernen(self, _mock_choice):
|
|
"""Prüft, dass die Nutzerwahl 'entfernen' bei bestehendem Verfahrensgebiet zur Aktion 'verfahrensgebiet_entfernen' führt."""
|
|
ergebnis = pruef_ergebnis(False, "VG existiert", "verfahrensgebiet_layer_existiert", None)
|
|
entscheidung = self.manager._handle_verfahrensgebiet_layer_existiert(ergebnis)
|
|
|
|
self.assertTrue(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "verfahrensgebiet_entfernen")
|
|
|
|
@patch("sn_basis.modules.Pruefmanager.ask_ergaenzen_entfernen_ersetzen_abbrechen", return_value="ersetzen")
|
|
def test_verfahrensgebiet_layer_existiert_ersetzen(self, _mock_choice):
|
|
"""Prüft, dass die Nutzerwahl 'ersetzen' bei bestehendem Verfahrensgebiet zur Aktion 'verfahrensgebiet_ersetzen' führt."""
|
|
ergebnis = pruef_ergebnis(False, "VG existiert", "verfahrensgebiet_layer_existiert", None)
|
|
entscheidung = self.manager._handle_verfahrensgebiet_layer_existiert(ergebnis)
|
|
|
|
self.assertTrue(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "verfahrensgebiet_ersetzen")
|
|
|
|
def test_verfahrensgebiet_layer_existiert_in_non_qgis_mode_returns_input(self):
|
|
"""Prüft, dass außerhalb des QGIS-Modus bei bestehendem Verfahrensgebiet keine Rückfrage erfolgt."""
|
|
manager = Pruefmanager(ui_modus="test")
|
|
ergebnis = pruef_ergebnis(False, "VG existiert", "verfahrensgebiet_layer_existiert", None)
|
|
|
|
entscheidung = manager.verarbeite(ergebnis)
|
|
|
|
self.assertFalse(entscheidung.ok)
|
|
self.assertEqual(entscheidung.aktion, "verfahrensgebiet_layer_existiert")
|
|
|
|
# -----------------------------------------------------
|
|
# 12. report_error: Einstufung nach Aktionscode
|
|
# -----------------------------------------------------
|
|
@patch("sn_basis.modules.Pruefmanager.error")
|
|
@patch("sn_basis.modules.Pruefmanager.warning")
|
|
def test_report_error_kritische_aktion_ruft_error_auf(self, mock_warning, mock_error):
|
|
"""Prüft, dass eine kritische Aktion (z. B. 'netzwerkfehler') über error() gemeldet wird, nicht über warning()."""
|
|
self.manager.report_error("Thema", "Meldung", aktion="netzwerkfehler")
|
|
|
|
mock_error.assert_called_once_with("Thema", "Meldung")
|
|
mock_warning.assert_not_called()
|
|
|
|
@patch("sn_basis.modules.Pruefmanager.error")
|
|
@patch("sn_basis.modules.Pruefmanager.warning")
|
|
def test_report_error_warn_aktion_ruft_warning_auf(self, mock_warning, mock_error):
|
|
"""Prüft, dass eine Warn-Aktion (z. B. 'datei_nicht_gefunden') über warning() gemeldet wird, nicht über error()."""
|
|
self.manager.report_error("Thema", "Meldung", aktion="datei_nicht_gefunden")
|
|
|
|
mock_warning.assert_called_once_with("Thema", "Meldung")
|
|
mock_error.assert_not_called()
|
|
|
|
@patch("sn_basis.modules.Pruefmanager.error")
|
|
@patch("sn_basis.modules.Pruefmanager.warning")
|
|
def test_report_error_unbekannte_aktion_faellt_auf_warning_zurueck(self, mock_warning, mock_error):
|
|
"""Prüft, dass eine nicht eingestufte Aktion als Fallback über warning() gemeldet wird."""
|
|
self.manager.report_error("Thema", "Meldung", aktion="voellig_unbekannt")
|
|
|
|
mock_warning.assert_called_once_with("Thema", "Meldung")
|
|
mock_error.assert_not_called()
|
|
|
|
# -----------------------------------------------------
|
|
# 13. frage_ja_nein
|
|
# -----------------------------------------------------
|
|
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=True)
|
|
def test_frage_ja_nein_im_qgis_modus_fragt_nutzer(self, mock_ask):
|
|
"""Prüft, dass frage_ja_nein im QGIS-Modus den Nutzer fragt und dessen Antwort liefert."""
|
|
ergebnis = self.manager.frage_ja_nein("Titel", "Meldung", default=False)
|
|
|
|
self.assertTrue(ergebnis)
|
|
mock_ask.assert_called_once()
|
|
|
|
@patch("sn_basis.modules.Pruefmanager.ask_yes_no")
|
|
def test_frage_ja_nein_ausserhalb_qgis_liefert_default_ohne_rueckfrage(self, mock_ask):
|
|
"""Prüft, dass frage_ja_nein außerhalb des QGIS-Modus den Default-Wert liefert, ohne den Nutzer zu fragen."""
|
|
manager = Pruefmanager(ui_modus="test")
|
|
|
|
ergebnis = manager.frage_ja_nein("Titel", "Meldung", default=True)
|
|
|
|
self.assertTrue(ergebnis)
|
|
mock_ask.assert_not_called()
|
|
|
|
# -----------------------------------------------------
|
|
# 14. frage_text
|
|
# -----------------------------------------------------
|
|
@patch("sn_basis.functions.dialog_wrapper.ask_text", return_value=("Neuer Text", True))
|
|
def test_frage_text_im_qgis_modus_fragt_nutzer(self, mock_ask):
|
|
"""Prüft, dass frage_text im QGIS-Modus den Nutzer fragt und Text plus OK-Status liefert."""
|
|
text, ok = self.manager.frage_text("Titel", "Meldung", default_text="Alt")
|
|
|
|
self.assertEqual(text, "Neuer Text")
|
|
self.assertTrue(ok)
|
|
mock_ask.assert_called_once()
|
|
|
|
@patch("sn_basis.functions.dialog_wrapper.ask_text")
|
|
def test_frage_text_ausserhalb_qgis_liefert_default_ohne_rueckfrage(self, mock_ask):
|
|
"""Prüft, dass frage_text außerhalb des QGIS-Modus den Standardtext mit OK=True liefert, ohne den Nutzer zu fragen."""
|
|
manager = Pruefmanager(ui_modus="test")
|
|
|
|
text, ok = manager.frage_text("Titel", "Meldung", default_text="Standard")
|
|
|
|
self.assertEqual(text, "Standard")
|
|
self.assertTrue(ok)
|
|
mock_ask.assert_not_called()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|