test_code_module.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. "Test InteractiveConsole and InteractiveInterpreter from code module"
  2. import sys
  3. import unittest
  4. from textwrap import dedent
  5. from contextlib import ExitStack
  6. from unittest import mock
  7. from test.support import import_helper
  8. code = import_helper.import_module('code')
  9. class TestInteractiveConsole(unittest.TestCase):
  10. def setUp(self):
  11. self.console = code.InteractiveConsole()
  12. self.mock_sys()
  13. def mock_sys(self):
  14. "Mock system environment for InteractiveConsole"
  15. # use exit stack to match patch context managers to addCleanup
  16. stack = ExitStack()
  17. self.addCleanup(stack.close)
  18. self.infunc = stack.enter_context(mock.patch('code.input',
  19. create=True))
  20. self.stdout = stack.enter_context(mock.patch('code.sys.stdout'))
  21. self.stderr = stack.enter_context(mock.patch('code.sys.stderr'))
  22. prepatch = mock.patch('code.sys', wraps=code.sys, spec=code.sys)
  23. self.sysmod = stack.enter_context(prepatch)
  24. if sys.excepthook is sys.__excepthook__:
  25. self.sysmod.excepthook = self.sysmod.__excepthook__
  26. del self.sysmod.ps1
  27. del self.sysmod.ps2
  28. def test_ps1(self):
  29. self.infunc.side_effect = EOFError('Finished')
  30. self.console.interact()
  31. self.assertEqual(self.sysmod.ps1, '>>> ')
  32. self.sysmod.ps1 = 'custom1> '
  33. self.console.interact()
  34. self.assertEqual(self.sysmod.ps1, 'custom1> ')
  35. def test_ps2(self):
  36. self.infunc.side_effect = EOFError('Finished')
  37. self.console.interact()
  38. self.assertEqual(self.sysmod.ps2, '... ')
  39. self.sysmod.ps1 = 'custom2> '
  40. self.console.interact()
  41. self.assertEqual(self.sysmod.ps1, 'custom2> ')
  42. def test_console_stderr(self):
  43. self.infunc.side_effect = ["'antioch'", "", EOFError('Finished')]
  44. self.console.interact()
  45. for call in list(self.stdout.method_calls):
  46. if 'antioch' in ''.join(call[1]):
  47. break
  48. else:
  49. raise AssertionError("no console stdout")
  50. def test_syntax_error(self):
  51. self.infunc.side_effect = ["undefined", EOFError('Finished')]
  52. self.console.interact()
  53. for call in self.stderr.method_calls:
  54. if 'NameError' in ''.join(call[1]):
  55. break
  56. else:
  57. raise AssertionError("No syntax error from console")
  58. def test_sysexcepthook(self):
  59. self.infunc.side_effect = ["raise ValueError('')",
  60. EOFError('Finished')]
  61. hook = mock.Mock()
  62. self.sysmod.excepthook = hook
  63. self.console.interact()
  64. self.assertTrue(hook.called)
  65. def test_banner(self):
  66. # with banner
  67. self.infunc.side_effect = EOFError('Finished')
  68. self.console.interact(banner='Foo')
  69. self.assertEqual(len(self.stderr.method_calls), 3)
  70. banner_call = self.stderr.method_calls[0]
  71. self.assertEqual(banner_call, ['write', ('Foo\n',), {}])
  72. # no banner
  73. self.stderr.reset_mock()
  74. self.infunc.side_effect = EOFError('Finished')
  75. self.console.interact(banner='')
  76. self.assertEqual(len(self.stderr.method_calls), 2)
  77. def test_exit_msg(self):
  78. # default exit message
  79. self.infunc.side_effect = EOFError('Finished')
  80. self.console.interact(banner='')
  81. self.assertEqual(len(self.stderr.method_calls), 2)
  82. err_msg = self.stderr.method_calls[1]
  83. expected = 'now exiting InteractiveConsole...\n'
  84. self.assertEqual(err_msg, ['write', (expected,), {}])
  85. # no exit message
  86. self.stderr.reset_mock()
  87. self.infunc.side_effect = EOFError('Finished')
  88. self.console.interact(banner='', exitmsg='')
  89. self.assertEqual(len(self.stderr.method_calls), 1)
  90. # custom exit message
  91. self.stderr.reset_mock()
  92. message = (
  93. 'bye! \N{GREEK SMALL LETTER ZETA}\N{CYRILLIC SMALL LETTER ZHE}'
  94. )
  95. self.infunc.side_effect = EOFError('Finished')
  96. self.console.interact(banner='', exitmsg=message)
  97. self.assertEqual(len(self.stderr.method_calls), 2)
  98. err_msg = self.stderr.method_calls[1]
  99. expected = message + '\n'
  100. self.assertEqual(err_msg, ['write', (expected,), {}])
  101. def test_cause_tb(self):
  102. self.infunc.side_effect = ["raise ValueError('') from AttributeError",
  103. EOFError('Finished')]
  104. self.console.interact()
  105. output = ''.join(''.join(call[1]) for call in self.stderr.method_calls)
  106. expected = dedent("""
  107. AttributeError
  108. The above exception was the direct cause of the following exception:
  109. Traceback (most recent call last):
  110. File "<console>", line 1, in <module>
  111. ValueError
  112. """)
  113. self.assertIn(expected, output)
  114. def test_context_tb(self):
  115. self.infunc.side_effect = ["try: ham\nexcept: eggs\n",
  116. EOFError('Finished')]
  117. self.console.interact()
  118. output = ''.join(''.join(call[1]) for call in self.stderr.method_calls)
  119. expected = dedent("""
  120. Traceback (most recent call last):
  121. File "<console>", line 1, in <module>
  122. NameError: name 'ham' is not defined
  123. During handling of the above exception, another exception occurred:
  124. Traceback (most recent call last):
  125. File "<console>", line 2, in <module>
  126. NameError: name 'eggs' is not defined
  127. """)
  128. self.assertIn(expected, output)
  129. if __name__ == "__main__":
  130. unittest.main()