Coverage for idle_test/test_run.py: 97%
352 statements
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-11 13:22 -0700
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-11 13:22 -0700
1"Test run, coverage 54%."
3from idlelib import run
4import io
5import sys
6from test.support import captured_output, captured_stderr
7import unittest
8from unittest import mock
9import idlelib
10from idlelib.idle_test.mock_idle import Func
12idlelib.testing = True # Use {} for executing test user code.
15class ExceptionTest(unittest.TestCase):
17 def test_print_exception_unhashable(self):
18 class UnhashableException(Exception): 1i
19 def __eq__(self, other): 1i
20 return True
22 ex1 = UnhashableException('ex1') 1i
23 ex2 = UnhashableException('ex2') 1i
24 try: 1i
25 raise ex2 from ex1 1i
26 except UnhashableException: 1i
27 try: 1i
28 raise ex1 1i
29 except UnhashableException: 1i
30 with captured_stderr() as output: 1i
31 with mock.patch.object(run, 'cleanup_traceback') as ct: 1i
32 ct.side_effect = lambda t, e: t 1i
33 run.print_exception() 1i
35 tb = output.getvalue().strip().splitlines() 1i
36 self.assertEqual(11, len(tb)) 1i
37 self.assertIn('UnhashableException: ex2', tb[3]) 1i
38 self.assertIn('UnhashableException: ex1', tb[10]) 1i
40 data = (('1/0', ZeroDivisionError, "division by zero\n"),
41 ('abc', NameError, "name 'abc' is not defined. "
42 "Did you mean: 'abs'? "
43 "Or did you forget to import 'abc'?\n"),
44 ('int.reel', AttributeError,
45 "type object 'int' has no attribute 'reel'. "
46 "Did you mean: 'real'?\n"),
47 )
49 def test_get_message(self):
50 for code, exc, msg in self.data: 1p
51 with self.subTest(code=code): 1p
52 try: 1p
53 eval(compile(code, '', 'eval')) 1p
54 except exc: 1p
55 typ, val, tb = sys.exc_info() 1p
56 actual = run.get_message_lines(typ, val, tb)[0] 1p
57 expect = f'{exc.__name__}: {msg}' 1p
58 self.assertEqual(actual, expect) 1p
60 @mock.patch.object(run, 'cleanup_traceback',
61 new_callable=lambda: (lambda t, e: None))
62 def test_get_multiple_message(self, mock):
63 d = self.data 1j
64 data2 = ((d[0], d[1]), (d[1], d[2]), (d[2], d[0])) 1j
65 subtests = 0 1j
66 for (code1, exc1, msg1), (code2, exc2, msg2) in data2: 1j
67 with self.subTest(codes=(code1,code2)): 1j
68 try: 1j
69 eval(compile(code1, '', 'eval')) 1j
70 except exc1: 1j
71 try: 1j
72 eval(compile(code2, '', 'eval')) 1j
73 except exc2: 1j
74 with captured_stderr() as output: 1j
75 run.print_exception() 1j
76 actual = output.getvalue() 1j
77 self.assertIn(msg1, actual) 1j
78 self.assertIn(msg2, actual) 1j
79 subtests += 1 1j
80 self.assertEqual(subtests, len(data2)) # All subtests ran? 1j
82# StdioFile tests.
84class S(str):
85 def __str__(self):
86 return '%s:str' % type(self).__name__
87 def __unicode__(self):
88 return '%s:unicode' % type(self).__name__
89 def __len__(self):
90 return 3
91 def __iter__(self):
92 return iter('abc')
93 def __getitem__(self, *args):
94 return '%s:item' % type(self).__name__
95 def __getslice__(self, *args):
96 return '%s:slice' % type(self).__name__
99class MockShell:
100 def __init__(self):
101 self.reset() 1klfcdqnmrehb
102 def write(self, *args):
103 self.written.append(args) 1nehb
104 def readline(self):
105 return self.lines.pop() 1kfcd
106 def close(self):
107 pass 1ak
108 def reset(self):
109 self.written = [] 1klfcdqnmrehb
110 def push(self, lines):
111 self.lines = list(lines)[::-1] 1kfcd
114class StdInputFilesTest(unittest.TestCase):
116 def test_misc(self):
117 shell = MockShell() 1l
118 f = run.StdInputFile(shell, 'stdin') 1l
119 self.assertIsInstance(f, io.TextIOBase) 1l
120 self.assertEqual(f.encoding, 'utf-8') 1l
121 self.assertEqual(f.errors, 'strict') 1l
122 self.assertIsNone(f.newlines) 1l
123 self.assertEqual(f.name, '<stdin>') 1l
124 self.assertFalse(f.closed) 1l
125 self.assertTrue(f.isatty()) 1l
126 self.assertTrue(f.readable()) 1l
127 self.assertFalse(f.writable()) 1l
128 self.assertFalse(f.seekable()) 1l
130 def test_unsupported(self):
131 shell = MockShell() 1q
132 f = run.StdInputFile(shell, 'stdin') 1q
133 self.assertRaises(OSError, f.fileno) 1q
134 self.assertRaises(OSError, f.tell) 1q
135 self.assertRaises(OSError, f.seek, 0) 1q
136 self.assertRaises(OSError, f.write, 'x') 1q
137 self.assertRaises(OSError, f.writelines, ['x']) 1q
139 def test_read(self):
140 shell = MockShell() 1f
141 f = run.StdInputFile(shell, 'stdin') 1f
142 shell.push(['one\n', 'two\n', '']) 1f
143 self.assertEqual(f.read(), 'one\ntwo\n') 1f
144 shell.push(['one\n', 'two\n', '']) 1f
145 self.assertEqual(f.read(-1), 'one\ntwo\n') 1f
146 shell.push(['one\n', 'two\n', '']) 1f
147 self.assertEqual(f.read(None), 'one\ntwo\n') 1f
148 shell.push(['one\n', 'two\n', 'three\n', '']) 1f
149 self.assertEqual(f.read(2), 'on') 1f
150 self.assertEqual(f.read(3), 'e\nt') 1f
151 self.assertEqual(f.read(10), 'wo\nthree\n') 1f
153 shell.push(['one\n', 'two\n']) 1f
154 self.assertEqual(f.read(0), '') 1f
155 self.assertRaises(TypeError, f.read, 1.5) 1f
156 self.assertRaises(TypeError, f.read, '1') 1f
157 self.assertRaises(TypeError, f.read, 1, 1) 1f
159 def test_readline(self):
160 shell = MockShell() 1c
161 f = run.StdInputFile(shell, 'stdin') 1c
162 shell.push(['one\n', 'two\n', 'three\n', 'four\n']) 1c
163 self.assertEqual(f.readline(), 'one\n') 1c
164 self.assertEqual(f.readline(-1), 'two\n') 1c
165 self.assertEqual(f.readline(None), 'three\n') 1c
166 shell.push(['one\ntwo\n']) 1c
167 self.assertEqual(f.readline(), 'one\n') 1c
168 self.assertEqual(f.readline(), 'two\n') 1c
169 shell.push(['one', 'two', 'three']) 1c
170 self.assertEqual(f.readline(), 'one') 1c
171 self.assertEqual(f.readline(), 'two') 1c
172 shell.push(['one\n', 'two\n', 'three\n']) 1c
173 self.assertEqual(f.readline(2), 'on') 1c
174 self.assertEqual(f.readline(1), 'e') 1c
175 self.assertEqual(f.readline(1), '\n') 1c
176 self.assertEqual(f.readline(10), 'two\n') 1c
178 shell.push(['one\n', 'two\n']) 1c
179 self.assertEqual(f.readline(0), '') 1c
180 self.assertRaises(TypeError, f.readlines, 1.5) 1c
181 self.assertRaises(TypeError, f.readlines, '1') 1c
182 self.assertRaises(TypeError, f.readlines, 1, 1) 1c
184 def test_readlines(self):
185 shell = MockShell() 1d
186 f = run.StdInputFile(shell, 'stdin') 1d
187 shell.push(['one\n', 'two\n', '']) 1d
188 self.assertEqual(f.readlines(), ['one\n', 'two\n']) 1d
189 shell.push(['one\n', 'two\n', '']) 1d
190 self.assertEqual(f.readlines(-1), ['one\n', 'two\n']) 1d
191 shell.push(['one\n', 'two\n', '']) 1d
192 self.assertEqual(f.readlines(None), ['one\n', 'two\n']) 1d
193 shell.push(['one\n', 'two\n', '']) 1d
194 self.assertEqual(f.readlines(0), ['one\n', 'two\n']) 1d
195 shell.push(['one\n', 'two\n', '']) 1d
196 self.assertEqual(f.readlines(3), ['one\n']) 1d
197 shell.push(['one\n', 'two\n', '']) 1d
198 self.assertEqual(f.readlines(4), ['one\n', 'two\n']) 1d
200 shell.push(['one\n', 'two\n', '']) 1d
201 self.assertRaises(TypeError, f.readlines, 1.5) 1d
202 self.assertRaises(TypeError, f.readlines, '1') 1d
203 self.assertRaises(TypeError, f.readlines, 1, 1) 1d
205 def test_close(self):
206 shell = MockShell() 1k
207 f = run.StdInputFile(shell, 'stdin') 1k
208 shell.push(['one\n', 'two\n', '']) 1k
209 self.assertFalse(f.closed) 1k
210 self.assertEqual(f.readline(), 'one\n') 1k
211 f.close() 1k
212 self.assertFalse(f.closed) 1k
213 self.assertEqual(f.readline(), 'two\n') 1k
214 self.assertRaises(TypeError, f.close, 1) 1k
217class StdOutputFilesTest(unittest.TestCase):
219 def test_misc(self):
220 shell = MockShell() 1m
221 f = run.StdOutputFile(shell, 'stdout') 1m
222 self.assertIsInstance(f, io.TextIOBase) 1m
223 self.assertEqual(f.encoding, 'utf-8') 1m
224 self.assertEqual(f.errors, 'strict') 1m
225 self.assertIsNone(f.newlines) 1m
226 self.assertEqual(f.name, '<stdout>') 1m
227 self.assertFalse(f.closed) 1m
228 self.assertTrue(f.isatty()) 1m
229 self.assertFalse(f.readable()) 1m
230 self.assertTrue(f.writable()) 1m
231 self.assertFalse(f.seekable()) 1m
233 def test_unsupported(self):
234 shell = MockShell() 1r
235 f = run.StdOutputFile(shell, 'stdout') 1r
236 self.assertRaises(OSError, f.fileno) 1r
237 self.assertRaises(OSError, f.tell) 1r
238 self.assertRaises(OSError, f.seek, 0) 1r
239 self.assertRaises(OSError, f.read, 0) 1r
240 self.assertRaises(OSError, f.readline, 0) 1r
242 def test_write(self):
243 shell = MockShell() 1e
244 f = run.StdOutputFile(shell, 'stdout') 1e
245 f.write('test') 1e
246 self.assertEqual(shell.written, [('test', 'stdout')]) 1e
247 shell.reset() 1e
248 f.write('t\xe8\u015b\U0001d599') 1e
249 self.assertEqual(shell.written, [('t\xe8\u015b\U0001d599', 'stdout')]) 1e
250 shell.reset() 1e
252 f.write(S('t\xe8\u015b\U0001d599')) 1e
253 self.assertEqual(shell.written, [('t\xe8\u015b\U0001d599', 'stdout')]) 1e
254 self.assertEqual(type(shell.written[0][0]), str) 1e
255 shell.reset() 1e
257 self.assertRaises(TypeError, f.write) 1e
258 self.assertEqual(shell.written, []) 1e
259 self.assertRaises(TypeError, f.write, b'test') 1e
260 self.assertRaises(TypeError, f.write, 123) 1e
261 self.assertEqual(shell.written, []) 1e
262 self.assertRaises(TypeError, f.write, 'test', 'spam') 1e
263 self.assertEqual(shell.written, []) 1e
265 def test_write_stderr_nonencodable(self):
266 shell = MockShell() 1h
267 f = run.StdOutputFile(shell, 'stderr', 'iso-8859-15', 'backslashreplace') 1h
268 f.write('t\xe8\u015b\U0001d599\xa4') 1h
269 self.assertEqual(shell.written, [('t\xe8\\u015b\\U0001d599\\xa4', 'stderr')]) 1h
270 shell.reset() 1h
272 f.write(S('t\xe8\u015b\U0001d599\xa4')) 1h
273 self.assertEqual(shell.written, [('t\xe8\\u015b\\U0001d599\\xa4', 'stderr')]) 1h
274 self.assertEqual(type(shell.written[0][0]), str) 1h
275 shell.reset() 1h
277 self.assertRaises(TypeError, f.write) 1h
278 self.assertEqual(shell.written, []) 1h
279 self.assertRaises(TypeError, f.write, b'test') 1h
280 self.assertRaises(TypeError, f.write, 123) 1h
281 self.assertEqual(shell.written, []) 1h
282 self.assertRaises(TypeError, f.write, 'test', 'spam') 1h
283 self.assertEqual(shell.written, []) 1h
285 def test_writelines(self):
286 shell = MockShell() 1b
287 f = run.StdOutputFile(shell, 'stdout') 1b
288 f.writelines([]) 1b
289 self.assertEqual(shell.written, []) 1b
290 shell.reset() 1b
291 f.writelines(['one\n', 'two']) 1b
292 self.assertEqual(shell.written, 1b
293 [('one\n', 'stdout'), ('two', 'stdout')])
294 shell.reset() 1b
295 f.writelines(['on\xe8\n', 'tw\xf2']) 1b
296 self.assertEqual(shell.written, 1b
297 [('on\xe8\n', 'stdout'), ('tw\xf2', 'stdout')])
298 shell.reset() 1b
300 f.writelines([S('t\xe8st')]) 1b
301 self.assertEqual(shell.written, [('t\xe8st', 'stdout')]) 1b
302 self.assertEqual(type(shell.written[0][0]), str) 1b
303 shell.reset() 1b
305 self.assertRaises(TypeError, f.writelines) 1b
306 self.assertEqual(shell.written, []) 1b
307 self.assertRaises(TypeError, f.writelines, 123) 1b
308 self.assertEqual(shell.written, []) 1b
309 self.assertRaises(TypeError, f.writelines, [b'test']) 1b
310 self.assertRaises(TypeError, f.writelines, [123]) 1b
311 self.assertEqual(shell.written, []) 1b
312 self.assertRaises(TypeError, f.writelines, [], []) 1b
313 self.assertEqual(shell.written, []) 1b
315 def test_close(self):
316 shell = MockShell() 1n
317 f = run.StdOutputFile(shell, 'stdout') 1n
318 self.assertFalse(f.closed) 1n
319 f.write('test') 1n
320 f.close() 1n
321 self.assertTrue(f.closed) 1n
322 self.assertRaises(ValueError, f.write, 'x') 1n
323 self.assertEqual(shell.written, [('test', 'stdout')]) 1n
324 f.close() 1n
325 self.assertRaises(TypeError, f.close, 1) 1n
328class RecursionLimitTest(unittest.TestCase):
329 # Test (un)install_recursionlimit_wrappers and fixdoc.
331 def test_bad_setrecursionlimit_calls(self):
332 run.install_recursionlimit_wrappers() 1t
333 self.addCleanup(run.uninstall_recursionlimit_wrappers) 1t
334 f = sys.setrecursionlimit 1t
335 self.assertRaises(TypeError, f, limit=100) 1t
336 self.assertRaises(TypeError, f, 100, 1000) 1t
337 self.assertRaises(ValueError, f, 0) 1t
339 def test_roundtrip(self):
340 run.install_recursionlimit_wrappers() 1s
341 self.addCleanup(run.uninstall_recursionlimit_wrappers) 1s
343 # Check that setting the recursion limit works.
344 orig_reclimit = sys.getrecursionlimit() 1s
345 self.addCleanup(sys.setrecursionlimit, orig_reclimit) 1s
346 sys.setrecursionlimit(orig_reclimit + 3) 1s
348 # Check that the new limit is returned by sys.getrecursionlimit().
349 new_reclimit = sys.getrecursionlimit() 1s
350 self.assertEqual(new_reclimit, orig_reclimit + 3) 1s
352 def test_default_recursion_limit_preserved(self):
353 orig_reclimit = sys.getrecursionlimit() 1v
354 run.install_recursionlimit_wrappers() 1v
355 self.addCleanup(run.uninstall_recursionlimit_wrappers) 1v
356 new_reclimit = sys.getrecursionlimit() 1v
357 self.assertEqual(new_reclimit, orig_reclimit) 1v
359 def test_fixdoc(self):
360 # Put here until better place for miscellaneous test.
361 def func(): "docstring" 361 ↛ exitline 361 didn't return from function 'func'1u
362 run.fixdoc(func, "more") 1u
363 self.assertEqual(func.__doc__, "docstring\n\nmore") 1u
364 func.__doc__ = None 1u
365 run.fixdoc(func, "more") 1u
366 self.assertEqual(func.__doc__, "more") 1u
369class HandleErrorTest(unittest.TestCase):
370 # Method of MyRPCServer
371 def test_fatal_error(self):
372 eq = self.assertEqual 1g
373 with captured_output('__stderr__') as err,\ 1g
374 mock.patch('idlelib.run.thread.interrupt_main',
375 new_callable=Func) as func:
376 try: 1g
377 raise EOFError 1g
378 except EOFError: 1g
379 run.MyRPCServer.handle_error(None, 'abc', '123') 1g
380 eq(run.exit_now, True) 1g
381 run.exit_now = False 1g
382 eq(err.getvalue(), '') 1g
384 try: 1g
385 raise IndexError 1g
386 except IndexError: 1g
387 run.MyRPCServer.handle_error(None, 'abc', '123') 1g
388 eq(run.quitting, True) 1g
389 run.quitting = False 1g
390 msg = err.getvalue() 1g
391 self.assertIn('abc', msg) 1g
392 self.assertIn('123', msg) 1g
393 self.assertIn('IndexError', msg) 1g
394 eq(func.called, 2) 1g
397class ExecRuncodeTest(unittest.TestCase):
399 @classmethod
400 def setUpClass(cls):
401 cls.addClassCleanup(setattr,run,'print_exception',run.print_exception)
402 cls.prt = Func() # Need reference.
403 run.print_exception = cls.prt
404 mockrpc = mock.Mock()
405 mockrpc.console.getvar = Func(result=False)
406 cls.ex = run.Executive(mockrpc)
408 @classmethod
409 def tearDownClass(cls):
410 assert sys.excepthook == sys.__excepthook__
412 def test_exceptions(self):
413 ex = self.ex 1o
414 ex.runcode('1/0') 1o
415 self.assertIs(ex.user_exc_info[0], ZeroDivisionError) 1o
417 self.addCleanup(setattr, sys, 'excepthook', sys.__excepthook__) 1o
418 sys.excepthook = lambda t, e, tb: run.print_exception(t) 1o
419 ex.runcode('1/0') 1o
420 self.assertIs(self.prt.args[0], ZeroDivisionError) 1o
422 sys.excepthook = lambda: None 422 ↛ exitline 422 didn't run the lambda on line 4221o
423 ex.runcode('1/0') 1o
424 t, e, tb = ex.user_exc_info 1o
425 self.assertIs(t, TypeError) 1o
426 self.assertTrue(isinstance(e.__context__, ZeroDivisionError)) 1o
429if __name__ == '__main__': 429 ↛ 430line 429 didn't jump to line 430, because the condition on line 429 was never true
430 unittest.main(verbosity=2)