Abbruch des Dialogs ist eine bewusste Nutzerentscheidung, kein Fehlerzustand – verfahrensgebiet_alkis_komplett() bricht jetzt still ab statt eine QMessageBox.critical zu zeigen. Test entsprechend angepasst/umbenannt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
784 lines
32 KiB
Python
784 lines
32 KiB
Python
"""sn_verfahrensgebiet/tests/test_verfahrensgebiet_alkis_komplett.py
|
||
|
||
Unit-Tests für :mod:`sn_verfahrensgebiet.functions.verfahrensgebiet_alkis_komplett`.
|
||
|
||
Getestete Szenarien:
|
||
|
||
Erfolgsfall (Flächenübereinstimmung):
|
||
- Vollständiger Workflow → enriched Layer + flst_layer + bror_layer + LoadStatus.FIRST
|
||
- VKZ aus Projektvariable wird als Feld gesetzt (wenn vorhanden)
|
||
- Kein VKZ in Projektvariable → Feld wird nicht gesetzt (kein Fehler)
|
||
|
||
Abbruchpfade:
|
||
- verfahrensgebiet_alkis gibt LoadStatus.NONE → (None, None, None, NONE)
|
||
- flurstueck_alkis gibt LoadStatus.NONE → (None, None, None, NONE)
|
||
- Keine Flurstücke selektiert → (None, flst_layer, None, NONE) + Warnung
|
||
- erstelle_verfahrensgebiet_aus_auswahl liefert ungültigen Layer → (None, flst_layer, None, NONE)
|
||
- Progress-Abbruch nach Schritt 1 → sofortiger sauberer Rückgabestatus
|
||
|
||
Flächenvergleich:
|
||
- Übereinstimmung → show_info_dialog, keine Detailprüfung
|
||
- Abweichung + abbrechen → kein Detailprüfungs-Aufruf
|
||
- Abweichung + als_vg_laden → BROR umbenannt, als enriched_layer zurückgegeben
|
||
- Abweichung + detailpruefung → lade_punktort_ta + knickpunkt_pruefung aufgerufen
|
||
|
||
Cleanup:
|
||
- BROR-Layer wird bei Erfolg NICHT entfernt
|
||
- BROR-Layer wird bei Fehler entfernt (wenn in diesem Lauf hinzugefügt)
|
||
- TempVerfahrensgebiet wird stets entfernt
|
||
|
||
Hilfsfunktionen:
|
||
- _select_by_location: processing-Fallback liefert 0 → keine Exception
|
||
- _fuege_vkz_feld_hinzu: leeres VKZ wird ignoriert
|
||
- _vergleiche_flaechen: korrekte Toleranzlogik
|
||
- _lese_flaechen_toleranz: Default 0.0, parst Projektvariable
|
||
"""
|
||
|
||
import sys
|
||
import types
|
||
import unittest
|
||
from unittest.mock import patch, MagicMock
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Minimales QGIS-Mock-Setup
|
||
# ---------------------------------------------------------------------------
|
||
if "qgis" not in sys.modules:
|
||
qgis_mod = types.ModuleType("qgis")
|
||
qgis_core = types.ModuleType("qgis.core")
|
||
qgis_utils = types.ModuleType("qgis.utils")
|
||
qgis_utils.iface = types.SimpleNamespace()
|
||
qgis_utils.plugins = {}
|
||
qgis_mod.utils = qgis_utils
|
||
qgis_mod.core = qgis_core
|
||
sys.modules["qgis"] = qgis_mod
|
||
sys.modules["qgis.core"] = qgis_core
|
||
sys.modules["qgis.utils"] = qgis_utils
|
||
|
||
from sn_verfahrensgebiet.functions.verfahrensgebiet_alkis import LoadStatus
|
||
from sn_verfahrensgebiet.functions.verfahrensgebiet_alkis_komplett import (
|
||
verfahrensgebiet_alkis_komplett,
|
||
_select_by_location,
|
||
_fuege_vkz_feld_hinzu,
|
||
_vergleiche_flaechen,
|
||
_lese_flaechen_toleranz,
|
||
)
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Dummies
|
||
# ---------------------------------------------------------------------------
|
||
|
||
class _DummyRect:
|
||
def xMinimum(self): return 414000.0
|
||
def yMinimum(self): return 5657000.0
|
||
def xMaximum(self): return 415000.0
|
||
def yMaximum(self): return 5658000.0
|
||
|
||
|
||
def _make_layer(valid=True, name="Layer", lid="L1", feature_count=1, area=1000.0):
|
||
"""Erzeugt einen konfigurierten Mock-Layer mit getFeatures-Support."""
|
||
layer = MagicMock()
|
||
layer.isValid.return_value = valid
|
||
layer.id.return_value = lid
|
||
layer.name.return_value = name
|
||
layer.extent.return_value = _DummyRect()
|
||
layer.featureCount.return_value = feature_count
|
||
layer.selectedFeatureCount.return_value = feature_count
|
||
|
||
mock_geom = MagicMock()
|
||
mock_geom.isEmpty.return_value = False
|
||
mock_geom.area.return_value = area
|
||
mock_geom.boundary.return_value = MagicMock(isEmpty=lambda: True)
|
||
mock_feat = MagicMock()
|
||
mock_feat.geometry.return_value = mock_geom
|
||
layer.getFeatures.return_value = [mock_feat]
|
||
|
||
mock_crs = MagicMock()
|
||
mock_crs.authid.return_value = "EPSG:25833"
|
||
layer.crs.return_value = mock_crs
|
||
return layer
|
||
|
||
|
||
class _DummyProject:
|
||
def __init__(self):
|
||
self.added = []
|
||
self.removed = []
|
||
self._layers_by_name: dict = {}
|
||
|
||
def addMapLayer(self, layer):
|
||
self.added.append(layer)
|
||
|
||
def removeMapLayer(self, lid):
|
||
self.removed.append(lid)
|
||
|
||
def mapLayersByName(self, name):
|
||
return self._layers_by_name.get(name, [])
|
||
|
||
def instance(self):
|
||
return self
|
||
|
||
|
||
def _make_progress_mock(canceled=False):
|
||
prog = MagicMock()
|
||
prog.is_canceled.return_value = canceled
|
||
return prog
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Patch-Konstanten
|
||
# ---------------------------------------------------------------------------
|
||
|
||
_MOD = "sn_verfahrensgebiet.functions.verfahrensgebiet_alkis_komplett"
|
||
_PATCH_VG_ALKIS = f"{_MOD}._suche_verfahrensgebiet_features"
|
||
_PATCH_GEM = f"{_MOD}.gemarkung_schluessel_und_namen_von_vg_geometrie"
|
||
_PATCH_FLST = f"{_MOD}.flurstueck_alkis"
|
||
_PATCH_SELECT = f"{_MOD}._select_by_location"
|
||
_PATCH_ERSTELLE = f"{_MOD}.erstelle_verfahrensgebiet_aus_auswahl"
|
||
_PATCH_VKZ = f"{_MOD}._fuege_vkz_feld_hinzu"
|
||
_PATCH_PROJECT = f"{_MOD}.QgsProject"
|
||
_PATCH_MSGBOX = f"{_MOD}.QMessageBox"
|
||
_PATCH_WARNING = f"{_MOD}.warning"
|
||
_PATCH_GET_VAR = f"{_MOD}.get_variable"
|
||
_PATCH_PROGRESS = f"{_MOD}.create_progress_dialog"
|
||
_PATCH_VERGLEICHE = f"{_MOD}._vergleiche_flaechen"
|
||
_PATCH_SHOW_INFO = f"{_MOD}.show_info_dialog"
|
||
_PATCH_ASK_DIALOG = f"{_MOD}.ask_detailpruefung_oder_vg_laden"
|
||
_PATCH_GP_ALKIS = f"{_MOD}.lade_punktort_ta"
|
||
_PATCH_KNICK = f"{_MOD}.knickpunkt_pruefung"
|
||
_PATCH_EXTRAHIERE = f"{_MOD}._extrahiere_knickpunkte"
|
||
_PATCH_LANDKREIS_SUCHE = f"{_MOD}._suche_landkreis_kombinationen"
|
||
_PATCH_LANDKREIS_BAU = f"{_MOD}._baue_layer_aus_landkreis_auswahl"
|
||
_PATCH_ASK_LANDKREIS = f"{_MOD}.ask_landkreis_auswahl"
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Tests: _select_by_location
|
||
# ---------------------------------------------------------------------------
|
||
|
||
class TestSelectByLocation(unittest.TestCase):
|
||
|
||
def test_processing_not_available_returns_zero(self):
|
||
flst, vg = MagicMock(), MagicMock()
|
||
with patch.dict("sys.modules", {"processing": None}):
|
||
result = _select_by_location(flst, vg)
|
||
self.assertEqual(result, 0)
|
||
|
||
def test_processing_success_returns_count(self):
|
||
flst = MagicMock()
|
||
flst.selectedFeatureCount.return_value = 7
|
||
vg = MagicMock()
|
||
mock_proc = MagicMock()
|
||
with patch.dict("sys.modules", {"processing": mock_proc}):
|
||
result = _select_by_location(flst, vg)
|
||
self.assertEqual(result, 7)
|
||
|
||
def test_processing_exception_returns_zero(self):
|
||
flst, vg = MagicMock(), MagicMock()
|
||
mock_proc = MagicMock()
|
||
mock_proc.run.side_effect = RuntimeError("Kein QGIS")
|
||
with patch.dict("sys.modules", {"processing": mock_proc}):
|
||
result = _select_by_location(flst, vg)
|
||
self.assertEqual(result, 0)
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Tests: _fuege_vkz_feld_hinzu
|
||
# ---------------------------------------------------------------------------
|
||
|
||
class TestFuegeVkzFeldHinzu(unittest.TestCase):
|
||
|
||
def test_empty_vkz_does_nothing(self):
|
||
layer = MagicMock()
|
||
_fuege_vkz_feld_hinzu(layer, "")
|
||
layer.dataProvider.assert_not_called()
|
||
|
||
def test_none_vkz_does_nothing(self):
|
||
layer = MagicMock()
|
||
_fuege_vkz_feld_hinzu(layer, None)
|
||
layer.dataProvider.assert_not_called()
|
||
|
||
def test_vkz_field_added(self):
|
||
pr = MagicMock()
|
||
pr.addAttributes.return_value = True
|
||
pr.changeAttributeValues.return_value = True
|
||
layer = MagicMock()
|
||
layer.dataProvider.return_value = pr
|
||
layer.fields.return_value.indexFromName.return_value = 2
|
||
layer.getFeatures.return_value = []
|
||
_fuege_vkz_feld_hinzu(layer, "VF-2024-001")
|
||
pr.addAttributes.assert_called_once()
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Tests: _vergleiche_flaechen / _lese_flaechen_toleranz
|
||
# ---------------------------------------------------------------------------
|
||
|
||
class TestFlaechenvergleich(unittest.TestCase):
|
||
|
||
def _layer(self, area: float):
|
||
layer = MagicMock()
|
||
geom = MagicMock()
|
||
geom.isEmpty.return_value = False
|
||
geom.area.return_value = area
|
||
feat = MagicMock()
|
||
feat.geometry.return_value = geom
|
||
layer.getFeatures.return_value = [feat]
|
||
return layer
|
||
|
||
def test_gleiche_flaeche_stimmt_ueberein(self):
|
||
self.assertTrue(_vergleiche_flaechen(self._layer(1234.5), self._layer(1234.5), 0.0)[2])
|
||
|
||
def test_verschiedene_flaeche_stimmt_nicht_ueberein(self):
|
||
self.assertFalse(_vergleiche_flaechen(self._layer(1234.5), self._layer(1200.0), 0.0)[2])
|
||
|
||
def test_differenz_innerhalb_toleranz(self):
|
||
self.assertTrue(_vergleiche_flaechen(self._layer(1234.5), self._layer(1234.8), 1.0)[2])
|
||
|
||
def test_differenz_ausserhalb_toleranz(self):
|
||
self.assertFalse(_vergleiche_flaechen(self._layer(1234.5), self._layer(1236.0), 1.0)[2])
|
||
|
||
def test_flaechen_werte_korrekt(self):
|
||
bror_f, vg_f, _ = _vergleiche_flaechen(self._layer(800.0), self._layer(750.0))
|
||
self.assertAlmostEqual(bror_f, 800.0)
|
||
self.assertAlmostEqual(vg_f, 750.0)
|
||
|
||
@patch(f"{_MOD}.get_variable", return_value=None)
|
||
def test_lese_toleranz_default_ist_null(self, _):
|
||
self.assertEqual(_lese_flaechen_toleranz(), 0.0)
|
||
|
||
@patch(f"{_MOD}.get_variable", return_value="2.5")
|
||
def test_lese_toleranz_parst_string(self, _):
|
||
self.assertAlmostEqual(_lese_flaechen_toleranz(), 2.5)
|
||
|
||
@patch(f"{_MOD}.get_variable", return_value="ungueltig")
|
||
def test_lese_toleranz_ungueltig_fallback_null(self, _):
|
||
self.assertEqual(_lese_flaechen_toleranz(), 0.0)
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Tests: verfahrensgebiet_alkis_komplett (Hauptworkflow)
|
||
# ---------------------------------------------------------------------------
|
||
|
||
class TestVerfahrensgebietAlkisKomplett(unittest.TestCase):
|
||
|
||
# ------------------------------------------------------------------ #
|
||
# Abbruchpfade
|
||
# ------------------------------------------------------------------ #
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_PROJECT)
|
||
@patch(_PATCH_VG_ALKIS)
|
||
@patch(_PATCH_GET_VAR, return_value="VF-2024-001")
|
||
def test_vg_alkis_none_aborts(self, mock_get_var, mock_vg, mock_proj, mock_prog):
|
||
mock_proj.instance.return_value = _DummyProject()
|
||
mock_vg.return_value = (None, LoadStatus.NONE, {}, None)
|
||
mock_prog.return_value = _make_progress_mock()
|
||
|
||
enriched, flst, bror, status = verfahrensgebiet_alkis_komplett(None)
|
||
|
||
self.assertIsNone(enriched)
|
||
self.assertIsNone(flst)
|
||
self.assertIsNone(bror)
|
||
self.assertEqual(status, LoadStatus.NONE)
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_PROJECT)
|
||
@patch(_PATCH_GEM)
|
||
@patch(_PATCH_VG_ALKIS)
|
||
@patch(_PATCH_GET_VAR, return_value="VF-2024-001")
|
||
def test_flst_none_aborts(self, mock_get_var, mock_vg, mock_gem, mock_proj, mock_prog):
|
||
mock_proj.instance.return_value = _DummyProject()
|
||
vg_layer = _make_layer(name="BauRaumOrdnungsrecht (ALKIS)")
|
||
mock_vg.return_value = (vg_layer, LoadStatus.FIRST, {}, None)
|
||
mock_gem.return_value = [("1234", "Muster")]
|
||
mock_prog.return_value = _make_progress_mock()
|
||
|
||
with patch(_PATCH_FLST, return_value=(None, LoadStatus.NONE)):
|
||
enriched, flst, bror, status = verfahrensgebiet_alkis_komplett(None)
|
||
|
||
self.assertIsNone(enriched)
|
||
self.assertIsNone(flst)
|
||
self.assertEqual(status, LoadStatus.NONE)
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_MSGBOX)
|
||
@patch(_PATCH_SELECT)
|
||
@patch(_PATCH_PROJECT)
|
||
@patch(_PATCH_GEM)
|
||
@patch(_PATCH_FLST)
|
||
@patch(_PATCH_VG_ALKIS)
|
||
@patch(_PATCH_GET_VAR, return_value="VF-2024-001")
|
||
def test_no_selection_returns_none_enriched(
|
||
self, mock_get_var, mock_vg, mock_flst, mock_gem, mock_proj, mock_select, mock_msgbox, mock_prog
|
||
):
|
||
mock_proj.instance.return_value = _DummyProject()
|
||
vg_layer = _make_layer(name="BauRaumOrdnungsrecht (ALKIS)")
|
||
flst_layer = _make_layer(name="Flurstücke")
|
||
mock_vg.return_value = (vg_layer, LoadStatus.FIRST, {}, None)
|
||
mock_gem.return_value = []
|
||
mock_flst.return_value = (flst_layer, LoadStatus.FIRST)
|
||
mock_select.return_value = 0
|
||
mock_prog.return_value = _make_progress_mock()
|
||
|
||
enriched, flst, bror, status = verfahrensgebiet_alkis_komplett(None)
|
||
|
||
self.assertIsNone(enriched)
|
||
self.assertIs(flst, flst_layer)
|
||
self.assertIsNone(bror)
|
||
self.assertEqual(status, LoadStatus.NONE)
|
||
mock_msgbox.warning.assert_called_once()
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_MSGBOX)
|
||
@patch(_PATCH_ERSTELLE)
|
||
@patch(_PATCH_SELECT)
|
||
@patch(_PATCH_PROJECT)
|
||
@patch(_PATCH_GEM)
|
||
@patch(_PATCH_FLST)
|
||
@patch(_PATCH_VG_ALKIS)
|
||
@patch(_PATCH_GET_VAR, return_value="VF-2024-001")
|
||
def test_invalid_enriched_layer_returns_none(
|
||
self, mock_get_var, mock_vg, mock_flst, mock_gem, mock_proj, mock_select, mock_erstelle, mock_msgbox, mock_prog
|
||
):
|
||
mock_proj.instance.return_value = _DummyProject()
|
||
vg_layer = _make_layer(name="BauRaumOrdnungsrecht (ALKIS)")
|
||
flst_layer = _make_layer(name="Flurstücke")
|
||
bad_enriched = _make_layer(valid=False)
|
||
|
||
mock_vg.return_value = (vg_layer, LoadStatus.FIRST, {}, None)
|
||
mock_gem.return_value = []
|
||
mock_flst.return_value = (flst_layer, LoadStatus.FIRST)
|
||
mock_select.return_value = 5
|
||
mock_erstelle.return_value = (bad_enriched, 0, 5)
|
||
mock_prog.return_value = _make_progress_mock()
|
||
|
||
enriched, flst, bror, status = verfahrensgebiet_alkis_komplett(None)
|
||
|
||
self.assertIsNone(enriched)
|
||
self.assertIs(flst, flst_layer)
|
||
self.assertIsNone(bror)
|
||
self.assertEqual(status, LoadStatus.NONE)
|
||
mock_msgbox.critical.assert_called_once()
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_PROJECT)
|
||
@patch(_PATCH_VG_ALKIS)
|
||
@patch(_PATCH_GET_VAR, return_value="VF-2024-001")
|
||
def test_progress_cancel_after_step1_returns_none(self, mock_get_var, mock_vg, mock_proj, mock_prog):
|
||
"""Abbruch nach Schritt 1 → sofortiger sauberer Rückgabestatus."""
|
||
mock_proj.instance.return_value = _DummyProject()
|
||
vg_layer = _make_layer(name="BauRaumOrdnungsrecht (ALKIS)")
|
||
mock_vg.return_value = (vg_layer, LoadStatus.FIRST, {}, None)
|
||
|
||
prog = MagicMock()
|
||
prog.is_canceled.side_effect = [False, True] # 1. Aufruf False, 2. True
|
||
mock_prog.return_value = prog
|
||
|
||
enriched, flst, bror, status = verfahrensgebiet_alkis_komplett(None)
|
||
|
||
self.assertIsNone(enriched)
|
||
self.assertEqual(status, LoadStatus.NONE)
|
||
|
||
# ------------------------------------------------------------------ #
|
||
# Flächenvergleich – Übereinstimmung
|
||
# ------------------------------------------------------------------ #
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_SHOW_INFO)
|
||
@patch(_PATCH_VERGLEICHE)
|
||
@patch(_PATCH_VKZ)
|
||
@patch(_PATCH_GET_VAR)
|
||
@patch(_PATCH_ERSTELLE)
|
||
@patch(_PATCH_SELECT)
|
||
@patch(_PATCH_PROJECT)
|
||
@patch(_PATCH_GEM)
|
||
@patch(_PATCH_FLST)
|
||
@patch(_PATCH_VG_ALKIS)
|
||
def test_success_flaechen_match_zeigt_info(
|
||
self, mock_vg, mock_flst, mock_gem, mock_proj, mock_select,
|
||
mock_erstelle, mock_get_var, mock_vkz, mock_vergl, mock_info, mock_prog,
|
||
):
|
||
"""Flächenübereinstimmung → show_info_dialog mit erwartetem Text."""
|
||
proj_inst = _DummyProject()
|
||
mock_proj.instance.return_value = proj_inst
|
||
|
||
vg_layer = _make_layer(name="BauRaumOrdnungsrecht (ALKIS)")
|
||
flst_layer = _make_layer(name="Flurstücke", lid="FLST1")
|
||
enriched = _make_layer(name="Verfahrensgebiet", lid="VG_ENRICHED", valid=True)
|
||
|
||
mock_vg.return_value = (vg_layer, LoadStatus.FIRST, {}, None)
|
||
mock_gem.return_value = [("1234", "Muster")]
|
||
mock_flst.return_value = (flst_layer, LoadStatus.FIRST)
|
||
mock_select.return_value = 3
|
||
mock_erstelle.return_value = (enriched, 3, 0)
|
||
mock_get_var.return_value = "VF-2024-001"
|
||
mock_vergl.return_value = (1234.5, 1234.5, True)
|
||
mock_prog.return_value = _make_progress_mock()
|
||
|
||
result_enriched, result_flst, result_bror, status = verfahrensgebiet_alkis_komplett(None)
|
||
|
||
self.assertIs(result_enriched, enriched)
|
||
self.assertIs(result_flst, flst_layer)
|
||
self.assertIs(result_bror, vg_layer)
|
||
self.assertEqual(status, LoadStatus.FIRST)
|
||
mock_vkz.assert_called_once_with(enriched, "VF-2024-001")
|
||
mock_info.assert_called_once()
|
||
self.assertIn("erwarteter Geometrie", mock_info.call_args[0][1])
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_SHOW_INFO)
|
||
@patch(_PATCH_VERGLEICHE)
|
||
@patch(_PATCH_VKZ)
|
||
@patch(_PATCH_GET_VAR)
|
||
@patch(_PATCH_ERSTELLE)
|
||
@patch(_PATCH_SELECT)
|
||
@patch(_PATCH_PROJECT)
|
||
@patch(_PATCH_GEM)
|
||
@patch(_PATCH_FLST)
|
||
@patch(_PATCH_VG_ALKIS)
|
||
def test_no_vkz_variable_passes_empty_string(
|
||
self, mock_vg, mock_flst, mock_gem, mock_proj, mock_select,
|
||
mock_erstelle, mock_get_var, mock_vkz, mock_vergl, mock_info, mock_prog,
|
||
):
|
||
mock_proj.instance.return_value = _DummyProject()
|
||
vg_layer = _make_layer(name="BauRaumOrdnungsrecht (ALKIS)")
|
||
flst_layer = _make_layer(name="Flurstücke")
|
||
enriched = _make_layer(name="Verfahrensgebiet", valid=True)
|
||
|
||
mock_vg.return_value = (vg_layer, LoadStatus.FIRST, {}, None)
|
||
mock_gem.return_value = []
|
||
mock_flst.return_value = (flst_layer, LoadStatus.FIRST)
|
||
mock_select.return_value = 2
|
||
mock_erstelle.return_value = (enriched, 2, 0)
|
||
mock_get_var.return_value = "VF-2024-001"
|
||
mock_vergl.return_value = (1000.0, 1000.0, True)
|
||
mock_prog.return_value = _make_progress_mock()
|
||
|
||
verfahrensgebiet_alkis_komplett(None)
|
||
|
||
mock_vkz.assert_called_once_with(enriched, "VF-2024-001")
|
||
|
||
# ------------------------------------------------------------------ #
|
||
# Flächenvergleich – Abweichung + Abbrechen
|
||
# ------------------------------------------------------------------ #
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_KNICK)
|
||
@patch(_PATCH_ASK_DIALOG)
|
||
@patch(_PATCH_VERGLEICHE)
|
||
@patch(_PATCH_VKZ)
|
||
@patch(_PATCH_GET_VAR)
|
||
@patch(_PATCH_ERSTELLE)
|
||
@patch(_PATCH_SELECT)
|
||
@patch(_PATCH_PROJECT)
|
||
@patch(_PATCH_GEM)
|
||
@patch(_PATCH_FLST)
|
||
@patch(_PATCH_VG_ALKIS)
|
||
def test_flaechen_abweichung_abbrechen_kein_detailcheck(
|
||
self, mock_vg, mock_flst, mock_gem, mock_proj, mock_select,
|
||
mock_erstelle, mock_get_var, mock_vkz, mock_vergl, mock_ask, mock_knick, mock_prog,
|
||
):
|
||
"""Abweichung + Abbrechen → knickpunkt_pruefung wird NICHT aufgerufen."""
|
||
mock_proj.instance.return_value = _DummyProject()
|
||
vg_layer = _make_layer(name="BauRaumOrdnungsrecht (ALKIS)")
|
||
flst_layer = _make_layer(name="Flurstücke")
|
||
enriched = _make_layer(name="Verfahrensgebiet", valid=True)
|
||
|
||
mock_vg.return_value = (vg_layer, LoadStatus.FIRST, {}, None)
|
||
mock_gem.return_value = []
|
||
mock_flst.return_value = (flst_layer, LoadStatus.FIRST)
|
||
mock_select.return_value = 3
|
||
mock_erstelle.return_value = (enriched, 3, 0)
|
||
mock_get_var.return_value = "VF-2024-001"
|
||
mock_vergl.return_value = (1000.0, 800.0, False)
|
||
mock_ask.return_value = "abbrechen"
|
||
mock_prog.return_value = _make_progress_mock()
|
||
|
||
result_enriched, _, _, status = verfahrensgebiet_alkis_komplett(None)
|
||
|
||
mock_knick.assert_not_called()
|
||
self.assertIs(result_enriched, enriched)
|
||
self.assertEqual(status, LoadStatus.FIRST)
|
||
|
||
# ------------------------------------------------------------------ #
|
||
# Flächenvergleich – Abweichung + Als VG laden
|
||
# ------------------------------------------------------------------ #
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_KNICK)
|
||
@patch(_PATCH_ASK_DIALOG)
|
||
@patch(_PATCH_VERGLEICHE)
|
||
@patch(_PATCH_VKZ)
|
||
@patch(_PATCH_GET_VAR)
|
||
@patch(_PATCH_ERSTELLE)
|
||
@patch(_PATCH_SELECT)
|
||
@patch(_PATCH_PROJECT)
|
||
@patch(_PATCH_GEM)
|
||
@patch(_PATCH_FLST)
|
||
@patch(_PATCH_VG_ALKIS)
|
||
def test_flaechen_abweichung_als_vg_laden(
|
||
self, mock_vg, mock_flst, mock_gem, mock_proj, mock_select,
|
||
mock_erstelle, mock_get_var, mock_vkz, mock_vergl, mock_ask, mock_knick, mock_prog,
|
||
):
|
||
"""Abweichung + Als VG laden → BROR-Layer wird umbenannt und als
|
||
enriched_layer zurückgegeben; flst_layer und bror_layer sind None."""
|
||
proj_inst = _DummyProject()
|
||
mock_proj.instance.return_value = proj_inst
|
||
|
||
vg_layer = _make_layer(name="BauRaumOrdnungsrecht (ALKIS)", lid="BROR_VG")
|
||
flst_layer = _make_layer(name="Flurstücke")
|
||
enriched = _make_layer(name="Verfahrensgebiet", valid=True)
|
||
|
||
mock_vg.return_value = (vg_layer, LoadStatus.FIRST, {}, None)
|
||
mock_gem.return_value = []
|
||
mock_flst.return_value = (flst_layer, LoadStatus.FIRST)
|
||
mock_select.return_value = 3
|
||
mock_erstelle.return_value = (enriched, 3, 0)
|
||
mock_get_var.return_value = "VF-2024-001"
|
||
mock_vergl.return_value = (1000.0, 800.0, False)
|
||
mock_ask.return_value = "als_vg_laden"
|
||
mock_prog.return_value = _make_progress_mock()
|
||
|
||
result_enriched, result_flst, result_bror, status = verfahrensgebiet_alkis_komplett(None)
|
||
|
||
mock_knick.assert_not_called()
|
||
# BROR-Layer wird als enriched_layer zurückgegeben
|
||
self.assertIs(result_enriched, vg_layer)
|
||
self.assertIsNone(result_flst)
|
||
self.assertIsNone(result_bror)
|
||
self.assertEqual(status, LoadStatus.FIRST)
|
||
# Name wurde auf VERF_LAYER_NAME geändert
|
||
vg_layer.setName.assert_called()
|
||
|
||
# ------------------------------------------------------------------ #
|
||
# Flächenvergleich – Abweichung + Detailprüfung
|
||
# ------------------------------------------------------------------ #
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_SHOW_INFO)
|
||
@patch(_PATCH_EXTRAHIERE)
|
||
@patch(_PATCH_KNICK)
|
||
@patch(_PATCH_GP_ALKIS)
|
||
@patch(_PATCH_ASK_DIALOG)
|
||
@patch(_PATCH_VERGLEICHE)
|
||
@patch(_PATCH_VKZ)
|
||
@patch(_PATCH_GET_VAR)
|
||
@patch(_PATCH_ERSTELLE)
|
||
@patch(_PATCH_SELECT)
|
||
@patch(_PATCH_PROJECT)
|
||
@patch(_PATCH_GEM)
|
||
@patch(_PATCH_FLST)
|
||
@patch(_PATCH_VG_ALKIS)
|
||
def test_flaechen_abweichung_detailpruefung_startet_knickpruefung(
|
||
self, mock_vg, mock_flst, mock_gem, mock_proj, mock_select,
|
||
mock_erstelle, mock_get_var, mock_vkz, mock_vergl, mock_ask,
|
||
mock_gp, mock_knick, mock_extrahiere, mock_info, mock_prog,
|
||
):
|
||
"""Abweichung + Detailprüfung → lade_punktort_ta + knickpunkt_pruefung
|
||
aufgerufen, Ergebnislayer ins Projekt, Abschlussmeldung mit Zählung."""
|
||
proj_inst = _DummyProject()
|
||
mock_proj.instance.return_value = proj_inst
|
||
|
||
vg_layer = _make_layer(name="BauRaumOrdnungsrecht (ALKIS)")
|
||
flst_layer = _make_layer(name="Flurstücke")
|
||
enriched = _make_layer(name="Verfahrensgebiet", valid=True)
|
||
punktort_layer = _make_layer(name="PunktortTA", lid="PTA_L")
|
||
ergebnis_layer = _make_layer(name="Knickpunktprüfung", lid="KNICK_L")
|
||
|
||
mock_vg.return_value = (vg_layer, LoadStatus.FIRST, {}, None)
|
||
mock_gem.return_value = []
|
||
mock_flst.return_value = (flst_layer, LoadStatus.FIRST)
|
||
mock_select.return_value = 3
|
||
mock_erstelle.return_value = (enriched, 3, 0)
|
||
mock_get_var.return_value = "VF-2024-001"
|
||
mock_vergl.return_value = (1000.0, 800.0, False)
|
||
mock_ask.return_value = "detailpruefung"
|
||
mock_extrahiere.return_value = [MagicMock(), MagicMock(), MagicMock()] # 3 Knickpunkte
|
||
mock_gp.return_value = punktort_layer
|
||
mock_knick.return_value = (ergebnis_layer, 2, 1, 0)
|
||
mock_prog.return_value = _make_progress_mock()
|
||
|
||
result_enriched, _, _, status = verfahrensgebiet_alkis_komplett(None)
|
||
|
||
mock_gp.assert_called_once()
|
||
mock_knick.assert_called_once()
|
||
self.assertIn(ergebnis_layer, proj_inst.added)
|
||
mock_info.assert_called_once()
|
||
# Abschlussmeldung muss Zahlen enthalten
|
||
info_text = mock_info.call_args[0][1]
|
||
self.assertIn("3", info_text) # Anzahl Knickpunkte
|
||
self.assertIn("2", info_text) # identisch
|
||
self.assertIn("1", info_text) # kein_pta
|
||
self.assertEqual(status, LoadStatus.FIRST)
|
||
|
||
# ------------------------------------------------------------------ #
|
||
# Cleanup-Verhalten
|
||
# ------------------------------------------------------------------ #
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_SHOW_INFO)
|
||
@patch(_PATCH_VERGLEICHE)
|
||
@patch(_PATCH_VKZ)
|
||
@patch(_PATCH_GET_VAR)
|
||
@patch(_PATCH_ERSTELLE)
|
||
@patch(_PATCH_SELECT)
|
||
@patch(_PATCH_PROJECT)
|
||
@patch(_PATCH_GEM)
|
||
@patch(_PATCH_FLST)
|
||
@patch(_PATCH_VG_ALKIS)
|
||
def test_bror_layer_bleibt_bei_erfolg_im_projekt(
|
||
self, mock_vg, mock_flst, mock_gem, mock_proj, mock_select,
|
||
mock_erstelle, mock_get_var, mock_vkz, mock_vergl, mock_info, mock_prog,
|
||
):
|
||
"""Bei Erfolg darf der BROR-Layer NICHT entfernt werden."""
|
||
proj_inst = _DummyProject()
|
||
mock_proj.instance.return_value = proj_inst
|
||
|
||
vg_layer = _make_layer(name="BauRaumOrdnungsrecht (ALKIS)", lid="BROR_ID")
|
||
flst_layer = _make_layer(name="Flurstücke")
|
||
enriched = _make_layer(name="Verfahrensgebiet", valid=True)
|
||
|
||
mock_vg.return_value = (vg_layer, LoadStatus.FIRST, {}, None)
|
||
mock_gem.return_value = []
|
||
mock_flst.return_value = (flst_layer, LoadStatus.FIRST)
|
||
mock_select.return_value = 3
|
||
mock_erstelle.return_value = (enriched, 3, 0)
|
||
mock_get_var.return_value = "VF-2024-001"
|
||
mock_vergl.return_value = (1000.0, 1000.0, True)
|
||
mock_prog.return_value = _make_progress_mock()
|
||
|
||
verfahrensgebiet_alkis_komplett(None)
|
||
|
||
self.assertNotIn("BROR_ID", proj_inst.removed)
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_PROJECT)
|
||
@patch(_PATCH_GEM)
|
||
@patch(_PATCH_VG_ALKIS)
|
||
@patch(_PATCH_GET_VAR, return_value="VF-2024-001")
|
||
def test_bror_layer_wird_bei_fehler_entfernt(
|
||
self, mock_get_var, mock_vg, mock_gem, mock_proj, mock_prog
|
||
):
|
||
"""Bei Fehler (flst_alkis NONE) wird der BROR-Layer aus dem Projekt entfernt."""
|
||
proj_inst = _DummyProject()
|
||
mock_proj.instance.return_value = proj_inst
|
||
|
||
vg_layer = _make_layer(name="BauRaumOrdnungsrecht (ALKIS)", lid="BROR_ERR")
|
||
mock_vg.return_value = (vg_layer, LoadStatus.FIRST, {}, None)
|
||
mock_gem.return_value = []
|
||
mock_prog.return_value = _make_progress_mock()
|
||
|
||
with patch(_PATCH_FLST, return_value=(None, LoadStatus.NONE)):
|
||
verfahrensgebiet_alkis_komplett(None)
|
||
|
||
self.assertIn("BROR_ERR", proj_inst.removed)
|
||
|
||
# ------------------------------------------------------------------ #
|
||
# Landkreis-Fallback (keine Verfahrensnummer)
|
||
# ------------------------------------------------------------------ #
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_MSGBOX)
|
||
@patch(_PATCH_ASK_LANDKREIS, return_value=None)
|
||
@patch(_PATCH_GET_VAR, return_value="")
|
||
def test_kein_vkz_kein_landkreis_dialog_abgebrochen(
|
||
self, mock_get_var, mock_ask_landkreis, mock_msgbox, mock_prog
|
||
):
|
||
"""Weder Verfahrensnummer noch Landkreis gesetzt, Nutzer bricht den
|
||
Landkreis-Auswahldialog ab → stiller Abbruch, kein Layer, KEINE
|
||
Fehlermeldung (bewusster Abbruch, kein Fehlerzustand)."""
|
||
enriched, flst, bror, status = verfahrensgebiet_alkis_komplett(None)
|
||
|
||
self.assertIsNone(enriched)
|
||
self.assertIsNone(flst)
|
||
self.assertIsNone(bror)
|
||
self.assertEqual(status, LoadStatus.NONE)
|
||
mock_msgbox.critical.assert_not_called()
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_PROJECT)
|
||
@patch(_PATCH_LANDKREIS_BAU)
|
||
@patch(_PATCH_LANDKREIS_SUCHE)
|
||
@patch(_PATCH_ASK_LANDKREIS, return_value="22")
|
||
@patch(_PATCH_GET_VAR, return_value="")
|
||
def test_kein_vkz_kein_landkreis_dialog_liefert_landkreis(
|
||
self, mock_get_var, mock_ask_landkreis, mock_such, mock_bau, mock_proj, mock_prog
|
||
):
|
||
"""Weder Verfahrensnummer noch Landkreis gesetzt, Nutzer wählt einen
|
||
Landkreis im Dialog → Landkreis-Suchpfad wird mit dieser Kennzahl
|
||
verwendet (wie im Fall 'Landkreis aus Projekteigenschaften')."""
|
||
proj_inst = _DummyProject()
|
||
mock_proj.instance.return_value = proj_inst
|
||
vg_layer = _make_layer(name="BauRaumOrdnungsrecht (ALKIS)")
|
||
mock_such.return_value = (None, LoadStatus.FIRST, {("A", "22015"): [MagicMock()]}, "EPSG:25833")
|
||
mock_bau.return_value = (vg_layer, LoadStatus.FIRST, True) # nur_laden=True
|
||
mock_prog.return_value = _make_progress_mock()
|
||
|
||
enriched, flst, bror, status = verfahrensgebiet_alkis_komplett(None)
|
||
|
||
mock_ask_landkreis.assert_called_once()
|
||
mock_such.assert_called_once_with(None, "22")
|
||
mock_bau.assert_called_once()
|
||
self.assertIs(enriched, vg_layer)
|
||
self.assertEqual(status, LoadStatus.FIRST)
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_PROJECT)
|
||
@patch(_PATCH_LANDKREIS_BAU)
|
||
@patch(_PATCH_LANDKREIS_SUCHE)
|
||
def test_landkreis_modus_wird_bei_fehlender_vkz_verwendet(
|
||
self, mock_such, mock_bau, mock_proj, mock_prog
|
||
):
|
||
"""Keine Verfahrensnummer, aber Landkreis gesetzt → Landkreis-Suchpfad
|
||
statt VKZ-Pfad wird verwendet."""
|
||
|
||
def _get_var_side_effect(key, scope="project"):
|
||
return {"verfahrensnummer": "", "landkreis_kennzahl": "22"}.get(key, "")
|
||
|
||
proj_inst = _DummyProject()
|
||
mock_proj.instance.return_value = proj_inst
|
||
vg_layer = _make_layer(name="BauRaumOrdnungsrecht (ALKIS)")
|
||
mock_such.return_value = (None, LoadStatus.FIRST, {("A", "22015"): [MagicMock()]}, "EPSG:25833")
|
||
mock_bau.return_value = (vg_layer, LoadStatus.FIRST, True) # nur_laden=True
|
||
mock_prog.return_value = _make_progress_mock()
|
||
|
||
with patch(_PATCH_GET_VAR, side_effect=_get_var_side_effect):
|
||
enriched, flst, bror, status = verfahrensgebiet_alkis_komplett(None)
|
||
|
||
mock_such.assert_called_once()
|
||
mock_bau.assert_called_once()
|
||
self.assertIs(enriched, vg_layer)
|
||
self.assertIsNone(flst)
|
||
self.assertIsNone(bror)
|
||
self.assertEqual(status, LoadStatus.FIRST)
|
||
|
||
@patch(_PATCH_PROGRESS)
|
||
@patch(_PATCH_PROJECT)
|
||
@patch(_PATCH_LANDKREIS_BAU)
|
||
@patch(_PATCH_LANDKREIS_SUCHE)
|
||
def test_landkreis_modus_nur_laden_ueberspringt_dialog2(
|
||
self, mock_such, mock_bau, mock_proj, mock_prog
|
||
):
|
||
"""nur_laden=True → Funktion kehrt sofort zurück, Dialog 2 (Gemarkung
|
||
etc.) wird nicht gestartet."""
|
||
|
||
def _get_var_side_effect(key, scope="project"):
|
||
return {"verfahrensnummer": "", "landkreis_kennzahl": "22"}.get(key, "")
|
||
|
||
proj_inst = _DummyProject()
|
||
mock_proj.instance.return_value = proj_inst
|
||
vg_layer = _make_layer(name="BauRaumOrdnungsrecht (ALKIS)")
|
||
mock_such.return_value = (None, LoadStatus.FIRST, {("A", "22015"): [MagicMock()]}, "EPSG:25833")
|
||
mock_bau.return_value = (vg_layer, LoadStatus.FIRST, True)
|
||
mock_prog.return_value = _make_progress_mock()
|
||
|
||
with patch(_PATCH_GET_VAR, side_effect=_get_var_side_effect), \
|
||
patch(_PATCH_GEM) as mock_gem:
|
||
verfahrensgebiet_alkis_komplett(None)
|
||
mock_gem.assert_not_called()
|
||
|
||
|
||
if __name__ == "__main__":
|
||
unittest.main()
|
||
|