blob: f9715158993623352f8dcd20b58020b70c39da4b [file] [log] [blame]
Éric Araujob4656242012-02-25 16:57:04 +01001"""Tests for scripts in the Tools directory.
2
3This file contains regression tests for some of the scripts found in the
4Tools directory of a Python checkout or tarball, such as reindent.py.
5"""
6
7import os
R David Murray54ac8322012-04-04 21:28:14 -04008import sys
Brett Cannonc0499522012-05-11 14:48:41 -04009import importlib.machinery
Éric Araujob4656242012-02-25 16:57:04 +010010import unittest
R David Murrayea169802012-04-11 15:17:37 -040011from unittest import mock
Serhiy Storchaka6840a542013-01-11 12:04:23 +020012import shutil
13import subprocess
Éric Araujob4656242012-02-25 16:57:04 +010014import sysconfig
R David Murrayd3af6342012-04-05 22:59:13 -040015import tempfile
Serhiy Storchaka6840a542013-01-11 12:04:23 +020016import textwrap
Éric Araujob4656242012-02-25 16:57:04 +010017from test import support
Serhiy Storchaka6840a542013-01-11 12:04:23 +020018from test.script_helper import assert_python_ok, temp_dir
Éric Araujob4656242012-02-25 16:57:04 +010019
20if not sysconfig.is_python_build():
21 # XXX some installers do contain the tools, should we detect that
22 # and run the tests in that case too?
23 raise unittest.SkipTest('test irrelevant for an installed Python')
24
Antoine Pitrou8afc2432012-06-28 01:20:26 +020025basepath = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
26 'Tools')
R David Murray54ac8322012-04-04 21:28:14 -040027scriptsdir = os.path.join(basepath, 'scripts')
Éric Araujob4656242012-02-25 16:57:04 +010028
29
30class ReindentTests(unittest.TestCase):
R David Murray54ac8322012-04-04 21:28:14 -040031 script = os.path.join(scriptsdir, 'reindent.py')
Éric Araujob4656242012-02-25 16:57:04 +010032
33 def test_noargs(self):
34 assert_python_ok(self.script)
35
36 def test_help(self):
37 rc, out, err = assert_python_ok(self.script, '-h')
38 self.assertEqual(out, b'')
39 self.assertGreater(err, b'')
40
41
Serhiy Storchaka6840a542013-01-11 12:04:23 +020042class PindentTests(unittest.TestCase):
43 script = os.path.join(scriptsdir, 'pindent.py')
44
45 def assertFileEqual(self, fn1, fn2):
46 with open(fn1) as f1, open(fn2) as f2:
47 self.assertEqual(f1.readlines(), f2.readlines())
48
49 def pindent(self, source, *args):
50 with subprocess.Popen(
51 (sys.executable, self.script) + args,
52 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
53 universal_newlines=True) as proc:
Serhiy Storchaka40ce22e2013-01-11 12:10:57 +020054 out, err = proc.communicate(source)
Serhiy Storchaka6840a542013-01-11 12:04:23 +020055 self.assertIsNone(err)
56 return out
57
58 def lstriplines(self, data):
59 return '\n'.join(line.lstrip() for line in data.splitlines()) + '\n'
60
61 def test_selftest(self):
Serhiy Storchakaa3a01b62013-01-11 22:18:17 +020062 self.maxDiff = None
Serhiy Storchaka6840a542013-01-11 12:04:23 +020063 with temp_dir() as directory:
64 data_path = os.path.join(directory, '_test.py')
65 with open(self.script) as f:
66 closed = f.read()
67 with open(data_path, 'w') as f:
68 f.write(closed)
69
70 rc, out, err = assert_python_ok(self.script, '-d', data_path)
71 self.assertEqual(out, b'')
72 self.assertEqual(err, b'')
73 backup = data_path + '~'
74 self.assertTrue(os.path.exists(backup))
75 with open(backup) as f:
76 self.assertEqual(f.read(), closed)
77 with open(data_path) as f:
78 clean = f.read()
79 compile(clean, '_test.py', 'exec')
80 self.assertEqual(self.pindent(clean, '-c'), closed)
81 self.assertEqual(self.pindent(closed, '-d'), clean)
82
83 rc, out, err = assert_python_ok(self.script, '-c', data_path)
84 self.assertEqual(out, b'')
85 self.assertEqual(err, b'')
86 with open(backup) as f:
87 self.assertEqual(f.read(), clean)
88 with open(data_path) as f:
89 self.assertEqual(f.read(), closed)
90
91 broken = self.lstriplines(closed)
92 with open(data_path, 'w') as f:
93 f.write(broken)
94 rc, out, err = assert_python_ok(self.script, '-r', data_path)
95 self.assertEqual(out, b'')
96 self.assertEqual(err, b'')
97 with open(backup) as f:
98 self.assertEqual(f.read(), broken)
99 with open(data_path) as f:
100 indented = f.read()
101 compile(indented, '_test.py', 'exec')
102 self.assertEqual(self.pindent(broken, '-r'), indented)
103
104 def pindent_test(self, clean, closed):
105 self.assertEqual(self.pindent(clean, '-c'), closed)
106 self.assertEqual(self.pindent(closed, '-d'), clean)
107 broken = self.lstriplines(closed)
108 self.assertEqual(self.pindent(broken, '-r', '-e', '-s', '4'), closed)
109
110 def test_statements(self):
111 clean = textwrap.dedent("""\
112 if a:
113 pass
114
115 if a:
116 pass
117 else:
118 pass
119
120 if a:
121 pass
122 elif:
123 pass
124 else:
125 pass
126
127 while a:
128 break
129
130 while a:
131 break
132 else:
133 pass
134
135 for i in a:
136 break
137
138 for i in a:
139 break
140 else:
141 pass
142
143 try:
144 pass
145 finally:
146 pass
147
148 try:
149 pass
150 except TypeError:
151 pass
152 except ValueError:
153 pass
154 else:
155 pass
156
157 try:
158 pass
159 except TypeError:
160 pass
161 except ValueError:
162 pass
163 finally:
164 pass
165
166 with a:
167 pass
168
169 class A:
170 pass
171
172 def f():
173 pass
174 """)
175
176 closed = textwrap.dedent("""\
177 if a:
178 pass
179 # end if
180
181 if a:
182 pass
183 else:
184 pass
185 # end if
186
187 if a:
188 pass
189 elif:
190 pass
191 else:
192 pass
193 # end if
194
195 while a:
196 break
197 # end while
198
199 while a:
200 break
201 else:
202 pass
203 # end while
204
205 for i in a:
206 break
207 # end for
208
209 for i in a:
210 break
211 else:
212 pass
213 # end for
214
215 try:
216 pass
217 finally:
218 pass
219 # end try
220
221 try:
222 pass
223 except TypeError:
224 pass
225 except ValueError:
226 pass
227 else:
228 pass
229 # end try
230
231 try:
232 pass
233 except TypeError:
234 pass
235 except ValueError:
236 pass
237 finally:
238 pass
239 # end try
240
241 with a:
242 pass
243 # end with
244
245 class A:
246 pass
247 # end class A
248
249 def f():
250 pass
251 # end def f
252 """)
253 self.pindent_test(clean, closed)
254
255 def test_multilevel(self):
256 clean = textwrap.dedent("""\
257 def foobar(a, b):
258 if a == b:
259 a = a+1
260 elif a < b:
261 b = b-1
262 if b > a: a = a-1
263 else:
264 print 'oops!'
265 """)
266 closed = textwrap.dedent("""\
267 def foobar(a, b):
268 if a == b:
269 a = a+1
270 elif a < b:
271 b = b-1
272 if b > a: a = a-1
273 # end if
274 else:
275 print 'oops!'
276 # end if
277 # end def foobar
278 """)
279 self.pindent_test(clean, closed)
280
281 def test_preserve_indents(self):
282 clean = textwrap.dedent("""\
283 if a:
284 if b:
285 pass
286 """)
287 closed = textwrap.dedent("""\
288 if a:
289 if b:
290 pass
291 # end if
292 # end if
293 """)
294 self.assertEqual(self.pindent(clean, '-c'), closed)
295 self.assertEqual(self.pindent(closed, '-d'), clean)
296 broken = self.lstriplines(closed)
297 self.assertEqual(self.pindent(broken, '-r', '-e', '-s', '9'), closed)
298 clean = textwrap.dedent("""\
299 if a:
300 \tif b:
301 \t\tpass
302 """)
303 closed = textwrap.dedent("""\
304 if a:
305 \tif b:
306 \t\tpass
307 \t# end if
308 # end if
309 """)
310 self.assertEqual(self.pindent(clean, '-c'), closed)
311 self.assertEqual(self.pindent(closed, '-d'), clean)
312 broken = self.lstriplines(closed)
313 self.assertEqual(self.pindent(broken, '-r'), closed)
314
315 def test_escaped_newline(self):
316 clean = textwrap.dedent("""\
317 class\\
318 \\
319 A:
320 def\
321 \\
322 f:
323 pass
324 """)
325 closed = textwrap.dedent("""\
326 class\\
327 \\
328 A:
329 def\
330 \\
331 f:
332 pass
333 # end def f
334 # end class A
335 """)
336 self.assertEqual(self.pindent(clean, '-c'), closed)
337 self.assertEqual(self.pindent(closed, '-d'), clean)
338
339 def test_empty_line(self):
340 clean = textwrap.dedent("""\
341 if a:
342
343 pass
344 """)
345 closed = textwrap.dedent("""\
346 if a:
347
348 pass
349 # end if
350 """)
351 self.pindent_test(clean, closed)
352
353 def test_oneline(self):
354 clean = textwrap.dedent("""\
355 if a: pass
356 """)
357 closed = textwrap.dedent("""\
358 if a: pass
359 # end if
360 """)
361 self.pindent_test(clean, closed)
362
363
R David Murray54ac8322012-04-04 21:28:14 -0400364class TestSundryScripts(unittest.TestCase):
365 # At least make sure the rest don't have syntax errors. When tests are
366 # added for a script it should be added to the whitelist below.
367
368 # scripts that have independent tests.
R David Murrayea169802012-04-11 15:17:37 -0400369 whitelist = ['reindent.py', 'pdeps.py', 'gprof2html']
R David Murray54ac8322012-04-04 21:28:14 -0400370 # scripts that can't be imported without running
371 blacklist = ['make_ctype.py']
372 # scripts that use windows-only modules
373 windows_only = ['win_add2path.py']
374 # blacklisted for other reasons
375 other = ['analyze_dxp.py']
376
377 skiplist = blacklist + whitelist + windows_only + other
378
379 def setUp(self):
380 cm = support.DirsOnSysPath(scriptsdir)
381 cm.__enter__()
382 self.addCleanup(cm.__exit__)
383
384 def test_sundry(self):
385 for fn in os.listdir(scriptsdir):
386 if fn.endswith('.py') and fn not in self.skiplist:
387 __import__(fn[:-3])
388
389 @unittest.skipIf(sys.platform != "win32", "Windows-only test")
390 def test_sundry_windows(self):
391 for fn in self.windows_only:
392 __import__(fn[:-3])
393
R David Murrayca60b362012-04-04 22:37:50 -0400394 @unittest.skipIf(not support.threading, "test requires _thread module")
R David Murray54ac8322012-04-04 21:28:14 -0400395 def test_analyze_dxp_import(self):
396 if hasattr(sys, 'getdxp'):
397 import analyze_dxp
398 else:
399 with self.assertRaises(RuntimeError):
400 import analyze_dxp
401
402
R David Murrayd3af6342012-04-05 22:59:13 -0400403class PdepsTests(unittest.TestCase):
404
405 @classmethod
406 def setUpClass(self):
407 path = os.path.join(scriptsdir, 'pdeps.py')
Brett Cannonc0499522012-05-11 14:48:41 -0400408 loader = importlib.machinery.SourceFileLoader('pdeps', path)
409 self.pdeps = loader.load_module()
R David Murrayd3af6342012-04-05 22:59:13 -0400410
411 @classmethod
412 def tearDownClass(self):
413 if 'pdeps' in sys.modules:
414 del sys.modules['pdeps']
415
416 def test_process_errors(self):
417 # Issue #14492: m_import.match(line) can be None.
418 with tempfile.TemporaryDirectory() as tmpdir:
419 fn = os.path.join(tmpdir, 'foo')
420 with open(fn, 'w') as stream:
421 stream.write("#!/this/will/fail")
422 self.pdeps.process(fn, {})
423
424 def test_inverse_attribute_error(self):
425 # Issue #14492: this used to fail with an AttributeError.
426 self.pdeps.inverse({'a': []})
427
428
R David Murrayea169802012-04-11 15:17:37 -0400429class Gprof2htmlTests(unittest.TestCase):
430
431 def setUp(self):
432 path = os.path.join(scriptsdir, 'gprof2html.py')
Brett Cannonc0499522012-05-11 14:48:41 -0400433 loader = importlib.machinery.SourceFileLoader('gprof2html', path)
434 self.gprof = loader.load_module()
R David Murrayea169802012-04-11 15:17:37 -0400435 oldargv = sys.argv
436 def fixup():
437 sys.argv = oldargv
438 self.addCleanup(fixup)
439 sys.argv = []
440
441 def test_gprof(self):
442 # Issue #14508: this used to fail with an NameError.
443 with mock.patch.object(self.gprof, 'webbrowser') as wmock, \
444 tempfile.TemporaryDirectory() as tmpdir:
445 fn = os.path.join(tmpdir, 'abc')
446 open(fn, 'w').close()
447 sys.argv = ['gprof2html', fn]
448 self.gprof.main()
449 self.assertTrue(wmock.open.called)
450
451
Mark Dickinson44ceea92012-05-07 10:27:23 +0100452# Run the tests in Tools/parser/test_unparse.py
453with support.DirsOnSysPath(os.path.join(basepath, 'parser')):
Mark Dickinson79575b22012-05-07 22:36:43 +0100454 from test_unparse import UnparseTestCase
Mark Dickinsonbe4fb692012-06-23 09:27:47 +0100455 from test_unparse import DirectoryTestCase
Mark Dickinson44ceea92012-05-07 10:27:23 +0100456
457
Éric Araujob4656242012-02-25 16:57:04 +0100458def test_main():
R David Murray54ac8322012-04-04 21:28:14 -0400459 support.run_unittest(*[obj for obj in globals().values()
460 if isinstance(obj, type)])
Éric Araujob4656242012-02-25 16:57:04 +0100461
462
463if __name__ == '__main__':
464 unittest.main()