Home | History | Annotate | Download | only in test
      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 = "Haso: "
     76         getpass._raw_input(prompt="Haso: ",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()
    164