@@ -1068,16 +1068,70 @@ def test_cmdloop_without_rawinput() -> None:
10681068    assert  out  ==  expected 
10691069
10701070
1071- @pytest .mark .skipif (sys .platform .startswith ('win' ), reason = "stty sane only run on Linux/Mac" ) 
1072- def  test_stty_sane (base_app , monkeypatch ) ->  None :
1073-     """Make sure stty sane is run on Linux/Mac after each command if stdin is a terminal""" 
1074-     with  mock .patch ('sys.stdin.isatty' , mock .MagicMock (name = 'isatty' , return_value = True )):
1075-         # Mock out the subprocess.Popen call so we don't actually run stty sane 
1076-         m  =  mock .MagicMock (name = 'Popen' )
1077-         monkeypatch .setattr ("subprocess.Popen" , m )
1071+ def  test_cmdfinalizations_runs (base_app , monkeypatch ) ->  None :
1072+     """Make sure _run_cmdfinalization_hooks is run after each command.""" 
1073+     with  (
1074+         mock .patch ('sys.stdin.isatty' , mock .MagicMock (name = 'isatty' , return_value = True )),
1075+         mock .patch ('sys.stdin.fileno' , mock .MagicMock (name = 'fileno' , return_value = 0 )),
1076+     ):
1077+         monkeypatch .setattr (base_app .stdin , "fileno" , lambda : 0 )
1078+         monkeypatch .setattr (base_app .stdin , "isatty" , lambda : True )
1079+ 
1080+         cmd_fin  =  mock .MagicMock (name = 'cmdfinalization' )
1081+         monkeypatch .setattr ("cmd2.Cmd._run_cmdfinalization_hooks" , cmd_fin )
10781082
10791083        base_app .onecmd_plus_hooks ('help' )
1080-         m .assert_called_once_with (['stty' , 'sane' ])
1084+         cmd_fin .assert_called_once ()
1085+ 
1086+ 
1087+ @pytest .mark .skipif (sys .platform .startswith ('win' ), reason = "termios is not available on Windows" ) 
1088+ @pytest .mark .parametrize ( 
1089+     ('is_tty' , 'settings_set' , 'raised_exception' , 'should_call' ), 
1090+     [ 
1091+         (True , True , None , True ), 
1092+         (True , True , 'termios_error' , True ), 
1093+         (True , True , 'unsupported_operation' , True ), 
1094+         (False , True , None , False ), 
1095+         (True , False , None , False ), 
1096+     ], 
1097+ ) 
1098+ def  test_restore_termios_settings (base_app , monkeypatch , is_tty , settings_set , raised_exception , should_call ):
1099+     """Test that terminal settings are restored after a command and that errors are suppressed.""" 
1100+     import  io 
1101+     import  termios   # Mock termios since it's imported within the method 
1102+ 
1103+     termios_mock  =  mock .MagicMock ()
1104+     # The error attribute needs to be the actual exception for isinstance checks 
1105+     termios_mock .error  =  termios .error 
1106+     monkeypatch .setitem (sys .modules , 'termios' , termios_mock )
1107+ 
1108+     # Set the exception to be raised by tcsetattr 
1109+     if  raised_exception  ==  'termios_error' :
1110+         termios_mock .tcsetattr .side_effect  =  termios .error ("test termios error" )
1111+     elif  raised_exception  ==  'unsupported_operation' :
1112+         termios_mock .tcsetattr .side_effect  =  io .UnsupportedOperation ("test io error" )
1113+ 
1114+     # Set initial termios settings so the logic will run 
1115+     if  settings_set :
1116+         termios_settings  =  ["dummy settings" ]
1117+         base_app ._initial_termios_settings  =  termios_settings 
1118+     else :
1119+         base_app ._initial_termios_settings  =  None 
1120+         termios_settings  =  None   # for the assert 
1121+ 
1122+     # Mock stdin to make it look like a TTY 
1123+     monkeypatch .setattr (base_app .stdin , "isatty" , lambda : is_tty )
1124+     monkeypatch .setattr (base_app .stdin , "fileno" , lambda : 0 )
1125+ 
1126+     # Run a command to trigger _run_cmdfinalization_hooks 
1127+     # This should not raise an exception 
1128+     base_app .onecmd_plus_hooks ('help' )
1129+ 
1130+     # Verify that tcsetattr was called with the correct arguments 
1131+     if  should_call :
1132+         termios_mock .tcsetattr .assert_called_once_with (0 , termios_mock .TCSANOW , termios_settings )
1133+     else :
1134+         termios_mock .tcsetattr .assert_not_called ()
10811135
10821136
10831137def  test_sigint_handler (base_app ) ->  None :
0 commit comments