Files
Plugin_SN_Basis/tests/test_print_tab.py
T
DanielandClaude Sonnet 5 8eb89e92a7 Kategorie "vielleicht testen" in sn_basis abgeschlossen (#67)
37 neue Testfälle für die 31 verbleibenden "vielleicht testen"-
Funktionen: os_wrapper.is_case_sensitive_fs, qgiscore_wrapper.
create_buffer_layer (nur die Wächter, echte Pufferlogik importiert
qgis.core direkt), qgisui_wrapper.find_dock_widgets/add_menu/remove_menu,
DataGrabber._aggregate_results, pruef_ergebnis.dateipfad,
Navigation (add_action, finalize_menu_and_toolbar, set_active_plugin,
remove_action, remove_all), SettingsTab._build_input und PrintTab
(18 Methoden: Zustandslogik, Signal-Handling, Atlas-/Theme-Verwaltung).

PrintTab._build_ui bekommt stattdessen den Vermerk "von Test abgesehen,
weil vernachlässigbar; HD 18.09.2026" - reine Qt-Widget-Konstruktion ohne
eigenständig prüfbare Logik. Damit ist die Kategorie "vielleicht testen"
für sn_basis aufgelöst: jede Funktion ist jetzt getestet oder mit einem
begründeten Vermerk versehen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 13:06:06 +02:00

650 lines
27 KiB
Python

"""Tests für sn_basis/ui/tabs/print_tab.py::PrintTab (Issue #67).
self.logic ist eine PrintLogic-Instanz (modules/print_logic.py) - die Klasse steht wegen einer
geplanten Grundüberarbeitung komplett unter "Test ausgesetzt, zunächst Refactor" (#63/#65). Wo eine
PrintTab-Methode self.logic.irgendwas(...) aufruft, wird self.logic hier durch ein Fake/Mock ersetzt;
geprüft wird nur, dass PrintTab die richtige Methode mit den richtigen Argumenten aufruft, nie das
tatsächliche PrintLogic-Verhalten.
PrintTab(QWidget) erbt von der im Mock-Modus leeren _MockWidget-Klasse (kein setLayout() usw.) - wie bei
SettingsTab/BaseDockWidget wird nie PrintTab() echt konstruiert, sondern PrintTab.__new__(PrintTab) mit
den je Test nötigen Instanzattributen von Hand.
"""
import unittest
from unittest.mock import MagicMock, call, patch
from sn_basis.functions.qt_wrapper import ArrowDown, ArrowRight
from sn_basis.ui.tabs.print_tab import (
ATLAS_ERZEUGEN_VAR,
DRUCKBEREICH_VAR,
DRUCKBEREICH_VERFAHRENSGEBIET,
DRUCKPUFFER_STANDARD_CM,
DRUCKPUFFER_VAR,
FORMFAKTOR_UI_VAR,
KARTENNAME_38,
KARTENNAME_PLACEHOLDER,
KARTENNAME_VAR,
MASSSTAB_VAR,
MASSSTAB_WIE_KARTENFENSTER,
PLOTMASSSTAB_BY_AUSWAHL,
THEMA_VAR,
THEMA_WIE_KARTENFENSTER,
DIN_STANDARD,
PrintTab,
ZIELGROESSE_UI_VAR,
)
def _neuer_tab() -> PrintTab:
return PrintTab.__new__(PrintTab)
class _FakeCombo:
def __init__(self, text: str = "") -> None:
self._text = text
self.added_items: list = []
def currentText(self) -> str:
return self._text
def setCurrentText(self, value: str) -> None:
self._text = value
def clear(self) -> None:
self.added_items = []
def addItems(self, items) -> None:
self.added_items.extend(items)
def blockSignals(self, value: bool) -> None:
pass
class _FakeCheckbox:
def __init__(self, checked: bool = False) -> None:
self._checked = checked
def isChecked(self) -> bool:
return self._checked
def setChecked(self, value: bool) -> None:
self._checked = value
class _FakeButton:
def __init__(self, text: str = "") -> None:
self._text = text
def setText(self, value: str) -> None:
self._text = value
def text(self) -> str:
return self._text
class _FakePruefmanager:
def __init__(self, frage_text_ergebnis) -> None:
self._frage_text_ergebnis = frage_text_ergebnis
self.zeige_hinweis_calls: list = []
def frage_text(self, titel, meldung, default_text=""):
return self._frage_text_ergebnis
def zeige_hinweis(self, titel, meldung) -> None:
self.zeige_hinweis_calls.append((titel, meldung))
class _FakeSignal:
def __init__(self) -> None:
self.connected: list = []
def connect(self, fn) -> None:
self.connected.append(fn)
def disconnect(self, fn) -> None:
self.connected.remove(fn)
class _FakeProjectSignals:
def __init__(self) -> None:
self.readProject = _FakeSignal()
self.newProjectCreated = _FakeSignal()
self.cleared = _FakeSignal()
class _FakeThemeCollection:
def __init__(self) -> None:
self.mapThemesChanged = _FakeSignal()
self.changed = _FakeSignal()
self.themeChanged = _FakeSignal()
class SetServicesTests(unittest.TestCase):
@patch("sn_basis.ui.tabs.print_tab.PrintLogic")
def test_ruft_alle_set_methoden_mit_combo_werten_auf(self, mock_logic_cls):
"""Prüft, dass set_services alle set_*-Methoden von PrintLogic mit den aktuellen Combo-Werten aufruft."""
tab = _neuer_tab()
tab._kartenname_combo = _FakeCombo("§38")
tab._massstab_combo = _FakeCombo("1:1000")
tab._thema_combo = _FakeCombo("Thema A")
tab._zielgroesse_combo = _FakeCombo("A3")
tab._druckbereich_combo = _FakeCombo("Verfahrensgebiet")
tab._endlosrolle_cb = _FakeCheckbox(True)
tab._get_current_canvas_scale = lambda: 5000.0
mock_logic = mock_logic_cls.return_value
pruefmanager = object()
tab.set_services(pruefmanager, object())
self.assertIs(tab.pruefmanager, pruefmanager)
mock_logic.set_kartenname_for_auswahl.assert_called_once_with("§38")
mock_logic.set_plotmassstab_for_auswahl.assert_called_once_with("1:1000", 5000.0)
mock_logic.set_view_for_auswahl.assert_called_once_with("Thema A")
mock_logic.set_zielgroesse_for_auswahl.assert_called_once_with("A3")
mock_logic.set_druckbereich_for_auswahl.assert_called_once_with("Verfahrensgebiet")
mock_logic.set_formfaktor.assert_called_once_with(True)
@patch("sn_basis.ui.tabs.print_tab.PrintLogic")
def test_ohne_combos_ruft_keine_set_methode_auf(self, mock_logic_cls):
"""Prüft, dass set_services ohne vorhandene Combos keine set_*-Methode von PrintLogic aufruft."""
tab = _neuer_tab()
tab._kartenname_combo = None
tab._massstab_combo = None
tab._thema_combo = None
tab._zielgroesse_combo = None
tab._druckbereich_combo = None
tab._endlosrolle_cb = None
mock_logic = mock_logic_cls.return_value
tab.set_services(object(), object())
mock_logic.set_kartenname_for_auswahl.assert_not_called()
mock_logic.set_plotmassstab_for_auswahl.assert_not_called()
mock_logic.set_view_for_auswahl.assert_not_called()
mock_logic.set_zielgroesse_for_auswahl.assert_not_called()
mock_logic.set_druckbereich_for_auswahl.assert_not_called()
mock_logic.set_formfaktor.assert_not_called()
self.assertIs(tab.logic, mock_logic)
class RestoreStateTests(unittest.TestCase):
def _neuer_tab_mit_widgets(self) -> PrintTab:
tab = _neuer_tab()
tab._kartenname_combo = _FakeCombo()
tab._massstab_combo = _FakeCombo()
tab._thema_combo = _FakeCombo()
tab._zielgroesse_combo = _FakeCombo()
tab._endlosrolle_cb = _FakeCheckbox()
tab._druckbereich_combo = _FakeCombo()
tab._druckpuffer_button = _FakeButton()
tab._atlas_erzeugen_cb = None
tab._atlas_layer_combo = None
tab._get_gespeicherte_themen = lambda: ["Thema A"]
return tab
def test_gueltige_gespeicherte_werte_werden_uebernommen(self):
"""Prüft, dass _restore_state gültige gespeicherte Werte in die jeweiligen Widgets übernimmt."""
tab = self._neuer_tab_mit_widgets()
massstab_gueltig = next(iter(PLOTMASSSTAB_BY_AUSWAHL.keys()))
werte = {
KARTENNAME_VAR: KARTENNAME_38,
MASSSTAB_VAR: massstab_gueltig,
THEMA_VAR: THEMA_WIE_KARTENFENSTER,
ZIELGROESSE_UI_VAR: DIN_STANDARD,
FORMFAKTOR_UI_VAR: "Blatt",
DRUCKBEREICH_VAR: DRUCKBEREICH_VERFAHRENSGEBIET,
DRUCKPUFFER_VAR: "7",
}
with patch("sn_basis.ui.tabs.print_tab.get_variable", side_effect=lambda key, scope=None: werte.get(key)):
tab._restore_state()
self.assertEqual(tab._kartenname_combo.currentText(), KARTENNAME_38)
self.assertEqual(tab._massstab_combo.currentText(), massstab_gueltig)
self.assertEqual(tab._druckbereich_combo.currentText(), DRUCKBEREICH_VERFAHRENSGEBIET)
self.assertEqual(tab._druckpuffer_button.text(), "7 cm")
def test_ungueltige_oder_fehlende_werte_fallen_auf_defaults_zurueck(self):
"""Prüft, dass _restore_state ohne (gültige) gespeicherte Werte auf die Default-Konstanten zurückfällt."""
tab = self._neuer_tab_mit_widgets()
with patch("sn_basis.ui.tabs.print_tab.get_variable", return_value=None):
tab._restore_state()
self.assertEqual(tab._kartenname_combo.currentText(), KARTENNAME_PLACEHOLDER)
self.assertEqual(tab._massstab_combo.currentText(), MASSSTAB_WIE_KARTENFENSTER)
self.assertEqual(tab._druckbereich_combo.currentText(), DRUCKBEREICH_VERFAHRENSGEBIET)
self.assertEqual(tab._druckpuffer_button.text(), f"{DRUCKPUFFER_STANDARD_CM} cm")
class OnDruckpufferClickedTests(unittest.TestCase):
def test_gueltige_zahl_setzt_variable_und_button_text(self):
"""Prüft, dass eine bestätigte, gültige Zahl den Druckpuffer speichert und den Button-Text aktualisiert."""
tab = _neuer_tab()
tab.pruefmanager = _FakePruefmanager(("5", True))
tab._druckpuffer_button = _FakeButton()
with patch("sn_basis.ui.tabs.print_tab.get_variable", return_value=None), \
patch("sn_basis.ui.tabs.print_tab.set_variable") as mock_set:
tab._on_druckpuffer_clicked()
mock_set.assert_called_once_with(DRUCKPUFFER_VAR, "5", scope="project")
self.assertEqual(tab._druckpuffer_button.text(), "5 cm")
def test_abgebrochen_aendert_nichts(self):
"""Prüft, dass ein abgebrochener Dialog den Druckpuffer nicht verändert."""
tab = _neuer_tab()
tab.pruefmanager = _FakePruefmanager(("5", False))
tab._druckpuffer_button = _FakeButton()
with patch("sn_basis.ui.tabs.print_tab.get_variable", return_value=None), \
patch("sn_basis.ui.tabs.print_tab.set_variable") as mock_set:
tab._on_druckpuffer_clicked()
mock_set.assert_not_called()
def test_ungueltige_zahl_zeigt_hinweis_und_setzt_nichts(self):
"""Prüft, dass eine nicht-numerische Eingabe einen Hinweis zeigt und den Druckpuffer nicht setzt."""
tab = _neuer_tab()
pruefmanager = _FakePruefmanager(("abc", True))
tab.pruefmanager = pruefmanager
tab._druckpuffer_button = _FakeButton()
with patch("sn_basis.ui.tabs.print_tab.get_variable", return_value=None), \
patch("sn_basis.ui.tabs.print_tab.set_variable") as mock_set:
tab._on_druckpuffer_clicked()
mock_set.assert_not_called()
self.assertEqual(len(pruefmanager.zeige_hinweis_calls), 1)
class OnVorlageErstellenTests(unittest.TestCase):
def test_ruft_druckvorlage_anlegen_mit_combo_werten_auf(self):
"""Prüft, dass _on_vorlage_erstellen druckvorlage_anlegen mit den aktuellen Combo-Werten aufruft."""
tab = _neuer_tab()
mock_logic = MagicMock()
tab.logic = mock_logic
tab.pruefmanager = object()
tab._kartenname_combo = _FakeCombo("§38")
tab._massstab_combo = _FakeCombo("1:1000")
tab._zielgroesse_combo = _FakeCombo("A3")
tab._endlosrolle_cb = _FakeCheckbox(True)
tab._druckbereich_combo = _FakeCombo("Verfahrensgebiet")
tab._on_vorlage_erstellen()
mock_logic.druckvorlage_anlegen.assert_called_once_with(
layer=None,
kartenname_auswahl="§38",
massstab_auswahl="1:1000",
zielgroesse="A3",
formfaktor=True,
druckbereich_auswahl="Verfahrensgebiet",
)
def test_ohne_logic_tut_nichts(self):
"""Prüft, dass _on_vorlage_erstellen ohne gesetzte PrintLogic keine Ausnahme wirft."""
tab = _neuer_tab()
tab.logic = None
tab.pruefmanager = object()
tab._on_vorlage_erstellen() # darf keine Ausnahme werfen
class ProjectSignalsTests(unittest.TestCase):
def test_connect_verbindet_alle_drei_signale(self):
"""Prüft, dass _connect_project_signals alle drei Projektsignale mit _on_project_changed verbindet."""
tab = _neuer_tab()
projekt = _FakeProjectSignals()
with patch("sn_basis.ui.tabs.print_tab.QgsProject") as mock_project:
mock_project.instance.return_value = projekt
tab._connect_project_signals()
self.assertEqual(projekt.readProject.connected, [tab._on_project_changed])
self.assertEqual(projekt.newProjectCreated.connected, [tab._on_project_changed])
self.assertEqual(projekt.cleared.connected, [tab._on_project_changed])
def test_disconnect_trennt_alle_drei_signale(self):
"""Prüft, dass _disconnect_project_signals alle drei zuvor verbundenen Projektsignale trennt."""
tab = _neuer_tab()
projekt = _FakeProjectSignals()
projekt.readProject.connect(tab._on_project_changed)
projekt.newProjectCreated.connect(tab._on_project_changed)
projekt.cleared.connect(tab._on_project_changed)
with patch("sn_basis.ui.tabs.print_tab.QgsProject") as mock_project:
mock_project.instance.return_value = projekt
tab._disconnect_project_signals()
self.assertEqual(projekt.readProject.connected, [])
self.assertEqual(projekt.newProjectCreated.connected, [])
self.assertEqual(projekt.cleared.connected, [])
def test_instance_wirft_ausnahme_wird_abgefangen(self):
"""Prüft, dass eine Ausnahme bei QgsProject.instance() in beiden Signalmethoden abgefangen wird."""
tab = _neuer_tab()
with patch("sn_basis.ui.tabs.print_tab.QgsProject") as mock_project:
mock_project.instance.side_effect = RuntimeError("kaputt")
tab._connect_project_signals() # darf keine Ausnahme werfen
tab._disconnect_project_signals() # darf keine Ausnahme werfen
class CleanupTests(unittest.TestCase):
def test_ruft_beide_disconnect_methoden_auf(self):
"""Prüft, dass cleanup sowohl die Theme- als auch die Projektsignale trennt."""
tab = _neuer_tab()
tab._disconnect_theme_collection_signals = MagicMock()
tab._disconnect_project_signals = MagicMock()
tab.cleanup()
tab._disconnect_theme_collection_signals.assert_called_once()
tab._disconnect_project_signals.assert_called_once()
class ToggleAtlasTests(unittest.TestCase):
def test_checked_true_setzt_arrow_down_und_zeigt_inhalt(self):
"""Prüft, dass _toggle_atlas bei checked=True den Pfeil nach unten dreht und den Inhalt einblendet."""
tab = _neuer_tab()
tab._atlas_button = MagicMock()
tab._atlas_content = MagicMock()
tab._toggle_atlas(True)
tab._atlas_button.setArrowType.assert_called_once_with(ArrowDown)
tab._atlas_content.setVisible.assert_called_once_with(True)
def test_checked_false_setzt_arrow_right_und_versteckt_inhalt(self):
"""Prüft, dass _toggle_atlas bei checked=False den Pfeil nach rechts dreht und den Inhalt ausblendet."""
tab = _neuer_tab()
tab._atlas_button = MagicMock()
tab._atlas_content = MagicMock()
tab._toggle_atlas(False)
tab._atlas_button.setArrowType.assert_called_once_with(ArrowRight)
tab._atlas_content.setVisible.assert_called_once_with(False)
class RestoreAtlasLayerSelectionTests(unittest.TestCase):
def test_vorhandene_layer_id_setzt_layer_in_combo(self):
"""Prüft, dass eine gespeicherte Layer-ID den zugehörigen Layer im Atlas-Dropdown auswählt."""
tab = _neuer_tab()
tab._atlas_layer_combo = MagicMock(spec=["setLayer"])
fake_layer = object()
with patch("sn_basis.ui.tabs.print_tab.get_variable", return_value="layer_1"), \
patch("sn_basis.ui.tabs.print_tab.QgsProject") as mock_project:
mock_project.instance.return_value.mapLayer.return_value = fake_layer
tab._restore_atlas_layer_selection()
tab._atlas_layer_combo.setLayer.assert_called_once_with(fake_layer)
def test_leere_gespeicherte_layer_id_tut_nichts(self):
"""Prüft, dass eine leere gespeicherte Layer-ID das Projekt gar nicht erst anfragt."""
tab = _neuer_tab()
tab._atlas_layer_combo = MagicMock(spec=["setLayer"])
with patch("sn_basis.ui.tabs.print_tab.get_variable", return_value=""), \
patch("sn_basis.ui.tabs.print_tab.QgsProject") as mock_project:
tab._restore_atlas_layer_selection()
tab._atlas_layer_combo.setLayer.assert_not_called()
mock_project.instance.assert_not_called()
class ThemeCollectionSignalsTests(unittest.TestCase):
def test_connect_verbindet_alle_signale(self):
"""Prüft, dass _connect_theme_collection_signals alle Signale der Theme-Collection verbindet."""
tab = _neuer_tab()
tab._theme_signal_connected = False
collection = _FakeThemeCollection()
with patch("sn_basis.ui.tabs.print_tab.QgsProject") as mock_project:
mock_project.instance.return_value.mapThemeCollection.return_value = collection
tab._connect_theme_collection_signals()
self.assertEqual(collection.mapThemesChanged.connected, [tab._refresh_thema_combo_live])
self.assertTrue(tab._theme_signal_connected)
self.assertIs(tab._connected_theme_collection, collection)
def test_connect_ist_idempotent_wenn_schon_verbunden(self):
"""Prüft, dass _connect_theme_collection_signals bei bereits verbundenem Signal nichts erneut tut."""
tab = _neuer_tab()
tab._theme_signal_connected = True
with patch("sn_basis.ui.tabs.print_tab.QgsProject") as mock_project:
tab._connect_theme_collection_signals()
mock_project.instance.assert_not_called()
def test_disconnect_trennt_alle_signale(self):
"""Prüft, dass _disconnect_theme_collection_signals alle verbundenen Theme-Signale trennt und zurücksetzt."""
tab = _neuer_tab()
collection = _FakeThemeCollection()
collection.mapThemesChanged.connect(tab._refresh_thema_combo_live)
collection.changed.connect(tab._refresh_thema_combo_live)
collection.themeChanged.connect(tab._refresh_thema_combo_live)
tab._connected_theme_collection = collection
tab._theme_signal_connected = True
tab._disconnect_theme_collection_signals()
self.assertEqual(collection.mapThemesChanged.connected, [])
self.assertIsNone(tab._connected_theme_collection)
self.assertFalse(tab._theme_signal_connected)
class RefreshThemaComboLiveTests(unittest.TestCase):
def test_erhaelt_vorherige_auswahl_wenn_noch_vorhanden(self):
"""Prüft, dass _refresh_thema_combo_live die vorherige Auswahl beibehält, wenn sie noch existiert."""
tab = _neuer_tab()
combo = _FakeCombo("Thema A")
tab._thema_combo = combo
tab._get_gespeicherte_themen = lambda: ["Thema A", "Thema B"]
tab._on_thema_changed = MagicMock()
tab._refresh_thema_combo_live()
self.assertEqual(combo.currentText(), "Thema A")
tab._on_thema_changed.assert_called_once_with("Thema A")
def test_faellt_auf_wie_kartenfenster_zurueck_wenn_auswahl_verschwunden(self):
"""Prüft, dass _refresh_thema_combo_live auf 'wie Kartenfenster' zurückfällt, wenn die Auswahl verschwunden ist."""
tab = _neuer_tab()
combo = _FakeCombo("Alte Auswahl")
tab._thema_combo = combo
tab._get_gespeicherte_themen = lambda: ["Thema B"]
tab._on_thema_changed = MagicMock()
tab._refresh_thema_combo_live()
self.assertEqual(combo.currentText(), THEMA_WIE_KARTENFENSTER)
tab._on_thema_changed.assert_called_once_with(THEMA_WIE_KARTENFENSTER)
class GetGespeicherteThemenTests(unittest.TestCase):
def test_dedupliziert_und_filtert_leere_eintraege(self):
"""Prüft, dass _get_gespeicherte_themen Duplikate und leere/None-Einträge entfernt."""
tab = _neuer_tab()
with patch("sn_basis.ui.tabs.print_tab.QgsProject") as mock_project:
mock_project.instance.return_value.mapThemeCollection.return_value.mapThemes.return_value = [
"A", "A", "", "B", None,
]
ergebnis = tab._get_gespeicherte_themen()
self.assertEqual(ergebnis, ["A", "B"])
def test_fehler_liefert_leere_liste(self):
"""Prüft, dass ein Fehler beim Zugriff auf die Theme-Collection eine leere Liste liefert."""
tab = _neuer_tab()
with patch("sn_basis.ui.tabs.print_tab.QgsProject") as mock_project:
mock_project.instance.side_effect = RuntimeError("kaputt")
ergebnis = tab._get_gespeicherte_themen()
self.assertEqual(ergebnis, [])
class GetCurrentCanvasScaleTests(unittest.TestCase):
def test_liefert_skalierung_als_float(self):
"""Prüft, dass _get_current_canvas_scale die Canvas-Skalierung als float liefert."""
tab = _neuer_tab()
fake_iface = MagicMock()
fake_iface.mapCanvas.return_value.scale.return_value = 5000
with patch("sn_basis.ui.tabs.print_tab.iface", fake_iface):
self.assertEqual(tab._get_current_canvas_scale(), 5000.0)
def test_ohne_canvas_liefert_none(self):
"""Prüft, dass _get_current_canvas_scale ohne verfügbares Kartenfenster None liefert."""
tab = _neuer_tab()
fake_iface = MagicMock()
fake_iface.mapCanvas.return_value = None
with patch("sn_basis.ui.tabs.print_tab.iface", fake_iface):
self.assertIsNone(tab._get_current_canvas_scale())
def test_skalierung_null_liefert_none(self):
"""Prüft, dass eine Skalierung von 0 als None statt als 0.0 gilt."""
tab = _neuer_tab()
fake_iface = MagicMock()
fake_iface.mapCanvas.return_value.scale.return_value = 0
with patch("sn_basis.ui.tabs.print_tab.iface", fake_iface):
self.assertIsNone(tab._get_current_canvas_scale())
class OnAtlasLayerChangedTests(unittest.TestCase):
def test_none_oder_leer_setzt_variable_leer(self):
"""Prüft, dass None oder ein leerer Wert die Abdeckungslayer-Variable leeren."""
tab = _neuer_tab()
with patch("sn_basis.ui.tabs.print_tab.set_variable") as mock_set:
tab._on_atlas_layer_changed(None)
tab._on_atlas_layer_changed("")
mock_set.assert_has_calls([
call("sn_abdeckungslayer", "", scope="project"),
call("sn_abdeckungslayer", "", scope="project"),
])
def test_layer_objekt_mit_id_methode_setzt_dessen_id(self):
"""Prüft, dass ein echtes Layer-Objekt (mit id()-Methode) dessen ID speichert."""
tab = _neuer_tab()
fake_layer = MagicMock()
fake_layer.id.return_value = "layer_42"
with patch("sn_basis.ui.tabs.print_tab.set_variable") as mock_set:
tab._on_atlas_layer_changed(fake_layer)
mock_set.assert_called_once_with("sn_abdeckungslayer", "layer_42", scope="project")
def test_string_fallback_sucht_layer_ueber_namen(self):
"""Prüft, dass ohne id()-Methode über den Layernamen im Projekt gesucht und dessen ID gespeichert wird."""
tab = _neuer_tab()
fake_layer = MagicMock(spec=["name"])
fake_layer.name.return_value = "Mein Layer"
with patch("sn_basis.ui.tabs.print_tab.set_variable") as mock_set, \
patch("sn_basis.ui.tabs.print_tab.QgsProject") as mock_project:
mock_project.instance.return_value.mapLayers.return_value = {"layer_7": fake_layer}
tab._on_atlas_layer_changed("Mein Layer")
mock_set.assert_called_once_with("sn_abdeckungslayer", "layer_7", scope="project")
class OnAuswahlAsAtlasClickedTests(unittest.TestCase):
def test_erfolgreicher_layer_aktualisiert_atlas_ui(self):
"""Prüft, dass ein erfolgreich erzeugter Atlas-Layer den Atlas-Bereich öffnet und ins Dropdown übernimmt."""
tab = _neuer_tab()
fake_layer = object()
mock_logic = MagicMock()
mock_logic.create_atlas_layer_from_selection.return_value = (fake_layer, "layer_9")
tab.logic = mock_logic
tab.pruefmanager = object()
tab._atlas_button = MagicMock()
tab._atlas_content = MagicMock()
tab._atlas_layer_combo = MagicMock(spec=["setLayer"])
tab._toggle_atlas = MagicMock()
tab._on_auswahl_as_atlas_clicked()
tab._atlas_button.setChecked.assert_called_once_with(True)
tab._toggle_atlas.assert_called_once_with(True)
tab._atlas_layer_combo.setLayer.assert_called_once_with(fake_layer)
def test_ohne_erzeugten_layer_tut_nichts_weiter(self):
"""Prüft, dass ohne erzeugten Atlas-Layer keine UI-Aktualisierung stattfindet."""
tab = _neuer_tab()
mock_logic = MagicMock()
mock_logic.create_atlas_layer_from_selection.return_value = (None, None)
tab.logic = mock_logic
tab.pruefmanager = object()
tab._atlas_button = MagicMock()
tab._atlas_content = MagicMock()
tab._atlas_layer_combo = MagicMock()
tab._on_auswahl_as_atlas_clicked() # darf keine Ausnahme werfen
tab._atlas_button.setChecked.assert_not_called()
class PopulateAtlasLayerComboTests(unittest.TestCase):
def test_befuellt_combo_ohne_druckrechteck_und_leere_namen(self):
"""Prüft, dass _populate_atlas_layer_combo alle Layernamen außer 'Druckrechteck' und leeren Namen einträgt."""
tab = _neuer_tab()
combo = MagicMock(spec=["clear", "addItem", "blockSignals"])
tab._atlas_layer_combo = combo
layer_normal = MagicMock()
layer_normal.name.return_value = "Flurstuecke"
layer_druckrechteck = MagicMock()
layer_druckrechteck.name.return_value = "Druckrechteck"
layer_leer = MagicMock()
layer_leer.name.return_value = ""
with patch("sn_basis.ui.tabs.print_tab.QgsProject") as mock_project:
mock_project.instance.return_value.mapLayers.return_value = {
"1": layer_normal, "2": layer_druckrechteck, "3": layer_leer,
}
tab._populate_atlas_layer_combo()
alle_aufrufe = [c.args[0] for c in combo.addItem.call_args_list]
self.assertIn("", alle_aufrufe)
self.assertIn("Flurstuecke", alle_aufrufe)
self.assertNotIn("Druckrechteck", alle_aufrufe)
self.assertEqual(alle_aufrufe.count(""), 1)
def test_ohne_atlas_layer_combo_tut_nichts(self):
"""Prüft, dass _populate_atlas_layer_combo ohne Atlas-Dropdown keine Ausnahme wirft."""
tab = _neuer_tab()
tab._atlas_layer_combo = None
tab._populate_atlas_layer_combo() # darf keine Ausnahme werfen
class OnAtlasErzeugenChangedTests(unittest.TestCase):
def test_aktiviert_speichert_variable_und_aktiviert_widgets(self):
"""Prüft, dass ein aktivierter Atlas-Schalter die Variable setzt und Layer-Combo/Button aktiviert."""
tab = _neuer_tab()
tab._atlas_layer_combo = MagicMock()
tab._btn_auswahl_as_atlas = MagicMock()
with patch("sn_basis.ui.tabs.print_tab.set_variable") as mock_set_variable:
tab._on_atlas_erzeugen_changed(1)
mock_set_variable.assert_called_once_with(ATLAS_ERZEUGEN_VAR, "1", scope="project")
tab._atlas_layer_combo.setEnabled.assert_called_once_with(True)
tab._btn_auswahl_as_atlas.setEnabled.assert_called_once_with(True)
def test_deaktiviert_speichert_variable_und_deaktiviert_widgets(self):
"""Prüft, dass ein deaktivierter Atlas-Schalter die Variable setzt und Layer-Combo/Button deaktiviert."""
tab = _neuer_tab()
tab._atlas_layer_combo = MagicMock()
tab._btn_auswahl_as_atlas = MagicMock()
with patch("sn_basis.ui.tabs.print_tab.set_variable") as mock_set_variable:
tab._on_atlas_erzeugen_changed(0)
mock_set_variable.assert_called_once_with(ATLAS_ERZEUGEN_VAR, "0", scope="project")
tab._atlas_layer_combo.setEnabled.assert_called_once_with(False)
tab._btn_auswahl_as_atlas.setEnabled.assert_called_once_with(False)
def test_ohne_widgets_wirft_keine_ausnahme(self):
"""Prüft, dass _on_atlas_erzeugen_changed ohne Atlas-Combo/-Button keine Ausnahme wirft."""
tab = _neuer_tab()
tab._atlas_layer_combo = None
tab._btn_auswahl_as_atlas = None
with patch("sn_basis.ui.tabs.print_tab.set_variable"):
tab._on_atlas_erzeugen_changed(1) # darf keine Ausnahme werfen
if __name__ == "__main__":
unittest.main()