blob: 3452e46213a76c4376252cdb083bf039e1a56a63 [file] [log] [blame]
R David Murrayc137f7c2013-04-08 08:48:03 -04001import getpass
2import os
R David Murrayc137f7c2013-04-08 08:48:03 -04003import unittest
R David Murrayd5aa4872014-04-13 22:07:39 -04004from io import BytesIO, StringIO, TextIOWrapper
R David Murrayc137f7c2013-04-08 08:48:03 -04005from unittest import mock
6from test import support
7
R David Murrayf1c42532013-04-11 17:45:32 -04008try:
9 import termios
10except ImportError:
11 termios = None
12try:
13 import pwd
14except ImportError:
15 pwd = None
16
R David Murrayc137f7c2013-04-08 08:48:03 -040017@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
R David Murrayf1c42532013-04-11 17:45:32 -040027 try:
28 getpass.getuser()
29 except ImportError: # in case there's no pwd module
30 pass
R David Murrayc137f7c2013-04-08 08:48:03 -040031 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
R David Murrayf1c42532013-04-11 17:45:32 -040038 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)
R David Murrayc137f7c2013-04-08 08:48:03 -040048
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
R David Murrayd5aa4872014-04-13 22:07:39 -040072 @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
R David Murrayc137f7c2013-04-08 08:48:03 -040080 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
R David Murrayf1c42532013-04-11 17:45:32 -040093# Some of these might run on platforms without termios, but play it safe.
94@unittest.skipUnless(termios, 'tests require system with termios')
R David Murrayc137f7c2013-04-08 08:48:03 -040095class UnixGetpassTest(unittest.TestCase):
96
97 def test_uses_tty_directly(self):
98 with mock.patch('os.open') as open, \
R David Murray16dbbae2013-07-10 17:02:24 -040099 mock.patch('io.FileIO') as fileio, \
100 mock.patch('io.TextIOWrapper') as textio:
R David Murrayc137f7c2013-04-08 08:48:03 -0400101 # 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)
R David Murray16dbbae2013-07-10 17:02:24 -0400108 fileio.assert_called_once_with(open.return_value, 'w+')
109 textio.assert_called_once_with(fileio.return_value)
R David Murrayc137f7c2013-04-08 08:48:03 -0400110
111 def test_resets_termios(self):
112 with mock.patch('os.open') as open, \
R David Murray16dbbae2013-07-10 17:02:24 -0400113 mock.patch('io.FileIO'), \
114 mock.patch('io.TextIOWrapper'), \
R David Murrayc137f7c2013-04-08 08:48:03 -0400115 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, \
R David Murray16dbbae2013-07-10 17:02:24 -0400125 mock.patch('io.FileIO') as fileio, \
126 mock.patch('io.TextIOWrapper') as textio, \
R David Murrayc137f7c2013-04-08 08:48:03 -0400127 mock.patch('termios.tcgetattr'), \
128 mock.patch('termios.tcsetattr') as tcsetattr, \
129 mock.patch('getpass.fallback_getpass') as fallback:
130 open.return_value = 3
R David Murray16dbbae2013-07-10 17:02:24 -0400131 fileio.return_value = BytesIO()
R David Murrayc137f7c2013-04-08 08:48:03 -0400132 tcsetattr.side_effect = termios.error
133 getpass.unix_getpass()
134 fallback.assert_called_once_with('Password: ',
R David Murray16dbbae2013-07-10 17:02:24 -0400135 textio.return_value)
R David Murrayc137f7c2013-04-08 08:48:03 -0400136
137 def test_flushes_stream_after_input(self):
138 # issue 7208
139 with mock.patch('os.open') as open, \
R David Murray16dbbae2013-07-10 17:02:24 -0400140 mock.patch('io.FileIO'), \
141 mock.patch('io.TextIOWrapper'), \
R David Murrayc137f7c2013-04-08 08:48:03 -0400142 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()