1"""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
8import sys
9import unittest
10import shutil
11import subprocess
12import sysconfig
13import tempfile
14import textwrap
15from test import test_support
16from test.script_helper import assert_python_ok, temp_dir
17
18if not sysconfig.is_python_build():
19    # XXX some installers do contain the tools, should we detect that
20    # and run the tests in that case too?
21    raise unittest.SkipTest('test irrelevant for an installed Python')
22
23basepath = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
24                        'Tools')
25scriptsdir = os.path.join(basepath, 'scripts')
26
27
28class ReindentTests(unittest.TestCase):
29    script = os.path.join(scriptsdir, 'reindent.py')
30
31    def test_noargs(self):
32        assert_python_ok(self.script)
33
34    def test_help(self):
35        rc, out, err = assert_python_ok(self.script, '-h')
36        self.assertEqual(out, b'')
37        self.assertGreater(err, b'')
38
39
40class PindentTests(unittest.TestCase):
41    script = os.path.join(scriptsdir, 'pindent.py')
42
43    def assertFileEqual(self, fn1, fn2):
44        with open(fn1) as f1, open(fn2) as f2:
45            self.assertEqual(f1.readlines(), f2.readlines())
46
47    def pindent(self, source, *args):
48        proc = subprocess.Popen(
49                (sys.executable, self.script) + args,
50                stdin=subprocess.PIPE, stdout=subprocess.PIPE,
51                universal_newlines=True)
52        out, err = proc.communicate(source)
53        self.assertIsNone(err)
54        return out
55
56    def lstriplines(self, data):
57        return '\n'.join(line.lstrip() for line in data.splitlines()) + '\n'
58
59    def test_selftest(self):
60        self.maxDiff = None
61        with temp_dir() as directory:
62            data_path = os.path.join(directory, '_test.py')
63            with open(self.script) as f:
64                closed = f.read()
65            with open(data_path, 'w') as f:
66                f.write(closed)
67
68            rc, out, err = assert_python_ok(self.script, '-d', data_path)
69            self.assertEqual(out, b'')
70            self.assertEqual(err, b'')
71            backup = data_path + '~'
72            self.assertTrue(os.path.exists(backup))
73            with open(backup) as f:
74                self.assertEqual(f.read(), closed)
75            with open(data_path) as f:
76                clean = f.read()
77            compile(clean, '_test.py', 'exec')
78            self.assertEqual(self.pindent(clean, '-c'), closed)
79            self.assertEqual(self.pindent(closed, '-d'), clean)
80
81            rc, out, err = assert_python_ok(self.script, '-c', data_path)
82            self.assertEqual(out, b'')
83            self.assertEqual(err, b'')
84            with open(backup) as f:
85                self.assertEqual(f.read(), clean)
86            with open(data_path) as f:
87                self.assertEqual(f.read(), closed)
88
89            broken = self.lstriplines(closed)
90            with open(data_path, 'w') as f:
91                f.write(broken)
92            rc, out, err = assert_python_ok(self.script, '-r', data_path)
93            self.assertEqual(out, b'')
94            self.assertEqual(err, b'')
95            with open(backup) as f:
96                self.assertEqual(f.read(), broken)
97            with open(data_path) as f:
98                indented = f.read()
99            compile(indented, '_test.py', 'exec')
100            self.assertEqual(self.pindent(broken, '-r'), indented)
101
102    def pindent_test(self, clean, closed):
103        self.assertEqual(self.pindent(clean, '-c'), closed)
104        self.assertEqual(self.pindent(closed, '-d'), clean)
105        broken = self.lstriplines(closed)
106        self.assertEqual(self.pindent(broken, '-r', '-e', '-s', '4'), closed)
107
108    def test_statements(self):
109        clean = textwrap.dedent("""\
110            if a:
111                pass
112
113            if a:
114                pass
115            else:
116                pass
117
118            if a:
119                pass
120            elif:
121                pass
122            else:
123                pass
124
125            while a:
126                break
127
128            while a:
129                break
130            else:
131                pass
132
133            for i in a:
134                break
135
136            for i in a:
137                break
138            else:
139                pass
140
141            try:
142                pass
143            finally:
144                pass
145
146            try:
147                pass
148            except TypeError:
149                pass
150            except ValueError:
151                pass
152            else:
153                pass
154
155            try:
156                pass
157            except TypeError:
158                pass
159            except ValueError:
160                pass
161            finally:
162                pass
163
164            with a:
165                pass
166
167            class A:
168                pass
169
170            def f():
171                pass
172            """)
173
174        closed = textwrap.dedent("""\
175            if a:
176                pass
177            # end if
178
179            if a:
180                pass
181            else:
182                pass
183            # end if
184
185            if a:
186                pass
187            elif:
188                pass
189            else:
190                pass
191            # end if
192
193            while a:
194                break
195            # end while
196
197            while a:
198                break
199            else:
200                pass
201            # end while
202
203            for i in a:
204                break
205            # end for
206
207            for i in a:
208                break
209            else:
210                pass
211            # end for
212
213            try:
214                pass
215            finally:
216                pass
217            # end try
218
219            try:
220                pass
221            except TypeError:
222                pass
223            except ValueError:
224                pass
225            else:
226                pass
227            # end try
228
229            try:
230                pass
231            except TypeError:
232                pass
233            except ValueError:
234                pass
235            finally:
236                pass
237            # end try
238
239            with a:
240                pass
241            # end with
242
243            class A:
244                pass
245            # end class A
246
247            def f():
248                pass
249            # end def f
250            """)
251        self.pindent_test(clean, closed)
252
253    def test_multilevel(self):
254        clean = textwrap.dedent("""\
255            def foobar(a, b):
256                if a == b:
257                    a = a+1
258                elif a < b:
259                    b = b-1
260                    if b > a: a = a-1
261                else:
262                    print 'oops!'
263            """)
264        closed = textwrap.dedent("""\
265            def foobar(a, b):
266                if a == b:
267                    a = a+1
268                elif a < b:
269                    b = b-1
270                    if b > a: a = a-1
271                    # end if
272                else:
273                    print 'oops!'
274                # end if
275            # end def foobar
276            """)
277        self.pindent_test(clean, closed)
278
279    def test_preserve_indents(self):
280        clean = textwrap.dedent("""\
281            if a:
282                     if b:
283                              pass
284            """)
285        closed = textwrap.dedent("""\
286            if a:
287                     if b:
288                              pass
289                     # end if
290            # end if
291            """)
292        self.assertEqual(self.pindent(clean, '-c'), closed)
293        self.assertEqual(self.pindent(closed, '-d'), clean)
294        broken = self.lstriplines(closed)
295        self.assertEqual(self.pindent(broken, '-r', '-e', '-s', '9'), closed)
296        clean = textwrap.dedent("""\
297            if a:
298            \tif b:
299            \t\tpass
300            """)
301        closed = textwrap.dedent("""\
302            if a:
303            \tif b:
304            \t\tpass
305            \t# end if
306            # end if
307            """)
308        self.assertEqual(self.pindent(clean, '-c'), closed)
309        self.assertEqual(self.pindent(closed, '-d'), clean)
310        broken = self.lstriplines(closed)
311        self.assertEqual(self.pindent(broken, '-r'), closed)
312
313    def test_escaped_newline(self):
314        clean = textwrap.dedent("""\
315            class\\
316            \\
317             A:
318               def\
319            \\
320            f:
321                  pass
322            """)
323        closed = textwrap.dedent("""\
324            class\\
325            \\
326             A:
327               def\
328            \\
329            f:
330                  pass
331               # end def f
332            # end class A
333            """)
334        self.assertEqual(self.pindent(clean, '-c'), closed)
335        self.assertEqual(self.pindent(closed, '-d'), clean)
336
337    def test_empty_line(self):
338        clean = textwrap.dedent("""\
339            if a:
340
341                pass
342            """)
343        closed = textwrap.dedent("""\
344            if a:
345
346                pass
347            # end if
348            """)
349        self.pindent_test(clean, closed)
350
351    def test_oneline(self):
352        clean = textwrap.dedent("""\
353            if a: pass
354            """)
355        closed = textwrap.dedent("""\
356            if a: pass
357            # end if
358            """)
359        self.pindent_test(clean, closed)
360
361
362def test_main():
363    test_support.run_unittest(*[obj for obj in globals().values()
364                                    if isinstance(obj, type)])
365
366
367if __name__ == '__main__':
368    unittest.main()
369