pep8: Move to third_party/.
[samba.git] / third_party / pep8 / testsuite / test_api.py
1 # -*- coding: utf-8 -*-
2 import os.path
3 import shlex
4 import sys
5 import unittest
6
7 import pep8
8 from testsuite.support import ROOT_DIR, PseudoFile
9
10 E11 = os.path.join(ROOT_DIR, 'testsuite', 'E11.py')
11
12
13 class DummyChecker(object):
14     def __init__(self, tree, filename):
15         pass
16
17     def run(self):
18         if False:
19             yield
20
21
22 class APITestCase(unittest.TestCase):
23     """Test the public methods."""
24
25     def setUp(self):
26         self._saved_stdout = sys.stdout
27         self._saved_stderr = sys.stderr
28         self._saved_checks = pep8._checks
29         sys.stdout = PseudoFile()
30         sys.stderr = PseudoFile()
31         pep8._checks = dict((k, dict((f, (vals[0][:], vals[1]))
32                                      for (f, vals) in v.items()))
33                             for (k, v) in self._saved_checks.items())
34
35     def tearDown(self):
36         sys.stdout = self._saved_stdout
37         sys.stderr = self._saved_stderr
38         pep8._checks = self._saved_checks
39
40     def reset(self):
41         del sys.stdout[:], sys.stderr[:]
42
43     def test_register_physical_check(self):
44         def check_dummy(physical_line, line_number):
45             if False:
46                 yield
47         pep8.register_check(check_dummy, ['Z001'])
48
49         self.assertTrue(check_dummy in pep8._checks['physical_line'])
50         codes, args = pep8._checks['physical_line'][check_dummy]
51         self.assertTrue('Z001' in codes)
52         self.assertEqual(args, ['physical_line', 'line_number'])
53
54         options = pep8.StyleGuide().options
55         self.assertTrue(any(func == check_dummy
56                             for name, func, args in options.physical_checks))
57
58     def test_register_logical_check(self):
59         def check_dummy(logical_line, tokens):
60             if False:
61                 yield
62         pep8.register_check(check_dummy, ['Z401'])
63
64         self.assertTrue(check_dummy in pep8._checks['logical_line'])
65         codes, args = pep8._checks['logical_line'][check_dummy]
66         self.assertTrue('Z401' in codes)
67         self.assertEqual(args, ['logical_line', 'tokens'])
68
69         pep8.register_check(check_dummy, [])
70         pep8.register_check(check_dummy, ['Z402', 'Z403'])
71         codes, args = pep8._checks['logical_line'][check_dummy]
72         self.assertEqual(codes, ['Z401', 'Z402', 'Z403'])
73         self.assertEqual(args, ['logical_line', 'tokens'])
74
75         options = pep8.StyleGuide().options
76         self.assertTrue(any(func == check_dummy
77                             for name, func, args in options.logical_checks))
78
79     def test_register_ast_check(self):
80         pep8.register_check(DummyChecker, ['Z701'])
81
82         self.assertTrue(DummyChecker in pep8._checks['tree'])
83         codes, args = pep8._checks['tree'][DummyChecker]
84         self.assertTrue('Z701' in codes)
85         self.assertTrue(args is None)
86
87         options = pep8.StyleGuide().options
88         self.assertTrue(any(cls == DummyChecker
89                             for name, cls, args in options.ast_checks))
90
91     def test_register_invalid_check(self):
92         class InvalidChecker(DummyChecker):
93             def __init__(self, filename):
94                 pass
95
96         def check_dummy(logical, tokens):
97             if False:
98                 yield
99         pep8.register_check(InvalidChecker, ['Z741'])
100         pep8.register_check(check_dummy, ['Z441'])
101
102         for checkers in pep8._checks.values():
103             self.assertTrue(DummyChecker not in checkers)
104             self.assertTrue(check_dummy not in checkers)
105
106         self.assertRaises(TypeError, pep8.register_check)
107
108     def test_styleguide(self):
109         report = pep8.StyleGuide().check_files()
110         self.assertEqual(report.total_errors, 0)
111         self.assertFalse(sys.stdout)
112         self.assertFalse(sys.stderr)
113         self.reset()
114
115         report = pep8.StyleGuide().check_files(['missing-file'])
116         stdout = sys.stdout.getvalue().splitlines()
117         self.assertEqual(len(stdout), report.total_errors)
118         self.assertEqual(report.total_errors, 1)
119         # < 3.3 returns IOError; >= 3.3 returns FileNotFoundError
120         self.assertTrue(stdout[0].startswith("missing-file:1:1: E902 "))
121         self.assertFalse(sys.stderr)
122         self.reset()
123
124         report = pep8.StyleGuide().check_files([E11])
125         stdout = sys.stdout.getvalue().splitlines()
126         self.assertEqual(len(stdout), report.total_errors)
127         self.assertEqual(report.total_errors, 17)
128         self.assertFalse(sys.stderr)
129         self.reset()
130
131         # Passing the paths in the constructor gives same result
132         report = pep8.StyleGuide(paths=[E11]).check_files()
133         stdout = sys.stdout.getvalue().splitlines()
134         self.assertEqual(len(stdout), report.total_errors)
135         self.assertEqual(report.total_errors, 17)
136         self.assertFalse(sys.stderr)
137         self.reset()
138
139     def test_styleguide_options(self):
140         # Instanciate a simple checker
141         pep8style = pep8.StyleGuide(paths=[E11])
142
143         # Check style's attributes
144         self.assertEqual(pep8style.checker_class, pep8.Checker)
145         self.assertEqual(pep8style.paths, [E11])
146         self.assertEqual(pep8style.runner, pep8style.input_file)
147         self.assertEqual(pep8style.options.ignore_code, pep8style.ignore_code)
148         self.assertEqual(pep8style.options.paths, pep8style.paths)
149
150         # Check unset options
151         for o in ('benchmark', 'config', 'count', 'diff',
152                   'doctest', 'quiet', 'show_pep8', 'show_source',
153                   'statistics', 'testsuite', 'verbose'):
154             oval = getattr(pep8style.options, o)
155             self.assertTrue(oval in (None, False), msg='%s = %r' % (o, oval))
156
157         # Check default options
158         self.assertTrue(pep8style.options.repeat)
159         self.assertEqual(pep8style.options.benchmark_keys,
160                          ['directories', 'files',
161                           'logical lines', 'physical lines'])
162         self.assertEqual(pep8style.options.exclude,
163                          ['.svn', 'CVS', '.bzr', '.hg',
164                           '.git', '__pycache__', '.tox'])
165         self.assertEqual(pep8style.options.filename, ['*.py'])
166         self.assertEqual(pep8style.options.format, 'default')
167         self.assertEqual(pep8style.options.select, ())
168         self.assertEqual(pep8style.options.ignore, ('E226', 'E24'))
169         self.assertEqual(pep8style.options.max_line_length, 79)
170
171     def test_styleguide_ignore_code(self):
172         def parse_argv(argstring):
173             _saved_argv = sys.argv
174             sys.argv = shlex.split('pep8 %s /dev/null' % argstring)
175             try:
176                 return pep8.StyleGuide(parse_argv=True)
177             finally:
178                 sys.argv = _saved_argv
179
180         options = parse_argv('').options
181         self.assertEqual(options.select, ())
182         self.assertEqual(
183             options.ignore,
184             ('E121', 'E123', 'E126', 'E226', 'E24', 'E704')
185         )
186
187         options = parse_argv('--doctest').options
188         self.assertEqual(options.select, ())
189         self.assertEqual(options.ignore, ())
190
191         options = parse_argv('--ignore E,W').options
192         self.assertEqual(options.select, ())
193         self.assertEqual(options.ignore, ('E', 'W'))
194
195         options = parse_argv('--select E,W').options
196         self.assertEqual(options.select, ('E', 'W'))
197         self.assertEqual(options.ignore, ('',))
198
199         options = parse_argv('--select E --ignore E24').options
200         self.assertEqual(options.select, ('E',))
201         self.assertEqual(options.ignore, ('',))
202
203         options = parse_argv('--ignore E --select E24').options
204         self.assertEqual(options.select, ('E24',))
205         self.assertEqual(options.ignore, ('',))
206
207         options = parse_argv('--ignore W --select E24').options
208         self.assertEqual(options.select, ('E24',))
209         self.assertEqual(options.ignore, ('',))
210
211         pep8style = pep8.StyleGuide(paths=[E11])
212         self.assertFalse(pep8style.ignore_code('E112'))
213         self.assertFalse(pep8style.ignore_code('W191'))
214         self.assertTrue(pep8style.ignore_code('E241'))
215
216         pep8style = pep8.StyleGuide(select='E', paths=[E11])
217         self.assertFalse(pep8style.ignore_code('E112'))
218         self.assertTrue(pep8style.ignore_code('W191'))
219         self.assertFalse(pep8style.ignore_code('E241'))
220
221         pep8style = pep8.StyleGuide(select='W', paths=[E11])
222         self.assertTrue(pep8style.ignore_code('E112'))
223         self.assertFalse(pep8style.ignore_code('W191'))
224         self.assertTrue(pep8style.ignore_code('E241'))
225
226         pep8style = pep8.StyleGuide(select=('F401',), paths=[E11])
227         self.assertEqual(pep8style.options.select, ('F401',))
228         self.assertEqual(pep8style.options.ignore, ('',))
229         self.assertFalse(pep8style.ignore_code('F'))
230         self.assertFalse(pep8style.ignore_code('F401'))
231         self.assertTrue(pep8style.ignore_code('F402'))
232
233     def test_styleguide_excluded(self):
234         pep8style = pep8.StyleGuide(paths=[E11])
235
236         self.assertFalse(pep8style.excluded('./foo/bar'))
237         self.assertFalse(pep8style.excluded('./foo/bar/main.py'))
238
239         self.assertTrue(pep8style.excluded('./CVS'))
240         self.assertTrue(pep8style.excluded('./.tox'))
241         self.assertTrue(pep8style.excluded('./subdir/CVS'))
242         self.assertTrue(pep8style.excluded('__pycache__'))
243         self.assertTrue(pep8style.excluded('./__pycache__'))
244         self.assertTrue(pep8style.excluded('subdir/__pycache__'))
245
246         self.assertFalse(pep8style.excluded('draftCVS'))
247         self.assertFalse(pep8style.excluded('./CVSoup'))
248         self.assertFalse(pep8style.excluded('./CVS/subdir'))
249
250     def test_styleguide_checks(self):
251         pep8style = pep8.StyleGuide(paths=[E11])
252
253         # Default lists of checkers
254         self.assertTrue(len(pep8style.options.physical_checks) > 4)
255         self.assertTrue(len(pep8style.options.logical_checks) > 10)
256         self.assertEqual(len(pep8style.options.ast_checks), 0)
257
258         # Sanity check
259         for name, check, args in pep8style.options.physical_checks:
260             self.assertEqual(check.__name__, name)
261             self.assertEqual(args[0], 'physical_line')
262         for name, check, args in pep8style.options.logical_checks:
263             self.assertEqual(check.__name__, name)
264             self.assertEqual(args[0], 'logical_line')
265
266         # Do run E11 checks
267         options = pep8.StyleGuide().options
268         self.assertTrue(any(func == pep8.indentation
269                             for name, func, args in options.logical_checks))
270         options = pep8.StyleGuide(select=['E']).options
271         self.assertTrue(any(func == pep8.indentation
272                             for name, func, args in options.logical_checks))
273         options = pep8.StyleGuide(ignore=['W']).options
274         self.assertTrue(any(func == pep8.indentation
275                             for name, func, args in options.logical_checks))
276         options = pep8.StyleGuide(ignore=['E12']).options
277         self.assertTrue(any(func == pep8.indentation
278                             for name, func, args in options.logical_checks))
279
280         # Do not run E11 checks
281         options = pep8.StyleGuide(select=['W']).options
282         self.assertFalse(any(func == pep8.indentation
283                              for name, func, args in options.logical_checks))
284         options = pep8.StyleGuide(ignore=['E']).options
285         self.assertFalse(any(func == pep8.indentation
286                              for name, func, args in options.logical_checks))
287         options = pep8.StyleGuide(ignore=['E11']).options
288         self.assertFalse(any(func == pep8.indentation
289                              for name, func, args in options.logical_checks))
290
291     def test_styleguide_init_report(self):
292         pep8style = pep8.StyleGuide(paths=[E11])
293
294         self.assertEqual(pep8style.options.reporter, pep8.StandardReport)
295         self.assertEqual(type(pep8style.options.report), pep8.StandardReport)
296
297         class MinorityReport(pep8.BaseReport):
298             pass
299
300         report = pep8style.init_report(MinorityReport)
301         self.assertEqual(pep8style.options.report, report)
302         self.assertEqual(type(report), MinorityReport)
303
304         pep8style = pep8.StyleGuide(paths=[E11], reporter=MinorityReport)
305         self.assertEqual(type(pep8style.options.report), MinorityReport)
306         self.assertEqual(pep8style.options.reporter, MinorityReport)
307
308     def test_styleguide_check_files(self):
309         pep8style = pep8.StyleGuide(paths=[E11])
310
311         report = pep8style.check_files()
312         self.assertTrue(report.total_errors)
313
314         self.assertRaises(TypeError, pep8style.check_files, 42)
315         # < 3.3 raises TypeError; >= 3.3 raises AttributeError
316         self.assertRaises(Exception, pep8style.check_files, [42])
317
318     def test_check_unicode(self):
319         # Do not crash if lines are Unicode (Python 2.x)
320         pep8.register_check(DummyChecker, ['Z701'])
321         source = '#\n'
322         if hasattr(source, 'decode'):
323             source = source.decode('ascii')
324
325         pep8style = pep8.StyleGuide()
326         count_errors = pep8style.input_file('stdin', lines=[source])
327
328         self.assertFalse(sys.stdout)
329         self.assertFalse(sys.stderr)
330         self.assertEqual(count_errors, 0)
331
332     def test_check_nullbytes(self):
333         pep8.register_check(DummyChecker, ['Z701'])
334
335         pep8style = pep8.StyleGuide()
336         count_errors = pep8style.input_file('stdin', lines=['\x00\n'])
337
338         stdout = sys.stdout.getvalue()
339         if 'SyntaxError' in stdout:
340             # PyPy 2.2 returns a SyntaxError
341             expected = "stdin:1:2: E901 SyntaxError"
342         else:
343             expected = "stdin:1:1: E901 TypeError"
344         self.assertTrue(stdout.startswith(expected),
345                         msg='Output %r does not start with %r' %
346                         (stdout, expected))
347         self.assertFalse(sys.stderr)
348         self.assertEqual(count_errors, 1)
349
350     def test_styleguide_unmatched_triple_quotes(self):
351         pep8.register_check(DummyChecker, ['Z701'])
352         lines = [
353             'def foo():\n',
354             '    """test docstring""\'\n',
355         ]
356
357         pep8style = pep8.StyleGuide()
358         pep8style.input_file('stdin', lines=lines)
359         stdout = sys.stdout.getvalue()
360
361         expected = 'stdin:2:5: E901 TokenError: EOF in multi-line string'
362         self.assertTrue(expected in stdout)
363
364     def test_styleguide_continuation_line_outdented(self):
365         pep8.register_check(DummyChecker, ['Z701'])
366         lines = [
367             'def foo():\n',
368             '    pass\n',
369             '\n',
370             '\\\n',
371             '\n',
372             'def bar():\n',
373             '    pass\n',
374         ]
375
376         pep8style = pep8.StyleGuide()
377         count_errors = pep8style.input_file('stdin', lines=lines)
378         self.assertEqual(count_errors, 2)
379         stdout = sys.stdout.getvalue()
380         expected = (
381             'stdin:6:1: '
382             'E122 continuation line missing indentation or outdented'
383         )
384         self.assertTrue(expected in stdout)
385         expected = 'stdin:6:1: E302 expected 2 blank lines, found 1'
386         self.assertTrue(expected in stdout)
387
388         # TODO: runner
389         # TODO: input_file