summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrien Di Mascio <Adrien.DiMascio@logilab.fr>2006-08-10 10:37:53 +0200
committerAdrien Di Mascio <Adrien.DiMascio@logilab.fr>2006-08-10 10:37:53 +0200
commit324fffb1bf5010d208130bd5f3eab1ef12ae9c55 (patch)
tree51ec6e8b18fbe099895374228e7855302c8fde48
parent70dc668e1df75aecfa18ea9dd2fcd5e0307dd107 (diff)
downloadlogilab-common-324fffb1bf5010d208130bd5f3eab1ef12ae9c55.tar.gz
added capture ability
-rw-r--r--ChangeLog4
-rw-r--r--__pkginfo__.py2
-rw-r--r--debian/changelog6
-rw-r--r--test/unittest_table.py1
-rw-r--r--test/unittest_testlib.py66
-rw-r--r--testlib.py86
6 files changed, 144 insertions, 21 deletions
diff --git a/ChangeLog b/ChangeLog
index feb58ba..9c9b94a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,10 @@
ChangeLog for logilab.common
============================
- --
+2006-08-09 -- 0.18.0
+ * added -c / --capture option to testlib.unittest_main
+ * fixed bugs in lgc.configuration
* optparser: added a OptionParser that extends optparse's with commands
2006-07-13 -- 0.17.0
diff --git a/__pkginfo__.py b/__pkginfo__.py
index 4c96f9b..8eba07a 100644
--- a/__pkginfo__.py
+++ b/__pkginfo__.py
@@ -18,7 +18,7 @@
__revision__ = "$Id: __pkginfo__.py,v 1.58 2006-04-25 12:08:52 syt Exp $"
modname = 'common'
-numversion = (0, 17, 0)
+numversion = (0, 18, 0)
version = '.'.join([str(num) for num in numversion])
license = 'GPL'
diff --git a/debian/changelog b/debian/changelog
index e495bce..3c167ae 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+logilab-common (0.18.0-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- Adrien.DiMascio <Adrien.DiMascio@logilab.fr> Wed, 9 Aug 2006 16:34:42 +0200
+
logilab-common (0.17.0-2) unstable; urgency=low
* removed python-xml dependency
diff --git a/test/unittest_table.py b/test/unittest_table.py
index c9478b2..496b8ef 100644
--- a/test/unittest_table.py
+++ b/test/unittest_table.py
@@ -5,6 +5,7 @@ Unittests for table management
__revision__ = '$Id: unittest_table.py,v 1.13 2006-04-09 22:30:53 nico Exp $'
import sys
+import os
from cStringIO import StringIO
from logilab.common.testlib import TestCase, unittest_main
diff --git a/test/unittest_testlib.py b/test/unittest_testlib.py
index ec311a9..2cf7d1b 100644
--- a/test/unittest_testlib.py
+++ b/test/unittest_testlib.py
@@ -4,6 +4,7 @@ __revision__ = '$Id: unittest_testlib.py,v 1.5 2006-02-09 22:37:46 nico Exp $'
import unittest
import os
+import sys
from os.path import join, dirname, isdir, isfile
from cStringIO import StringIO
import tempfile
@@ -14,7 +15,6 @@ from logilab.common.compat import sorted
try:
__file__
except NameError:
- import sys
__file__ = sys.argv[0]
from logilab.common.testlib import TestCase, unittest_main, SkipAwareTextTestRunner
@@ -319,7 +319,69 @@ class TestLoaderTC(TestCase):
collected = self.loader.loadTestsFromName(pattern, self.module)
yield self.assertEquals, len(collected), expected_count
-
+
+
+
+class OutErrCaptureTC(TestCase):
+
+ def setUp(self):
+ sys.stdout = sys.stderr = StringIO()
+ self.runner = SkipAwareTextTestRunner(stream=StringIO(), exitfirst=True, capture=True)
+
+ def tearDown(self):
+ sys.stdout = sys.__stdout__
+ sys.stderr = sys.__stderr__
+
+ def test_stdout_capture(self):
+ class FooTC(TestCase):
+ def test_stdout(self):
+ print "foo"
+ self.assert_(False)
+ test = FooTC('test_stdout')
+ result = self.runner.run(test)
+ captured_out, captured_err = test.captured_output()
+ self.assertEqual(captured_out.strip(), "foo")
+ self.assertEqual(captured_err.strip(), "")
+
+ def test_stderr_capture(self):
+ class FooTC(TestCase):
+ def test_stderr(self):
+ print >> sys.stderr, "foo"
+ self.assert_(False)
+ test = FooTC('test_stderr')
+ result = self.runner.run(test)
+ captured_out, captured_err = test.captured_output()
+ self.assertEqual(captured_out.strip(), "")
+ self.assertEqual(captured_err.strip(), "foo")
+
+
+ def test_both_capture(self):
+ class FooTC(TestCase):
+ def test_stderr(self):
+ print >> sys.stderr, "foo"
+ print "bar"
+ self.assert_(False)
+ test = FooTC('test_stderr')
+ result = self.runner.run(test)
+ captured_out, captured_err = test.captured_output()
+ self.assertEqual(captured_out.strip(), "bar")
+ self.assertEqual(captured_err.strip(), "foo")
+
+ def test_no_capture(self):
+ class FooTC(TestCase):
+ def test_stderr(self):
+ print >> sys.stderr, "foo"
+ print "bar"
+ self.assert_(False)
+ test = FooTC('test_stderr')
+ # this runner should not capture stdout / stderr
+ runner = SkipAwareTextTestRunner(stream=StringIO(), exitfirst=True)
+ result = runner.run(test)
+ captured_out, captured_err = test.captured_output()
+ self.assertEqual(captured_out.strip(), "")
+ self.assertEqual(captured_err.strip(), "")
+
+
if __name__ == '__main__':
unittest_main()
diff --git a/testlib.py b/testlib.py
index c163899..7b5dd65 100644
--- a/testlib.py
+++ b/testlib.py
@@ -303,20 +303,21 @@ from cStringIO import StringIO
class SkipAwareTestResult(unittest._TextTestResult):
- def __init__(self, stream, descriptions, verbosity, exitfirst=False):
+ def __init__(self, stream, descriptions, verbosity,
+ exitfirst=False, capture=False):
unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
self.skipped = []
self.debuggers = []
self.descrs = []
self.exitfirst = exitfirst
-
+ self.capture = capture
+
def _create_pdb(self, test_descr):
self.debuggers.append(Debugger(sys.exc_info()[2]))
self.descrs.append(test_descr)
def addError(self, test, err):
exc_type, exc, tcbk = err
- # hack to avoid overriding the whole __call__ machinery in TestCase
if exc_type == TestSkipped:
self.addSkipped(test, exc)
else:
@@ -348,16 +349,35 @@ class SkipAwareTestResult(unittest._TextTestResult):
self.stream.writeln("%s: %s" % ('SKIPPED', self.getDescription(test)))
self.stream.writeln("\t%s" % err)
+ def printErrorList(self, flavour, errors):
+ for test, err in errors:
+ self.stream.writeln(self.separator1)
+ self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
+ self.stream.writeln(self.separator2)
+ self.stream.writeln("%s" % err)
+ if self.capture:
+ output, errput = test.captured_output()
+ self.stream.writeln(self.separator2)
+ self.stream.writeln("captured stdout".center(len(self.separator2)))
+ self.stream.writeln(self.separator2)
+ self.stream.writeln(output)
+ self.stream.writeln(self.separator2)
+ self.stream.writeln("captured stderr".center(len(self.separator2)))
+ self.stream.writeln(self.separator2)
+ self.stream.writeln(errput)
+
class SkipAwareTextTestRunner(unittest.TextTestRunner):
- def __init__(self, stream=sys.stderr, verbosity=1, exitfirst=False):
+ def __init__(self, stream=sys.stderr, verbosity=1,
+ exitfirst=False, capture=False):
unittest.TextTestRunner.__init__(self, stream=stream, verbosity=verbosity)
self.exitfirst = exitfirst
-
+ self.capture = capture
+
def _makeResult(self):
- return SkipAwareTestResult(self.stream, self.descriptions,
- self.verbosity, self.exitfirst)
+ return SkipAwareTestResult(self.stream, self.descriptions, self.verbosity,
+ self.exitfirst, self.capture)
class keywords(dict):
@@ -484,10 +504,11 @@ Examples:
def parseArgs(self, argv):
self.pdbmode = False
self.exitfirst = False
+ self.capture = False
import getopt
try:
- options, args = getopt.getopt(argv[1:], 'hHvixq',
- ['help','verbose','quiet', 'pdb', 'exitfirst'])
+ options, args = getopt.getopt(argv[1:], 'hHvixqc',
+ ['help','verbose','quiet', 'pdb', 'exitfirst', 'capture'])
for opt, value in options:
if opt in ('-h','-H','--help'):
self.usageExit()
@@ -499,6 +520,8 @@ Examples:
self.verbosity = 0
if opt in ('-v','--verbose'):
self.verbosity = 2
+ if opt in ('-c', '--capture'):
+ self.capture = True
if len(args) == 0 and self.defaultTest is None:
self.test = self.testLoader.loadTestsFromModule(self.module)
return
@@ -514,7 +537,8 @@ Examples:
def runTests(self):
self.testRunner = SkipAwareTextTestRunner(verbosity=self.verbosity,
- exitfirst=self.exitfirst)
+ exitfirst=self.exitfirst,
+ capture=self.capture)
result = self.testRunner.run(self.test)
if os.environ.get('PYDEBUG'):
warn("PYDEBUG usage is deprecated, use -i / --pdb instead", DeprecationWarning)
@@ -523,6 +547,18 @@ Examples:
start_interactive_mode(result.debuggers, result.descrs)
sys.exit(not result.wasSuccessful())
+
+from cStringIO import StringIO
+def quiet_run(function, *args, **kwargs):
+ stdout, stderr = StringIO(), StringIO()
+ sys.stdout, sys.stderr = stdout, stderr
+ try:
+ result = function(*args, **kwargs)
+ finally:
+ sys.stdout, sys.stderr = sys.__stdout__, sys.__stderr__
+ return result, stdout.getvalue(), stderr.getvalue()
+
+
def unittest_main():
"""use this functon if you want to have the same functionality
as unittest.main"""
@@ -569,15 +605,14 @@ class TestCase(unittest.TestCase):
if sys.version_info >= (2, 5):
self.__exc_info = self._exc_info
self.__testMethodName = self._testMethodName
+ self._captured_stdout = ""
+ self._captured_stderr = ""
-
+ def captured_output(self):
+ return self._captured_stdout, self._captured_stderr
- def __call__(self, result=None):
- """rewrite TestCase.__call__ to support generative tests
- This is mostly a copy/paste from unittest.py (i.e same
- variable names, same logic, except for the generative tests part)
- """
- if result is None: result = self.defaultTestResult()
+
+ def __run__(self, result=None):
result.startTest(self)
testMethod = getattr(self, self.__testMethodName)
try:
@@ -605,6 +640,23 @@ class TestCase(unittest.TestCase):
result.addSuccess(self)
finally:
result.stopTest(self)
+
+ def __call__(self, result=None):
+ """rewrite TestCase.__call__ to support generative tests
+ This is mostly a copy/paste from unittest.py (i.e same
+ variable names, same logic, except for the generative tests part)
+ """
+ if result is None:
+ result = self.defaultTestResult()
+ capture = getattr(result, 'capture', False)
+ if capture:
+ retval, out, err = quiet_run(self.__run__, result)
+ self._captured_stdout = out
+ self._captured_stderr = err
+ return retval
+ else:
+ return self.__run__(result)
+
def _proceed_generative(self, result, testfunc, args=()):
# cancel startTest()'s increment