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