| 
									
										
										
										
											2012-08-20 23:02:28 +10:00
										 |  |  | "Test InteractiveConsole and InteractiveInterpreter from code module" | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import unittest | 
					
						
							| 
									
										
										
										
											2014-09-29 11:25:00 -04:00
										 |  |  | from textwrap import dedent | 
					
						
							| 
									
										
										
										
											2012-08-20 23:02:28 +10:00
										 |  |  | from contextlib import ExitStack | 
					
						
							|  |  |  | from unittest import mock | 
					
						
							| 
									
										
										
										
											2020-08-04 00:47:42 +08:00
										 |  |  | from test.support import import_helper | 
					
						
							| 
									
										
										
										
											2012-08-20 23:02:28 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-04 00:47:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | code = import_helper.import_module('code') | 
					
						
							| 
									
										
										
										
											2012-08-20 23:02:28 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestInteractiveConsole(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setUp(self): | 
					
						
							|  |  |  |         self.console = code.InteractiveConsole() | 
					
						
							|  |  |  |         self.mock_sys() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def mock_sys(self): | 
					
						
							|  |  |  |         "Mock system environment for InteractiveConsole" | 
					
						
							|  |  |  |         # use exit stack to match patch context managers to addCleanup | 
					
						
							|  |  |  |         stack = ExitStack() | 
					
						
							|  |  |  |         self.addCleanup(stack.close) | 
					
						
							|  |  |  |         self.infunc = stack.enter_context(mock.patch('code.input', | 
					
						
							|  |  |  |                                           create=True)) | 
					
						
							|  |  |  |         self.stdout = stack.enter_context(mock.patch('code.sys.stdout')) | 
					
						
							|  |  |  |         self.stderr = stack.enter_context(mock.patch('code.sys.stderr')) | 
					
						
							|  |  |  |         prepatch = mock.patch('code.sys', wraps=code.sys, spec=code.sys) | 
					
						
							|  |  |  |         self.sysmod = stack.enter_context(prepatch) | 
					
						
							|  |  |  |         if sys.excepthook is sys.__excepthook__: | 
					
						
							|  |  |  |             self.sysmod.excepthook = self.sysmod.__excepthook__ | 
					
						
							| 
									
										
										
										
											2017-10-27 21:45:19 -04:00
										 |  |  |         del self.sysmod.ps1 | 
					
						
							|  |  |  |         del self.sysmod.ps2 | 
					
						
							| 
									
										
										
										
											2012-08-20 23:02:28 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_ps1(self): | 
					
						
							|  |  |  |         self.infunc.side_effect = EOFError('Finished') | 
					
						
							|  |  |  |         self.console.interact() | 
					
						
							|  |  |  |         self.assertEqual(self.sysmod.ps1, '>>> ') | 
					
						
							| 
									
										
										
										
											2017-10-27 21:45:19 -04:00
										 |  |  |         self.sysmod.ps1 = 'custom1> ' | 
					
						
							|  |  |  |         self.console.interact() | 
					
						
							|  |  |  |         self.assertEqual(self.sysmod.ps1, 'custom1> ') | 
					
						
							| 
									
										
										
										
											2012-08-20 23:02:28 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_ps2(self): | 
					
						
							|  |  |  |         self.infunc.side_effect = EOFError('Finished') | 
					
						
							|  |  |  |         self.console.interact() | 
					
						
							|  |  |  |         self.assertEqual(self.sysmod.ps2, '... ') | 
					
						
							| 
									
										
										
										
											2017-10-27 21:45:19 -04:00
										 |  |  |         self.sysmod.ps1 = 'custom2> ' | 
					
						
							|  |  |  |         self.console.interact() | 
					
						
							|  |  |  |         self.assertEqual(self.sysmod.ps1, 'custom2> ') | 
					
						
							| 
									
										
										
										
											2012-08-20 23:02:28 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_console_stderr(self): | 
					
						
							|  |  |  |         self.infunc.side_effect = ["'antioch'", "", EOFError('Finished')] | 
					
						
							|  |  |  |         self.console.interact() | 
					
						
							|  |  |  |         for call in list(self.stdout.method_calls): | 
					
						
							|  |  |  |             if 'antioch' in ''.join(call[1]): | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise AssertionError("no console stdout") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_syntax_error(self): | 
					
						
							|  |  |  |         self.infunc.side_effect = ["undefined", EOFError('Finished')] | 
					
						
							|  |  |  |         self.console.interact() | 
					
						
							|  |  |  |         for call in self.stderr.method_calls: | 
					
						
							| 
									
										
										
										
											2014-05-13 11:28:12 +02:00
										 |  |  |             if 'NameError' in ''.join(call[1]): | 
					
						
							| 
									
										
										
										
											2012-08-20 23:02:28 +10:00
										 |  |  |                 break | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise AssertionError("No syntax error from console") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_sysexcepthook(self): | 
					
						
							|  |  |  |         self.infunc.side_effect = ["raise ValueError('')", | 
					
						
							|  |  |  |                                     EOFError('Finished')] | 
					
						
							|  |  |  |         hook = mock.Mock() | 
					
						
							|  |  |  |         self.sysmod.excepthook = hook | 
					
						
							|  |  |  |         self.console.interact() | 
					
						
							|  |  |  |         self.assertTrue(hook.called) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-13 21:49:06 +02:00
										 |  |  |     def test_banner(self): | 
					
						
							|  |  |  |         # with banner | 
					
						
							|  |  |  |         self.infunc.side_effect = EOFError('Finished') | 
					
						
							|  |  |  |         self.console.interact(banner='Foo') | 
					
						
							| 
									
										
										
										
											2016-08-15 04:14:33 +10:00
										 |  |  |         self.assertEqual(len(self.stderr.method_calls), 3) | 
					
						
							| 
									
										
										
										
											2013-10-13 21:49:06 +02:00
										 |  |  |         banner_call = self.stderr.method_calls[0] | 
					
						
							|  |  |  |         self.assertEqual(banner_call, ['write', ('Foo\n',), {}]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # no banner | 
					
						
							|  |  |  |         self.stderr.reset_mock() | 
					
						
							|  |  |  |         self.infunc.side_effect = EOFError('Finished') | 
					
						
							|  |  |  |         self.console.interact(banner='') | 
					
						
							| 
									
										
										
										
											2016-08-15 04:14:33 +10:00
										 |  |  |         self.assertEqual(len(self.stderr.method_calls), 2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_exit_msg(self): | 
					
						
							| 
									
										
										
										
											2016-08-24 01:42:15 +10:00
										 |  |  |         # default exit message | 
					
						
							| 
									
										
										
										
											2016-08-15 04:14:33 +10:00
										 |  |  |         self.infunc.side_effect = EOFError('Finished') | 
					
						
							|  |  |  |         self.console.interact(banner='') | 
					
						
							|  |  |  |         self.assertEqual(len(self.stderr.method_calls), 2) | 
					
						
							|  |  |  |         err_msg = self.stderr.method_calls[1] | 
					
						
							|  |  |  |         expected = 'now exiting InteractiveConsole...\n' | 
					
						
							|  |  |  |         self.assertEqual(err_msg, ['write', (expected,), {}]) | 
					
						
							| 
									
										
										
										
											2013-10-13 21:49:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 01:42:15 +10:00
										 |  |  |         # no exit message | 
					
						
							|  |  |  |         self.stderr.reset_mock() | 
					
						
							|  |  |  |         self.infunc.side_effect = EOFError('Finished') | 
					
						
							|  |  |  |         self.console.interact(banner='', exitmsg='') | 
					
						
							|  |  |  |         self.assertEqual(len(self.stderr.method_calls), 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # custom exit message | 
					
						
							|  |  |  |         self.stderr.reset_mock() | 
					
						
							|  |  |  |         message = ( | 
					
						
							|  |  |  |             'bye! \N{GREEK SMALL LETTER ZETA}\N{CYRILLIC SMALL LETTER ZHE}' | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         self.infunc.side_effect = EOFError('Finished') | 
					
						
							|  |  |  |         self.console.interact(banner='', exitmsg=message) | 
					
						
							|  |  |  |         self.assertEqual(len(self.stderr.method_calls), 2) | 
					
						
							|  |  |  |         err_msg = self.stderr.method_calls[1] | 
					
						
							|  |  |  |         expected = message + '\n' | 
					
						
							|  |  |  |         self.assertEqual(err_msg, ['write', (expected,), {}]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-29 11:25:00 -04:00
										 |  |  |     def test_cause_tb(self): | 
					
						
							|  |  |  |         self.infunc.side_effect = ["raise ValueError('') from AttributeError", | 
					
						
							|  |  |  |                                     EOFError('Finished')] | 
					
						
							|  |  |  |         self.console.interact() | 
					
						
							|  |  |  |         output = ''.join(''.join(call[1]) for call in self.stderr.method_calls) | 
					
						
							|  |  |  |         expected = dedent("""
 | 
					
						
							|  |  |  |         AttributeError | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         The above exception was the direct cause of the following exception: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Traceback (most recent call last): | 
					
						
							|  |  |  |           File "<console>", line 1, in <module> | 
					
						
							|  |  |  |         ValueError | 
					
						
							|  |  |  |         """)
 | 
					
						
							|  |  |  |         self.assertIn(expected, output) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_context_tb(self): | 
					
						
							|  |  |  |         self.infunc.side_effect = ["try: ham\nexcept: eggs\n", | 
					
						
							|  |  |  |                                     EOFError('Finished')] | 
					
						
							|  |  |  |         self.console.interact() | 
					
						
							|  |  |  |         output = ''.join(''.join(call[1]) for call in self.stderr.method_calls) | 
					
						
							|  |  |  |         expected = dedent("""
 | 
					
						
							|  |  |  |         Traceback (most recent call last): | 
					
						
							|  |  |  |           File "<console>", line 1, in <module> | 
					
						
							|  |  |  |         NameError: name 'ham' is not defined | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         During handling of the above exception, another exception occurred: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Traceback (most recent call last): | 
					
						
							|  |  |  |           File "<console>", line 2, in <module> | 
					
						
							|  |  |  |         NameError: name 'eggs' is not defined | 
					
						
							|  |  |  |         """)
 | 
					
						
							|  |  |  |         self.assertIn(expected, output) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-20 23:02:28 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     unittest.main() |