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

1"Test run, coverage 54%." 

2 

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 

11 

12idlelib.testing = True # Use {} for executing test user code. 

13 

14 

15class ExceptionTest(unittest.TestCase): 

16 

17 def test_print_exception_unhashable(self): 

18 class UnhashableException(Exception): 1i

19 def __eq__(self, other): 1i

20 return True 

21 

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

34 

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

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: 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

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 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

81 

82# StdioFile tests. 

83 

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__ 

97 

98 

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

112 

113 

114class StdInputFilesTest(unittest.TestCase): 

115 

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

129 

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

138 

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

152 

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

158 

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

177 

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

183 

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

199 

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

204 

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

215 

216 

217class StdOutputFilesTest(unittest.TestCase): 

218 

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

232 

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

241 

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

251 

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

256 

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

264 

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

271 

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

276 

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

284 

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

299 

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

304 

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

314 

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

326 

327 

328class RecursionLimitTest(unittest.TestCase): 

329 # Test (un)install_recursionlimit_wrappers and fixdoc. 

330 

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

338 

339 def test_roundtrip(self): 

340 run.install_recursionlimit_wrappers() 1s

341 self.addCleanup(run.uninstall_recursionlimit_wrappers) 1s

342 

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

347 

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

351 

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

358 

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

367 

368 

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

383 

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

395 

396 

397class ExecRuncodeTest(unittest.TestCase): 

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 1o

414 ex.runcode('1/0') 1o

415 self.assertIs(ex.user_exc_info[0], ZeroDivisionError) 1o

416 

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

421 

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

427 

428 

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)