2026-10-05 21:53:50 +02:00
"""Tests für sn_basis/ui/base_dockwidget.py: closeEvent (Issue #65) und Scroll-Bereich je Tab (Basis #104)."""
2026-09-18 11:20:10 +02:00
import unittest
2026-10-05 21:53:50 +02:00
from sn_basis.functions.qt_wrapper import QScrollArea , QTabWidget
2026-09-18 11:20:10 +02:00
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
2026-10-05 21:53:50 +02:00
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 )
2026-09-18 11:20:10 +02:00
if __name__ == "__main__" :
unittest . main ()