@@ -47,6 +47,7 @@ class Lauf:
raise
raise
pytest . skip ( f " kein Bildschirm: { exc } " )
pytest . skip ( f " kein Bildschirm: { exc } " )
self . fehler : list [ str ] = [ ]
self . fehler : list [ str ] = [ ]
self . watchdog = False # True = der TEST hat wegen Zeitüberschreitung abgebrochen
from provtool . gui import app as A
from provtool . gui import app as A
self . app = A . App ( self . root )
self . app = A . App ( self . root )
echt = self . root . report_callback_exception
echt = self . root . report_callback_exception
@@ -62,6 +63,13 @@ class Lauf:
self . root . report_callback_exception = melden
self . root . report_callback_exception = melden
# ---------------------------------------------------------------- Zustand
# ---------------------------------------------------------------- Zustand
def lebt_sonst ( self , text : str ) - > str :
""" Fehlertext für „Programm ist zu“, der Watchdog-Abbrüche klar unterscheidet. """
if self . watchdog :
return " Zeitüberschreitung – der Test hat abgebrochen (nicht das Programm hat sich beendet): \n " \
+ " \n " . join ( self . fehler )
return text
@property
@property
def lebt ( self ) - > bool :
def lebt ( self ) - > bool :
try :
try :
@@ -95,6 +103,7 @@ class Lauf:
d . destroy ( )
d . destroy ( )
def _notaus ( self ) :
def _notaus ( self ) :
self . watchdog = True
for d in reversed ( self . dialoge ( ) ) :
for d in reversed ( self . dialoge ( ) ) :
try :
try :
d . destroy ( )
d . destroy ( )
@@ -219,11 +228,11 @@ def test_alt_f4_im_assistent_fragt_und_schliesst_nur_assistent(home):
d . destroy ( )
d . destroy ( )
lauf . ablauf ( [
lauf . ablauf ( [
( _assistent_offen ( lauf ) , lambda : lauf . dialog ( Einrichtungsassistent ) . event_generate ( " <Alt-F4> " ) , " Alt+F4 " ) ,
( _assistent_offen ( lauf ) , lambda : lauf . app . rahmen . alt_f4 ( lauf . dialog ( Einrichtungsassistent ) ) , " Alt+F4 " ) ,
( lambda : rueckfrage ( ) is not None , ja_klicken , " Rückfrage mit Ja beantworten " ) ,
( lambda : rueckfrage ( ) is not None , ja_klicken , " Rückfrage mit Ja beantworten " ) ,
( lambda : lauf . dialog ( Einrichtungsassistent ) is None , lambda : None , " Assistent ist zu " ) ,
( lambda : lauf . dialog ( Einrichtungsassistent ) is None , lambda : None , " Assistent ist zu " ) ,
] )
] )
assert lauf . lebt , " Programm darf nicht beendet werden "
assert lauf . lebt , lauf . lebt_sonst ( " Programm darf nicht beendet werden " )
assert not lauf . uebrig , lauf . uebrig
assert not lauf . uebrig , lauf . uebrig
assert lauf . app . settings . get ( " assistent_erledigt " ) is True
assert lauf . app . settings . get ( " assistent_erledigt " ) is True
lauf . pruefen ( )
lauf . pruefen ( )
@@ -231,17 +240,37 @@ def test_alt_f4_im_assistent_fragt_und_schliesst_nur_assistent(home):
lauf . pruefen ( )
lauf . pruefen ( )
def test_alt_f4_im_dialog_schliesst_nur_den_dialog ( lauf_mit_daten ) :
def test_alt_f4_im_dialog_schliesst_nur_den_dialog ( lauf_mit_daten , monkeypatch ) :
from provtool . gui import rahmen
from provtool . gui . dialogs import InfoDialog
from provtool . gui . dialogs import InfoDialog
lauf = lauf_mit_daten
lauf = lauf_mit_daten
protokoll : list [ str ] = [ ] # Diagnose: wer hat Alt+F4 bzw. Beenden ausgelöst?
alt_f4 , beenden = rahmen . Hauptrahmen . alt_f4 , type ( lauf . app ) . beenden
def alt_f4_spion ( self , widget ) :
protokoll . append ( f " alt_f4(widget= { widget } , sperre= { self . root . grab_current ( ) } , "
f " popup= { self . _offenes_popup ( ) } , fokus= { self . root . focus_get ( ) } ) \n "
+ " " . join ( traceback . format_stack ( limit = 8 ) ) )
return alt_f4 ( self , widget )
def beenden_spion ( self ) :
protokoll . append ( " beenden() \n " + " " . join ( traceback . format_stack ( limit = 10 ) ) )
return beenden ( self )
monkeypatch . setattr ( rahmen . Hauptrahmen , " alt_f4 " , alt_f4_spion )
monkeypatch . setattr ( type ( lauf . app ) , " beenden " , beenden_spion )
lauf . ablauf ( [
lauf . ablauf ( [
( IMMER , lambda : InfoDialog ( lauf . root ) . zeigen ( ) , " Info öffnen " ) ,
( IMMER , lambda : InfoDialog ( lauf . root ) . zeigen ( ) , " Info öffnen " ) ,
# Handler direkt mit dem Dialog als Empfänger aufrufen: Erzeugte Tastendrücke stellt Tk unter
# Windows nur dem Fenster mit Tastaturfokus zu – auf dem Build-Rechner gingen sie verloren.
# Dass Alt+F4 an diesen Handler gebunden ist, prüft test_alt_f4_ist_gebunden.
( lambda : lauf . dialog ( InfoDialog ) is not None ,
( lambda : lauf . dialog ( InfoDialog ) is not None ,
lambda : lauf . dialog ( InfoDialog ) . event_generate ( " <Alt-F4> " ) , " Alt+F4 im Dialog " ) ,
lambda : lauf . app . rahmen . alt_f4 ( lauf . dialog ( InfoDialog ) ) , " Alt+F4 im Dialog " ) ,
( lambda : lauf . dialog ( InfoDialog ) is None , lambda : None , " Dialog geschlossen " ) ,
( lambda : lauf . dialog ( InfoDialog ) is None , lambda : None , " Dialog geschlossen " ) ,
] , sekunden = 8 )
] , sekunden = 8 )
assert lauf . lebt , " Alt+F4 im Dialog darf nicht das ganze Programm beenden "
diagnose = " \n --- \n " . join ( protokoll ) + " \n Fehler: \n " + " \n " . join ( lauf . fehler )
assert not lauf . uebrig , lauf . uebrig
assert lauf . lebt , lauf . lebt_sonst ( " Alt+F4 im Dialog darf nicht das ganze Programm beenden \n " + diagnose )
assert not lauf . uebrig , f " { lauf . uebrig } \n { diagnose } "
lauf . pruefen ( )
lauf . pruefen ( )
@@ -298,16 +327,46 @@ def test_schliessen_waehrend_rundgang(lauf_mit_daten):
lauf . pruefen ( )
lauf . pruefen ( )
def test_alt_f4_ist_gebunden ( lauf_mit_daten ) :
""" Alt+F4 muss im Win95-Rahmen an den eigenen Handler gebunden sein (für alle Fenster). """
lauf = lauf_mit_daten
if not lauf . app . rahmen . klassisch :
pytest . skip ( " nur im Win95-Rahmen " )
skript = lauf . root . bind_all ( " <Alt-F4> " )
assert skript , " Alt+F4 ist nicht gebunden "
lauf . pruefen ( )
def test_alt_f4_bevor_die_sperre_steht ( lauf_mit_daten , monkeypatch ) :
""" Erzwingt den Zustand vom langsamen Build-Rechner: Dialog ist offen, aber Tk-Sperre und
Zeichnen sind noch nicht fertig. Alt+F4 muss trotzdem nur den Dialog schließen. """
from provtool . gui import win95 as w
from provtool . gui . dialogs import InfoDialog
monkeypatch . setattr ( w . Dialog , " _sperre_setzen " , lambda self , versuch = 0 : None ) # keine Sperre
monkeypatch . setattr ( w . Dialog , " winfo_ismapped " , lambda self : 0 ) # „noch nicht gezeichnet“
lauf = lauf_mit_daten
lauf . ablauf ( [
( IMMER , lambda : InfoDialog ( lauf . root ) . zeigen ( ) , " Info öffnen " ) ,
# wie unter Windows: Tk liefert den Tastendruck an das Fenster mit Fokus – hier noch das Hauptfenster
( lambda : lauf . dialog ( InfoDialog ) is not None , lambda : lauf . app . rahmen . alt_f4 ( lauf . root ) ,
" Alt+F4 (Fokus noch beim Hauptfenster) " ) ,
( lambda : lauf . dialog ( InfoDialog ) is None , lambda : None , " Dialog geschlossen " ) ,
] , sekunden = 8 )
assert lauf . lebt , lauf . lebt_sonst ( " Alt+F4 darf bei offenem Dialog nicht das ganze Programm beenden " )
assert not lauf . uebrig , lauf . uebrig
lauf . pruefen ( )
def test_alt_f4_im_rundgang_beendet_nur_den_rundgang ( lauf_mit_daten ) :
def test_alt_f4_im_rundgang_beendet_nur_den_rundgang ( lauf_mit_daten ) :
lauf = lauf_mit_daten
lauf = lauf_mit_daten
rg = lambda : getattr ( lauf . app , " _rundgang " , None ) # noqa: E731
rg = lambda : getattr ( lauf . app , " _rundgang " , None ) # noqa: E731
lauf . ablauf ( [
lauf . ablauf ( [
( IMMER , lauf . app . rundgang , " Rundgang starten " ) ,
( IMMER , lauf . app . rundgang , " Rundgang starten " ) ,
( lambda : rg ( ) is not None and rg ( ) . blase is not None ,
( lambda : rg ( ) is not None and rg ( ) . blase is not None ,
lambda : rg ( ) . blase . event_generate ( " <Alt-F4> " ) , " Alt+F4 " ) ,
lambda : lauf . app . rahmen . alt_f4 ( rg ( ) . blase ) , " Alt+F4 " ) ,
( lambda : rg ( ) . blase is None and not rg ( ) . rahmen , lambda : None , " Rundgang samt Rahmen weg " ) ,
( lambda : rg ( ) . blase is None and not rg ( ) . rahmen , lambda : None , " Rundgang samt Rahmen weg " ) ,
] , sekunden = 8 )
] , sekunden = 8 )
assert lauf . lebt , " Alt+F4 im Rundgang darf nicht das Programm beenden "
assert lauf . lebt , lauf . lebt_sonst ( " Alt+F4 im Rundgang darf nicht das Programm beenden " )
assert not lauf . uebrig , lauf . uebrig
assert not lauf . uebrig , lauf . uebrig
lauf . pruefen ( )
lauf . pruefen ( )