1import getpass 2import os 3import unittest 4from io import BytesIO, StringIO, TextIOWrapper 5from unittest import mock 6from test import support 7 8try: 9 import termios 10except ImportError: 11 termios = None 12try: 13 import pwd 14except ImportError: 15 pwd = None 16 17@mock.patch('os.environ') 18class GetpassGetuserTest(unittest.TestCase): 19 20 def test_username_takes_username_from_env(self, environ): 21 expected_name = 'some_name' 22 environ.get.return_value = expected_name 23 self.assertEqual(expected_name, getpass.getuser()) 24 25 def test_username_priorities_of_env_values(self, environ): 26 environ.get.return_value = None 27 try: 28 getpass.getuser() 29 except ImportError: # in case there's no pwd module 30 pass 31 self.assertEqual( 32 environ.get.call_args_list, 33 [mock.call(x) for x in ('LOGNAME', 'USER', 'LNAME', 'USERNAME')]) 34 35 def test_username_falls_back_to_pwd(self, environ): 36 expected_name = 'some_name' 37 environ.get.return_value = None 38 if pwd: 39 with mock.patch('os.getuid') as uid, \ 40 mock.patch('pwd.getpwuid') as getpw: 41 uid.return_value = 42 42 getpw.return_value = [expected_name] 43 self.assertEqual(expected_name, 44 getpass.getuser()) 45 getpw.assert_called_once_with(42) 46 else: 47 self.assertRaises(ImportError, getpass.getuser) 48 49 50class GetpassRawinputTest(unittest.TestCase): 51 52 def test_flushes_stream_after_prompt(self): 53 # see issue 1703 54 stream = mock.Mock(spec=StringIO) 55 input = StringIO('input_string') 56 getpass._raw_input('some_prompt', stream, input=input) 57 stream.flush.assert_called_once_with() 58 59 def test_uses_stderr_as_default(self): 60 input = StringIO('input_string') 61 prompt = 'some_prompt' 62 with mock.patch('sys.stderr') as stderr: 63 getpass._raw_input(prompt, input=input) 64 stderr.write.assert_called_once_with(prompt) 65 66 @mock.patch('sys.stdin') 67 def test_uses_stdin_as_default_input(self, mock_input): 68 mock_input.readline.return_value = 'input_string' 69 getpass._raw_input(stream=StringIO()) 70 mock_input.readline.assert_called_once_with() 71 72 @mock.patch('sys.stdin') 73 def test_uses_stdin_as_different_locale(self, mock_input): 74 stream = TextIOWrapper(BytesIO(), encoding="ascii") 75 mock_input.readline.return_value = "Hasło: " 76 getpass._raw_input(prompt="Hasło: ",stream=stream) 77 mock_input.readline.assert_called_once_with() 78 79 80 def test_raises_on_empty_input(self): 81 input = StringIO('') 82 self.assertRaises(EOFError, getpass._raw_input, input=input) 83 84 def test_trims_trailing_newline(self): 85 input = StringIO('test\n') 86 self.assertEqual('test', getpass._raw_input(input=input)) 87 88 89# Some of these tests are a bit white-box. The functional requirement is that 90# the password input be taken directly from the tty, and that it not be echoed 91# on the screen, unless we are falling back to stderr/stdin. 92 93# Some of these might run on platforms without termios, but play it safe. 94@unittest.skipUnless(termios, 'tests require system with termios') 95class UnixGetpassTest(unittest.TestCase): 96 97 def test_uses_tty_directly(self): 98 with mock.patch('os.open') as open, \ 99 mock.patch('io.FileIO') as fileio, \ 100 mock.patch('io.TextIOWrapper') as textio: 101 # By setting open's return value to None the implementation will 102 # skip code we don't care about in this test. We can mock this out 103 # fully if an alternate implementation works differently. 104 open.return_value = None 105 getpass.unix_getpass() 106 open.assert_called_once_with('/dev/tty', 107 os.O_RDWR | os.O_NOCTTY) 108 fileio.assert_called_once_with(open.return_value, 'w+') 109 textio.assert_called_once_with(fileio.return_value) 110 111 def test_resets_termios(self): 112 with mock.patch('os.open') as open, \ 113 mock.patch('io.FileIO'), \ 114 mock.patch('io.TextIOWrapper'), \ 115 mock.patch('termios.tcgetattr') as tcgetattr, \ 116 mock.patch('termios.tcsetattr') as tcsetattr: 117 open.return_value = 3 118 fake_attrs = [255, 255, 255, 255, 255] 119 tcgetattr.return_value = list(fake_attrs) 120 getpass.unix_getpass() 121 tcsetattr.assert_called_with(3, mock.ANY, fake_attrs) 122 123 def test_falls_back_to_fallback_if_termios_raises(self): 124 with mock.patch('os.open') as open, \ 125 mock.patch('io.FileIO') as fileio, \ 126 mock.patch('io.TextIOWrapper') as textio, \ 127 mock.patch('termios.tcgetattr'), \ 128 mock.patch('termios.tcsetattr') as tcsetattr, \ 129 mock.patch('getpass.fallback_getpass') as fallback: 130 open.return_value = 3 131 fileio.return_value = BytesIO() 132 tcsetattr.side_effect = termios.error 133 getpass.unix_getpass() 134 fallback.assert_called_once_with('Password: ', 135 textio.return_value) 136 137 def test_flushes_stream_after_input(self): 138 # issue 7208 139 with mock.patch('os.open') as open, \ 140 mock.patch('io.FileIO'), \ 141 mock.patch('io.TextIOWrapper'), \ 142 mock.patch('termios.tcgetattr'), \ 143 mock.patch('termios.tcsetattr'): 144 open.return_value = 3 145 mock_stream = mock.Mock(spec=StringIO) 146 getpass.unix_getpass(stream=mock_stream) 147 mock_stream.flush.assert_called_with() 148 149 def test_falls_back_to_stdin(self): 150 with mock.patch('os.open') as os_open, \ 151 mock.patch('sys.stdin', spec=StringIO) as stdin: 152 os_open.side_effect = IOError 153 stdin.fileno.side_effect = AttributeError 154 with support.captured_stderr() as stderr: 155 with self.assertWarns(getpass.GetPassWarning): 156 getpass.unix_getpass() 157 stdin.readline.assert_called_once_with() 158 self.assertIn('Warning', stderr.getvalue()) 159 self.assertIn('Password:', stderr.getvalue()) 160 161 162if __name__ == "__main__": 163 unittest.main() 164