summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorent Xicluna <florent.xicluna@gmail.com>2013-02-10 00:44:08 +0100
committerFlorent Xicluna <florent.xicluna@gmail.com>2013-02-10 00:44:08 +0100
commitfab1a793a6751c40a4f624d71b9e7657788c6fea (patch)
treece83fc55bc8512ff917784a9498dfe7b297b0627
parentcf05bb6ec795a0256812b3ae82d0ab7caf971da5 (diff)
downloadpep8-fab1a793a6751c40a4f624d71b9e7657788c6fea.tar.gz
Refactor the testing framework into a separate module
-rw-r--r--CHANGES.txt3
-rw-r--r--docs/api.rst4
-rwxr-xr-xpep8.py155
-rw-r--r--testsuite/test_pep8.py170
4 files changed, 180 insertions, 152 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 5c08819..c8afd95 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -21,6 +21,9 @@ Changelog
* Expand tabs when checking E12 continuation lines. (Issue #155)
+* Refactor the testing class ``TestReport`` and the specific test
+ functions into a separate test module.
+
1.4.1 (2013-01-18)
------------------
diff --git a/docs/api.rst b/docs/api.rst
index 2349e5c..6bd4a1a 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -68,8 +68,6 @@ Report Classes
.. autoclass:: DiffReport
-.. autoclass:: TestReport
-
Utilities
---------
@@ -89,5 +87,3 @@ Utilities
.. autofunction:: filename_match(filename, patterns, default=True)
.. autofunction:: get_parser(prog='pep8', version=pep8.__version__)
.. autofunction:: init_checks_registry()
- .. autofunction:: init_tests(pep8style)
- .. autofunction:: selftest(options)
diff --git a/pep8.py b/pep8.py
index 17f9f25..54ac0b0 100755
--- a/pep8.py
+++ b/pep8.py
@@ -93,7 +93,6 @@ BENCHMARK_KEYS = ['directories', 'files', 'logical lines', 'physical lines']
INDENT_REGEX = re.compile(r'([ \t]*)')
RAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*(,)')
RERAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,\s*\w+\s*,\s*\w+')
-SELFTEST_REGEX = re.compile(r'\b(Okay|[EW]\d{3}):\s(.*)')
ERRORCODE_REGEX = re.compile(r'\b[A-Z]\d{3}\b')
DOCSTRING_REGEX = re.compile(r'u?r?["\']')
EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[[({] | []}),;:]')
@@ -1556,45 +1555,6 @@ class DiffReport(StandardReport):
return super(DiffReport, self).error(line_number, offset, text, check)
-class TestReport(StandardReport):
- """Collect the results for the tests."""
-
- def __init__(self, options):
- options.benchmark_keys += ['test cases', 'failed tests']
- super(TestReport, self).__init__(options)
- self._verbose = options.verbose
-
- def get_file_results(self):
- # Check if the expected errors were found
- label = '%s:%s:1' % (self.filename, self.line_offset)
- codes = sorted(self.expected)
- for code in codes:
- if not self.counters.get(code):
- self.file_errors += 1
- self.total_errors += 1
- print('%s: error %s not found' % (label, code))
- if self._verbose and not self.file_errors:
- print('%s: passed (%s)' %
- (label, ' '.join(codes) or 'Okay'))
- self.counters['test cases'] += 1
- if self.file_errors:
- self.counters['failed tests'] += 1
- # Reset counters
- for key in set(self.counters) - set(self._benchmark_keys):
- del self.counters[key]
- self.messages = {}
- return self.file_errors
-
- def print_results(self):
- results = ("%(physical lines)d lines tested: %(files)d files, "
- "%(test cases)d test cases%%s." % self.counters)
- if self.total_errors:
- print(results % ", %s failures" % self.total_errors)
- else:
- print(results % "")
- print("Test failed." if self.total_errors else "Test passed.")
-
-
class StyleGuide(object):
"""Initialize a PEP-8 instance with few options."""
@@ -1713,100 +1673,6 @@ class StyleGuide(object):
return sorted(checks)
-def init_tests(pep8style):
- """
- Initialize testing framework.
-
- A test file can provide many tests. Each test starts with a
- declaration. This declaration is a single line starting with '#:'.
- It declares codes of expected failures, separated by spaces or 'Okay'
- if no failure is expected.
- If the file does not contain such declaration, it should pass all
- tests. If the declaration is empty, following lines are not checked,
- until next declaration.
-
- Examples:
-
- * Only E224 and W701 are expected: #: E224 W701
- * Following example is conform: #: Okay
- * Don't check these lines: #:
- """
- report = pep8style.init_report(TestReport)
- runner = pep8style.input_file
-
- def run_tests(filename):
- """Run all the tests from a file."""
- lines = readlines(filename) + ['#:\n']
- line_offset = 0
- codes = ['Okay']
- testcase = []
- count_files = report.counters['files']
- for index, line in enumerate(lines):
- if not line.startswith('#:'):
- if codes:
- # Collect the lines of the test case
- testcase.append(line)
- continue
- if codes and index:
- codes = [c for c in codes if c != 'Okay']
- # Run the checker
- runner(filename, testcase, expected=codes,
- line_offset=line_offset)
- # output the real line numbers
- line_offset = index + 1
- # configure the expected errors
- codes = line.split()[1:]
- # empty the test case buffer
- del testcase[:]
- report.counters['files'] = count_files + 1
- return report.counters['failed tests']
-
- pep8style.runner = run_tests
-
-
-def selftest(options):
- """
- Test all check functions with test cases in docstrings.
- """
- count_failed = count_all = 0
- report = BaseReport(options)
- counters = report.counters
- checks = options.physical_checks + options.logical_checks
- for name, check, argument_names in checks:
- for line in check.__doc__.splitlines():
- line = line.lstrip()
- match = SELFTEST_REGEX.match(line)
- if match is None:
- continue
- code, source = match.groups()
- lines = [part.replace(r'\t', '\t') + '\n'
- for part in source.split(r'\n')]
- checker = Checker(lines=lines, options=options, report=report)
- checker.check_all()
- error = None
- if code == 'Okay':
- if len(counters) > len(options.benchmark_keys):
- codes = [key for key in counters
- if key not in options.benchmark_keys]
- error = "incorrectly found %s" % ', '.join(codes)
- elif not counters.get(code):
- error = "failed to find %s" % code
- # Keep showing errors for multiple tests
- for key in set(counters) - set(options.benchmark_keys):
- del counters[key]
- report.messages = {}
- count_all += 1
- if not error:
- if options.verbose:
- print("%s: %s" % (code, source))
- else:
- count_failed += 1
- print("%s: %s:" % (__file__, error))
- for line in checker.lines:
- print(line.rstrip())
- return count_failed, count_all
-
-
def get_parser(prog='pep8', version=__version__):
parser = OptionParser(prog=prog, version=version,
usage="%prog [options] input ...")
@@ -1978,20 +1844,13 @@ def _main():
"""Parse options and run checks on Python source."""
pep8style = StyleGuide(parse_argv=True, config_file=True)
options = pep8style.options
- if options.doctest:
- import doctest
- fail_d, done_d = doctest.testmod(report=False, verbose=options.verbose)
- fail_s, done_s = selftest(options)
- count_failed = fail_s + fail_d
- if not options.quiet:
- count_passed = done_d + done_s - count_failed
- print("%d passed and %d failed." % (count_passed, count_failed))
- print("Test failed." if count_failed else "Test passed.")
- if count_failed:
- sys.exit(1)
- if options.testsuite:
- init_tests(pep8style)
- report = pep8style.check_files()
+ if options.doctest or options.testsuite:
+ sys.path[:0] = [os.path.join(os.path.dirname(__file__), 'testsuite')]
+ from test_pep8 import run_tests
+ del sys.path[0]
+ report = run_tests(pep8style, options.doctest, options.testsuite)
+ else:
+ report = pep8style.check_files()
if options.statistics:
report.print_statistics()
if options.benchmark:
diff --git a/testsuite/test_pep8.py b/testsuite/test_pep8.py
new file mode 100644
index 0000000..90ceef3
--- /dev/null
+++ b/testsuite/test_pep8.py
@@ -0,0 +1,170 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import os.path
+import re
+import sys
+
+import pep8
+from pep8 import Checker, StyleGuide, BaseReport, StandardReport, readlines
+
+SELFTEST_REGEX = re.compile(r'\b(Okay|[EW]\d{3}):\s(.*)')
+
+
+class TestReport(StandardReport):
+ """Collect the results for the tests."""
+
+ def __init__(self, options):
+ options.benchmark_keys += ['test cases', 'failed tests']
+ super(TestReport, self).__init__(options)
+ self._verbose = options.verbose
+
+ def get_file_results(self):
+ # Check if the expected errors were found
+ label = '%s:%s:1' % (self.filename, self.line_offset)
+ codes = sorted(self.expected)
+ for code in codes:
+ if not self.counters.get(code):
+ self.file_errors += 1
+ self.total_errors += 1
+ print('%s: error %s not found' % (label, code))
+ if self._verbose and not self.file_errors:
+ print('%s: passed (%s)' %
+ (label, ' '.join(codes) or 'Okay'))
+ self.counters['test cases'] += 1
+ if self.file_errors:
+ self.counters['failed tests'] += 1
+ # Reset counters
+ for key in set(self.counters) - set(self._benchmark_keys):
+ del self.counters[key]
+ self.messages = {}
+ return self.file_errors
+
+ def print_results(self):
+ results = ("%(physical lines)d lines tested: %(files)d files, "
+ "%(test cases)d test cases%%s." % self.counters)
+ if self.total_errors:
+ print(results % ", %s failures" % self.total_errors)
+ else:
+ print(results % "")
+ print("Test failed." if self.total_errors else "Test passed.")
+
+
+def init_tests(pep8style):
+ """
+ Initialize testing framework.
+
+ A test file can provide many tests. Each test starts with a
+ declaration. This declaration is a single line starting with '#:'.
+ It declares codes of expected failures, separated by spaces or 'Okay'
+ if no failure is expected.
+ If the file does not contain such declaration, it should pass all
+ tests. If the declaration is empty, following lines are not checked,
+ until next declaration.
+
+ Examples:
+
+ * Only E224 and W701 are expected: #: E224 W701
+ * Following example is conform: #: Okay
+ * Don't check these lines: #:
+ """
+ report = pep8style.init_report(TestReport)
+ runner = pep8style.input_file
+
+ def run_tests(filename):
+ """Run all the tests from a file."""
+ lines = readlines(filename) + ['#:\n']
+ line_offset = 0
+ codes = ['Okay']
+ testcase = []
+ count_files = report.counters['files']
+ for index, line in enumerate(lines):
+ if not line.startswith('#:'):
+ if codes:
+ # Collect the lines of the test case
+ testcase.append(line)
+ continue
+ if codes and index:
+ codes = [c for c in codes if c != 'Okay']
+ # Run the checker
+ runner(filename, testcase, expected=codes,
+ line_offset=line_offset)
+ # output the real line numbers
+ line_offset = index + 1
+ # configure the expected errors
+ codes = line.split()[1:]
+ # empty the test case buffer
+ del testcase[:]
+ report.counters['files'] = count_files + 1
+ return report.counters['failed tests']
+
+ pep8style.runner = run_tests
+
+
+def selftest(options):
+ """
+ Test all check functions with test cases in docstrings.
+ """
+ count_failed = count_all = 0
+ report = BaseReport(options)
+ counters = report.counters
+ checks = options.physical_checks + options.logical_checks
+ for name, check, argument_names in checks:
+ for line in check.__doc__.splitlines():
+ line = line.lstrip()
+ match = SELFTEST_REGEX.match(line)
+ if match is None:
+ continue
+ code, source = match.groups()
+ lines = [part.replace(r'\t', '\t') + '\n'
+ for part in source.split(r'\n')]
+ checker = Checker(lines=lines, options=options, report=report)
+ checker.check_all()
+ error = None
+ if code == 'Okay':
+ if len(counters) > len(options.benchmark_keys):
+ codes = [key for key in counters
+ if key not in options.benchmark_keys]
+ error = "incorrectly found %s" % ', '.join(codes)
+ elif not counters.get(code):
+ error = "failed to find %s" % code
+ # Keep showing errors for multiple tests
+ for key in set(counters) - set(options.benchmark_keys):
+ del counters[key]
+ report.messages = {}
+ count_all += 1
+ if not error:
+ if options.verbose:
+ print("%s: %s" % (code, source))
+ else:
+ count_failed += 1
+ print("%s: %s:" % (__file__, error))
+ for line in checker.lines:
+ print(line.rstrip())
+ return count_failed, count_all
+
+
+def run_tests(style, doctest=True, testsuite=False):
+ options = style.options
+ if doctest:
+ import doctest
+ fail_d, done_d = doctest.testmod(report=False, verbose=options.verbose)
+ fail_s, done_s = selftest(options)
+ count_failed = fail_s + fail_d
+ if not options.quiet:
+ count_passed = done_d + done_s - count_failed
+ print("%d passed and %d failed." % (count_passed, count_failed))
+ print("Test failed." if count_failed else "Test passed.")
+ if count_failed:
+ sys.exit(1)
+ if testsuite:
+ init_tests(style)
+ return style.check_files()
+
+
+if __name__ == '__main__':
+ if len(sys.argv) > 1:
+ sys.exit(pep8._main())
+ pep8style = StyleGuide(paths=[os.path.dirname(__file__)], ignore=None)
+ report = run_tests(pep8style, True, True)
+ report.print_results()
+ sys.exit(1 if report.total_errors else 0)