1 # -*- coding: utf-8 -*-
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."""
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."""
31 if code
in self
.counters
:
32 self
.counters
[code
] += 1
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
:
39 self
._deferred
_print
.append(
40 (line_number
, offset
, detailed_code
, text
[5:], check
.__doc
__))
42 self
.total_errors
+= 1
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
):
52 self
.total_errors
+= 1
53 print('%s: error %s not found' % (label
, extended_code
))
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
:
60 self
.total_errors
+= 1
61 print('%s: error %s found too many times (+%d)' %
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
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
)
77 print(results
% ", %s failures" % self
.total_errors
)
80 print("Test failed." if self
.total_errors
else "Test passed.")
83 def selftest(options
):
85 Test all check functions with test cases in docstrings.
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():
94 match
= SELFTEST_REGEX
.match(line
)
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
)
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
):
116 print("%s: %s" % (code
, source
))
119 print("pep8.py: %s:" % error
)
120 for line
in checker
.lines
:
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.
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']
152 count_files
= report
.counters
['files']
153 for index
, line
in enumerate(lines
):
154 if not line
.startswith('#:'):
156 # Collect the lines of the test case
157 testcase
.append(line
)
161 testcase
[-1] = testcase
[-1].rstrip('\n')
162 codes
= [c
for c
in codes
163 if c
not in ('Okay', 'noeol')]
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
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
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.")
192 if options
.testsuite
:
194 return style
.check_files()
196 # nose should not collect these functions
197 init_tests
.__test
__ = run_tests
.__test
__ = False