Improvement TW-1255

- #TW-1255 New testing framework (thanks to Renato Alves).

Signed-off-by: Paul Beckingham <paul@beckingham.net>
This commit is contained in:
Renato Alves 2014-02-09 20:10:24 -05:00 committed by Paul Beckingham
parent d83f90f82b
commit 112d4bfb14
4 changed files with 145 additions and 100 deletions

View file

@ -7,6 +7,7 @@ Features
+ #1501 info report streamlining - partially implemented.
+ #TW-255 'Mask' instead of 'iMask' shown in info report (thanks to Benjamin
Weber)
+ #TW-1255 New testing framework (thanks to Renato Alves).
+ Removed deprecated 'echo.command' setting, in favor of the 'header' and
'affected' verbosity tokens.
+ Removed deprecated 'edit.verbose' setting, in favor of the 'edit' verbosity

134
test/simpletap/__init__.py Normal file
View file

@ -0,0 +1,134 @@
################################################################################
## taskwarrior - a command line task list manager.
##
## Copyright 2006-2014, Paul Beckingham, Federico Hernandez.
##
## Permission is hereby granted, free of charge, to any person obtaining a copy
## of this software and associated documentation files (the "Software"), to deal
## in the Software without restriction, including without limitation the rights
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
## copies of the Software, and to permit persons to whom the Software is
## furnished to do so, subject to the following conditions:
##
## The above copyright notice and this permission notice shall be included
## in all copies or substantial portions of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
## SOFTWARE.
##
## http://www.opensource.org/licenses/mit-license.php
##
################################################################################
# Original version by Renato Alves
import sys
import time
import unittest
import warnings
class TAPTestResult(unittest.result.TestResult):
def __init__(self, stream, descriptions, verbosity):
super(TAPTestResult, self).__init__(stream, descriptions, verbosity)
self.stream = stream
self.descriptions = descriptions
self.verbosity = verbosity
def getDescription(self, test):
doc_first_line = test.shortDescription()
if self.descriptions and doc_first_line:
return doc_first_line
else:
return str(test)
def startTestRun(self, total="unk"):
self.stream.writeln("1..{0}".format(total))
def report(self, test, status=None, err=None):
desc = self.getDescription(test)
try:
exception, msg, _ = err
except (TypeError, ValueError):
exception = ""
msg = err
else:
exception = exception.__name__
msg = str(msg)
if status:
if status == "SKIP":
self.stream.writeln("skip {0} - {1}".format(self.testsRun,
desc))
else:
self.stream.writeln("not ok {0} - {1}".format(self.testsRun,
desc))
self.stream.writeln("# {0}: {1}".format(status, exception))
padding = " " * (len(status) + 3)
for line in msg.splitlines():
self.stream.writeln("#{0}{1}".format(padding, line))
else:
self.stream.writeln("ok {0} - {1}".format(self.testsRun, desc))
self.stream.flush()
def addSuccess(self, test):
super(TAPTestResult, self).addSuccess(test)
self.report(test)
def addError(self, test, err):
super(TAPTestResult, self).addError(test, err)
self.report(test, "ERROR", err)
def addFailure(self, test, err):
super(TAPTestResult, self).addFailure(test, err)
self.report(test, "FAIL", err)
def addSkip(self, test, reason):
super(TAPTestResult, self).addSkip(test, reason)
self.report(test, "SKIP", reason)
class TAPTestRunner(unittest.runner.TextTestRunner):
"""A test runner that displays results using the Test Anything Protocol
syntax.
Inherits from TextTestRunner the default runner.
"""
resultclass = TAPTestResult
def run(self, test):
result = self._makeResult()
unittest.signals.registerResult(result)
result.failfast = self.failfast
result.buffer = self.buffer
with warnings.catch_warnings():
if getattr(self, "warnings", None):
# if self.warnings is set, use it to filter all the warnings
warnings.simplefilter(self.warnings)
# if the filter is 'default' or 'always', special-case the
# warnings from the deprecated unittest methods to show them
# no more than once per module, because they can be fairly
# noisy. The -Wd and -Wa flags can be used to bypass this
# only when self.warnings is None.
if self.warnings in ['default', 'always']:
warnings.filterwarnings('module',
category=DeprecationWarning,
message='Please use assert\w+ instead.')
startTestRun = getattr(result, 'startTestRun', None)
if startTestRun is not None:
startTestRun(test.countTestCases())
try:
test(result)
finally:
stopTestRun = getattr(result, 'stopTestRun', None)
if stopTestRun is not None:
stopTestRun()
return result

