1 "Test run, coverage 54%."
2
3 from idlelib import run
4 import io
5 import sys
6 from test.support import captured_output, captured_stderr
7 import unittest
8 from unittest import mock
9 import idlelib
10 from idlelib.idle_test.mock_idle import Func
11
12 idlelib.testing = True # Use {} for executing test user code.
13
14
15 class ESC[4;38;5;81mExceptionTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
16
17 def test_print_exception_unhashable(self):
18 class ESC[4;38;5;81mUnhashableException(ESC[4;38;5;149mException):
19 def __eq__(self, other):
20 return True
21
22 ex1 = UnhashableException('ex1')
23 ex2 = UnhashableException('ex2')
24 try:
25 raise ex2 from ex1
26 except UnhashableException:
27 try:
28 raise ex1
29 except UnhashableException:
30 with captured_stderr() as output:
31 with mock.patch.object(run, 'cleanup_traceback') as ct:
32 ct.side_effect = lambda t, e: t
33 run.print_exception()
34
35 tb = output.getvalue().strip().splitlines()
36 self.assertEqual(11, len(tb))
37 self.assertIn('UnhashableException: ex2', tb[3])
38 self.assertIn('UnhashableException: ex1', tb[10])
39
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 )
48
49 def test_get_message(self):
50 for code, exc, msg in self.data:
51 with self.subTest(code=code):
52 try:
53 eval(compile(code, '', 'eval'))
54 except exc:
55 typ, val, tb = sys.exc_info()
56 actual = run.get_message_lines(typ, val, tb)[0]
57 expect = f'{exc.__name__}: {msg}'
58 self.assertEqual(actual, expect)
59
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
64 data2 = ((d[0], d[1]), (d[1], d[2]), (d[2], d[0]))
65 subtests = 0
66 for (code1, exc1, msg1), (code2, exc2, msg2) in data2:
67 with self.subTest(codes=(code1,code2)):
68 try:
69 eval(compile(code1, '', 'eval'))
70 except exc1:
71 try:
72 eval(compile(code2, '', 'eval'))
73 except exc2:
74 with captured_stderr() as output:
75 run.print_exception()
76 actual = output.getvalue()
77 self.assertIn(msg1, actual)
78 self.assertIn(msg2, actual)
79 subtests += 1
80 self.assertEqual(subtests, len(data2)) # All subtests ran?
81
82 # StdioFile tests.
83
84 class ESC[4;38;5;81mS(ESC[4;38;5;149mstr):
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__
97
98
99 class ESC[4;38;5;81mMockShell:
100 def __init__(self):
101 self.reset()
102 def write(self, *args):
103 self.written.append(args)
104 def readline(self):
105 return self.lines.pop()
106 def close(self):
107 pass
108 def reset(self):
109 self.written = []
110 def push(self, lines):
111 self.lines = list(lines)[::-1]
112
113
114 class ESC[4;38;5;81mStdInputFilesTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
115
116 def test_misc(self):
117 shell = MockShell()
118 f = run.StdInputFile(shell, 'stdin')
119 self.assertIsInstance(f, io.TextIOBase)
120 self.assertEqual(f.encoding, 'utf-8')
121 self.assertEqual(f.errors, 'strict')
122 self.assertIsNone(f.newlines)
123 self.assertEqual(f.name, '<stdin>')
124 self.assertFalse(f.closed)
125 self.assertTrue(f.isatty())
126 self.assertTrue(f.readable())
127 self.assertFalse(f.writable())
128 self.assertFalse(f.seekable())
129
130 def test_unsupported(self):
131 shell = MockShell()
132 f = run.StdInputFile(shell, 'stdin')
133 self.assertRaises(OSError, f.fileno)
134 self.assertRaises(OSError, f.tell)
135 self.assertRaises(OSError, f.seek, 0)
136 self.assertRaises(OSError, f.write, 'x')
137 self.assertRaises(OSError, f.writelines, ['x'])
138
139 def test_read(self):
140 shell = MockShell()
141 f = run.StdInputFile(shell, 'stdin')
142 shell.push(['one\n', 'two\n', ''])
143 self.assertEqual(f.read(), 'one\ntwo\n')
144 shell.push(['one\n', 'two\n', ''])
145 self.assertEqual(f.read(-1), 'one\ntwo\n')
146 shell.push(['one\n', 'two\n', ''])
147 self.assertEqual(f.read(None), 'one\ntwo\n')
148 shell.push(['one\n', 'two\n', 'three\n', ''])
149 self.assertEqual(f.read(2), 'on')
150 self.assertEqual(f.read(3), 'e\nt')
151 self.assertEqual(f.read(10), 'wo\nthree\n')
152
153 shell.push(['one\n', 'two\n'])
154 self.assertEqual(f.read(0), '')
155 self.assertRaises(TypeError, f.read, 1.5)
156 self.assertRaises(TypeError, f.read, '1')
157 self.assertRaises(TypeError, f.read, 1, 1)
158
159 def test_readline(self):
160 shell = MockShell()
161 f = run.StdInputFile(shell, 'stdin')
162 shell.push(['one\n', 'two\n', 'three\n', 'four\n'])
163 self.assertEqual(f.readline(), 'one\n')
164 self.assertEqual(f.readline(-1), 'two\n')
165 self.assertEqual(f.readline(None), 'three\n')
166 shell.push(['one\ntwo\n'])
167 self.assertEqual(f.readline(), 'one\n')
168 self.assertEqual(f.readline(), 'two\n')
169 shell.push(['one', 'two', 'three'])
170 self.assertEqual(f.readline(), 'one')
171 self.assertEqual(f.readline(), 'two')
172 shell.push(['one\n', 'two\n', 'three\n'])
173 self.assertEqual(f.readline(2), 'on')
174 self.assertEqual(f.readline(1), 'e')
175 self.assertEqual(f.readline(1), '\n')
176 self.assertEqual(f.readline(10), 'two\n')
177
178 shell.push(['one\n', 'two\n'])
179 self.assertEqual(f.readline(0), '')
180 self.assertRaises(TypeError, f.readlines, 1.5)
181 self.assertRaises(TypeError, f.readlines, '1')
182 self.assertRaises(TypeError, f.readlines, 1, 1)
183
184 def test_readlines(self):
185 shell = MockShell()
186 f = run.StdInputFile(shell, 'stdin')
187 shell.push(['one\n', 'two\n', ''])
188 self.assertEqual(f.readlines(), ['one\n', 'two\n'])
189 shell.push(['one\n', 'two\n', ''])
190 self.assertEqual(f.readlines(-1), ['one\n', 'two\n'])
191 shell.push(['one\n', 'two\n', ''])
192 self.assertEqual(f.readlines(None), ['one\n', 'two\n'])
193 shell.push(['one\n', 'two\n', ''])
194 self.assertEqual(f.readlines(0), ['one\n', 'two\n'])
195 shell.push(['one\n', 'two\n', ''])
196 self.assertEqual(f.readlines(3), ['one\n'])
197 shell.push(['one\n', 'two\n', ''])
198 self.assertEqual(f.readlines(4), ['one\n', 'two\n'])
199
200 shell.push(['one\n', 'two\n', ''])
201 self.assertRaises(TypeError, f.readlines, 1.5)
202 self.assertRaises(TypeError, f.readlines, '1')
203 self.assertRaises(TypeError, f.readlines, 1, 1)
204
205 def test_close(self):
206 shell = MockShell()
207 f = run.StdInputFile(shell, 'stdin')
208 shell.push(['one\n', 'two\n', ''])
209 self.assertFalse(f.closed)
210 self.assertEqual(f.readline(), 'one\n')
211 f.close()
212 self.assertFalse(f.closed)
213 self.assertEqual(f.readline(), 'two\n')
214 self.assertRaises(TypeError, f.close, 1)
215
216
217 class ESC[4;38;5;81mStdOutputFilesTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
218
219 def test_misc(self):
220 shell = MockShell()
221 f = run.StdOutputFile(shell, 'stdout')
222 self.assertIsInstance(f, io.TextIOBase)
223 self.assertEqual(f.encoding, 'utf-8')
224 self.assertEqual(f.errors, 'strict')
225 self.assertIsNone(f.newlines)
226 self.assertEqual(f.name, '<stdout>')
227 self.assertFalse(f.closed)
228 self.assertTrue(f.isatty())
229 self.assertFalse(f.readable())
230 self.assertTrue(f.writable())
231 self.assertFalse(f.seekable())
232
233 def test_unsupported(self):
234 shell = MockShell()
235 f = run.StdOutputFile(shell, 'stdout')
236 self.assertRaises(OSError, f.fileno)
237 self.assertRaises(OSError, f.tell)
238 self.assertRaises(OSError, f.seek, 0)
239 self.assertRaises(OSError, f.read, 0)
240 self.assertRaises(OSError, f.readline, 0)
241
242 def test_write(self):
243 shell = MockShell()
244 f = run.StdOutputFile(shell, 'stdout')
245 f.write('test')
246 self.assertEqual(shell.written, [('test', 'stdout')])
247 shell.reset()
248 f.write('t\xe8\u015b\U0001d599')
249 self.assertEqual(shell.written, [('t\xe8\u015b\U0001d599', 'stdout')])
250 shell.reset()
251
252 f.write(S('t\xe8\u015b\U0001d599'))
253 self.assertEqual(shell.written, [('t\xe8\u015b\U0001d599', 'stdout')])
254 self.assertEqual(type(shell.written[0][0]), str)
255 shell.reset()
256
257 self.assertRaises(TypeError, f.write)
258 self.assertEqual(shell.written, [])
259 self.assertRaises(TypeError, f.write, b'test')
260 self.assertRaises(TypeError, f.write, 123)
261 self.assertEqual(shell.written, [])
262 self.assertRaises(TypeError, f.write, 'test', 'spam')
263 self.assertEqual(shell.written, [])
264
265 def test_write_stderr_nonencodable(self):
266 shell = MockShell()
267 f = run.StdOutputFile(shell, 'stderr', 'iso-8859-15', 'backslashreplace')
268 f.write('t\xe8\u015b\U0001d599\xa4')
269 self.assertEqual(shell.written, [('t\xe8\\u015b\\U0001d599\\xa4', 'stderr')])
270 shell.reset()
271
272 f.write(S('t\xe8\u015b\U0001d599\xa4'))
273 self.assertEqual(shell.written, [('t\xe8\\u015b\\U0001d599\\xa4', 'stderr')])
274 self.assertEqual(type(shell.written[0][0]), str)
275 shell.reset()
276
277 self.assertRaises(TypeError, f.write)
278 self.assertEqual(shell.written, [])
279 self.assertRaises(TypeError, f.write, b'test')
280 self.assertRaises(TypeError, f.write, 123)
281 self.assertEqual(shell.written, [])
282 self.assertRaises(TypeError, f.write, 'test', 'spam')
283 self.assertEqual(shell.written, [])
284
285 def test_writelines(self):
286 shell = MockShell()
287 f = run.StdOutputFile(shell, 'stdout')
288 f.writelines([])
289 self.assertEqual(shell.written, [])
290 shell.reset()
291 f.writelines(['one\n', 'two'])
292 self.assertEqual(shell.written,
293 [('one\n', 'stdout'), ('two', 'stdout')])
294 shell.reset()
295 f.writelines(['on\xe8\n', 'tw\xf2'])
296 self.assertEqual(shell.written,
297 [('on\xe8\n', 'stdout'), ('tw\xf2', 'stdout')])
298 shell.reset()
299
300 f.writelines([S('t\xe8st')])
301 self.assertEqual(shell.written, [('t\xe8st', 'stdout')])
302 self.assertEqual(type(shell.written[0][0]), str)
303 shell.reset()
304
305 self.assertRaises(TypeError, f.writelines)
306 self.assertEqual(shell.written, [])
307 self.assertRaises(TypeError, f.writelines, 123)
308 self.assertEqual(shell.written, [])
309 self.assertRaises(TypeError, f.writelines, [b'test'])
310 self.assertRaises(TypeError, f.writelines, [123])
311 self.assertEqual(shell.written, [])
312 self.assertRaises(TypeError, f.writelines, [], [])
313 self.assertEqual(shell.written, [])
314
315 def test_close(self):
316 shell = MockShell()
317 f = run.StdOutputFile(shell, 'stdout')
318 self.assertFalse(f.closed)
319 f.write('test')
320 f.close()
321 self.assertTrue(f.closed)
322 self.assertRaises(ValueError, f.write, 'x')
323 self.assertEqual(shell.written, [('test', 'stdout')])
324 f.close()
325 self.assertRaises(TypeError, f.close, 1)
326
327
328 class ESC[4;38;5;81mRecursionLimitTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
329 # Test (un)install_recursionlimit_wrappers and fixdoc.
330
331 def test_bad_setrecursionlimit_calls(self):
332 run.install_recursionlimit_wrappers()
333 self.addCleanup(run.uninstall_recursionlimit_wrappers)
334 f = sys.setrecursionlimit
335 self.assertRaises(TypeError, f, limit=100)
336 self.assertRaises(TypeError, f, 100, 1000)
337 self.assertRaises(ValueError, f, 0)
338
339 def test_roundtrip(self):
340 run.install_recursionlimit_wrappers()
341 self.addCleanup(run.uninstall_recursionlimit_wrappers)
342
343 # Check that setting the recursion limit works.
344 orig_reclimit = sys.getrecursionlimit()
345 self.addCleanup(sys.setrecursionlimit, orig_reclimit)
346 sys.setrecursionlimit(orig_reclimit + 3)
347
348 # Check that the new limit is returned by sys.getrecursionlimit().
349 new_reclimit = sys.getrecursionlimit()
350 self.assertEqual(new_reclimit, orig_reclimit + 3)
351
352 def test_default_recursion_limit_preserved(self):
353 orig_reclimit = sys.getrecursionlimit()
354 run.install_recursionlimit_wrappers()
355 self.addCleanup(run.uninstall_recursionlimit_wrappers)
356 new_reclimit = sys.getrecursionlimit()
357 self.assertEqual(new_reclimit, orig_reclimit)
358
359 def test_fixdoc(self):
360 # Put here until better place for miscellaneous test.
361 def func(): "docstring"
362 run.fixdoc(func, "more")
363 self.assertEqual(func.__doc__, "docstring\n\nmore")
364 func.__doc__ = None
365 run.fixdoc(func, "more")
366 self.assertEqual(func.__doc__, "more")
367
368
369 class ESC[4;38;5;81mHandleErrorTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
370 # Method of MyRPCServer
371 def test_fatal_error(self):
372 eq = self.assertEqual
373 with captured_output('__stderr__') as err,\
374 mock.patch('idlelib.run.thread.interrupt_main',
375 new_callable=Func) as func:
376 try:
377 raise EOFError
378 except EOFError:
379 run.MyRPCServer.handle_error(None, 'abc', '123')
380 eq(run.exit_now, True)
381 run.exit_now = False
382 eq(err.getvalue(), '')
383
384 try:
385 raise IndexError
386 except IndexError:
387 run.MyRPCServer.handle_error(None, 'abc', '123')
388 eq(run.quitting, True)
389 run.quitting = False
390 msg = err.getvalue()
391 self.assertIn('abc', msg)
392 self.assertIn('123', msg)
393 self.assertIn('IndexError', msg)
394 eq(func.called, 2)
395
396
397 class ESC[4;38;5;81mExecRuncodeTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
398
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)
407
408 @classmethod
409 def tearDownClass(cls):
410 assert sys.excepthook == sys.__excepthook__
411
412 def test_exceptions(self):
413 ex = self.ex
414 ex.runcode('1/0')
415 self.assertIs(ex.user_exc_info[0], ZeroDivisionError)
416
417 self.addCleanup(setattr, sys, 'excepthook', sys.__excepthook__)
418 sys.excepthook = lambda t, e, tb: run.print_exception(t)
419 ex.runcode('1/0')
420 self.assertIs(self.prt.args[0], ZeroDivisionError)
421
422 sys.excepthook = lambda: None
423 ex.runcode('1/0')
424 t, e, tb = ex.user_exc_info
425 self.assertIs(t, TypeError)
426 self.assertTrue(isinstance(e.__context__, ZeroDivisionError))
427
428
429 if __name__ == '__main__':
430 unittest.main(verbosity=2)