mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-08-20 04:13:07 +02:00
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:
parent
d83f90f82b
commit
112d4bfb14
4 changed files with 145 additions and 100 deletions
|
@ -7,6 +7,7 @@ Features
|
||||||
+ #1501 info report streamlining - partially implemented.
|
+ #1501 info report streamlining - partially implemented.
|
||||||
+ #TW-255 'Mask' instead of 'iMask' shown in info report (thanks to Benjamin
|
+ #TW-255 'Mask' instead of 'iMask' shown in info report (thanks to Benjamin
|
||||||
Weber)
|
Weber)
|
||||||
|
+ #TW-1255 New testing framework (thanks to Renato Alves).
|
||||||
+ Removed deprecated 'echo.command' setting, in favor of the 'header' and
|
+ Removed deprecated 'echo.command' setting, in favor of the 'header' and
|
||||||
'affected' verbosity tokens.
|
'affected' verbosity tokens.
|
||||||
+ Removed deprecated 'edit.verbose' setting, in favor of the 'edit' verbosity
|
+ Removed deprecated 'edit.verbose' setting, in favor of the 'edit' verbosity
|
||||||
|
|
134
test/simpletap/__init__.py
Normal file
134
test/simpletap/__init__.py
Normal 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
|
|
@ -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
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/env python2.7
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
@ -43,6 +43,14 @@ class TestVersion(unittest.TestCase):
|
||||||
expected = "Copyright \(C\) \d{4} - %d" % (datetime.now().year - 1,)
|
expected = "Copyright \(C\) \d{4} - %d" % (datetime.now().year - 1,)
|
||||||
self.assertRegexpMatches(out.decode("utf8"), expected)
|
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):
|
def tearDown(self):
|
||||||
"""Executed after each test in the class"""
|
"""Executed after each test in the class"""
|
||||||
|
|
||||||
|
@ -53,7 +61,7 @@ class TestVersion(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from taprunner import TAPTestRunner
|
from simpletap import TAPTestRunner
|
||||||
unittest.main(testRunner=TAPTestRunner())
|
unittest.main(testRunner=TAPTestRunner())
|
||||||
|
|
||||||
# vim: ai sts=4 et sw=4
|
# vim: ai sts=4 et sw=4
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue