commit d02aa3e9128e92982e6f2760594523556bd45e85 Author: Damian Johnson atagar@torproject.org Date: Wed Dec 28 09:24:35 2011 -0800
Moving python testing output filters to module
Rewriting the hacks I was applying to test output for better readability as a proper module. Nicer code and now much easier to add more filters. --- run_tests.py | 34 ++++++-------------- test/__init__.py | 2 +- test/output.py | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 25 deletions(-)
diff --git a/run_tests.py b/run_tests.py index 7247dd7..7e3dadb 100755 --- a/run_tests.py +++ b/run_tests.py @@ -12,6 +12,7 @@ import logging import unittest import StringIO
+import test.output import test.runner import test.unit.version import test.unit.socket.control_message @@ -94,30 +95,10 @@ TEST_OUTPUT_ATTR = { "... skipped": (term.Color.BLUE,), }
-# lines that print_test_results have processed which contained a test failure -PRINTED_ERRORS = [] - def print_divider(msg, is_header = False): attr = HEADER_ATTR if is_header else CATEGORY_ATTR print term.format("%s\n%s\n%s\n" % (DIVIDER, msg.center(70), DIVIDER), *attr)
-def print_test_results(test_results): - test_results.seek(0) - for line in test_results.readlines(): - line_attr = DEFAULT_TEST_ATTR - - for result in TEST_OUTPUT_ATTR: - if result in line: - line_attr = TEST_OUTPUT_ATTR[result] - - if result in ("... FAIL", "... ERROR"): - PRINTED_ERRORS.append(line) - - break - - if line_attr: line = term.format(line, *line_attr) - sys.stdout.write(line) - if __name__ == '__main__': start_time = time.time() run_unit_tests = False @@ -193,6 +174,9 @@ if __name__ == '__main__':
+ error_tracker = test.output.ErrorTracker() + output_filters = (error_tracker.get_filter(), test.output.colorize, ) + if run_unit_tests: print_divider("UNIT TESTS", True)
@@ -201,7 +185,8 @@ if __name__ == '__main__': suite = unittest.TestLoader().loadTestsFromTestCase(test_class) test_results = StringIO.StringIO() unittest.TextTestRunner(test_results, verbosity=2).run(suite) - print_test_results(test_results) + + sys.stdout.write(test.output.apply_filters(test_results.getvalue(), *output_filters)) print
print @@ -251,7 +236,8 @@ if __name__ == '__main__': suite = unittest.TestLoader().loadTestsFromTestCase(test_class) test_results = StringIO.StringIO() unittest.TextTestRunner(test_results, verbosity=2).run(suite) - print_test_results(test_results) + + sys.stdout.write(test.output.apply_filters(test_results.getvalue(), *output_filters)) print except OSError: pass @@ -262,10 +248,10 @@ if __name__ == '__main__':
runtime_label = "(%i seconds)" % (time.time() - start_time)
- if PRINTED_ERRORS: + if error_tracker.has_error_occured(): print term.format("TESTING FAILED %s" % runtime_label, term.Color.RED, term.Attr.BOLD)
- for line in PRINTED_ERRORS: + for line in error_tracker: print term.format(" %s" % line, term.Color.RED, term.Attr.BOLD) else: print term.format("TESTING PASSED %s" % runtime_label, term.Color.GREEN, term.Attr.BOLD) diff --git a/test/__init__.py b/test/__init__.py index 9afce0a..a663300 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -2,5 +2,5 @@ Unit and integration tests for the stem library. """
-__all__ = ["runner"] +__all__ = ["output", "runner"]
diff --git a/test/output.py b/test/output.py new file mode 100644 index 0000000..4b53e52 --- /dev/null +++ b/test/output.py @@ -0,0 +1,93 @@ +""" +Variety of filters for the python unit testing output, which can be chained +together for improved readability. +""" + +import stem.util.enum +import stem.util.term as term + +LineType = stem.util.enum.Enum("OK", "FAIL", "ERROR", "SKIPPED", "CONTENT") + +LINE_ENDINGS = { + "... ok": LineType.OK, + "... FAIL": LineType.FAIL, + "... ERROR": LineType.ERROR, + "... skipped": LineType.SKIPPED, +} + +LINE_ATTR = { + LineType.OK: (term.Color.GREEN,), + LineType.FAIL: (term.Color.RED, term.Attr.BOLD), + LineType.ERROR: (term.Color.RED, term.Attr.BOLD), + LineType.SKIPPED: (term.Color.BLUE,), + LineType.CONTENT: (term.Color.CYAN,), +} + +def apply_filters(testing_output, *filters): + """ + Gets the tests results, possably processed through a series of filters. The + filters are applied in order, each getting the output of the previous. + + A filter's input arguments should be the line's (type, content) and the + output is either a string with the new content or None if the line should be + omitted. + + Arguments: + testing_output (str) - output from the unit testing + filters (list) - functors to be applied to each line of the results + + Returns: + str with the processed test results + """ + + results = [] + + for line in testing_output.split("\n"): + # determine the type of the line + line_type = LineType.CONTENT + + for ending in LINE_ENDINGS: + if line.endswith(ending): + line_type = LINE_ENDINGS[ending] + break + + for result_filter in filters: + line = result_filter(line_type, line) + if line == None: break + + if line != None: + results.append(line) + + return "\n".join(results) + +def colorize(line_type, line_content): + """ + Applies escape sequences so each line is colored according to its type. + """ + + return term.format(line_content, *LINE_ATTR[line_type]) + +class ErrorTracker: + """ + Stores any failure or error results we've encountered. + """ + + def __init__(self): + self._errors = [] + + def has_error_occured(self): + return bool(self._errors) + + def get_filter(self): + def _error_tracker(line_type, line_content): + if line_type in (LineType.FAIL, LineType.ERROR): + self._errors.append(line_content) + + return line_content + + return _error_tracker + + def __iter__(self): + for error_line in self._errors: + yield error_line +
tor-commits@lists.torproject.org