View file

@ -1,98 +0,0 @@
#
# Code from https://github.com/vit1251/unittest-tap-reporting
# No explicit license
#
# With modifications by Renato Alves
#
import sys
import time
import unittest
class TAPTestResult(unittest.result.TestResult):
version = 13
def __init__(self, stream=None, descriptions=None, plan=None):
super(TAPTestResult, self).__init__()
#self.stream = sys.stdout
self.stream = stream
self._current = 0
self.descriptions = descriptions
#self.stream.write("TAP version %d\n" % (self.version, ))
self.stream.write("%d..%d\n" % (1, plan, ))
def getDescription(self, test):
doc_first_line = test.shortDescription()
if self.descriptions and doc_first_line:
return doc_first_line
#return ' - '.join((str(test), doc_first_line))
else:
return str(test)
def addSuccess(self, test):
#super(TAPTestResult, self).addSuccess(test)
#print test
self.stream.write("ok %d - %s\n" % (self._current+1, self.getDescription(test)))
self.stream.flush()
self._current += 1
def addError(self, test, err):
(exctype, value, tb) = err
self.stream.write("not ok %d - %s\n# ERROR: %s\n" % (self._current+1, self.getDescription(test), value))
self.stream.flush()
self._current += 1
def addFailure(self, test, err):
(exctype, value, tb) = err
self.stream.write("not ok %d - %s\n# FAIL: %s\n" % (self._current+1, self.getDescription(test), value))
self.stream.flush()
self._current += 1
def addSkip(self, test, reason):
self.stream.write("not ok %d - %s # SKIP: %s\n" % (self._current+1, self.getDescription(test), reason))
self.stream.flush()
self._current += 1
class TAPTestRunner(object):
"""A test runner ia abstract class that displays results in user defined form.
It prints out the names of tests as they are run, errors as they
occur, and a summary of the results at the end of the test run.
"""
resultclass = TAPTestResult
def __init__(self, stream=sys.stderr, descriptions=True, plan=None, failfast=False, buffer=False, resultclass=None):
self.stream = stream
self.descriptions = descriptions
self.plan = plan
self.failfast = failfast
self.buffer = buffer
if resultclass is not None:
self.resultclass = resultclass
def _makeResult(self, test):
if self.plan is None:
self.plan = test.countTestCases()
return self.resultclass(self.stream, self.descriptions, self.plan)
def run(self, test):
"Run the given test case or test suite."
result = self._makeResult(test=test)
#registerResult(result)
result.failfast = self.failfast
result.buffer = self.buffer
startTime = time.time()
startTestRun = getattr(result, 'startTestRun', None)
if startTestRun is not None:
startTestRun()
try:
test(result)
finally:
stopTestRun = getattr(result, 'stopTestRun', None)
if stopTestRun is not None:
stopTestRun()
stopTime = time.time()
timeTaken = stopTime - startTime
return result

View file

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
import sys
@ -43,6 +43,14 @@ class TestVersion(unittest.TestCase):
expected = "Copyright \(C\) \d{4} - %d" % (datetime.now().year - 1,)
self.assertRegexpMatches(out.decode("utf8"), expected)
def testFailOther(self):
"""Nothing to do with Copyright"""
self.assertEqual("I like to code", "I like\nto code\n")
@unittest.skipIf(1 != 0, "This machine has sane logic")
def testSkipped(self):
"""Test all logic of the world"""
def tearDown(self):
"""Executed after each test in the class"""
@ -53,7 +61,7 @@ class TestVersion(unittest.TestCase):
if __name__ == "__main__":
from taprunner import TAPTestRunner
from simpletap import TAPTestRunner
unittest.main(testRunner=TAPTestRunner())
# vim: ai sts=4 et sw=4