2013-04-08 08:48:03 -04:00
|
|
|
|
import getpass
|
|
|
|
|
|
import os
|
|
|
|
|
|
import unittest
|
2014-04-13 22:07:39 -04:00
|
|
|
|
from io import BytesIO, StringIO, TextIOWrapper
|
2013-04-08 08:48:03 -04:00
|
|
|
|
from unittest import mock
|
|
|
|
|
|
from test import support
|
|
|
|
|
|
|
2013-04-11 17:45:32 -04:00
|
|
|
|
try:
|
|
|
|
|
|
import termios
|
|
|
|
|
|
except ImportError:
|
|
|
|
|
|
termios = None
|
|
|
|
|
|
try:
|
|
|
|
|
|
import pwd
|
|
|
|
|
|
except ImportError:
|
|
|
|
|
|
pwd = None
|
|
|
|
|
|
|
2013-04-08 08:48:03 -04:00
|
|
|
|
@mock.patch('os.environ')
|
|
|
|
|
|
class GetpassGetuserTest(unittest.TestCase):
|
|
|
|
|
|
|
|
|
|
|
|
def test_username_takes_username_from_env(self, environ):
|
|
|
|
|
|
expected_name = 'some_name'
|
|
|
|
|
|
environ.get.return_value = expected_name
|
|
|
|
|
|
self.assertEqual(expected_name, getpass.getuser())
|
|
|
|
|
|
|
|
|
|
|
|
def test_username_priorities_of_env_values(self, environ):
|
|
|
|
|
|
environ.get.return_value = None
|
2013-04-11 17:45:32 -04:00
|
|
|
|
try:
|
|
|
|
|
|
getpass.getuser()
|
2023-11-27 13:05:55 -05:00
|
|
|
|
except OSError: # in case there's no pwd module
|
2013-04-11 17:45:32 -04:00
|
|
|
|
pass
|
2022-02-05 21:52:01 +02:00
|
|
|
|
except KeyError:
|
|
|
|
|
|
# current user has no pwd entry
|
|
|
|
|
|
pass
|
2013-04-08 08:48:03 -04:00
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
environ.get.call_args_list,
|
|
|
|
|
|
[mock.call(x) for x in ('LOGNAME', 'USER', 'LNAME', 'USERNAME')])
|
|
|
|
|
|
|
|
|
|
|
|
def test_username_falls_back_to_pwd(self, environ):
|
|
|
|
|
|
expected_name = 'some_name'
|
|
|
|
|
|
environ.get.return_value = None
|
2013-04-11 17:45:32 -04:00
|
|
|
|
if pwd:
|
|
|
|
|
|
with mock.patch('os.getuid') as uid, \
|
|
|
|
|
|
mock.patch('pwd.getpwuid') as getpw:
|
|
|
|
|
|
uid.return_value = 42
|
|
|
|
|
|
getpw.return_value = [expected_name]
|
|
|
|
|
|
self.assertEqual(expected_name,
|
|
|
|
|
|
getpass.getuser())
|
|
|
|
|
|
getpw.assert_called_once_with(42)
|
|
|
|
|
|
else:
|
2023-11-27 13:05:55 -05:00
|
|
|
|
self.assertRaises(OSError, getpass.getuser)
|
2013-04-08 08:48:03 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GetpassRawinputTest(unittest.TestCase):
|
|
|
|
|
|
|
|
|
|
|
|
def test_flushes_stream_after_prompt(self):
|
|
|
|
|
|
# see issue 1703
|
|
|
|
|
|
stream = mock.Mock(spec=StringIO)
|
|
|
|
|
|
input = StringIO('input_string')
|
|
|
|
|
|
getpass._raw_input('some_prompt', stream, input=input)
|
|
|
|
|
|
stream.flush.assert_called_once_with()
|
|
|
|
|
|
|
|
|
|
|
|
def test_uses_stderr_as_default(self):
|
|
|
|
|
|
input = StringIO('input_string')
|
|
|
|
|
|
prompt = 'some_prompt'
|
|
|
|
|
|
with mock.patch('sys.stderr') as stderr:
|
|
|
|
|
|
getpass._raw_input(prompt, input=input)
|
|
|
|
|
|
stderr.write.assert_called_once_with(prompt)
|
|
|
|
|
|
|
|
|
|
|
|
@mock.patch('sys.stdin')
|
|
|
|
|
|
def test_uses_stdin_as_default_input(self, mock_input):
|
|
|
|
|
|
mock_input.readline.return_value = 'input_string'
|
|
|
|
|
|
getpass._raw_input(stream=StringIO())
|
|
|
|
|
|
mock_input.readline.assert_called_once_with()
|
|
|
|
|
|
|
2014-04-13 22:07:39 -04:00
|
|
|
|
@mock.patch('sys.stdin')
|
|
|
|
|
|
def test_uses_stdin_as_different_locale(self, mock_input):
|
|
|
|
|
|
stream = TextIOWrapper(BytesIO(), encoding="ascii")
|
|
|
|
|
|
mock_input.readline.return_value = "Hasło: "
|
|
|
|
|
|
getpass._raw_input(prompt="Hasło: ",stream=stream)
|
|
|
|
|
|
mock_input.readline.assert_called_once_with()
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-04-08 08:48:03 -04:00
|
|
|
|
def test_raises_on_empty_input(self):
|
|
|
|
|
|
input = StringIO('')
|
|
|
|
|
|
self.assertRaises(EOFError, getpass._raw_input, input=input)
|
|
|
|
|
|
|
|
|
|
|
|
def test_trims_trailing_newline(self):
|
|
|
|
|
|
input = StringIO('test\n')
|
|
|
|
|
|
self.assertEqual('test', getpass._raw_input(input=input))
|
|
|
|
|
|
|
2026-03-30 05:11:13 -04:00
|
|
|
|
def check_raw_input(self, inputs, expect_result, prompt='Password: '):
|
|
|
|
|
|
mock_input = StringIO(inputs)
|
|
|
|
|
|
mock_output = StringIO()
|
|
|
|
|
|
result = getpass._raw_input(prompt, mock_output, mock_input, '*')
|
|
|
|
|
|
self.assertEqual(result, expect_result)
|
|
|
|
|
|
return mock_output.getvalue()
|
|
|
|
|
|
|
|
|
|
|
|
def test_null_char(self):
|
|
|
|
|
|
self.check_raw_input('pass\x00word\n', 'password')
|
|
|
|
|
|
|
|
|
|
|
|
def test_raw_input_with_echo_char(self):
|
|
|
|
|
|
output = self.check_raw_input('my1pa$$word!\n', 'my1pa$$word!')
|
|
|
|
|
|
self.assertEqual('Password: ************', output)
|
|
|
|
|
|
|
|
|
|
|
|
def test_control_chars_with_echo_char(self):
|
|
|
|
|
|
output = self.check_raw_input('pass\twd\b\n', 'pass\tw')
|
|
|
|
|
|
# After backspace: refresh rewrites prompt + 6 echo chars
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
'Password: *******' # initial prompt + 7 echo chars
|
|
|
|
|
|
'\r' + ' ' * 17 + '\r' # clear line (10 prompt + 7 prev)
|
|
|
|
|
|
'Password: ******', # rewrite prompt + 6 echo chars
|
|
|
|
|
|
output
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def test_kill_ctrl_u_with_echo_char(self):
|
|
|
|
|
|
# Ctrl+U (KILL) should clear the entire line
|
|
|
|
|
|
output = self.check_raw_input('foo\x15bar\n', 'bar')
|
|
|
|
|
|
# Should show "***" then refresh to clear, then show "***" for "bar"
|
|
|
|
|
|
self.assertIn('***', output)
|
|
|
|
|
|
# Display refresh uses \r to rewrite the line including prompt
|
|
|
|
|
|
self.assertIn('\r', output)
|
|
|
|
|
|
|
|
|
|
|
|
def test_werase_ctrl_w_with_echo_char(self):
|
|
|
|
|
|
# Ctrl+W (WERASE) should delete the previous word
|
|
|
|
|
|
self.check_raw_input('hello world\x17end\n', 'hello end')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_w_display_preserves_prompt(self):
|
|
|
|
|
|
# Reproducer from gh-138577: type "hello world", Ctrl+W
|
|
|
|
|
|
# Display must show "Password: ******" not "******rd: ***********"
|
|
|
|
|
|
output = self.check_raw_input('hello world\x17\n', 'hello ')
|
|
|
|
|
|
# The final visible state should be "Password: ******"
|
|
|
|
|
|
# Verify prompt is rewritten during refresh, not overwritten by stars
|
|
|
|
|
|
self.assertEndsWith(output, 'Password: ******')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_a_insert_display_preserves_prompt(self):
|
|
|
|
|
|
# Reproducer from gh-138577: type "abc", Ctrl+A, type "x"
|
|
|
|
|
|
# Display must show "Password: ****" not "****word: ***"
|
|
|
|
|
|
output = self.check_raw_input('abc\x01x\n', 'xabc')
|
|
|
|
|
|
# The final visible state should be "Password: ****"
|
|
|
|
|
|
self.assertEndsWith(output, 'Password: ****\x08\x08\x08')
|
|
|
|
|
|
|
|
|
|
|
|
def test_lnext_ctrl_v_with_echo_char(self):
|
|
|
|
|
|
# Ctrl+V (LNEXT) should insert the next character literally
|
|
|
|
|
|
self.check_raw_input('test\x16\x15more\n', 'test\x15more')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_a_move_to_start_with_echo_char(self):
|
|
|
|
|
|
# Ctrl+A should move cursor to start
|
|
|
|
|
|
self.check_raw_input('end\x01start\n', 'startend')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_a_cursor_position(self):
|
|
|
|
|
|
# After Ctrl+A, cursor is at position 0.
|
|
|
|
|
|
# Refresh writes backspaces to move cursor from end to start.
|
|
|
|
|
|
output = self.check_raw_input('abc\x01\n', 'abc')
|
|
|
|
|
|
self.assertEndsWith(output, 'Password: ***\x08\x08\x08')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_a_on_empty(self):
|
|
|
|
|
|
# Ctrl+A on empty line should be a no-op
|
|
|
|
|
|
self.check_raw_input('\x01hello\n', 'hello')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_a_already_at_start(self):
|
|
|
|
|
|
# Double Ctrl+A should be same as single Ctrl+A
|
|
|
|
|
|
self.check_raw_input('abc\x01\x01start\n', 'startabc')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_a_then_backspace(self):
|
|
|
|
|
|
# Backspace after Ctrl+A should do nothing (cursor at 0)
|
|
|
|
|
|
self.check_raw_input('abc\x01\x7f\n', 'abc')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_e_move_to_end_with_echo_char(self):
|
|
|
|
|
|
# Ctrl+E should move cursor to end
|
|
|
|
|
|
self.check_raw_input('start\x01X\x05end\n', 'Xstartend')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_e_cursor_position(self):
|
|
|
|
|
|
# After Ctrl+A then Ctrl+E, cursor is back at end.
|
|
|
|
|
|
# Refresh has no backspaces since cursor is at end.
|
|
|
|
|
|
output = self.check_raw_input('abc\x01\x05\n', 'abc')
|
|
|
|
|
|
self.assertEndsWith(output, 'Password: ***')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_e_on_empty(self):
|
|
|
|
|
|
# Ctrl+E on empty line should be a no-op
|
|
|
|
|
|
self.check_raw_input('\x05hello\n', 'hello')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_e_already_at_end(self):
|
|
|
|
|
|
# Ctrl+E when already at end should be a no-op
|
|
|
|
|
|
self.check_raw_input('abc\x05more\n', 'abcmore')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_a_then_ctrl_e(self):
|
|
|
|
|
|
# Ctrl+A then Ctrl+E should return cursor to end, typing appends
|
|
|
|
|
|
self.check_raw_input('abc\x01\x05def\n', 'abcdef')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_k_kill_forward_with_echo_char(self):
|
|
|
|
|
|
# Ctrl+K should kill from cursor to end
|
|
|
|
|
|
self.check_raw_input('delete\x01\x0bkeep\n', 'keep')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_c_interrupt_with_echo_char(self):
|
|
|
|
|
|
# Ctrl+C should raise KeyboardInterrupt
|
|
|
|
|
|
with self.assertRaises(KeyboardInterrupt):
|
|
|
|
|
|
self.check_raw_input('test\x03more', '')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_d_eof_with_echo_char(self):
|
|
|
|
|
|
# Ctrl+D twice should cause EOF
|
|
|
|
|
|
self.check_raw_input('test\x04\x04', 'test')
|
|
|
|
|
|
|
|
|
|
|
|
def test_backspace_at_start_with_echo_char(self):
|
|
|
|
|
|
# Backspace at start should do nothing
|
|
|
|
|
|
self.check_raw_input('\x7fhello\n', 'hello')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_k_at_end_with_echo_char(self):
|
|
|
|
|
|
# Ctrl+K at end should do nothing
|
|
|
|
|
|
self.check_raw_input('hello\x0b\n', 'hello')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_w_on_empty_with_echo_char(self):
|
|
|
|
|
|
# Ctrl+W on empty line should do nothing
|
|
|
|
|
|
self.check_raw_input('\x17hello\n', 'hello')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_u_on_empty_with_echo_char(self):
|
|
|
|
|
|
# Ctrl+U on empty line should do nothing
|
|
|
|
|
|
self.check_raw_input('\x15hello\n', 'hello')
|
|
|
|
|
|
|
|
|
|
|
|
def test_multiple_ctrl_operations_with_echo_char(self):
|
|
|
|
|
|
# Test combination: type, move, insert, delete
|
|
|
|
|
|
# "world", Ctrl+A, "hello ", Ctrl+E, "!", Ctrl+A, Ctrl+K, "start"
|
|
|
|
|
|
self.check_raw_input('world\x01hello \x05!\x01\x0bstart\n', 'start')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_w_multiple_words_with_echo_char(self):
|
|
|
|
|
|
# Ctrl+W should delete only the last word
|
|
|
|
|
|
self.check_raw_input('one two three\x17\n', 'one two ')
|
|
|
|
|
|
|
|
|
|
|
|
def test_ctrl_v_then_ctrl_c_with_echo_char(self):
|
|
|
|
|
|
# Ctrl+V should make Ctrl+C literal (not interrupt)
|
|
|
|
|
|
self.check_raw_input('test\x16\x03end\n', 'test\x03end')
|
|
|
|
|
|
|
2013-04-08 08:48:03 -04:00
|
|
|
|
|
|
|
|
|
|
# Some of these tests are a bit white-box. The functional requirement is that
|
|
|
|
|
|
# the password input be taken directly from the tty, and that it not be echoed
|
|
|
|
|
|
# on the screen, unless we are falling back to stderr/stdin.
|
|
|
|
|
|
|
2013-04-11 17:45:32 -04:00
|
|
|
|
# Some of these might run on platforms without termios, but play it safe.
|
|
|
|
|
|
@unittest.skipUnless(termios, 'tests require system with termios')
|
2013-04-08 08:48:03 -04:00
|
|
|
|
class UnixGetpassTest(unittest.TestCase):
|
|
|
|
|
|
|
|
|
|
|
|
def test_uses_tty_directly(self):
|
|
|
|
|
|
with mock.patch('os.open') as open, \
|
2013-07-10 17:02:24 -04:00
|
|
|
|
mock.patch('io.FileIO') as fileio, \
|
|
|
|
|
|
mock.patch('io.TextIOWrapper') as textio:
|
2013-04-08 08:48:03 -04:00
|
|
|
|
# By setting open's return value to None the implementation will
|
|
|
|
|
|
# skip code we don't care about in this test. We can mock this out
|
|
|
|
|
|
# fully if an alternate implementation works differently.
|
|
|
|
|
|
open.return_value = None
|
|
|
|
|
|
getpass.unix_getpass()
|
|
|
|
|
|
open.assert_called_once_with('/dev/tty',
|
|
|
|
|
|
os.O_RDWR | os.O_NOCTTY)
|
2013-07-10 17:02:24 -04:00
|
|
|
|
fileio.assert_called_once_with(open.return_value, 'w+')
|
|
|
|
|
|
textio.assert_called_once_with(fileio.return_value)
|
2013-04-08 08:48:03 -04:00
|
|
|
|
|
|
|
|
|
|
def test_resets_termios(self):
|
|
|
|
|
|
with mock.patch('os.open') as open, \
|
2013-07-10 17:02:24 -04:00
|
|
|
|
mock.patch('io.FileIO'), \
|
|
|
|
|
|
mock.patch('io.TextIOWrapper'), \
|
2013-04-08 08:48:03 -04:00
|
|
|
|
mock.patch('termios.tcgetattr') as tcgetattr, \
|
|
|
|
|
|
mock.patch('termios.tcsetattr') as tcsetattr:
|
|
|
|
|
|
open.return_value = 3
|
|
|
|
|
|
fake_attrs = [255, 255, 255, 255, 255]
|
|
|
|
|
|
tcgetattr.return_value = list(fake_attrs)
|
|
|
|
|
|
getpass.unix_getpass()
|
|
|
|
|
|
tcsetattr.assert_called_with(3, mock.ANY, fake_attrs)
|
|
|
|
|
|
|
|
|
|
|
|
def test_falls_back_to_fallback_if_termios_raises(self):
|
|
|
|
|
|
with mock.patch('os.open') as open, \
|
2013-07-10 17:02:24 -04:00
|
|
|
|
mock.patch('io.FileIO') as fileio, \
|
|
|
|
|
|
mock.patch('io.TextIOWrapper') as textio, \
|
2013-04-08 08:48:03 -04:00
|
|
|
|
mock.patch('termios.tcgetattr'), \
|
|
|
|
|
|
mock.patch('termios.tcsetattr') as tcsetattr, \
|
|
|
|
|
|
mock.patch('getpass.fallback_getpass') as fallback:
|
|
|
|
|
|
open.return_value = 3
|
2013-07-10 17:02:24 -04:00
|
|
|
|
fileio.return_value = BytesIO()
|
2013-04-08 08:48:03 -04:00
|
|
|
|
tcsetattr.side_effect = termios.error
|
|
|
|
|
|
getpass.unix_getpass()
|
|
|
|
|
|
fallback.assert_called_once_with('Password: ',
|
2013-07-10 17:02:24 -04:00
|
|
|
|
textio.return_value)
|
2013-04-08 08:48:03 -04:00
|
|
|
|
|
|
|
|
|
|
def test_flushes_stream_after_input(self):
|
|
|
|
|
|
# issue 7208
|
|
|
|
|
|
with mock.patch('os.open') as open, \
|
2013-07-10 17:02:24 -04:00
|
|
|
|
mock.patch('io.FileIO'), \
|
|
|
|
|
|
mock.patch('io.TextIOWrapper'), \
|
2013-04-08 08:48:03 -04:00
|
|
|
|
mock.patch('termios.tcgetattr'), \
|
|
|
|
|
|
mock.patch('termios.tcsetattr'):
|
|
|
|
|
|
open.return_value = 3
|
|
|
|
|
|
mock_stream = mock.Mock(spec=StringIO)
|
|
|
|
|
|
getpass.unix_getpass(stream=mock_stream)
|
|
|
|
|
|
mock_stream.flush.assert_called_with()
|
|
|
|
|
|
|
|
|
|
|
|
def test_falls_back_to_stdin(self):
|
|
|
|
|
|
with mock.patch('os.open') as os_open, \
|
|
|
|
|
|
mock.patch('sys.stdin', spec=StringIO) as stdin:
|
|
|
|
|
|
os_open.side_effect = IOError
|
|
|
|
|
|
stdin.fileno.side_effect = AttributeError
|
|
|
|
|
|
with support.captured_stderr() as stderr:
|
|
|
|
|
|
with self.assertWarns(getpass.GetPassWarning):
|
|
|
|
|
|
getpass.unix_getpass()
|
|
|
|
|
|
stdin.readline.assert_called_once_with()
|
|
|
|
|
|
self.assertIn('Warning', stderr.getvalue())
|
|
|
|
|
|
self.assertIn('Password:', stderr.getvalue())
|
|
|
|
|
|
|
2025-05-06 15:56:20 +04:00
|
|
|
|
def test_echo_char_replaces_input_with_asterisks(self):
|
|
|
|
|
|
mock_result = '*************'
|
|
|
|
|
|
with mock.patch('os.open') as os_open, \
|
|
|
|
|
|
mock.patch('io.FileIO'), \
|
|
|
|
|
|
mock.patch('io.TextIOWrapper') as textio, \
|
|
|
|
|
|
mock.patch('termios.tcgetattr'), \
|
|
|
|
|
|
mock.patch('termios.tcsetattr'), \
|
|
|
|
|
|
mock.patch('getpass._raw_input') as mock_input:
|
|
|
|
|
|
os_open.return_value = 3
|
|
|
|
|
|
mock_input.return_value = mock_result
|
|
|
|
|
|
|
|
|
|
|
|
result = getpass.unix_getpass(echo_char='*')
|
|
|
|
|
|
mock_input.assert_called_once_with('Password: ', textio(),
|
2026-03-30 05:11:13 -04:00
|
|
|
|
input=textio(), echo_char='*',
|
|
|
|
|
|
term_ctrl_chars=mock.ANY)
|
2025-05-06 15:56:20 +04:00
|
|
|
|
self.assertEqual(result, mock_result)
|
|
|
|
|
|
|
2025-09-16 08:21:55 -06:00
|
|
|
|
class GetpassEchoCharTest(unittest.TestCase):
|
|
|
|
|
|
|
|
|
|
|
|
def test_accept_none(self):
|
|
|
|
|
|
getpass._check_echo_char(None)
|
|
|
|
|
|
|
|
|
|
|
|
@support.subTests('echo_char', ["*", "A", " "])
|
|
|
|
|
|
def test_accept_single_printable_ascii(self, echo_char):
|
|
|
|
|
|
getpass._check_echo_char(echo_char)
|
|
|
|
|
|
|
|
|
|
|
|
def test_reject_empty_string(self):
|
|
|
|
|
|
self.assertRaises(ValueError, getpass.getpass, echo_char="")
|
|
|
|
|
|
|
|
|
|
|
|
@support.subTests('echo_char', ["***", "AA", "aA*!"])
|
|
|
|
|
|
def test_reject_multi_character_strings(self, echo_char):
|
|
|
|
|
|
self.assertRaises(ValueError, getpass.getpass, echo_char=echo_char)
|
|
|
|
|
|
|
|
|
|
|
|
@support.subTests('echo_char', [
|
|
|
|
|
|
'\N{LATIN CAPITAL LETTER AE}', # non-ASCII single character
|
|
|
|
|
|
'\N{HEAVY BLACK HEART}', # non-ASCII multibyte character
|
|
|
|
|
|
])
|
|
|
|
|
|
def test_reject_non_ascii(self, echo_char):
|
|
|
|
|
|
self.assertRaises(ValueError, getpass.getpass, echo_char=echo_char)
|
|
|
|
|
|
|
|
|
|
|
|
@support.subTests('echo_char', [
|
|
|
|
|
|
ch for ch in map(chr, range(0, 128))
|
|
|
|
|
|
if not ch.isprintable()
|
|
|
|
|
|
])
|
|
|
|
|
|
def test_reject_non_printable_characters(self, echo_char):
|
|
|
|
|
|
self.assertRaises(ValueError, getpass.getpass, echo_char=echo_char)
|
|
|
|
|
|
|
|
|
|
|
|
# TypeError Rejection
|
|
|
|
|
|
@support.subTests('echo_char', [b"*", 0, 0.0, [], {}])
|
|
|
|
|
|
def test_reject_non_string(self, echo_char):
|
|
|
|
|
|
self.assertRaises(TypeError, getpass.getpass, echo_char=echo_char)
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-04-08 08:48:03 -04:00
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
unittest.main()
|