"""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()