1 import getpass
2 import os
3 import unittest
4 from io import BytesIO, StringIO, TextIOWrapper
5 from unittest import mock
6 from test import support
7
8 try:
9 import termios
10 except ImportError:
11 termios = None
12 try:
13 import pwd
14 except ImportError:
15 pwd = None
16
17 @mock.patch('os.environ')
18 class ESC[4;38;5;81mGetpassGetuserTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
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
53 class ESC[4;38;5;81mGetpassRawinputTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
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')
98 class ESC[4;38;5;81mUnixGetpassTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
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
165 if __name__ == "__main__":
166 unittest.main()