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