Skip to content

Commit 1a8b904

Browse files
committed
Starting on a basic colored output test runner using colorama. Haven't tested it on Win32 yet.
1 parent 352d67a commit 1a8b904

File tree

2 files changed

+86
-7
lines changed

2 files changed

+86
-7
lines changed

pyzen/flaskext/script.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from flaskext.script import Command, Option
88

99
from pyzen.core import main
10+
from pyzen.runner import ColoredTextTestRunner
1011

1112
try:
1213
from unittest2 import TestLoader
@@ -26,17 +27,21 @@ def _match_path(self, path, full_path, pattern):
2627
return True
2728
return False
2829

29-
def run_tests(app, pattern, start_dir, verbosity):
30+
def run_tests(app, pattern, start_dir, verbosity, nocolor):
3031
print start_dir
3132
loader = ZenTestLoader()
3233
suite = loader.discover(start_dir, pattern, start_dir)
33-
result = unittest.TextTestRunner(verbosity=verbosity).run(suite)
34+
if nocolor:
35+
runner = unittest.TextTestRunner
36+
else:
37+
runner = ColoredTextTestRunner
38+
result = runner(verbosity=verbosity).run(suite)
3439
return result
3540

3641
class Test(Command):
3742
"""Run app tests."""
3843

39-
def __init__(self, pattern='*/tests/*.py;*/tests.py', start_dir=None, verbosity=0):
44+
def __init__(self, pattern='*/tests/*.py;*/tests.py', start_dir=None, verbosity=1):
4045
if start_dir is None:
4146
# Find the file that called this constructor and use its directory
4247
for f in inspect.stack():
@@ -54,10 +59,11 @@ def get_options(self):
5459
Option('-p', '--pattern', dest='pattern', default=self.default_pattern),
5560
Option('-s', '--start_dir', dest='start_dir', default=self.default_start_dir),
5661
Option('-v', '--verbosity', dest='verbosity', default=self.default_verbosity),
62+
Option('--nocolor', action='store_true', default=False, help='Disable colored output'),
5763
]
5864

59-
def run(self, app, pattern, start_dir, verbosity):
60-
result = run_tests(app, pattern, start_dir, verbosity)
65+
def run(self, app, pattern, start_dir, verbosity, nocolor):
66+
result = run_tests(app, pattern, start_dir, verbosity, nocolor)
6167
if result.failures or result.errors:
6268
sys.exit(1)
6369

@@ -70,8 +76,8 @@ def get_options(self):
7076
options.append(Option('-u', '--ui', help='Force the use of the given PyZen UI'))
7177
return options
7278

73-
def run(self, app, pattern, start_dir, verbosity, ui):
79+
def run(self, app, pattern, start_dir, verbosity, ui, nocolor):
7480
try:
75-
main(ui, run_tests, app, pattern, start_dir, verbosity)
81+
main(ui, run_tests, app, pattern, start_dir, verbosity, nocolor)
7682
except KeyboardInterrupt:
7783
pass

pyzen/runner.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import time
2+
import unittest
3+
4+
try:
5+
import colorama
6+
except ImportError:
7+
from pyzen import _colorama as colorama
8+
9+
COLOR_SUCCESS = colorama.Fore.GREEN
10+
COLOR_FAIL = colorama.Fore.RED
11+
COLOR_RESET = colorama.Fore.RESET
12+
13+
class ColoredTextTestResult(unittest._TextTestResult):
14+
15+
def addSuccess(self, test):
16+
self.stream.write(COLOR_SUCCESS)
17+
unittest._TextTestResult.addSuccess(self, test)
18+
self.stream.write(COLOR_RESET)
19+
20+
def addError(self, test, err):
21+
self.stream.write(COLOR_FAIL)
22+
unittest._TextTestResult.addError(self, test, err)
23+
self.stream.write(COLOR_RESET)
24+
25+
def addFailure(self, test, err):
26+
self.stream.write(COLOR_FAIL)
27+
unittest._TextTestResult.addFailure(self, test, err)
28+
self.stream.write(COLOR_RESET)
29+
30+
def printErrorList(self, flavour, errors):
31+
for test, err in errors:
32+
self.stream.writeln(self.separator1)
33+
self.stream.writeln("%s%s: %s%s" % (COLOR_FAIL,flavour,self.getDescription(test),COLOR_RESET))
34+
self.stream.writeln(self.separator2)
35+
self.stream.writeln("%s" % err)
36+
37+
class ColoredTextTestRunner(unittest.TextTestRunner):
38+
39+
def __init__(self, *args, **kwargs):
40+
unittest.TextTestRunner.__init__(self, *args, **kwargs)
41+
wrapper = colorama.AnsiToWin32(self.stream)
42+
if wrapper.should_wrap():
43+
self.stream = wrapper.stream
44+
45+
def _makeResult(self):
46+
return ColoredTextTestResult(self.stream, self.descriptions, self.verbosity)
47+
48+
def run(self, test):
49+
"Run the given test case or test suite."
50+
result = self._makeResult()
51+
startTime = time.time()
52+
test(result)
53+
stopTime = time.time()
54+
timeTaken = stopTime - startTime
55+
result.printErrors()
56+
self.stream.writeln(result.separator2)
57+
run = result.testsRun
58+
self.stream.writeln("Ran %d test%s in %.3fs" %
59+
(run, run != 1 and "s" or "", timeTaken))
60+
self.stream.writeln()
61+
if not result.wasSuccessful():
62+
self.stream.write(COLOR_FAIL)
63+
self.stream.write("FAILED (")
64+
failed, errored = map(len, (result.failures, result.errors))
65+
if failed:
66+
self.stream.write("failures=%d" % failed)
67+
if errored:
68+
if failed: self.stream.write(", ")
69+
self.stream.write("errors=%d" % errored)
70+
self.stream.writeln(")"+COLOR_RESET)
71+
else:
72+
self.stream.writeln(COLOR_SUCCESS+"OK"+COLOR_RESET)
73+
return result

0 commit comments

Comments
 (0)