summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--functional_tests/test_loader.py2
-rw-r--r--nose/config.py17
-rw-r--r--nose/core.py7
-rw-r--r--nose/exc.py7
-rw-r--r--nose/plugins/base.py28
-rw-r--r--nose/plugins/builtin.py5
-rw-r--r--nose/plugins/capture.py31
-rw-r--r--nose/plugins/manager.py4
-rw-r--r--nose/proxy.py7
-rw-r--r--unit_tests/test_capture_plugin.py44
-rw-r--r--unit_tests/test_config.py2
11 files changed, 116 insertions, 38 deletions
diff --git a/functional_tests/test_loader.py b/functional_tests/test_loader.py
index 2b84b42..256fac2 100644
--- a/functional_tests/test_loader.py
+++ b/functional_tests/test_loader.py
@@ -187,6 +187,7 @@ class TestNoseTestLoader(unittest.TestCase):
"Expected to run 0 tests but ran %s" % res.testsRun
def test_mod_setup_skip_no_tests_run_no_errors(self):
+ # FIXME need to load a config with builtin plugins
ctx = os.path.join(support, 'ctx')
l = loader.TestLoader(workingDir=ctx)
suite = l.loadTestsFromName('mod_setup_skip.py')
@@ -201,6 +202,7 @@ class TestNoseTestLoader(unittest.TestCase):
"Expected to run 0 tests but ran %s" % res.testsRun
def test_mod_import_skip_one_test_no_errors(self):
+ # FIXME need to load a config with builtin plugins
ctx = os.path.join(support, 'ctx')
l = loader.TestLoader(workingDir=ctx)
suite = l.loadTestsFromName('mod_import_skip.py')
diff --git a/nose/config.py b/nose/config.py
index 8b94d94..bcee140 100644
--- a/nose/config.py
+++ b/nose/config.py
@@ -12,10 +12,7 @@ class Config(object):
self.testMatch = re.compile(r'(?:^|[\b_\.%s-])[Tt]est' % os.sep)
self.addPaths = True
- self.capture = True
self.detailedErrors = False
- self.debugErrors = False
- self.debugFailures = False
self.exclude = None
self.exit = True
self.includeExe = sys.platform=='win32'
@@ -39,7 +36,6 @@ class Config(object):
self.args = ()
self.testMatch = re.compile(r'(?:^|[\b_\.%s-])[Tt]est' % os.sep)
self.addPaths = not env.get('NOSE_NOPATH', False)
- self.capture = not env.get('NOSE_NOCAPTURE', False)
self.detailedErrors = env.get('NOSE_DETAILED_ERRORS', False)
self.debug = env.get('NOSE_DEBUG')
self.debugLog = env.get('NOSE_DEBUG_LOG')
@@ -117,10 +113,7 @@ class Config(object):
self.configureLogging(options)
self.addPaths = options.addPaths
- self.capture = options.capture
self.detailedErrors = options.detailedErrors
- self.debugErrors = options.debugErrors
- self.debugFailures = options.debugFailures
self.stopOnError = options.stopOnError
self.verbosity = options.verbosity
self.includeExe = options.includeExe
@@ -153,7 +146,7 @@ class Config(object):
def configureLogging(self, options):
# FIXME
- # logging.basicConfig(level=logging.DEBUG)
+ # xlogging.basicConfig(level=logging.DEBUG)
pass
def default(self):
@@ -188,8 +181,7 @@ class Config(object):
help="Log debug messages to this file "
"(default: sys.stderr)")
parser.add_option(
- "-q", "--quiet", action="store_const",
- const=0, dest="verbosity")
+ "-q", "--quiet", action="store_const", const=0, dest="verbosity")
parser.add_option(
"-w", "--where", action="append", dest="where",
help="DEPRECATED Look for tests in this directory. "
@@ -205,11 +197,6 @@ class Config(object):
help="Also run tests that match regular "
"expression [NOSE_INCLUDE]")
parser.add_option(
- "-s", "--nocapture", action="store_false",
- default=self.capture, dest="capture",
- help="Don't capture stdout (any stdout output "
- "will be printed immediately) [NOSE_NOCAPTURE]")
- parser.add_option(
"-d", "--detailed-errors", action="store_true",
default=self.detailedErrors,
dest="detailedErrors", help="Add detail to error"
diff --git a/nose/core.py b/nose/core.py
index 13ac2e7..3f06827 100644
--- a/nose/core.py
+++ b/nose/core.py
@@ -14,7 +14,7 @@ from nose.importer import add_path
from nose.loader import defaultTestLoader
from nose.plugins.manager import DefaultPluginManager
from nose.result import TextTestResult
-from nose.util import absdir, tolist, start_capture, end_capture
+from nose.util import absdir, tolist
log = logging.getLogger('nose.core')
@@ -230,11 +230,6 @@ class TestProgram(unittest.TestProgram):
log.debug("configured %s", self.config)
- # call early to ensure we get our hooks into sys.stdout before
- # any subject modules are loaded and import it
- if self.config.capture:
- start_capture()
-
# instantiate the test loader
if self.testLoader is None:
self.testLoader = defaultTestLoader(config=self.config)
diff --git a/nose/exc.py b/nose/exc.py
index b0cd2dd..851c5df 100644
--- a/nose/exc.py
+++ b/nose/exc.py
@@ -1,11 +1,8 @@
"""Exceptions for marking tests as skipped or deprecated.
"""
+from nose.plugins.skip import SkipTest
+
class DeprecatedTest(Exception):
"""Raise this exception to mark a test as deprecated.
"""
pass
-
-class SkipTest(Exception):
- """Raise this exception to mark a test as skipped.
- """
- pass
diff --git a/nose/plugins/base.py b/nose/plugins/base.py
index 16abe73..a4810ad 100644
--- a/nose/plugins/base.py
+++ b/nose/plugins/base.py
@@ -268,6 +268,34 @@ class IPluginInterface(object):
"""
pass
+ def formatError(self, test, err):
+ """Called in result.addError, before plugin.addError. If you
+ want to replace or modify the error tuple, return a new error
+ tuple.
+
+ Parameters:
+ * test:
+ the test case
+ * err:
+ the error tuple (class, value, traceback)
+ """
+ pass
+ formatError._new = True
+
+ def formatFailure(self, test, err):
+ """Called in result.addFailure, before plugin.addFailure. If you
+ want to replace or modify the error tuple, return a new error
+ tuple.
+
+ Parameters:
+ * test:
+ the test case
+ * err:
+ the error tuple (class, value, traceback)
+ """
+ pass
+ formatFailure._new = True
+
def handleError(self, test, err):
"""Called on addError. To handle the error yourself and prevent normal
error processing, return a true value.
diff --git a/nose/plugins/builtin.py b/nose/plugins/builtin.py
index 55253ad..cb5ee17 100644
--- a/nose/plugins/builtin.py
+++ b/nose/plugins/builtin.py
@@ -3,9 +3,12 @@ Lists builtin plugins
"""
from nose.plugins.attrib import AttributeSelector
+from nose.plugins.capture import Capture
from nose.plugins.cover import Coverage
+from nose.plugins.debug import Pdb
from nose.plugins.doctests import Doctest
## from nose.plugins.isolation import
from nose.plugins.prof import Profile
+from nose.plugins.skip import Skip
-plugins = [AttributeSelector, Coverage, Doctest, Profile]
+plugins = [AttributeSelector, Capture, Coverage, Doctest, Pdb, Profile, Skip]
diff --git a/nose/plugins/capture.py b/nose/plugins/capture.py
index 350abaa..2819780 100644
--- a/nose/plugins/capture.py
+++ b/nose/plugins/capture.py
@@ -1,3 +1,4 @@
+import os
import sys
from nose.plugins.base import Plugin
from nose.util import ln
@@ -8,14 +9,40 @@ except ImportError:
class Capture(Plugin):
-
+ """Output capture plugin. Enabled by default. Disable with -s or
+ --nocapture. This plugin captures stdout during test execution,
+ appending any output capture to the error or failure output,
+ should the test fail or raise an error.
+ """
+ enabled = True
+ env_opt = 'NOSE_NOCAPTURE'
+ name = 'capture'
+
def __init__(self):
self.stdout = None
self._buf = None
+ def options(self, parser, env=os.environ):
+ parser.add_option(
+ "-s", "--nocapture", action="store_false",
+ default=not env.get(self.env_opt), dest="capture",
+ help="Don't capture stdout (any stdout output "
+ "will be printed immediately) [NOSE_NOCAPTURE]")
+
+ def configure(self, options, conf):
+ self.conf = conf
+ if not options.capture:
+ self.enabled = False
+
+ def afterTest(self, test):
+ self.end()
+
def begin(self):
self.start() # get an early handle on sys.stdout
+ def beforeTest(self, test):
+ self.start()
+
def formatError(self, test, err):
self.end()
test.captured_output = output = self.buffer
@@ -25,7 +52,7 @@ class Capture(Plugin):
return (ec, self.addCaptureToErr(ev, output), tb)
def formatFailure(self, test, err):
- return self.formatError(self, test, err)
+ return self.formatError(test, err)
def addCaptureToErr(self, ev, output):
return '\n'.join([str(ev) , ln('>> begin captured stdout <<'),
diff --git a/nose/plugins/manager.py b/nose/plugins/manager.py
index 2c67d1d..7b85798 100644
--- a/nose/plugins/manager.py
+++ b/nose/plugins/manager.py
@@ -44,11 +44,13 @@ class PluginManager(object):
and config instance. After configuration, disabled plugins
are removed from the plugins list.
"""
+ log.debug("Configuring plugins")
self.config = config
cfg = PluginProxy('configure', self._plugins)
cfg(options, config)
enabled = [plug for plug in self._plugins if plug.enabled]
- self.plugins = enabled
+ self.plugins = enabled
+ log.debug("Plugins enabled: %s", enabled)
def loadPlugins(self):
pass
diff --git a/nose/proxy.py b/nose/proxy.py
index b2ff945..a2cdca8 100644
--- a/nose/proxy.py
+++ b/nose/proxy.py
@@ -83,9 +83,10 @@ class ResultProxy(object):
def assertMyTest(self, test):
# The test I was called with must be my .test or my
# .test's .test.
- assert test is getattr(self.test, 'test', self.test), \
- "ResultProxy for %r was called with test %r" \
- % (self.test, test)
+
+ assert test is self.test or test is getattr(self.test, 'test', None), \
+ "ResultProxy for %r (%s) was called with test %r (%s)" \
+ % (self.test, id(self.test), test, id(test))
def afterTest(self, test):
self.assertMyTest(test)
diff --git a/unit_tests/test_capture_plugin.py b/unit_tests/test_capture_plugin.py
index 0504f98..58cc2ec 100644
--- a/unit_tests/test_capture_plugin.py
+++ b/unit_tests/test_capture_plugin.py
@@ -1,9 +1,46 @@
import sys
import unittest
+from optparse import OptionParser
+from nose.config import Config
from nose.plugins.capture import Capture
class TestCapturePlugin(unittest.TestCase):
+ def test_enabled_by_default(self):
+ c = Capture()
+ assert c.enabled
+
+ def test_can_be_disabled(self):
+ c = Capture()
+ parser = OptionParser()
+ c.addOptions(parser)
+ options, args = parser.parse_args(['test_can_be_disabled',
+ '-s'])
+ c.configure(options, Config())
+ assert not c.enabled
+
+ c = Capture()
+ options, args = parser.parse_args(['test_can_be_disabled_long',
+ '--nocapture'])
+ c.configure(options, Config())
+ assert not c.enabled
+
+ env = {'NOSE_NOCAPTURE': 1}
+ c = Capture()
+ parser = OptionParser()
+ c.addOptions(parser, env)
+ options, args = parser.parse_args(['test_can_be_disabled'])
+ c.configure(options, Config())
+ assert not c.enabled
+
+ c = Capture()
+ parser = OptionParser()
+ c.addOptions(parser)
+
+ options, args = parser.parse_args(['test_can_be_disabled'])
+ c.configure(options, Config())
+ assert c.enabled
+
def test_captures_stdout(self):
c = Capture()
c.start()
@@ -25,11 +62,12 @@ class TestCapturePlugin(unittest.TestCase):
formatted = c.formatError(d, err)
ec, ev, tb = err
fec, fev, ftb = formatted
+ # print fec, fev, ftb
+
self.assertEqual(ec, fec)
self.assertEqual(tb, ftb)
-
- assert 'Oh my!' in fev
- assert 'Oh my!' in d.captured_output
+ assert 'Oh my!' in fev, "Output not found in error message"
+ assert 'Oh my!' in d.captured_output, "Output not attached to test"
if __name__ == '__main__':
unittest.main()
diff --git a/unit_tests/test_config.py b/unit_tests/test_config.py
index 660d298..2378bf6 100644
--- a/unit_tests/test_config.py
+++ b/unit_tests/test_config.py
@@ -7,8 +7,6 @@ class TestNoseConfig(unittest.TestCase):
def test_defaults(self):
c = nose.config.Config()
assert c.addPaths == True
- assert c.capture == True
- assert c.detailedErrors == False
# FIXME etc
def test_reset(self):