pep8: Move to third_party/.
[Samba.git] / third_party / pep8 / testsuite / support.py
blob5185005750cab39ad7ad40175b9983c67db43086
1 # -*- coding: utf-8 -*-
2 import os.path
3 import re
4 import sys
6 from pep8 import Checker, BaseReport, StandardReport, readlines
8 SELFTEST_REGEX = re.compile(r'\b(Okay|[EW]\d{3}):\s(.*)')
9 ROOT_DIR = os.path.dirname(os.path.dirname(__file__))
12 class PseudoFile(list):
13 """Simplified file interface."""
14 write = list.append
16 def getvalue(self):
17 return ''.join(self)
20 class TestReport(StandardReport):
21 """Collect the results for the tests."""
23 def __init__(self, options):
24 options.benchmark_keys += ['test cases', 'failed tests']
25 super(TestReport, self).__init__(options)
26 self._verbose = options.verbose
28 def error(self, line_number, offset, text, check):
29 """Report an error, according to options."""
30 code = text[:4]
31 if code in self.counters:
32 self.counters[code] += 1
33 else:
34 self.counters[code] = 1
35 detailed_code = '%s:%s:%s' % (code, line_number, offset + 1)
36 # Don't care about expected errors or warnings
37 if code in self.expected or detailed_code in self.expected:
38 return
39 self._deferred_print.append(
40 (line_number, offset, detailed_code, text[5:], check.__doc__))
41 self.file_errors += 1
42 self.total_errors += 1
43 return code
45 def get_file_results(self):
46 # Check if the expected errors were found
47 label = '%s:%s:1' % (self.filename, self.line_offset)
48 for extended_code in self.expected:
49 code = extended_code.split(':')[0]
50 if not self.counters.get(code):
51 self.file_errors += 1
52 self.total_errors += 1
53 print('%s: error %s not found' % (label, extended_code))
54 else:
55 self.counters[code] -= 1
56 for code, extra in sorted(self.counters.items()):
57 if code not in self._benchmark_keys:
58 if extra and code in self.expected:
59 self.file_errors += 1
60 self.total_errors += 1
61 print('%s: error %s found too many times (+%d)' %
62 (label, code, extra))
63 # Reset counters
64 del self.counters[code]
65 if self._verbose and not self.file_errors:
66 print('%s: passed (%s)' %
67 (label, ' '.join(self.expected) or 'Okay'))
68 self.counters['test cases'] += 1
69 if self.file_errors:
70 self.counters['failed tests'] += 1
71 return super(TestReport, self).get_file_results()
73 def print_results(self):
74 results = ("%(physical lines)d lines tested: %(files)d files, "
75 "%(test cases)d test cases%%s." % self.counters)
76 if self.total_errors:
77 print(results % ", %s failures" % self.total_errors)
78 else:
79 print(results % "")
80 print("Test failed." if self.total_errors else "Test passed.")
83 def selftest(options):
84 """
85 Test all check functions with test cases in docstrings.
86 """
87 count_failed = count_all = 0
88 report = BaseReport(options)
89 counters = report.counters
90 checks = options.physical_checks + options.logical_checks
91 for name, check, argument_names in checks:
92 for line in check.__doc__.splitlines():
93 line = line.lstrip()
94 match = SELFTEST_REGEX.match(line)
95 if match is None:
96 continue
97 code, source = match.groups()
98 lines = [part.replace(r'\t', '\t') + '\n'
99 for part in source.split(r'\n')]
100 checker = Checker(lines=lines, options=options, report=report)
101 checker.check_all()
102 error = None
103 if code == 'Okay':
104 if len(counters) > len(options.benchmark_keys):
105 codes = [key for key in counters
106 if key not in options.benchmark_keys]
107 error = "incorrectly found %s" % ', '.join(codes)
108 elif not counters.get(code):
109 error = "failed to find %s" % code
110 # Keep showing errors for multiple tests
111 for key in set(counters) - set(options.benchmark_keys):
112 del counters[key]
113 count_all += 1
114 if not error:
115 if options.verbose:
116 print("%s: %s" % (code, source))
117 else:
118 count_failed += 1
119 print("pep8.py: %s:" % error)
120 for line in checker.lines:
121 print(line.rstrip())
122 return count_failed, count_all
125 def init_tests(pep8style):
127 Initialize testing framework.
129 A test file can provide many tests. Each test starts with a
130 declaration. This declaration is a single line starting with '#:'.
131 It declares codes of expected failures, separated by spaces or 'Okay'
132 if no failure is expected.
133 If the file does not contain such declaration, it should pass all
134 tests. If the declaration is empty, following lines are not checked,
135 until next declaration.
137 Examples:
139 * Only E224 and W701 are expected: #: E224 W701
140 * Following example is conform: #: Okay
141 * Don't check these lines: #:
143 report = pep8style.init_report(TestReport)
144 runner = pep8style.input_file
146 def run_tests(filename):
147 """Run all the tests from a file."""
148 lines = readlines(filename) + ['#:\n']
149 line_offset = 0
150 codes = ['Okay']
151 testcase = []
152 count_files = report.counters['files']
153 for index, line in enumerate(lines):
154 if not line.startswith('#:'):
155 if codes:
156 # Collect the lines of the test case
157 testcase.append(line)
158 continue
159 if codes and index:
160 if 'noeol' in codes:
161 testcase[-1] = testcase[-1].rstrip('\n')
162 codes = [c for c in codes
163 if c not in ('Okay', 'noeol')]
164 # Run the checker
165 runner(filename, testcase, expected=codes,
166 line_offset=line_offset)
167 # output the real line numbers
168 line_offset = index + 1
169 # configure the expected errors
170 codes = line.split()[1:]
171 # empty the test case buffer
172 del testcase[:]
173 report.counters['files'] = count_files + 1
174 return report.counters['failed tests']
176 pep8style.runner = run_tests
179 def run_tests(style):
180 options = style.options
181 if options.doctest:
182 import doctest
183 fail_d, done_d = doctest.testmod(report=False, verbose=options.verbose)
184 fail_s, done_s = selftest(options)
185 count_failed = fail_s + fail_d
186 if not options.quiet:
187 count_passed = done_d + done_s - count_failed
188 print("%d passed and %d failed." % (count_passed, count_failed))
189 print("Test failed." if count_failed else "Test passed.")
190 if count_failed:
191 sys.exit(1)
192 if options.testsuite:
193 init_tests(style)
194 return style.check_files()
196 # nose should not collect these functions
197 init_tests.__test__ = run_tests.__test__ = False