test_getpass.py 6.4 KB

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