diff options
author | Adrien Di Mascio <Adrien.DiMascio@logilab.fr> | 2006-08-10 10:37:53 +0200 |
---|---|---|
committer | Adrien Di Mascio <Adrien.DiMascio@logilab.fr> | 2006-08-10 10:37:53 +0200 |
commit | 324fffb1bf5010d208130bd5f3eab1ef12ae9c55 (patch) | |
tree | 51ec6e8b18fbe099895374228e7855302c8fde48 | |
parent | 70dc668e1df75aecfa18ea9dd2fcd5e0307dd107 (diff) | |
download | logilab-common-324fffb1bf5010d208130bd5f3eab1ef12ae9c55.tar.gz |
added capture ability
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | __pkginfo__.py | 2 | ||||
-rw-r--r-- | debian/changelog | 6 | ||||
-rw-r--r-- | test/unittest_table.py | 1 | ||||
-rw-r--r-- | test/unittest_testlib.py | 66 | ||||
-rw-r--r-- | testlib.py | 86 |
6 files changed, 144 insertions, 21 deletions
@@ -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() @@ -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 |