@@ -1070,38 +1070,6 @@ def test_cmdloop_without_rawinput() -> None:
10701070
10711071def test_cmdfinalizations_runs (base_app , monkeypatch ) -> None :
10721072 """Make sure _run_cmdfinalization_hooks is run after each command."""
1073- termios_settings = [
1074- 27394 ,
1075- 3 ,
1076- 19200 ,
1077- 536872399 ,
1078- 38400 ,
1079- 38400 ,
1080- [
1081- b'\x04 ' ,
1082- b'\xff ' ,
1083- b'\xff ' ,
1084- b'\x7f ' ,
1085- b'\x17 ' ,
1086- b'\x15 ' ,
1087- b'\x12 ' ,
1088- b'\x00 ' ,
1089- b'\x03 ' ,
1090- b'\x1c ' ,
1091- b'\x1a ' ,
1092- b'\x19 ' ,
1093- b'\x11 ' ,
1094- b'\x13 ' ,
1095- b'\x16 ' ,
1096- b'\x0f ' ,
1097- b'\x01 ' ,
1098- b'\x00 ' ,
1099- b'\x14 ' ,
1100- b'\x00 ' ,
1101- ],
1102- ]
1103-
1104- base_app ._initial_termios_settings = termios_settings
11051073 with (
11061074 mock .patch ('sys.stdin.isatty' , mock .MagicMock (name = 'isatty' , return_value = True )),
11071075 mock .patch ('sys.stdin.fileno' , mock .MagicMock (name = 'fileno' , return_value = 0 )),
@@ -1116,6 +1084,56 @@ def test_cmdfinalizations_runs(base_app, monkeypatch) -> None:
11161084 cmd_fin .assert_called_once ()
11171085
11181086
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 ()
1135+
1136+
11191137def test_sigint_handler (base_app ) -> None :
11201138 # No KeyboardInterrupt should be raised when using sigint_protection
11211139 with base_app .sigint_protection :
0 commit comments