"""Tests für sn_basis/ui/base_dockwidget.py: closeEvent (Issue #65) und Scroll-Bereich je Tab (Basis #104).""" import unittest from sn_basis.functions.qt_wrapper import QScrollArea, QTabWidget from sn_basis.ui.base_dockwidget import BaseDockWidget class _FakeTab: def __init__(self, mit_cleanup: bool = True) -> None: self.cleanup_aufgerufen = False if mit_cleanup: self.cleanup = self._cleanup def _cleanup(self) -> None: self.cleanup_aufgerufen = True class _FehlerhafterTab: def cleanup(self) -> None: raise RuntimeError("cleanup kaputt") class _FakeTabWidget: def __init__(self, tabs) -> None: self._tabs = tabs def count(self) -> int: return len(self._tabs) def widget(self, index: int): return self._tabs[index] class _FakeAction: def __init__(self) -> None: self.checked = None def setChecked(self, value: bool) -> None: self.checked = value def _neues_dock() -> BaseDockWidget: """Erzeugt ein BaseDockWidget ohne den echten __init__ (keine Qt-Tab-Erzeugung nötig für closeEvent).""" dock = BaseDockWidget.__new__(BaseDockWidget) dock.action = None return dock class CloseEventTests(unittest.TestCase): def test_ruft_cleanup_aller_tabs_auf(self): """Prüft, dass closeEvent cleanup() auf allen Tabs des Dock-Widgets aufruft.""" dock = _neues_dock() tab1, tab2 = _FakeTab(), _FakeTab() dock.widget = lambda: _FakeTabWidget([tab1, tab2]) dock.closeEvent(None) self.assertTrue(tab1.cleanup_aufgerufen) self.assertTrue(tab2.cleanup_aufgerufen) def test_ignoriert_tabs_ohne_cleanup(self): """Prüft, dass ein Tab ohne cleanup()-Methode nicht zu einem Fehler führt.""" dock = _neues_dock() dock.widget = lambda: _FakeTabWidget([_FakeTab(mit_cleanup=False)]) dock.closeEvent(None) # darf keine Ausnahme werfen def test_fehler_in_cleanup_wird_abgefangen_und_andere_tabs_laufen_weiter(self): """Prüft, dass ein Fehler in cleanup() eines Tabs nicht die übrigen Tabs verhindert.""" dock = _neues_dock() funktionierender_tab = _FakeTab() dock.widget = lambda: _FakeTabWidget([_FehlerhafterTab(), funktionierender_tab]) dock.closeEvent(None) self.assertTrue(funktionierender_tab.cleanup_aufgerufen) def test_setzt_toolbar_action_zurueck(self): """Prüft, dass closeEvent die verknüpfte Toolbar-Action auf 'nicht gedrückt' zurücksetzt.""" dock = _neues_dock() dock.widget = lambda: _FakeTabWidget([]) action = _FakeAction() dock.action = action dock.closeEvent(None) self.assertFalse(action.checked) def test_ohne_action_wird_nichts_zurueckgesetzt(self): """Prüft, dass closeEvent ohne verknüpfte Toolbar-Action keine Ausnahme wirft.""" dock = _neues_dock() dock.widget = lambda: _FakeTabWidget([]) dock.action = None dock.closeEvent(None) # darf keine Ausnahme werfen class _TabA: tab_title = "Daten" class _TabB: tab_title = "Druck" class _Dock(BaseDockWidget): tabs = [_TabA, _TabB] class ScrollbereichTests(unittest.TestCase): """Lange Tabs dürfen das QGIS-Fenster nicht über den Bildschirmrand schieben (Basis #104).""" def test_jeder_tab_liegt_in_einem_scrollbereich(self): """Prüft, dass BaseDockWidget jeden Tab in einen mitwachsenden Scroll-Bereich packt, damit ein langer Tab scrollt, statt das Fenster zu verlängern.""" reiter = _Dock().widget() self.assertEqual(reiter.count(), 2) for index, klasse in enumerate((_TabA, _TabB)): bereich = reiter.widget(index) self.assertIsInstance(bereich, QScrollArea) self.assertTrue(bereich.widgetResizable()) self.assertIsInstance(bereich.widget(), klasse) self.assertEqual(reiter.tabText(index), klasse.tab_title) def test_fachplugin_mit_eigenem_tabaufbau_bekommt_scrollbereich(self): """Prüft, dass auch ein Fachplugin, das seine Tabs selbst aufbaut und per setWidget einsetzt (wie Plan41, Verfahrensgebiet), Scroll-Bereiche bekommt.""" dock = _Dock() eigene = QTabWidget() tab = _TabA() eigene.addTab(tab, "Eigener Tab") eigene.setCurrentIndex(0) dock.setWidget(eigene) self.assertIs(dock.widget(), eigene) self.assertIsInstance(eigene.widget(0), QScrollArea) self.assertIs(eigene.widget(0).widget(), tab) self.assertEqual(eigene.tabText(0), "Eigener Tab") self.assertEqual(eigene.currentIndex(), 0) def test_scrollbereich_wird_nicht_doppelt_angelegt(self): """Prüft, dass ein Tab, der schon in einem Scroll-Bereich liegt, beim erneuten Einsetzen nicht ein zweites Mal verpackt wird.""" dock = _Dock() reiter = dock.widget() bereich = reiter.widget(0) dock.setWidget(reiter) self.assertIs(reiter.widget(0), bereich) def test_setwidget_none_und_andere_widgets_bleiben_unveraendert(self): """Prüft, dass setWidget(None) und Widgets ohne Tabs ohne Fehler und unverändert eingesetzt werden.""" dock = _Dock() dock.setWidget(None) self.assertIsNone(dock.widget()) einfach = _TabA() dock.setWidget(einfach) self.assertIs(dock.widget(), einfach) def test_cleanup_erreicht_tabs_im_scrollbereich(self): """Prüft, dass closeEvent cleanup() auch für Tabs aufruft, die in einem Scroll-Bereich liegen.""" dock = _neues_dock() tab = _FakeTab() bereich = QScrollArea() bereich.setWidget(tab) dock.widget = lambda: _FakeTabWidget([bereich]) dock.closeEvent(None) self.assertTrue(tab.cleanup_aufgerufen) if __name__ == "__main__": unittest.main()