Skip to content

Commit 1e1514f

Browse files
committed
Create WinGetpassTest class
1 parent 3a555f0 commit 1e1514f

File tree

1 file changed

+59
-0
lines changed

1 file changed

+59
-0
lines changed

Lib/test/test_getpass.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,5 +162,64 @@ def test_falls_back_to_stdin(self):
162162
self.assertIn('Password:', stderr.getvalue())
163163

164164

165+
try:
166+
import msvcrt
167+
msvcrt = True
168+
except ImportError:
169+
msvcrt = False
170+
171+
@unittest.skipUnless(msvcrt, 'tests require system with msvcrt (Windows)')
172+
class WinGetpassTest(unittest.TestCase):
173+
174+
def test_uses_msvcrt_directly(self):
175+
# Mock the msvcrt.getch function to return a sequence ending with Enter key
176+
with mock.patch('msvcrt.getch') as getch:
177+
getch.side_effect = [b'a', b'b', b'c', b'\r']
178+
mock_stream = mock.Mock(spec=StringIO)
179+
result = getpass.win_getpass(stream=mock_stream)
180+
self.assertEqual(getch.call_count, 4)
181+
self.assertEqual(result, 'abc')
182+
# Check that the prompt was written to the stream
183+
mock_stream.write.assert_any_call('Password: ')
184+
# Check that the stream was flushed
185+
mock_stream.flush.assert_called()
186+
187+
def test_handles_backspace(self):
188+
with mock.patch('msvcrt.getch') as getch, \
189+
mock.patch('msvcrt.putch') as putch:
190+
getch.side_effect = [b'a', b'b', b'\b', b'c', b'\r']
191+
result = getpass.win_getpass()
192+
self.assertEqual(result, 'ac')
193+
# Verify putch was called to handle the backspace (erase character)
194+
# The exact sequence depends on the implementation, but should include
195+
# calls to handle the backspace character
196+
putch.assert_any_call(b'\b')
197+
198+
def test_handles_ctrl_c(self):
199+
with mock.patch('msvcrt.getch') as getch:
200+
# Simulate typing 'a' then Ctrl+C (ASCII value 3)
201+
getch.side_effect = [b'a', b'\x03']
202+
# Verify that KeyboardInterrupt is raised
203+
with self.assertRaises(KeyboardInterrupt):
204+
getpass.win_getpass()
205+
206+
def test_flushes_stream_after_input(self):
207+
with mock.patch('msvcrt.getch') as getch:
208+
# Simulate typing 'a' then Enter
209+
getch.side_effect = [b'a', b'\r']
210+
mock_stream = mock.Mock(spec=StringIO)
211+
getpass.win_getpass(stream=mock_stream)
212+
mock_stream.flush.assert_called()
213+
214+
def test_falls_back_to_fallback_if_msvcrt_raises(self):
215+
with mock.patch('msvcrt.getch') as getch, \
216+
mock.patch('getpass.fallback_getpass') as fallback:
217+
# Make getch raise an exception to trigger the fallback
218+
getch.side_effect = RuntimeError("Simulated msvcrt failure")
219+
mock_stream = mock.Mock(spec=StringIO)
220+
getpass.win_getpass(stream=mock_stream)
221+
fallback.assert_called_once_with('Password: ', mock_stream)
222+
223+
165224
if __name__ == "__main__":
166225
unittest.main()

0 commit comments

Comments
 (0)