Skip to content

Commit 28ea92c

Browse files
authored
Merge pull request RustPython#2498 from fanninpm/test-getpass
Add test_getpass from CPython 3.8.7
2 parents 3dc018b + d9245d4 commit 28ea92c

File tree

1 file changed

+163
-0
lines changed

1 file changed

+163
-0
lines changed

Lib/test/test_getpass.py

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
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 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+
50+
class 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')
95+
class 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+
162+
if __name__ == "__main__":
163+
unittest.main()

0 commit comments

Comments
 (0)