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