Open Media Library Platform

This commit is contained in:
j 2013-10-11 19:28:32 +02:00
commit 411ad5b16f
5849 changed files with 1778641 additions and 0 deletions

View file

@ -0,0 +1,6 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Unit tests for the Trial unit-testing framework.
"""

View file

@ -0,0 +1,203 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for Deferred handling by L{twisted.trial.unittest.TestCase}.
"""
from __future__ import division, absolute_import
from twisted.trial import unittest
from twisted.internet import defer, threads, reactor
class DeferredSetUpOK(unittest.TestCase):
def setUp(self):
d = defer.succeed('value')
d.addCallback(self._cb_setUpCalled)
return d
def _cb_setUpCalled(self, ignored):
self._setUpCalled = True
def test_ok(self):
self.failUnless(self._setUpCalled)
class DeferredSetUpFail(unittest.TestCase):
testCalled = False
def setUp(self):
return defer.fail(unittest.FailTest('i fail'))
def test_ok(self):
DeferredSetUpFail.testCalled = True
self.fail("I should not get called")
class DeferredSetUpCallbackFail(unittest.TestCase):
testCalled = False
def setUp(self):
d = defer.succeed('value')
d.addCallback(self._cb_setUpCalled)
return d
def _cb_setUpCalled(self, ignored):
self.fail('deliberate failure')
def test_ok(self):
DeferredSetUpCallbackFail.testCalled = True
class DeferredSetUpError(unittest.TestCase):
testCalled = False
def setUp(self):
return defer.fail(RuntimeError('deliberate error'))
def test_ok(self):
DeferredSetUpError.testCalled = True
class DeferredSetUpNeverFire(unittest.TestCase):
testCalled = False
def setUp(self):
return defer.Deferred()
def test_ok(self):
DeferredSetUpNeverFire.testCalled = True
class DeferredSetUpSkip(unittest.TestCase):
testCalled = False
def setUp(self):
d = defer.succeed('value')
d.addCallback(self._cb1)
return d
def _cb1(self, ignored):
raise unittest.SkipTest("skip me")
def test_ok(self):
DeferredSetUpSkip.testCalled = True
class DeferredTests(unittest.TestCase):
touched = False
def _cb_fail(self, reason):
self.fail(reason)
def _cb_error(self, reason):
raise RuntimeError(reason)
def _cb_skip(self, reason):
raise unittest.SkipTest(reason)
def _touchClass(self, ignored):
self.__class__.touched = True
def setUp(self):
self.__class__.touched = False
def test_pass(self):
return defer.succeed('success')
def test_passGenerated(self):
self._touchClass(None)
yield None
test_passGenerated = defer.deferredGenerator(test_passGenerated)
def test_fail(self):
return defer.fail(self.failureException('I fail'))
def test_failureInCallback(self):
d = defer.succeed('fail')
d.addCallback(self._cb_fail)
return d
def test_errorInCallback(self):
d = defer.succeed('error')
d.addCallback(self._cb_error)
return d
def test_skip(self):
d = defer.succeed('skip')
d.addCallback(self._cb_skip)
d.addCallback(self._touchClass)
return d
def test_thread(self):
return threads.deferToThread(lambda : None)
def test_expectedFailure(self):
d = defer.succeed('todo')
d.addCallback(self._cb_error)
return d
test_expectedFailure.todo = "Expected failure"
class TimeoutTests(unittest.TestCase):
timedOut = None
def test_pass(self):
d = defer.Deferred()
reactor.callLater(0, d.callback, 'hoorj!')
return d
test_pass.timeout = 2
def test_passDefault(self):
# test default timeout
d = defer.Deferred()
reactor.callLater(0, d.callback, 'hoorj!')
return d
def test_timeout(self):
return defer.Deferred()
test_timeout.timeout = 0.1
def test_timeoutZero(self):
return defer.Deferred()
test_timeoutZero.timeout = 0
def test_expectedFailure(self):
return defer.Deferred()
test_expectedFailure.timeout = 0.1
test_expectedFailure.todo = "i will get it right, eventually"
def test_skip(self):
return defer.Deferred()
test_skip.timeout = 0.1
test_skip.skip = "i will get it right, eventually"
def test_errorPropagation(self):
def timedOut(err):
self.__class__.timedOut = err
return err
d = defer.Deferred()
d.addErrback(timedOut)
return d
test_errorPropagation.timeout = 0.1
def test_calledButNeverCallback(self):
d = defer.Deferred()
def neverFire(r):
return defer.Deferred()
d.addCallback(neverFire)
d.callback(1)
return d
test_calledButNeverCallback.timeout = 0.1
class TestClassTimeoutAttribute(unittest.TestCase):
timeout = 0.2
def setUp(self):
self.d = defer.Deferred()
def testMethod(self):
self.methodCalled = True
return self.d

View file

@ -0,0 +1,188 @@
# -*- test-case-name: twisted.trial.test.test_tests -*-
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Definitions of test cases with various interesting error-related behaviors, to
be used by test modules to exercise different features of trial's test runner.
See the L{twisted.trial.test.test_tests} module docstring for details about how
this code is arranged.
"""
from __future__ import division, absolute_import
from twisted.trial import unittest, util
from twisted.internet import reactor, protocol, defer
class FoolishError(Exception):
pass
class FailureInSetUpMixin(object):
def setUp(self):
raise FoolishError("I am a broken setUp method")
def test_noop(self):
pass
class SynchronousTestFailureInSetUp(
FailureInSetUpMixin, unittest.SynchronousTestCase):
pass
class AsynchronousTestFailureInSetUp(
FailureInSetUpMixin, unittest.TestCase):
pass
class FailureInTearDownMixin(object):
def tearDown(self):
raise FoolishError("I am a broken tearDown method")
def test_noop(self):
pass
class SynchronousTestFailureInTearDown(
FailureInTearDownMixin, unittest.SynchronousTestCase):
pass
class AsynchronousTestFailureInTearDown(
FailureInTearDownMixin, unittest.TestCase):
pass
class TestRegularFail(unittest.SynchronousTestCase):
def test_fail(self):
self.fail("I fail")
def test_subfail(self):
self.subroutine()
def subroutine(self):
self.fail("I fail inside")
class TestAsynchronousFail(unittest.TestCase):
"""
Test failures for L{unittest.TestCase} based classes.
"""
def test_fail(self):
"""
A test which fails in the callback of the returned L{defer.Deferred}.
"""
d = defer.Deferred()
d.addCallback(self._later)
reactor.callLater(0, d.callback, None)
return d
def _later(self, res):
self.fail("I fail later")
def test_exception(self):
"""
A test which raises an exception synchronously.
"""
raise Exception("I fail")
class ErrorTest(unittest.SynchronousTestCase):
"""
A test case which has a L{test_foo} which will raise an error.
@ivar ran: boolean indicating whether L{test_foo} has been run.
"""
ran = False
def test_foo(self):
"""
Set C{self.ran} to True and raise a C{ZeroDivisionError}
"""
self.ran = True
1/0
class TestSkipTestCase(unittest.SynchronousTestCase):
pass
TestSkipTestCase.skip = "skipping this test"
class DelayedCall(unittest.TestCase):
hiddenExceptionMsg = "something blew up"
def go(self):
raise RuntimeError(self.hiddenExceptionMsg)
def testHiddenException(self):
"""
What happens if an error is raised in a DelayedCall and an error is
also raised in the test?
L{test_reporter.TestErrorReporting.testHiddenException} checks that
both errors get reported.
Note that this behaviour is deprecated. A B{real} test would return a
Deferred that got triggered by the callLater. This would guarantee the
delayed call error gets reported.
"""
reactor.callLater(0, self.go)
reactor.iterate(0.01)
self.fail("Deliberate failure to mask the hidden exception")
testHiddenException.suppress = [util.suppress(
message=r'reactor\.iterate cannot be used.*',
category=DeprecationWarning)]
class ReactorCleanupTests(unittest.TestCase):
def test_leftoverPendingCalls(self):
def _():
print('foo!')
reactor.callLater(10000.0, _)
class SocketOpenTest(unittest.TestCase):
def test_socketsLeftOpen(self):
f = protocol.Factory()
f.protocol = protocol.Protocol
reactor.listenTCP(0, f)
class TimingOutDeferred(unittest.TestCase):
def test_alpha(self):
pass
def test_deferredThatNeverFires(self):
self.methodCalled = True
d = defer.Deferred()
return d
def test_omega(self):
pass
def unexpectedException(self):
"""i will raise an unexpected exception...
... *CAUSE THAT'S THE KINDA GUY I AM*
>>> 1/0
"""

View file

@ -0,0 +1,21 @@
# Copyright (c) 2006 Twisted Matrix Laboratories. See LICENSE for details
"""
Mock test module that contains a C{test_suite} method. L{runner.TestLoader}
should load the tests from the C{test_suite}, not from the C{Foo} C{TestCase}.
See {twisted.trial.test.test_loader.LoaderTest.test_loadModuleWith_test_suite}.
"""
from twisted.trial import unittest, runner
class Foo(unittest.SynchronousTestCase):
def test_foo(self):
pass
def test_suite():
ts = runner.TestSuite()
ts.name = "MyCustomSuite"
return ts

View file

@ -0,0 +1,21 @@
# Copyright (c) 2006 Twisted Matrix Laboratories. See LICENSE for details
"""
Mock test module that contains a C{testSuite} method. L{runner.TestLoader}
should load the tests from the C{testSuite}, not from the C{Foo} C{TestCase}.
See L{twisted.trial.test.test_loader.LoaderTest.test_loadModuleWith_testSuite}.
"""
from twisted.trial import unittest, runner
class Foo(unittest.SynchronousTestCase):
def test_foo(self):
pass
def testSuite():
ts = runner.TestSuite()
ts.name = "MyCustomSuite"
return ts

View file

@ -0,0 +1,28 @@
# Copyright (c) 2006 Twisted Matrix Laboratories. See LICENSE for details
"""
Mock test module that contains both a C{test_suite} and a C{testSuite} method.
L{runner.TestLoader} should load the tests from the C{testSuite}, not from the
C{Foo} C{TestCase} nor from the C{test_suite} method.
See {twisted.trial.test.test_loader.LoaderTest.test_loadModuleWithBothCustom}.
"""
from twisted.trial import unittest, runner
class Foo(unittest.SynchronousTestCase):
def test_foo(self):
pass
def test_suite():
ts = runner.TestSuite()
ts.name = "test_suite"
return ts
def testSuite():
ts = runner.TestSuite()
ts.name = "testSuite"
return ts

View file

@ -0,0 +1,104 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
# this module is a trivial class with doctests to test trial's doctest
# support.
from __future__ import division, absolute_import
class Counter(object):
"""a simple counter object for testing trial's doctest support
>>> c = Counter()
>>> c.value()
0
>>> c += 3
>>> c.value()
3
>>> c.incr()
>>> c.value() == 4
True
>>> c == 4
True
>>> c != 9
True
"""
_count = 0
def __init__(self, initialValue=0, maxval=None):
self._count = initialValue
self.maxval = maxval
def __iadd__(self, other):
"""add other to my value and return self
>>> c = Counter(100)
>>> c += 333
>>> c == 433
True
"""
if self.maxval is not None and ((self._count + other) > self.maxval):
raise ValueError, "sorry, counter got too big"
else:
self._count += other
return self
def __eq__(self, other):
"""equality operator, compare other to my value()
>>> c = Counter()
>>> c == 0
True
>>> c += 10
>>> c.incr()
>>> c == 10 # fail this test on purpose
True
"""
return self._count == other
def __ne__(self, other):
"""inequality operator
>>> c = Counter()
>>> c != 10
True
"""
return not self.__eq__(other)
def incr(self):
"""increment my value by 1
>>> from twisted.trial.test.mockdoctest import Counter
>>> c = Counter(10, 11)
>>> c.incr()
>>> c.value() == 11
True
>>> c.incr()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "twisted/trial/test/mockdoctest.py", line 51, in incr
self.__iadd__(1)
File "twisted/trial/test/mockdoctest.py", line 39, in __iadd__
raise ValueError, "sorry, counter got too big"
ValueError: sorry, counter got too big
"""
self.__iadd__(1)
def value(self):
"""return this counter's value
>>> c = Counter(555)
>>> c.value() == 555
True
"""
return self._count
def unexpectedException(self):
"""i will raise an unexpected exception...
... *CAUSE THAT'S THE KINDA GUY I AM*
>>> 1/0
"""

View file

@ -0,0 +1,7 @@
# -*- test-case-name: twisted.trial.test.moduleself -*-
from twisted.trial import unittest
class Foo(unittest.SynchronousTestCase):
def testFoo(self):
pass

View file

@ -0,0 +1,11 @@
# -*- test-case-name: twisted.trial.test.test_log -*-
# fodder for test_script, which parses files for emacs local variable
# declarations. This one is supposed to have:
# test-case-name: twisted.trial.test.test_log.
# in the first line
# The class declaration is irrelevant
class Foo(object):
pass

View file

@ -0,0 +1,6 @@
# fodder for test_script, which parses files for emacs local variable
# declarations. This one is supposed to have none.
# The class declaration is irrelevant
class Bar(object):
pass

View file

@ -0,0 +1,50 @@
# -*- test-case-name: twisted.trial.test.test_script -*-
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for handling of trial's --order option.
"""
from twisted.trial import unittest
class FooTest(unittest.TestCase):
"""
Used to make assertions about the order its tests will be run in.
"""
def test_first(self):
pass
def test_second(self):
pass
def test_third(self):
pass
def test_fourth(self):
pass
class BazTest(unittest.TestCase):
"""
Used to make assertions about the order the test cases in this module are
run in.
"""
def test_baz(self):
pass
class BarTest(unittest.TestCase):
"""
Used to make assertions about the order the test cases in this module are
run in.
"""
def test_bar(self):
pass

View file

@ -0,0 +1,181 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
#
"""
Classes and functions used by L{twisted.trial.test.test_util}
and L{twisted.trial.test.test_loader}.
"""
from __future__ import division, absolute_import
import sys, os
from twisted.trial import unittest
testModule = """
from twisted.trial import unittest
class FooTest(unittest.SynchronousTestCase):
def testFoo(self):
pass
"""
dosModule = testModule.replace('\n', '\r\n')
testSample = """
'''This module is used by test_loader to test the Trial test loading
functionality. Do NOT change the number of tests in this module.
Do NOT change the names the tests in this module.
'''
import unittest as pyunit
from twisted.trial import unittest
class FooTest(unittest.SynchronousTestCase):
def test_foo(self):
pass
def test_bar(self):
pass
class PyunitTest(pyunit.TestCase):
def test_foo(self):
pass
def test_bar(self):
pass
class NotATest(object):
def test_foo(self):
pass
class AlphabetTest(unittest.SynchronousTestCase):
def test_a(self):
pass
def test_b(self):
pass
def test_c(self):
pass
"""
testInheritanceSample = """
'''This module is used by test_loader to test the Trial test loading
functionality. Do NOT change the number of tests in this module.
Do NOT change the names the tests in this module.
'''
from twisted.trial import unittest
class X(object):
def test_foo(self):
pass
class A(unittest.SynchronousTestCase, X):
pass
class B(unittest.SynchronousTestCase, X):
pass
"""
class PackageTest(unittest.SynchronousTestCase):
files = [
('badpackage/__init__.py', 'frotz\n'),
('badpackage/test_module.py', ''),
('package2/__init__.py', ''),
('package2/test_module.py', 'import frotz\n'),
('package/__init__.py', ''),
('package/frotz.py', 'frotz\n'),
('package/test_bad_module.py',
'raise ZeroDivisionError("fake error")'),
('package/test_dos_module.py', dosModule),
('package/test_import_module.py', 'import frotz'),
('package/test_module.py', testModule),
('goodpackage/__init__.py', ''),
('goodpackage/test_sample.py', testSample),
('goodpackage/sub/__init__.py', ''),
('goodpackage/sub/test_sample.py', testSample),
('inheritancepackage/__init__.py', ''),
('inheritancepackage/test_x.py', testInheritanceSample),
]
def _toModuleName(self, filename):
name = os.path.splitext(filename)[0]
segs = name.split('/')
if segs[-1] == '__init__':
segs = segs[:-1]
return '.'.join(segs)
def getModules(self):
"""
Return matching module names for files listed in C{self.files}.
"""
return [self._toModuleName(filename) for (filename, code) in self.files]
def cleanUpModules(self):
modules = self.getModules()
modules.sort()
modules.reverse()
for module in modules:
try:
del sys.modules[module]
except KeyError:
pass
def createFiles(self, files, parentDir='.'):
for filename, contents in self.files:
filename = os.path.join(parentDir, filename)
self._createDirectory(filename)
fd = open(filename, 'w')
fd.write(contents)
fd.close()
def _createDirectory(self, filename):
directory = os.path.dirname(filename)
if not os.path.exists(directory):
os.makedirs(directory)
def setUp(self, parentDir=None):
if parentDir is None:
parentDir = self.mktemp()
self.parent = parentDir
self.createFiles(self.files, parentDir)
def tearDown(self):
self.cleanUpModules()
class SysPathManglingTest(PackageTest):
def setUp(self, parent=None):
self.oldPath = sys.path[:]
self.newPath = sys.path[:]
if parent is None:
parent = self.mktemp()
PackageTest.setUp(self, parent)
self.newPath.append(self.parent)
self.mangleSysPath(self.newPath)
def tearDown(self):
PackageTest.tearDown(self)
self.mangleSysPath(self.oldPath)
def mangleSysPath(self, pathVar):
sys.path[:] = pathVar

View file

@ -0,0 +1,108 @@
"""This module is used by test_loader to test the Trial test loading
functionality. Do NOT change the number of tests in this module. Do NOT change
the names the tests in this module.
"""
import unittest as pyunit
from twisted.trial import unittest
from twisted.python.util import mergeFunctionMetadata
class FooTest(unittest.SynchronousTestCase):
def test_foo(self):
pass
def test_bar(self):
pass
def badDecorator(fn):
"""
Decorate a function without preserving the name of the original function.
Always return a function with the same name.
"""
def nameCollision(*args, **kwargs):
return fn(*args, **kwargs)
return nameCollision
def goodDecorator(fn):
"""
Decorate a function and preserve the original name.
"""
def nameCollision(*args, **kwargs):
return fn(*args, **kwargs)
return mergeFunctionMetadata(fn, nameCollision)
class DecorationTest(unittest.SynchronousTestCase):
def test_badDecorator(self):
"""
This test method is decorated in a way that gives it a confusing name
that collides with another method.
"""
test_badDecorator = badDecorator(test_badDecorator)
def test_goodDecorator(self):
"""
This test method is decorated in a way that preserves its name.
"""
test_goodDecorator = goodDecorator(test_goodDecorator)
def renamedDecorator(self):
"""
This is secretly a test method and will be decorated and then renamed so
test discovery can find it.
"""
test_renamedDecorator = goodDecorator(renamedDecorator)
def nameCollision(self):
"""
This isn't a test, it's just here to collide with tests.
"""
class PyunitTest(pyunit.TestCase):
def test_foo(self):
pass
def test_bar(self):
pass
class NotATest(object):
def test_foo(self):
pass
class AlphabetTest(unittest.SynchronousTestCase):
def test_a(self):
pass
def test_b(self):
pass
def test_c(self):
pass

View file

@ -0,0 +1,14 @@
#!/usr/bin/env python
# -*- test-case-name: twisted.trial.test.test_log,twisted.trial.test.test_class -*-
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
# fodder for test_script, which parses files for emacs local variable
# declarations. This one is supposed to have:
# test-case-name: twisted.trial.test.test_log,twisted.trial.test.test_class
# in the second line
# The class declaration is irrelevant
class Foo(object):
pass

View file

@ -0,0 +1,270 @@
# -*- test-case-name: twisted.trial.test.test_tests -*-
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Definitions of test cases with various interesting behaviors, to be used by
L{twisted.trial.test.test_tests} and other test modules to exercise different
features of trial's test runner.
See the L{twisted.trial.test.test_tests} module docstring for details about how
this code is arranged.
"""
from __future__ import division, absolute_import
from twisted.trial.unittest import (
SynchronousTestCase, TestCase, SkipTest, FailTest)
class SkippingMixin(object):
def test_skip1(self):
raise SkipTest('skip1')
def test_skip2(self):
raise RuntimeError("I should not get raised")
test_skip2.skip = 'skip2'
def test_skip3(self):
self.fail('I should not fail')
test_skip3.skip = 'skip3'
class SynchronousSkipping(SkippingMixin, SynchronousTestCase):
pass
class AsynchronousSkipping(SkippingMixin, TestCase):
pass
class SkippingSetUpMixin(object):
def setUp(self):
raise SkipTest('skipSetUp')
def test_1(self):
pass
def test_2(self):
pass
class SynchronousSkippingSetUp(SkippingSetUpMixin, SynchronousTestCase):
pass
class AsynchronousSkippingSetUp(SkippingSetUpMixin, TestCase):
pass
class DeprecatedReasonlessSkipMixin(object):
def test_1(self):
raise SkipTest()
class SynchronousDeprecatedReasonlessSkip(
DeprecatedReasonlessSkipMixin, SynchronousTestCase):
pass
class AsynchronousDeprecatedReasonlessSkip(
DeprecatedReasonlessSkipMixin, TestCase):
pass
class SkippedClassMixin(object):
skip = 'class'
def setUp(self):
self.__class__._setUpRan = True
def test_skip1(self):
raise SkipTest('skip1')
def test_skip2(self):
raise RuntimeError("Ought to skip me")
test_skip2.skip = 'skip2'
def test_skip3(self):
pass
def test_skip4(self):
raise RuntimeError("Skip me too")
class SynchronousSkippedClass(SkippedClassMixin, SynchronousTestCase):
pass
class AsynchronousSkippedClass(SkippedClassMixin, TestCase):
pass
class TodoMixin(object):
def test_todo1(self):
self.fail("deliberate failure")
test_todo1.todo = "todo1"
def test_todo2(self):
raise RuntimeError("deliberate error")
test_todo2.todo = "todo2"
def test_todo3(self):
"""unexpected success"""
test_todo3.todo = 'todo3'
class SynchronousTodo(TodoMixin, SynchronousTestCase):
pass
class AsynchronousTodo(TodoMixin, TestCase):
pass
class SetUpTodoMixin(object):
def setUp(self):
raise RuntimeError("deliberate error")
def test_todo1(self):
pass
test_todo1.todo = "setUp todo1"
class SynchronousSetUpTodo(SetUpTodoMixin, SynchronousTestCase):
pass
class AsynchronousSetUpTodo(SetUpTodoMixin, TestCase):
pass
class TearDownTodoMixin(object):
def tearDown(self):
raise RuntimeError("deliberate error")
def test_todo1(self):
pass
test_todo1.todo = "tearDown todo1"
class SynchronousTearDownTodo(TearDownTodoMixin, SynchronousTestCase):
pass
class AsynchronousTearDownTodo(TearDownTodoMixin, TestCase):
pass
class TodoClassMixin(object):
todo = "class"
def test_todo1(self):
pass
test_todo1.todo = "method"
def test_todo2(self):
pass
def test_todo3(self):
self.fail("Deliberate Failure")
test_todo3.todo = "method"
def test_todo4(self):
self.fail("Deliberate Failure")
class SynchronousTodoClass(TodoClassMixin, SynchronousTestCase):
pass
class AsynchronousTodoClass(TodoClassMixin, TestCase):
pass
class StrictTodoMixin(object):
def test_todo1(self):
raise RuntimeError("expected failure")
test_todo1.todo = (RuntimeError, "todo1")
def test_todo2(self):
raise RuntimeError("expected failure")
test_todo2.todo = ((RuntimeError, OSError), "todo2")
def test_todo3(self):
raise RuntimeError("we had no idea!")
test_todo3.todo = (OSError, "todo3")
def test_todo4(self):
raise RuntimeError("we had no idea!")
test_todo4.todo = ((OSError, SyntaxError), "todo4")
def test_todo5(self):
self.fail("deliberate failure")
test_todo5.todo = (FailTest, "todo5")
def test_todo6(self):
self.fail("deliberate failure")
test_todo6.todo = (RuntimeError, "todo6")
def test_todo7(self):
pass
test_todo7.todo = (RuntimeError, "todo7")
class SynchronousStrictTodo(StrictTodoMixin, SynchronousTestCase):
pass
class AsynchronousStrictTodo(StrictTodoMixin, TestCase):
pass
class AddCleanupMixin(object):
def setUp(self):
self.log = ['setUp']
def brokenSetUp(self):
self.log = ['setUp']
raise RuntimeError("Deliberate failure")
def skippingSetUp(self):
self.log = ['setUp']
raise SkipTest("Don't do this")
def append(self, thing):
self.log.append(thing)
def tearDown(self):
self.log.append('tearDown')
def runTest(self):
self.log.append('runTest')
class SynchronousAddCleanup(AddCleanupMixin, SynchronousTestCase):
pass
class AsynchronousAddCleanup(AddCleanupMixin, TestCase):
pass

View file

@ -0,0 +1,115 @@
# -*- test-case-name: twisted.trial.test.test_tests -*-
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Test cases used to make sure that warning supression works at the module,
method, and class levels.
See the L{twisted.trial.test.test_tests} module docstring for details about how
this code is arranged.
"""
from __future__ import division, absolute_import
import warnings
from twisted.python.compat import _PY3
from twisted.trial import unittest, util
METHOD_WARNING_MSG = "method warning message"
CLASS_WARNING_MSG = "class warning message"
MODULE_WARNING_MSG = "module warning message"
class MethodWarning(Warning):
pass
class ClassWarning(Warning):
pass
class ModuleWarning(Warning):
pass
class EmitMixin:
def _emit(self):
warnings.warn(METHOD_WARNING_MSG, MethodWarning)
warnings.warn(CLASS_WARNING_MSG, ClassWarning)
warnings.warn(MODULE_WARNING_MSG, ModuleWarning)
class SuppressionMixin(EmitMixin):
suppress = [util.suppress(message=CLASS_WARNING_MSG)]
def testSuppressMethod(self):
self._emit()
testSuppressMethod.suppress = [util.suppress(message=METHOD_WARNING_MSG)]
def testSuppressClass(self):
self._emit()
def testOverrideSuppressClass(self):
self._emit()
testOverrideSuppressClass.suppress = []
class SetUpSuppressionMixin(object):
def setUp(self):
self._emit()
class TearDownSuppressionMixin(object):
def tearDown(self):
self._emit()
class TestSuppression2Mixin(EmitMixin):
def testSuppressModule(self):
self._emit()
suppress = [util.suppress(message=MODULE_WARNING_MSG)]
class SynchronousTestSuppression(SuppressionMixin, unittest.SynchronousTestCase):
pass
class SynchronousTestSetUpSuppression(SetUpSuppressionMixin, SynchronousTestSuppression):
pass
class SynchronousTestTearDownSuppression(TearDownSuppressionMixin, SynchronousTestSuppression):
pass
class SynchronousTestSuppression2(TestSuppression2Mixin, unittest.SynchronousTestCase):
pass
class AsynchronousTestSuppression(SuppressionMixin, unittest.TestCase):
pass
class AsynchronousTestSetUpSuppression(SetUpSuppressionMixin, AsynchronousTestSuppression):
pass
class AsynchronousTestTearDownSuppression(TearDownSuppressionMixin, AsynchronousTestSuppression):
pass
class AsynchronousTestSuppression2(TestSuppression2Mixin, unittest.TestCase):
pass

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,83 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for async assertions provided by C{twisted.trial.unittest.TestCase}.
"""
from __future__ import division, absolute_import
import unittest as pyunit
from twisted.python import failure
from twisted.internet import defer
from twisted.trial import unittest
class TestAsynchronousAssertions(unittest.TestCase):
"""
Tests for L{TestCase}'s asynchronous extensions to L{SynchronousTestCase}.
That is, assertFailure.
"""
def test_assertFailure(self):
d = defer.maybeDeferred(lambda: 1/0)
return self.assertFailure(d, ZeroDivisionError)
def test_assertFailure_wrongException(self):
d = defer.maybeDeferred(lambda: 1/0)
self.assertFailure(d, OverflowError)
d.addCallbacks(lambda x: self.fail('Should have failed'),
lambda x: x.trap(self.failureException))
return d
def test_assertFailure_noException(self):
d = defer.succeed(None)
self.assertFailure(d, ZeroDivisionError)
d.addCallbacks(lambda x: self.fail('Should have failed'),
lambda x: x.trap(self.failureException))
return d
def test_assertFailure_moreInfo(self):
"""
In the case of assertFailure failing, check that we get lots of
information about the exception that was raised.
"""
try:
1/0
except ZeroDivisionError:
f = failure.Failure()
d = defer.fail(f)
d = self.assertFailure(d, RuntimeError)
d.addErrback(self._checkInfo, f)
return d
def _checkInfo(self, assertionFailure, f):
assert assertionFailure.check(self.failureException)
output = assertionFailure.getErrorMessage()
self.assertIn(f.getErrorMessage(), output)
self.assertIn(f.getBriefTraceback(), output)
def test_assertFailure_masked(self):
"""
A single wrong assertFailure should fail the whole test.
"""
class ExampleFailure(Exception):
pass
class TC(unittest.TestCase):
failureException = ExampleFailure
def test_assertFailure(self):
d = defer.maybeDeferred(lambda: 1/0)
self.assertFailure(d, OverflowError)
self.assertFailure(d, ZeroDivisionError)
return d
test = TC('test_assertFailure')
result = pyunit.TestResult()
test.run(result)
self.assertEqual(1, len(result.failures))

View file

@ -0,0 +1,236 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for returning Deferreds from a TestCase.
"""
from __future__ import division, absolute_import
import unittest as pyunit
from twisted.internet import defer
from twisted.trial import unittest, reporter
from twisted.trial import util
from twisted.trial.test import detests
class TestSetUp(unittest.TestCase):
def _loadSuite(self, klass):
loader = pyunit.TestLoader()
r = reporter.TestResult()
s = loader.loadTestsFromTestCase(klass)
return r, s
def test_success(self):
result, suite = self._loadSuite(detests.DeferredSetUpOK)
suite(result)
self.failUnless(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
def test_fail(self):
self.failIf(detests.DeferredSetUpFail.testCalled)
result, suite = self._loadSuite(detests.DeferredSetUpFail)
suite(result)
self.failIf(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self.assertEqual(len(result.failures), 0)
self.assertEqual(len(result.errors), 1)
self.failIf(detests.DeferredSetUpFail.testCalled)
def test_callbackFail(self):
self.failIf(detests.DeferredSetUpCallbackFail.testCalled)
result, suite = self._loadSuite(detests.DeferredSetUpCallbackFail)
suite(result)
self.failIf(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self.assertEqual(len(result.failures), 0)
self.assertEqual(len(result.errors), 1)
self.failIf(detests.DeferredSetUpCallbackFail.testCalled)
def test_error(self):
self.failIf(detests.DeferredSetUpError.testCalled)
result, suite = self._loadSuite(detests.DeferredSetUpError)
suite(result)
self.failIf(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self.assertEqual(len(result.failures), 0)
self.assertEqual(len(result.errors), 1)
self.failIf(detests.DeferredSetUpError.testCalled)
def test_skip(self):
self.failIf(detests.DeferredSetUpSkip.testCalled)
result, suite = self._loadSuite(detests.DeferredSetUpSkip)
suite(result)
self.failUnless(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self.assertEqual(len(result.failures), 0)
self.assertEqual(len(result.errors), 0)
self.assertEqual(len(result.skips), 1)
self.failIf(detests.DeferredSetUpSkip.testCalled)
class TestNeverFire(unittest.TestCase):
def setUp(self):
self._oldTimeout = util.DEFAULT_TIMEOUT_DURATION
util.DEFAULT_TIMEOUT_DURATION = 0.1
def tearDown(self):
util.DEFAULT_TIMEOUT_DURATION = self._oldTimeout
def _loadSuite(self, klass):
loader = pyunit.TestLoader()
r = reporter.TestResult()
s = loader.loadTestsFromTestCase(klass)
return r, s
def test_setUp(self):
self.failIf(detests.DeferredSetUpNeverFire.testCalled)
result, suite = self._loadSuite(detests.DeferredSetUpNeverFire)
suite(result)
self.failIf(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self.assertEqual(len(result.failures), 0)
self.assertEqual(len(result.errors), 1)
self.failIf(detests.DeferredSetUpNeverFire.testCalled)
self.failUnless(result.errors[0][1].check(defer.TimeoutError))
class TestTester(unittest.TestCase):
def getTest(self, name):
raise NotImplementedError("must override me")
def runTest(self, name):
result = reporter.TestResult()
self.getTest(name).run(result)
return result
class TestDeferred(TestTester):
def getTest(self, name):
return detests.DeferredTests(name)
def test_pass(self):
result = self.runTest('test_pass')
self.failUnless(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
def test_passGenerated(self):
result = self.runTest('test_passGenerated')
self.failUnless(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self.failUnless(detests.DeferredTests.touched)
def test_fail(self):
result = self.runTest('test_fail')
self.failIf(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self.assertEqual(len(result.failures), 1)
def test_failureInCallback(self):
result = self.runTest('test_failureInCallback')
self.failIf(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self.assertEqual(len(result.failures), 1)
def test_errorInCallback(self):
result = self.runTest('test_errorInCallback')
self.failIf(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self.assertEqual(len(result.errors), 1)
def test_skip(self):
result = self.runTest('test_skip')
self.failUnless(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self.assertEqual(len(result.skips), 1)
self.failIf(detests.DeferredTests.touched)
def test_todo(self):
result = self.runTest('test_expectedFailure')
self.failUnless(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self.assertEqual(len(result.errors), 0)
self.assertEqual(len(result.failures), 0)
self.assertEqual(len(result.expectedFailures), 1)
def test_thread(self):
result = self.runTest('test_thread')
self.assertEqual(result.testsRun, 1)
self.failUnless(result.wasSuccessful(), result.errors)
class TestTimeout(TestTester):
def getTest(self, name):
return detests.TimeoutTests(name)
def _wasTimeout(self, error):
self.assertEqual(error.check(defer.TimeoutError),
defer.TimeoutError)
def test_pass(self):
result = self.runTest('test_pass')
self.failUnless(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
def test_passDefault(self):
result = self.runTest('test_passDefault')
self.failUnless(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
def test_timeout(self):
result = self.runTest('test_timeout')
self.failIf(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self.assertEqual(len(result.errors), 1)
self._wasTimeout(result.errors[0][1])
def test_timeoutZero(self):
result = self.runTest('test_timeoutZero')
self.failIf(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self.assertEqual(len(result.errors), 1)
self._wasTimeout(result.errors[0][1])
def test_skip(self):
result = self.runTest('test_skip')
self.failUnless(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self.assertEqual(len(result.skips), 1)
def test_todo(self):
result = self.runTest('test_expectedFailure')
self.failUnless(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self.assertEqual(len(result.expectedFailures), 1)
self._wasTimeout(result.expectedFailures[0][1])
def test_errorPropagation(self):
result = self.runTest('test_errorPropagation')
self.failIf(result.wasSuccessful())
self.assertEqual(result.testsRun, 1)
self._wasTimeout(detests.TimeoutTests.timedOut)
def test_classTimeout(self):
loader = pyunit.TestLoader()
suite = loader.loadTestsFromTestCase(detests.TestClassTimeoutAttribute)
result = reporter.TestResult()
suite.run(result)
self.assertEqual(len(result.errors), 1)
self._wasTimeout(result.errors[0][1])
def test_callbackReturnsNonCallingDeferred(self):
#hacky timeout
# raises KeyboardInterrupt because Trial sucks
from twisted.internet import reactor
call = reactor.callLater(2, reactor.crash)
result = self.runTest('test_calledButNeverCallback')
if call.active():
call.cancel()
self.failIf(result.wasSuccessful())
self._wasTimeout(result.errors[0][1])
# The test loader erroneously attempts to run this:
del TestTester

View file

@ -0,0 +1,62 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Test Twisted's doctest support.
"""
from twisted.trial import itrial, runner, unittest, reporter
from twisted.trial.test import mockdoctest
class TestRunners(unittest.SynchronousTestCase):
"""
Tests for Twisted's doctest support.
"""
def test_id(self):
"""
Check that the id() of the doctests' case object contains the FQPN of
the actual tests.
"""
loader = runner.TestLoader()
suite = loader.loadDoctests(mockdoctest)
idPrefix = 'twisted.trial.test.mockdoctest.Counter'
for test in suite._tests:
self.assertIn(idPrefix, itrial.ITestCase(test).id())
def test_basicTrialIntegration(self):
"""
L{loadDoctests} loads all of the doctests in the given module.
"""
loader = runner.TestLoader()
suite = loader.loadDoctests(mockdoctest)
self.assertEqual(7, suite.countTestCases())
def _testRun(self, suite):
"""
Run C{suite} and check the result.
"""
result = reporter.TestResult()
suite.run(result)
self.assertEqual(5, result.successes)
self.assertEqual(2, len(result.failures))
def test_expectedResults(self, count=1):
"""
Trial can correctly run doctests with its xUnit test APIs.
"""
suite = runner.TestLoader().loadDoctests(mockdoctest)
self._testRun(suite)
def test_repeatable(self):
"""
Doctests should be runnable repeatably.
"""
suite = runner.TestLoader().loadDoctests(mockdoctest)
self._testRun(suite)
self._testRun(suite)

View file

@ -0,0 +1,119 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for interrupting tests with Control-C.
"""
import StringIO
from twisted.trial import unittest
from twisted.trial import reporter, runner
class TrialTest(unittest.SynchronousTestCase):
def setUp(self):
self.output = StringIO.StringIO()
self.reporter = reporter.TestResult()
self.loader = runner.TestLoader()
class TestInterruptInTest(TrialTest):
class InterruptedTest(unittest.TestCase):
def test_02_raiseInterrupt(self):
raise KeyboardInterrupt
def test_01_doNothing(self):
pass
def test_03_doNothing(self):
TestInterruptInTest.test_03_doNothing_run = True
def setUp(self):
super(TestInterruptInTest, self).setUp()
self.suite = self.loader.loadClass(TestInterruptInTest.InterruptedTest)
TestInterruptInTest.test_03_doNothing_run = None
def test_setUpOK(self):
self.assertEqual(3, self.suite.countTestCases())
self.assertEqual(0, self.reporter.testsRun)
self.failIf(self.reporter.shouldStop)
def test_interruptInTest(self):
runner.TrialSuite([self.suite]).run(self.reporter)
self.failUnless(self.reporter.shouldStop)
self.assertEqual(2, self.reporter.testsRun)
self.failIf(TestInterruptInTest.test_03_doNothing_run,
"test_03_doNothing ran.")
class TestInterruptInSetUp(TrialTest):
testsRun = 0
class InterruptedTest(unittest.TestCase):
def setUp(self):
if TestInterruptInSetUp.testsRun > 0:
raise KeyboardInterrupt
def test_01(self):
TestInterruptInSetUp.testsRun += 1
def test_02(self):
TestInterruptInSetUp.testsRun += 1
TestInterruptInSetUp.test_02_run = True
def setUp(self):
super(TestInterruptInSetUp, self).setUp()
self.suite = self.loader.loadClass(
TestInterruptInSetUp.InterruptedTest)
TestInterruptInSetUp.test_02_run = False
TestInterruptInSetUp.testsRun = 0
def test_setUpOK(self):
self.assertEqual(0, TestInterruptInSetUp.testsRun)
self.assertEqual(2, self.suite.countTestCases())
self.assertEqual(0, self.reporter.testsRun)
self.failIf(self.reporter.shouldStop)
def test_interruptInSetUp(self):
runner.TrialSuite([self.suite]).run(self.reporter)
self.failUnless(self.reporter.shouldStop)
self.assertEqual(2, self.reporter.testsRun)
self.failIf(TestInterruptInSetUp.test_02_run,
"test_02 ran")
class TestInterruptInTearDown(TrialTest):
testsRun = 0
class InterruptedTest(unittest.TestCase):
def tearDown(self):
if TestInterruptInTearDown.testsRun > 0:
raise KeyboardInterrupt
def test_01(self):
TestInterruptInTearDown.testsRun += 1
def test_02(self):
TestInterruptInTearDown.testsRun += 1
TestInterruptInTearDown.test_02_run = True
def setUp(self):
super(TestInterruptInTearDown, self).setUp()
self.suite = self.loader.loadClass(
TestInterruptInTearDown.InterruptedTest)
TestInterruptInTearDown.testsRun = 0
TestInterruptInTearDown.test_02_run = False
def test_setUpOK(self):
self.assertEqual(0, TestInterruptInTearDown.testsRun)
self.assertEqual(2, self.suite.countTestCases())
self.assertEqual(0, self.reporter.testsRun)
self.failIf(self.reporter.shouldStop)
def test_interruptInTearDown(self):
runner.TrialSuite([self.suite]).run(self.reporter)
self.assertEqual(1, self.reporter.testsRun)
self.failUnless(self.reporter.shouldStop)
self.failIf(TestInterruptInTearDown.test_02_run,
"test_02 ran")

View file

@ -0,0 +1,656 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for loading tests by name.
"""
import os
import sys
import unittest as pyunit
from hashlib import md5
from twisted.python import util, filepath
from twisted.trial.test import packages
from twisted.trial import runner, reporter, unittest
from twisted.trial.itrial import ITestCase
from twisted.python.modules import getModule
def testNames(tests):
"""
Return the id of each test within the given test suite or case.
"""
names = []
for test in unittest._iterateTests(tests):
names.append(test.id())
return names
class FinderTest(packages.PackageTest):
"""
Tests for L{runner.TestLoader.findByName}.
"""
def setUp(self):
packages.PackageTest.setUp(self)
self.loader = runner.TestLoader()
def tearDown(self):
packages.PackageTest.tearDown(self)
def test_findPackage(self):
sample1 = self.loader.findByName('twisted')
import twisted as sample2
self.assertEqual(sample1, sample2)
def test_findModule(self):
sample1 = self.loader.findByName('twisted.trial.test.sample')
import sample as sample2
self.assertEqual(sample1, sample2)
def test_findFile(self):
path = util.sibpath(__file__, 'sample.py')
sample1 = self.loader.findByName(path)
import sample as sample2
self.assertEqual(sample1, sample2)
def test_findObject(self):
sample1 = self.loader.findByName('twisted.trial.test.sample.FooTest')
import sample
self.assertEqual(sample.FooTest, sample1)
def test_findNonModule(self):
self.failUnlessRaises(AttributeError,
self.loader.findByName,
'twisted.trial.test.nonexistent')
def test_findNonPackage(self):
self.failUnlessRaises(ValueError,
self.loader.findByName,
'nonextant')
def test_findNonFile(self):
path = util.sibpath(__file__, 'nonexistent.py')
self.failUnlessRaises(ValueError, self.loader.findByName, path)
class FileTest(packages.SysPathManglingTest):
"""
Tests for L{runner.filenameToModule}.
"""
def test_notFile(self):
"""
L{runner.filenameToModule} raises a C{ValueError} when a non-existing
file is passed.
"""
err = self.assertRaises(ValueError, runner.filenameToModule, 'it')
self.assertEqual(str(err), "'it' doesn't exist")
def test_moduleInPath(self):
"""
If the file in question is a module on the Python path, then it should
properly import and return that module.
"""
sample1 = runner.filenameToModule(util.sibpath(__file__, 'sample.py'))
import sample as sample2
self.assertEqual(sample2, sample1)
def test_moduleNotInPath(self):
"""
If passed the path to a file containing the implementation of a
module within a package which is not on the import path,
L{runner.filenameToModule} returns a module object loosely
resembling the module defined by that file anyway.
"""
# "test_sample" isn't actually the name of this module. However,
# filenameToModule can't seem to figure that out. So clean up this
# mis-named module. It would be better if this weren't necessary
# and filenameToModule either didn't exist or added a correctly
# named module to sys.modules.
self.addCleanup(sys.modules.pop, 'test_sample', None)
self.mangleSysPath(self.oldPath)
sample1 = runner.filenameToModule(
os.path.join(self.parent, 'goodpackage', 'test_sample.py'))
self.mangleSysPath(self.newPath)
from goodpackage import test_sample as sample2
self.assertEqual(os.path.splitext(sample2.__file__)[0],
os.path.splitext(sample1.__file__)[0])
def test_packageInPath(self):
"""
If the file in question is a package on the Python path, then it should
properly import and return that package.
"""
package1 = runner.filenameToModule(os.path.join(self.parent,
'goodpackage'))
import goodpackage
self.assertEqual(goodpackage, package1)
def test_packageNotInPath(self):
"""
If passed the path to a directory which represents a package which
is not on the import path, L{runner.filenameToModule} returns a
module object loosely resembling the package defined by that
directory anyway.
"""
# "__init__" isn't actually the name of the package! However,
# filenameToModule is pretty stupid and decides that is its name
# after all. Make sure it gets cleaned up. See the comment in
# test_moduleNotInPath for possible courses of action related to
# this.
self.addCleanup(sys.modules.pop, "__init__")
self.mangleSysPath(self.oldPath)
package1 = runner.filenameToModule(
os.path.join(self.parent, 'goodpackage'))
self.mangleSysPath(self.newPath)
import goodpackage
self.assertEqual(os.path.splitext(goodpackage.__file__)[0],
os.path.splitext(package1.__file__)[0])
def test_directoryNotPackage(self):
"""
L{runner.filenameToModule} raises a C{ValueError} when the name of an
empty directory is passed that isn't considered a valid Python package
because it doesn't contain a C{__init__.py} file.
"""
emptyDir = filepath.FilePath(self.parent).child("emptyDirectory")
emptyDir.createDirectory()
err = self.assertRaises(ValueError, runner.filenameToModule,
emptyDir.path)
self.assertEqual(str(err), "%r is not a package directory" % (
emptyDir.path,))
def test_filenameNotPython(self):
"""
L{runner.filenameToModule} raises a C{SyntaxError} when a non-Python
file is passed.
"""
filename = filepath.FilePath(self.parent).child('notpython')
filename.setContent("This isn't python")
self.failUnlessRaises(
SyntaxError, runner.filenameToModule, filename.path)
def test_filenameMatchesPackage(self):
"""
The C{__file__} attribute of the module should match the package name.
"""
filename = filepath.FilePath(self.parent).child('goodpackage.py')
filename.setContent(packages.testModule)
try:
module = runner.filenameToModule(filename.path)
self.assertEqual(filename.path, module.__file__)
finally:
filename.remove()
def test_directory(self):
"""
Test loader against a filesystem directory containing an empty
C{__init__.py} file. It should handle 'path' and 'path/' the same way.
"""
goodDir = filepath.FilePath(self.parent).child('goodDirectory')
goodDir.createDirectory()
goodDir.child('__init__.py').setContent('')
try:
module = runner.filenameToModule(goodDir.path)
self.assert_(module.__name__.endswith('goodDirectory'))
module = runner.filenameToModule(goodDir.path + os.path.sep)
self.assert_(module.__name__.endswith('goodDirectory'))
finally:
goodDir.remove()
class LoaderTest(packages.SysPathManglingTest):
"""
Tests for L{trial.TestLoader}.
"""
def setUp(self):
self.loader = runner.TestLoader()
packages.SysPathManglingTest.setUp(self)
def test_sortCases(self):
import sample
suite = self.loader.loadClass(sample.AlphabetTest)
self.assertEqual(['test_a', 'test_b', 'test_c'],
[test._testMethodName for test in suite._tests])
newOrder = ['test_b', 'test_c', 'test_a']
sortDict = dict(zip(newOrder, range(3)))
self.loader.sorter = lambda x : sortDict.get(x.shortDescription(), -1)
suite = self.loader.loadClass(sample.AlphabetTest)
self.assertEqual(newOrder,
[test._testMethodName for test in suite._tests])
def test_loadMethod(self):
import sample
suite = self.loader.loadMethod(sample.FooTest.test_foo)
self.assertEqual(1, suite.countTestCases())
self.assertEqual('test_foo', suite._testMethodName)
def test_loadFailingMethod(self):
# test added for issue1353
import erroneous
suite = self.loader.loadMethod(erroneous.TestRegularFail.test_fail)
result = reporter.TestResult()
suite.run(result)
self.assertEqual(result.testsRun, 1)
self.assertEqual(len(result.failures), 1)
def test_loadNonMethod(self):
import sample
self.failUnlessRaises(TypeError, self.loader.loadMethod, sample)
self.failUnlessRaises(TypeError,
self.loader.loadMethod, sample.FooTest)
self.failUnlessRaises(TypeError, self.loader.loadMethod, "string")
self.failUnlessRaises(TypeError,
self.loader.loadMethod, ('foo', 'bar'))
def test_loadBadDecorator(self):
"""
A decorated test method for which the decorator has failed to set the
method's __name__ correctly is loaded and its name in the class scope
discovered.
"""
import sample
suite = self.loader.loadMethod(sample.DecorationTest.test_badDecorator)
self.assertEqual(1, suite.countTestCases())
self.assertEqual('test_badDecorator', suite._testMethodName)
def test_loadGoodDecorator(self):
"""
A decorated test method for which the decorator has set the method's
__name__ correctly is loaded and the only name by which it goes is used.
"""
import sample
suite = self.loader.loadMethod(
sample.DecorationTest.test_goodDecorator)
self.assertEqual(1, suite.countTestCases())
self.assertEqual('test_goodDecorator', suite._testMethodName)
def test_loadRenamedDecorator(self):
"""
Load a decorated method which has been copied to a new name inside the
class. Thus its __name__ and its key in the class's __dict__ no
longer match.
"""
import sample
suite = self.loader.loadMethod(
sample.DecorationTest.test_renamedDecorator)
self.assertEqual(1, suite.countTestCases())
self.assertEqual('test_renamedDecorator', suite._testMethodName)
def test_loadClass(self):
import sample
suite = self.loader.loadClass(sample.FooTest)
self.assertEqual(2, suite.countTestCases())
self.assertEqual(['test_bar', 'test_foo'],
[test._testMethodName for test in suite._tests])
def test_loadNonClass(self):
import sample
self.failUnlessRaises(TypeError, self.loader.loadClass, sample)
self.failUnlessRaises(TypeError,
self.loader.loadClass, sample.FooTest.test_foo)
self.failUnlessRaises(TypeError, self.loader.loadClass, "string")
self.failUnlessRaises(TypeError,
self.loader.loadClass, ('foo', 'bar'))
def test_loadNonTestCase(self):
import sample
self.failUnlessRaises(ValueError, self.loader.loadClass,
sample.NotATest)
def test_loadModule(self):
import sample
suite = self.loader.loadModule(sample)
self.assertEqual(10, suite.countTestCases())
def test_loadNonModule(self):
import sample
self.failUnlessRaises(TypeError,
self.loader.loadModule, sample.FooTest)
self.failUnlessRaises(TypeError,
self.loader.loadModule, sample.FooTest.test_foo)
self.failUnlessRaises(TypeError, self.loader.loadModule, "string")
self.failUnlessRaises(TypeError,
self.loader.loadModule, ('foo', 'bar'))
def test_loadPackage(self):
import goodpackage
suite = self.loader.loadPackage(goodpackage)
self.assertEqual(7, suite.countTestCases())
def test_loadNonPackage(self):
import sample
self.failUnlessRaises(TypeError,
self.loader.loadPackage, sample.FooTest)
self.failUnlessRaises(TypeError,
self.loader.loadPackage, sample.FooTest.test_foo)
self.failUnlessRaises(TypeError, self.loader.loadPackage, "string")
self.failUnlessRaises(TypeError,
self.loader.loadPackage, ('foo', 'bar'))
def test_loadModuleAsPackage(self):
import sample
## XXX -- should this instead raise a ValueError? -- jml
self.failUnlessRaises(TypeError, self.loader.loadPackage, sample)
def test_loadPackageRecursive(self):
import goodpackage
suite = self.loader.loadPackage(goodpackage, recurse=True)
self.assertEqual(14, suite.countTestCases())
def test_loadAnythingOnModule(self):
import sample
suite = self.loader.loadAnything(sample)
self.assertEqual(sample.__name__,
suite._tests[0]._tests[0].__class__.__module__)
def test_loadAnythingOnClass(self):
import sample
suite = self.loader.loadAnything(sample.FooTest)
self.assertEqual(2, suite.countTestCases())
def test_loadAnythingOnMethod(self):
import sample
suite = self.loader.loadAnything(sample.FooTest.test_foo)
self.assertEqual(1, suite.countTestCases())
def test_loadAnythingOnPackage(self):
import goodpackage
suite = self.loader.loadAnything(goodpackage)
self.failUnless(isinstance(suite, self.loader.suiteFactory))
self.assertEqual(7, suite.countTestCases())
def test_loadAnythingOnPackageRecursive(self):
import goodpackage
suite = self.loader.loadAnything(goodpackage, recurse=True)
self.failUnless(isinstance(suite, self.loader.suiteFactory))
self.assertEqual(14, suite.countTestCases())
def test_loadAnythingOnString(self):
# the important thing about this test is not the string-iness
# but the non-handledness.
self.failUnlessRaises(TypeError,
self.loader.loadAnything, "goodpackage")
def test_importErrors(self):
import package
suite = self.loader.loadPackage(package, recurse=True)
result = reporter.Reporter()
suite.run(result)
self.assertEqual(False, result.wasSuccessful())
self.assertEqual(2, len(result.errors))
errors = [test.id() for test, error in result.errors]
errors.sort()
self.assertEqual(errors, ['package.test_bad_module',
'package.test_import_module'])
def test_differentInstances(self):
"""
L{TestLoader.loadClass} returns a suite with each test method
represented by a different instances of the L{TestCase} they are
defined on.
"""
class DistinctInstances(pyunit.TestCase):
def test_1(self):
self.first = 'test1Run'
def test_2(self):
self.assertFalse(hasattr(self, 'first'))
suite = self.loader.loadClass(DistinctInstances)
result = reporter.Reporter()
suite.run(result)
self.assertTrue(result.wasSuccessful())
def test_loadModuleWith_test_suite(self):
"""
Check that C{test_suite} is used when present and other L{TestCase}s are
not included.
"""
from twisted.trial.test import mockcustomsuite
suite = self.loader.loadModule(mockcustomsuite)
self.assertEqual(0, suite.countTestCases())
self.assertEqual("MyCustomSuite", getattr(suite, 'name', None))
def test_loadModuleWith_testSuite(self):
"""
Check that C{testSuite} is used when present and other L{TestCase}s are
not included.
"""
from twisted.trial.test import mockcustomsuite2
suite = self.loader.loadModule(mockcustomsuite2)
self.assertEqual(0, suite.countTestCases())
self.assertEqual("MyCustomSuite", getattr(suite, 'name', None))
def test_loadModuleWithBothCustom(self):
"""
Check that if C{testSuite} and C{test_suite} are both present in a
module then C{testSuite} gets priority.
"""
from twisted.trial.test import mockcustomsuite3
suite = self.loader.loadModule(mockcustomsuite3)
self.assertEqual('testSuite', getattr(suite, 'name', None))
def test_customLoadRaisesAttributeError(self):
"""
Make sure that any C{AttributeError}s raised by C{testSuite} are not
swallowed by L{TestLoader}.
"""
def testSuite():
raise AttributeError('should be reraised')
from twisted.trial.test import mockcustomsuite2
mockcustomsuite2.testSuite, original = (testSuite,
mockcustomsuite2.testSuite)
try:
self.assertRaises(AttributeError, self.loader.loadModule,
mockcustomsuite2)
finally:
mockcustomsuite2.testSuite = original
# XXX - duplicated and modified from test_script
def assertSuitesEqual(self, test1, test2):
names1 = testNames(test1)
names2 = testNames(test2)
names1.sort()
names2.sort()
self.assertEqual(names1, names2)
def test_loadByNamesDuplicate(self):
"""
Check that loadByNames ignores duplicate names
"""
module = 'twisted.trial.test.test_log'
suite1 = self.loader.loadByNames([module, module], True)
suite2 = self.loader.loadByName(module, True)
self.assertSuitesEqual(suite1, suite2)
def test_loadByNamesPreservesOrder(self):
"""
L{TestLoader.loadByNames} preserves the order of tests provided to it.
"""
modules = [
"inheritancepackage.test_x.A.test_foo",
"twisted.trial.test.sample",
"goodpackage",
"twisted.trial.test.test_log",
"twisted.trial.test.sample.FooTest",
"package.test_module"]
suite1 = self.loader.loadByNames(modules)
suite2 = runner.TestSuite(map(self.loader.loadByName, modules))
self.assertEqual(testNames(suite1), testNames(suite2))
def test_loadDifferentNames(self):
"""
Check that loadByNames loads all the names that it is given
"""
modules = ['goodpackage', 'package.test_module']
suite1 = self.loader.loadByNames(modules)
suite2 = runner.TestSuite(map(self.loader.loadByName, modules))
self.assertSuitesEqual(suite1, suite2)
def test_loadInheritedMethods(self):
"""
Check that test methods names which are inherited from are all
loaded rather than just one.
"""
methods = ['inheritancepackage.test_x.A.test_foo',
'inheritancepackage.test_x.B.test_foo']
suite1 = self.loader.loadByNames(methods)
suite2 = runner.TestSuite(map(self.loader.loadByName, methods))
self.assertSuitesEqual(suite1, suite2)
class ZipLoadingTest(LoaderTest):
def setUp(self):
from twisted.python.test.test_zippath import zipit
LoaderTest.setUp(self)
zipit(self.parent, self.parent+'.zip')
self.parent += '.zip'
self.mangleSysPath(self.oldPath+[self.parent])
class PackageOrderingTest(packages.SysPathManglingTest):
def setUp(self):
self.loader = runner.TestLoader()
self.topDir = self.mktemp()
parent = os.path.join(self.topDir, "uberpackage")
os.makedirs(parent)
open(os.path.join(parent, "__init__.py"), "wb").close()
packages.SysPathManglingTest.setUp(self, parent)
self.mangleSysPath(self.oldPath + [self.topDir])
def _trialSortAlgorithm(self, sorter):
"""
Right now, halfway by accident, trial sorts like this:
1. all modules are grouped together in one list and sorted.
2. within each module, the classes are grouped together in one list
and sorted.
3. finally within each class, each test method is grouped together
in a list and sorted.
This attempts to return a sorted list of testable thingies following
those rules, so that we can compare the behavior of loadPackage.
The things that show as 'cases' are errors from modules which failed to
import, and test methods. Let's gather all those together.
"""
pkg = getModule('uberpackage')
testModules = []
for testModule in pkg.walkModules():
if testModule.name.split(".")[-1].startswith("test_"):
testModules.append(testModule)
sortedModules = sorted(testModules, key=sorter) # ONE
for modinfo in sortedModules:
# Now let's find all the classes.
module = modinfo.load(None)
if module is None:
yield modinfo
else:
testClasses = []
for attrib in modinfo.iterAttributes():
if runner.isTestCase(attrib.load()):
testClasses.append(attrib)
sortedClasses = sorted(testClasses, key=sorter) # TWO
for clsinfo in sortedClasses:
testMethods = []
for attr in clsinfo.iterAttributes():
if attr.name.split(".")[-1].startswith('test'):
testMethods.append(attr)
sortedMethods = sorted(testMethods, key=sorter) # THREE
for methinfo in sortedMethods:
yield methinfo
def loadSortedPackages(self, sorter=runner.name):
"""
Verify that packages are loaded in the correct order.
"""
import uberpackage
self.loader.sorter = sorter
suite = self.loader.loadPackage(uberpackage, recurse=True)
# XXX: Work around strange, unexplained Zope crap.
# jml, 2007-11-15.
suite = unittest.decorate(suite, ITestCase)
resultingTests = list(unittest._iterateTests(suite))
manifest = list(self._trialSortAlgorithm(sorter))
for number, (manifestTest, actualTest) in enumerate(
zip(manifest, resultingTests)):
self.assertEqual(
manifestTest.name, actualTest.id(),
"#%d: %s != %s" %
(number, manifestTest.name, actualTest.id()))
self.assertEqual(len(manifest), len(resultingTests))
def test_sortPackagesDefaultOrder(self):
self.loadSortedPackages()
def test_sortPackagesSillyOrder(self):
def sillySorter(s):
# This has to work on fully-qualified class names and class
# objects, which is silly, but it's the "spec", such as it is.
# if isinstance(s, type) or isinstance(s, types.ClassType):
# return s.__module__+'.'+s.__name__
n = runner.name(s)
d = md5(n).hexdigest()
return d
self.loadSortedPackages(sillySorter)

View file

@ -0,0 +1,235 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Test the interaction between trial and errors logged during test run.
"""
from __future__ import division
import time
from twisted.internet import reactor, task
from twisted.python import failure, log
from twisted.trial import unittest, reporter
def makeFailure():
"""
Return a new, realistic failure.
"""
try:
1/0
except ZeroDivisionError:
f = failure.Failure()
return f
class Mask(object):
"""
Hide C{MockTest}s from Trial's automatic test finder.
"""
class FailureLoggingMixin(object):
def test_silent(self):
"""
Don't log any errors.
"""
def test_single(self):
"""
Log a single error.
"""
log.err(makeFailure())
def test_double(self):
"""
Log two errors.
"""
log.err(makeFailure())
log.err(makeFailure())
class SynchronousFailureLogging(FailureLoggingMixin, unittest.SynchronousTestCase):
pass
class AsynchronousFailureLogging(FailureLoggingMixin, unittest.TestCase):
def test_inCallback(self):
"""
Log an error in an asynchronous callback.
"""
return task.deferLater(reactor, 0, lambda: log.err(makeFailure()))
class TestObserver(unittest.SynchronousTestCase):
"""
Tests for L{unittest._LogObserver}, a helper for the implementation of
L{SynchronousTestCase.flushLoggedErrors}.
"""
def setUp(self):
self.result = reporter.TestResult()
self.observer = unittest._LogObserver()
def test_msg(self):
"""
Test that a standard log message doesn't go anywhere near the result.
"""
self.observer.gotEvent({'message': ('some message',),
'time': time.time(), 'isError': 0,
'system': '-'})
self.assertEqual(self.observer.getErrors(), [])
def test_error(self):
"""
Test that an observed error gets added to the result
"""
f = makeFailure()
self.observer.gotEvent({'message': (),
'time': time.time(), 'isError': 1,
'system': '-', 'failure': f,
'why': None})
self.assertEqual(self.observer.getErrors(), [f])
def test_flush(self):
"""
Check that flushing the observer with no args removes all errors.
"""
self.test_error()
flushed = self.observer.flushErrors()
self.assertEqual(self.observer.getErrors(), [])
self.assertEqual(len(flushed), 1)
self.assertTrue(flushed[0].check(ZeroDivisionError))
def _makeRuntimeFailure(self):
return failure.Failure(RuntimeError('test error'))
def test_flushByType(self):
"""
Check that flushing the observer remove all failures of the given type.
"""
self.test_error() # log a ZeroDivisionError to the observer
f = self._makeRuntimeFailure()
self.observer.gotEvent(dict(message=(), time=time.time(), isError=1,
system='-', failure=f, why=None))
flushed = self.observer.flushErrors(ZeroDivisionError)
self.assertEqual(self.observer.getErrors(), [f])
self.assertEqual(len(flushed), 1)
self.assertTrue(flushed[0].check(ZeroDivisionError))
def test_ignoreErrors(self):
"""
Check that C{_ignoreErrors} actually causes errors to be ignored.
"""
self.observer._ignoreErrors(ZeroDivisionError)
f = makeFailure()
self.observer.gotEvent({'message': (),
'time': time.time(), 'isError': 1,
'system': '-', 'failure': f,
'why': None})
self.assertEqual(self.observer.getErrors(), [])
def test_clearIgnores(self):
"""
Check that C{_clearIgnores} ensures that previously ignored errors
get captured.
"""
self.observer._ignoreErrors(ZeroDivisionError)
self.observer._clearIgnores()
f = makeFailure()
self.observer.gotEvent({'message': (),
'time': time.time(), 'isError': 1,
'system': '-', 'failure': f,
'why': None})
self.assertEqual(self.observer.getErrors(), [f])
class LogErrorsMixin(object):
"""
High-level tests demonstrating the expected behaviour of logged errors
during tests.
"""
def setUp(self):
self.result = reporter.TestResult()
def tearDown(self):
self.flushLoggedErrors(ZeroDivisionError)
def test_singleError(self):
"""
Test that a logged error gets reported as a test error.
"""
test = self.MockTest('test_single')
test(self.result)
self.assertEqual(len(self.result.errors), 1)
self.assertTrue(self.result.errors[0][1].check(ZeroDivisionError),
self.result.errors[0][1])
self.assertEqual(0, self.result.successes)
def test_twoErrors(self):
"""
Test that when two errors get logged, they both get reported as test
errors.
"""
test = self.MockTest('test_double')
test(self.result)
self.assertEqual(len(self.result.errors), 2)
self.assertEqual(0, self.result.successes)
def test_errorsIsolated(self):
"""
Check that an error logged in one test doesn't fail the next test.
"""
t1 = self.MockTest('test_single')
t2 = self.MockTest('test_silent')
t1(self.result)
t2(self.result)
self.assertEqual(len(self.result.errors), 1)
self.assertEqual(self.result.errors[0][0], t1)
self.assertEqual(1, self.result.successes)
def test_boundedObservers(self):
"""
There are no extra log observers after a test runs.
"""
# XXX trial is *all about* global log state. It should really be fixed.
observer = unittest._LogObserver()
self.patch(unittest, '_logObserver', observer)
observers = log.theLogPublisher.observers[:]
test = self.MockTest()
test(self.result)
self.assertEqual(observers, log.theLogPublisher.observers)
class SynchronousLogErrorsTests(LogErrorsMixin, unittest.SynchronousTestCase):
MockTest = Mask.SynchronousFailureLogging
class AsynchronousLogErrorsTests(LogErrorsMixin, unittest.TestCase):
MockTest = Mask.AsynchronousFailureLogging
def test_inCallback(self):
"""
Test that errors logged in callbacks get reported as test errors.
"""
test = self.MockTest('test_inCallback')
test(self.result)
self.assertEqual(len(self.result.errors), 1)
self.assertTrue(self.result.errors[0][1].check(ZeroDivisionError),
self.result.errors[0][1])

View file

@ -0,0 +1,179 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for the output generated by trial.
"""
import os, StringIO
from twisted.scripts import trial
from twisted.trial import runner
from twisted.trial.test import packages
def runTrial(*args):
from twisted.trial import reporter
config = trial.Options()
config.parseOptions(args)
output = StringIO.StringIO()
myRunner = runner.TrialRunner(
reporter.VerboseTextReporter,
stream=output,
workingDirectory=config['temp-directory'])
suite = trial._getSuite(config)
result = myRunner.run(suite)
return output.getvalue()
class TestImportErrors(packages.SysPathManglingTest):
"""Actually run trial as if on the command line and check that the output
is what we expect.
"""
debug = False
parent = "_testImportErrors"
def runTrial(self, *args):
return runTrial('--temp-directory', self.mktemp(), *args)
def _print(self, stuff):
print stuff
return stuff
def assertIn(self, container, containee, *args, **kwargs):
# redefined to be useful in callbacks
super(TestImportErrors, self).assertIn(
containee, container, *args, **kwargs)
return container
def assertNotIn(self, container, containee, *args, **kwargs):
# redefined to be useful in callbacks
super(TestImportErrors, self).assertNotIn(
containee, container, *args, **kwargs)
return container
def test_trialRun(self):
self.runTrial()
def test_nonexistentModule(self):
d = self.runTrial('twisted.doesntexist')
self.assertIn(d, '[ERROR]')
self.assertIn(d, 'twisted.doesntexist')
return d
def test_nonexistentPackage(self):
d = self.runTrial('doesntexist')
self.assertIn(d, 'doesntexist')
self.assertIn(d, 'ModuleNotFound')
self.assertIn(d, '[ERROR]')
return d
def test_nonexistentPackageWithModule(self):
d = self.runTrial('doesntexist.barney')
self.assertIn(d, 'doesntexist.barney')
self.assertIn(d, 'ObjectNotFound')
self.assertIn(d, '[ERROR]')
return d
def test_badpackage(self):
d = self.runTrial('badpackage')
self.assertIn(d, '[ERROR]')
self.assertIn(d, 'badpackage')
self.assertNotIn(d, 'IOError')
return d
def test_moduleInBadpackage(self):
d = self.runTrial('badpackage.test_module')
self.assertIn(d, "[ERROR]")
self.assertIn(d, "badpackage.test_module")
self.assertNotIn(d, 'IOError')
return d
def test_badmodule(self):
d = self.runTrial('package.test_bad_module')
self.assertIn(d, '[ERROR]')
self.assertIn(d, 'package.test_bad_module')
self.assertNotIn(d, 'IOError')
self.assertNotIn(d, '<module ')
return d
def test_badimport(self):
d = self.runTrial('package.test_import_module')
self.assertIn(d, '[ERROR]')
self.assertIn(d, 'package.test_import_module')
self.assertNotIn(d, 'IOError')
self.assertNotIn(d, '<module ')
return d
def test_recurseImport(self):
d = self.runTrial('package')
self.assertIn(d, '[ERROR]')
self.assertIn(d, 'test_bad_module')
self.assertIn(d, 'test_import_module')
self.assertNotIn(d, '<module ')
self.assertNotIn(d, 'IOError')
return d
def test_recurseImportErrors(self):
d = self.runTrial('package2')
self.assertIn(d, '[ERROR]')
self.assertIn(d, 'package2')
self.assertIn(d, 'test_module')
self.assertIn(d, "No module named frotz")
self.assertNotIn(d, '<module ')
self.assertNotIn(d, 'IOError')
return d
def test_nonRecurseImportErrors(self):
d = self.runTrial('-N', 'package2')
self.assertIn(d, '[ERROR]')
self.assertIn(d, "No module named frotz")
self.assertNotIn(d, '<module ')
return d
def test_regularRun(self):
d = self.runTrial('package.test_module')
self.assertNotIn(d, '[ERROR]')
self.assertNotIn(d, 'IOError')
self.assertIn(d, 'OK')
self.assertIn(d, 'PASSED (successes=1)')
return d
def test_filename(self):
self.mangleSysPath(self.oldPath)
d = self.runTrial(
os.path.join(self.parent, 'package', 'test_module.py'))
self.assertNotIn(d, '[ERROR]')
self.assertNotIn(d, 'IOError')
self.assertIn(d, 'OK')
self.assertIn(d, 'PASSED (successes=1)')
return d
def test_dosFile(self):
## XXX -- not really an output test, more of a script test
self.mangleSysPath(self.oldPath)
d = self.runTrial(
os.path.join(self.parent,
'package', 'test_dos_module.py'))
self.assertNotIn(d, '[ERROR]')
self.assertNotIn(d, 'IOError')
self.assertIn(d, 'OK')
self.assertIn(d, 'PASSED (successes=1)')
return d

View file

@ -0,0 +1,46 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
#
# Maintainer: Jonathan Lange
"""
Tests for L{twisted.plugins.twisted_trial}.
"""
from twisted.plugin import getPlugins
from twisted.trial import unittest
from twisted.trial.itrial import IReporter
class TestPlugins(unittest.SynchronousTestCase):
"""
Tests for Trial's reporter plugins.
"""
def getPluginsByLongOption(self, longOption):
"""
Return the Trial reporter plugin with the given long option.
If more than one is found, raise ValueError. If none are found, raise
IndexError.
"""
plugins = [
plugin for plugin in getPlugins(IReporter)
if plugin.longOpt == longOption]
if len(plugins) > 1:
raise ValueError(
"More than one plugin found with long option %r: %r"
% (longOption, plugins))
return plugins[0]
def test_subunitPlugin(self):
"""
One of the reporter plugins is the subunit reporter plugin.
"""
subunitPlugin = self.getPluginsByLongOption('subunit')
self.assertEqual('Subunit Reporter', subunitPlugin.name)
self.assertEqual('twisted.trial.reporter', subunitPlugin.module)
self.assertEqual('subunit', subunitPlugin.longOpt)
self.assertIdentical(None, subunitPlugin.shortOpt)
self.assertEqual('SubunitReporter', subunitPlugin.klass)

View file

@ -0,0 +1,287 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
from __future__ import division, absolute_import
import sys
import traceback
from zope.interface import implementer
from twisted.python.compat import _PY3
from twisted.python.failure import Failure
from twisted.trial.unittest import SynchronousTestCase, PyUnitResultAdapter
from twisted.trial.itrial import IReporter, ITestCase
import unittest as pyunit
class TestPyUnitTestCase(SynchronousTestCase):
class PyUnitTest(pyunit.TestCase):
def test_pass(self):
pass
def setUp(self):
self.original = self.PyUnitTest('test_pass')
self.test = ITestCase(self.original)
def test_callable(self):
"""
Tests must be callable in order to be used with Python's unittest.py.
"""
self.assertTrue(callable(self.test),
"%r is not callable." % (self.test,))
# Remove this when we port twisted.trial._synctest to Python 3:
if _PY3:
del TestPyUnitTestCase
class TestPyUnitResult(SynchronousTestCase):
"""
Tests to show that PyUnitResultAdapter wraps TestResult objects from the
standard library 'unittest' module in such a way as to make them usable and
useful from Trial.
"""
# Once erroneous is ported to Python 3 this can be replaced with
# erroneous.ErrorTest:
class ErrorTest(SynchronousTestCase):
"""
A test case which has a L{test_foo} which will raise an error.
@ivar ran: boolean indicating whether L{test_foo} has been run.
"""
ran = False
def test_foo(self):
"""
Set C{self.ran} to True and raise a C{ZeroDivisionError}
"""
self.ran = True
1/0
def test_dontUseAdapterWhenReporterProvidesIReporter(self):
"""
The L{PyUnitResultAdapter} is only used when the result passed to
C{run} does *not* provide L{IReporter}.
"""
@implementer(IReporter)
class StubReporter(object):
"""
A reporter which records data about calls made to it.
@ivar errors: Errors passed to L{addError}.
@ivar failures: Failures passed to L{addFailure}.
"""
def __init__(self):
self.errors = []
self.failures = []
def startTest(self, test):
"""
Do nothing.
"""
def stopTest(self, test):
"""
Do nothing.
"""
def addError(self, test, error):
"""
Record the error.
"""
self.errors.append(error)
test = self.ErrorTest("test_foo")
result = StubReporter()
test.run(result)
self.assertIsInstance(result.errors[0], Failure)
def test_success(self):
class SuccessTest(SynchronousTestCase):
ran = False
def test_foo(s):
s.ran = True
test = SuccessTest('test_foo')
result = pyunit.TestResult()
test.run(result)
self.failUnless(test.ran)
self.assertEqual(1, result.testsRun)
self.failUnless(result.wasSuccessful())
def test_failure(self):
class FailureTest(SynchronousTestCase):
ran = False
def test_foo(s):
s.ran = True
s.fail('boom!')
test = FailureTest('test_foo')
result = pyunit.TestResult()
test.run(result)
self.failUnless(test.ran)
self.assertEqual(1, result.testsRun)
self.assertEqual(1, len(result.failures))
self.failIf(result.wasSuccessful())
def test_error(self):
test = self.ErrorTest('test_foo')
result = pyunit.TestResult()
test.run(result)
self.failUnless(test.ran)
self.assertEqual(1, result.testsRun)
self.assertEqual(1, len(result.errors))
self.failIf(result.wasSuccessful())
def test_setUpError(self):
class ErrorTest(SynchronousTestCase):
ran = False
def setUp(self):
1/0
def test_foo(s):
s.ran = True
test = ErrorTest('test_foo')
result = pyunit.TestResult()
test.run(result)
self.failIf(test.ran)
self.assertEqual(1, result.testsRun)
self.assertEqual(1, len(result.errors))
self.failIf(result.wasSuccessful())
def test_tracebackFromFailure(self):
"""
Errors added through the L{PyUnitResultAdapter} have the same traceback
information as if there were no adapter at all.
"""
try:
1/0
except ZeroDivisionError:
exc_info = sys.exc_info()
f = Failure()
pyresult = pyunit.TestResult()
result = PyUnitResultAdapter(pyresult)
result.addError(self, f)
self.assertEqual(pyresult.errors[0][1],
''.join(traceback.format_exception(*exc_info)))
def test_traceback(self):
"""
As test_tracebackFromFailure, but covering more code.
"""
class ErrorTest(SynchronousTestCase):
exc_info = None
def test_foo(self):
try:
1/0
except ZeroDivisionError:
self.exc_info = sys.exc_info()
raise
test = ErrorTest('test_foo')
result = pyunit.TestResult()
test.run(result)
# We can't test that the tracebacks are equal, because Trial's
# machinery inserts a few extra frames on the top and we don't really
# want to trim them off without an extremely good reason.
#
# So, we just test that the result's stack ends with the the
# exception's stack.
expected_stack = ''.join(traceback.format_tb(test.exc_info[2]))
observed_stack = '\n'.join(result.errors[0][1].splitlines()[:-1])
self.assertEqual(expected_stack.strip(),
observed_stack[-len(expected_stack):].strip())
def test_tracebackFromCleanFailure(self):
"""
Errors added through the L{PyUnitResultAdapter} have the same
traceback information as if there were no adapter at all, even
if the Failure that held the information has been cleaned.
"""
try:
1/0
except ZeroDivisionError:
exc_info = sys.exc_info()
f = Failure()
f.cleanFailure()
pyresult = pyunit.TestResult()
result = PyUnitResultAdapter(pyresult)
result.addError(self, f)
self.assertEqual(pyresult.errors[0][1],
''.join(traceback.format_exception(*exc_info)))
def test_trialSkip(self):
"""
Skips using trial's skipping functionality are reported as skips in
the L{pyunit.TestResult}.
"""
class SkipTest(SynchronousTestCase):
def test_skip(self):
1/0
test_skip.skip = "Let's skip!"
test = SkipTest('test_skip')
result = pyunit.TestResult()
test.run(result)
self.assertEqual(result.skipped, [(test, "Let's skip!")])
def test_pyunitSkip(self):
"""
Skips using pyunit's skipping functionality are reported as skips in
the L{pyunit.TestResult}.
"""
class SkipTest(SynchronousTestCase):
@pyunit.skip("skippy")
def test_skip(self):
1/0
test = SkipTest('test_skip')
result = pyunit.TestResult()
test.run(result)
self.assertEqual(result.skipped, [(test, "skippy")])
def test_skip26(self):
"""
On Python 2.6, pyunit doesn't support skipping, so it gets added as a
failure to the L{pyunit.TestResult}.
"""
class SkipTest(SynchronousTestCase):
def test_skip(self):
1/0
test_skip.skip = "Let's skip!"
test = SkipTest('test_skip')
result = pyunit.TestResult()
test.run(result)
self.assertEqual(len(result.failures), 1)
test2, reason = result.failures[0]
self.assertIdentical(test, test2)
self.assertIn("UnsupportedTrialFeature", reason)
if sys.version_info[:2] < (2, 7):
message = "pyunit doesn't support skipping in Python 2.6"
test_trialSkip.skip = message
test_pyunitSkip.skip = message
del message
else:
test_skip26.skip = "This test is only relevant to Python 2.6"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,867 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
import StringIO
import gc
import re
import sys
import textwrap
import types
from twisted.trial import unittest
from twisted.trial.runner import (
TrialRunner, TestSuite, DestructiveTestSuite, TestLoader)
from twisted.trial._dist.disttrial import DistTrialRunner
from twisted.scripts import trial
from twisted.python import util
from twisted.python.usage import UsageError
from twisted.python.filepath import FilePath
from twisted.trial.test.test_loader import testNames
pyunit = __import__('unittest')
def sibpath(filename):
"""
For finding files in twisted/trial/test
"""
return util.sibpath(__file__, filename)
class ForceGarbageCollection(unittest.SynchronousTestCase):
"""
Tests for the --force-gc option.
"""
def setUp(self):
self.config = trial.Options()
self.log = []
self.patch(gc, 'collect', self.collect)
test = pyunit.FunctionTestCase(self.simpleTest)
self.test = TestSuite([test, test])
def simpleTest(self):
"""
A simple test method that records that it was run.
"""
self.log.append('test')
def collect(self):
"""
A replacement for gc.collect that logs calls to itself.
"""
self.log.append('collect')
def makeRunner(self):
"""
Return a L{TrialRunner} object that is safe to use in tests.
"""
runner = trial._makeRunner(self.config)
runner.stream = StringIO.StringIO()
return runner
def test_forceGc(self):
"""
Passing the --force-gc option to the trial script forces the garbage
collector to run before and after each test.
"""
self.config['force-gc'] = True
self.config.postOptions()
runner = self.makeRunner()
runner.run(self.test)
self.assertEqual(self.log, ['collect', 'test', 'collect',
'collect', 'test', 'collect'])
def test_unforceGc(self):
"""
By default, no garbage collection is forced.
"""
self.config.postOptions()
runner = self.makeRunner()
runner.run(self.test)
self.assertEqual(self.log, ['test', 'test'])
class TestSuiteUsed(unittest.SynchronousTestCase):
"""
Check the category of tests suite used by the loader.
"""
def setUp(self):
"""
Create a trial configuration object.
"""
self.config = trial.Options()
def test_defaultSuite(self):
"""
By default, the loader should use L{DestructiveTestSuite}
"""
loader = trial._getLoader(self.config)
self.assertEqual(loader.suiteFactory, DestructiveTestSuite)
def test_untilFailureSuite(self):
"""
The C{until-failure} configuration uses the L{TestSuite} to keep
instances alive across runs.
"""
self.config['until-failure'] = True
loader = trial._getLoader(self.config)
self.assertEqual(loader.suiteFactory, TestSuite)
class TestModuleTest(unittest.SynchronousTestCase):
def setUp(self):
self.config = trial.Options()
def tearDown(self):
self.config = None
def test_testNames(self):
"""
Check that the testNames helper method accurately collects the
names of tests in suite.
"""
self.assertEqual(testNames(self), [self.id()])
def assertSuitesEqual(self, test1, names):
loader = TestLoader()
names1 = testNames(test1)
names2 = testNames(TestSuite(map(loader.loadByName, names)))
names1.sort()
names2.sort()
self.assertEqual(names1, names2)
def test_baseState(self):
self.assertEqual(0, len(self.config['tests']))
def test_testmoduleOnModule(self):
"""
Check that --testmodule loads a suite which contains the tests
referred to in test-case-name inside its parameter.
"""
self.config.opt_testmodule(sibpath('moduletest.py'))
self.assertSuitesEqual(trial._getSuite(self.config),
['twisted.trial.test.test_log'])
def test_testmoduleTwice(self):
"""
When the same module is specified with two --testmodule flags, it
should only appear once in the suite.
"""
self.config.opt_testmodule(sibpath('moduletest.py'))
self.config.opt_testmodule(sibpath('moduletest.py'))
self.assertSuitesEqual(trial._getSuite(self.config),
['twisted.trial.test.test_log'])
def test_testmoduleOnSourceAndTarget(self):
"""
If --testmodule is specified twice, once for module A and once for
a module which refers to module A, then make sure module A is only
added once.
"""
self.config.opt_testmodule(sibpath('moduletest.py'))
self.config.opt_testmodule(sibpath('test_log.py'))
self.assertSuitesEqual(trial._getSuite(self.config),
['twisted.trial.test.test_log'])
def test_testmoduleOnSelfModule(self):
"""
When given a module that refers to *itself* in the test-case-name
variable, check that --testmodule only adds the tests once.
"""
self.config.opt_testmodule(sibpath('moduleself.py'))
self.assertSuitesEqual(trial._getSuite(self.config),
['twisted.trial.test.moduleself'])
def test_testmoduleOnScript(self):
"""
Check that --testmodule loads tests referred to in test-case-name
buffer variables.
"""
self.config.opt_testmodule(sibpath('scripttest.py'))
self.assertSuitesEqual(trial._getSuite(self.config),
['twisted.trial.test.test_log',
'twisted.trial.test.test_class'])
def test_testmoduleOnNonexistentFile(self):
"""
Check that --testmodule displays a meaningful error message when
passed a non-existent filename.
"""
buffy = StringIO.StringIO()
stderr, sys.stderr = sys.stderr, buffy
filename = 'test_thisbetternoteverexist.py'
try:
self.config.opt_testmodule(filename)
self.assertEqual(0, len(self.config['tests']))
self.assertEqual("File %r doesn't exist\n" % (filename,),
buffy.getvalue())
finally:
sys.stderr = stderr
def test_testmoduleOnEmptyVars(self):
"""
Check that --testmodule adds no tests to the suite for modules
which lack test-case-name buffer variables.
"""
self.config.opt_testmodule(sibpath('novars.py'))
self.assertEqual(0, len(self.config['tests']))
def test_testmoduleOnModuleName(self):
"""
Check that --testmodule does *not* support module names as arguments
and that it displays a meaningful error message.
"""
buffy = StringIO.StringIO()
stderr, sys.stderr = sys.stderr, buffy
moduleName = 'twisted.trial.test.test_script'
try:
self.config.opt_testmodule(moduleName)
self.assertEqual(0, len(self.config['tests']))
self.assertEqual("File %r doesn't exist\n" % (moduleName,),
buffy.getvalue())
finally:
sys.stderr = stderr
def test_parseLocalVariable(self):
declaration = '-*- test-case-name: twisted.trial.test.test_tests -*-'
localVars = trial._parseLocalVariables(declaration)
self.assertEqual({'test-case-name':
'twisted.trial.test.test_tests'},
localVars)
def test_trailingSemicolon(self):
declaration = '-*- test-case-name: twisted.trial.test.test_tests; -*-'
localVars = trial._parseLocalVariables(declaration)
self.assertEqual({'test-case-name':
'twisted.trial.test.test_tests'},
localVars)
def test_parseLocalVariables(self):
declaration = ('-*- test-case-name: twisted.trial.test.test_tests; '
'foo: bar -*-')
localVars = trial._parseLocalVariables(declaration)
self.assertEqual({'test-case-name':
'twisted.trial.test.test_tests',
'foo': 'bar'},
localVars)
def test_surroundingGuff(self):
declaration = ('## -*- test-case-name: '
'twisted.trial.test.test_tests -*- #')
localVars = trial._parseLocalVariables(declaration)
self.assertEqual({'test-case-name':
'twisted.trial.test.test_tests'},
localVars)
def test_invalidLine(self):
self.failUnlessRaises(ValueError, trial._parseLocalVariables,
'foo')
def test_invalidDeclaration(self):
self.failUnlessRaises(ValueError, trial._parseLocalVariables,
'-*- foo -*-')
self.failUnlessRaises(ValueError, trial._parseLocalVariables,
'-*- foo: bar; qux -*-')
self.failUnlessRaises(ValueError, trial._parseLocalVariables,
'-*- foo: bar: baz; qux: qax -*-')
def test_variablesFromFile(self):
localVars = trial.loadLocalVariables(sibpath('moduletest.py'))
self.assertEqual({'test-case-name':
'twisted.trial.test.test_log'},
localVars)
def test_noVariablesInFile(self):
localVars = trial.loadLocalVariables(sibpath('novars.py'))
self.assertEqual({}, localVars)
def test_variablesFromScript(self):
localVars = trial.loadLocalVariables(sibpath('scripttest.py'))
self.assertEqual(
{'test-case-name': ('twisted.trial.test.test_log,'
'twisted.trial.test.test_class')},
localVars)
def test_getTestModules(self):
modules = trial.getTestModules(sibpath('moduletest.py'))
self.assertEqual(modules, ['twisted.trial.test.test_log'])
def test_getTestModules_noVars(self):
modules = trial.getTestModules(sibpath('novars.py'))
self.assertEqual(len(modules), 0)
def test_getTestModules_multiple(self):
modules = trial.getTestModules(sibpath('scripttest.py'))
self.assertEqual(set(modules),
set(['twisted.trial.test.test_log',
'twisted.trial.test.test_class']))
def test_looksLikeTestModule(self):
for filename in ['test_script.py', 'twisted/trial/test/test_script.py']:
self.failUnless(trial.isTestFile(filename),
"%r should be a test file" % (filename,))
for filename in ['twisted/trial/test/moduletest.py',
sibpath('scripttest.py'), sibpath('test_foo.bat')]:
self.failIf(trial.isTestFile(filename),
"%r should *not* be a test file" % (filename,))
class WithoutModuleTests(unittest.SynchronousTestCase):
"""
Test the C{without-module} flag.
"""
def setUp(self):
"""
Create a L{trial.Options} object to be used in the tests, and save
C{sys.modules}.
"""
self.config = trial.Options()
self.savedModules = dict(sys.modules)
def tearDown(self):
"""
Restore C{sys.modules}.
"""
for module in ('imaplib', 'smtplib'):
if module in self.savedModules:
sys.modules[module] = self.savedModules[module]
else:
sys.modules.pop(module, None)
def _checkSMTP(self):
"""
Try to import the C{smtplib} module, and return it.
"""
import smtplib
return smtplib
def _checkIMAP(self):
"""
Try to import the C{imaplib} module, and return it.
"""
import imaplib
return imaplib
def test_disableOneModule(self):
"""
Check that after disabling a module, it can't be imported anymore.
"""
self.config.parseOptions(["--without-module", "smtplib"])
self.assertRaises(ImportError, self._checkSMTP)
# Restore sys.modules
del sys.modules["smtplib"]
# Then the function should succeed
self.assertIsInstance(self._checkSMTP(), types.ModuleType)
def test_disableMultipleModules(self):
"""
Check that several modules can be disabled at once.
"""
self.config.parseOptions(["--without-module", "smtplib,imaplib"])
self.assertRaises(ImportError, self._checkSMTP)
self.assertRaises(ImportError, self._checkIMAP)
# Restore sys.modules
del sys.modules["smtplib"]
del sys.modules["imaplib"]
# Then the functions should succeed
self.assertIsInstance(self._checkSMTP(), types.ModuleType)
self.assertIsInstance(self._checkIMAP(), types.ModuleType)
def test_disableAlreadyImportedModule(self):
"""
Disabling an already imported module should produce a warning.
"""
self.assertIsInstance(self._checkSMTP(), types.ModuleType)
self.assertWarns(RuntimeWarning,
"Module 'smtplib' already imported, disabling anyway.",
trial.__file__,
self.config.parseOptions, ["--without-module", "smtplib"])
self.assertRaises(ImportError, self._checkSMTP)
class CoverageTests(unittest.SynchronousTestCase):
"""
Tests for the I{coverage} option.
"""
if getattr(sys, 'gettrace', None) is None:
skip = (
"Cannot test trace hook installation without inspection API.")
def setUp(self):
"""
Arrange for the current trace hook to be restored when the
test is complete.
"""
self.addCleanup(sys.settrace, sys.gettrace())
def test_tracerInstalled(self):
"""
L{trial.Options} handles C{"--coverage"} by installing a trace
hook to record coverage information.
"""
options = trial.Options()
options.parseOptions(["--coverage"])
self.assertEqual(sys.gettrace(), options.tracer.globaltrace)
def test_coverdirDefault(self):
"""
L{trial.Options.coverdir} returns a L{FilePath} based on the default
for the I{temp-directory} option if that option is not specified.
"""
options = trial.Options()
self.assertEqual(
options.coverdir(),
FilePath(".").descendant([options["temp-directory"], "coverage"]))
def test_coverdirOverridden(self):
"""
If a value is specified for the I{temp-directory} option,
L{trial.Options.coverdir} returns a child of that path.
"""
path = self.mktemp()
options = trial.Options()
options.parseOptions(["--temp-directory", path])
self.assertEqual(
options.coverdir(), FilePath(path).child("coverage"))
class OptionsTestCase(unittest.TestCase):
"""
Tests for L{trial.Options}.
"""
def setUp(self):
"""
Build an L{Options} object to be used in the tests.
"""
self.options = trial.Options()
def test_getWorkerArguments(self):
"""
C{_getWorkerArguments} discards options like C{random} as they only
matter in the manager, and forwards options like C{recursionlimit} or
C{disablegc}.
"""
self.addCleanup(sys.setrecursionlimit, sys.getrecursionlimit())
if gc.isenabled():
self.addCleanup(gc.enable)
self.options.parseOptions(["--recursionlimit", "2000", "--random",
"4", "--disablegc"])
args = self.options._getWorkerArguments()
self.assertIn("--disablegc", args)
args.remove("--disablegc")
self.assertEqual(["--recursionlimit", "2000"], args)
def test_jobsConflictWithDebug(self):
"""
C{parseOptions} raises a C{UsageError} when C{--debug} is passed along
C{--jobs} as it's not supported yet.
@see: U{http://twistedmatrix.com/trac/ticket/5825}
"""
error = self.assertRaises(
UsageError, self.options.parseOptions, ["--jobs", "4", "--debug"])
self.assertEqual("You can't specify --debug when using --jobs",
str(error))
def test_jobsConflictWithProfile(self):
"""
C{parseOptions} raises a C{UsageError} when C{--profile} is passed
along C{--jobs} as it's not supported yet.
@see: U{http://twistedmatrix.com/trac/ticket/5827}
"""
error = self.assertRaises(
UsageError, self.options.parseOptions,
["--jobs", "4", "--profile"])
self.assertEqual("You can't specify --profile when using --jobs",
str(error))
def test_jobsConflictWithDebugStackTraces(self):
"""
C{parseOptions} raises a C{UsageError} when C{--debug-stacktraces} is
passed along C{--jobs} as it's not supported yet.
@see: U{http://twistedmatrix.com/trac/ticket/5826}
"""
error = self.assertRaises(
UsageError, self.options.parseOptions,
["--jobs", "4", "--debug-stacktraces"])
self.assertEqual(
"You can't specify --debug-stacktraces when using --jobs",
str(error))
def test_jobsConflictWithExitFirst(self):
"""
C{parseOptions} raises a C{UsageError} when C{--exitfirst} is passed
along C{--jobs} as it's not supported yet.
@see: U{http://twistedmatrix.com/trac/ticket/6436}
"""
error = self.assertRaises(
UsageError, self.options.parseOptions,
["--jobs", "4", "--exitfirst"])
self.assertEqual(
"You can't specify --exitfirst when using --jobs",
str(error))
def test_orderConflictWithRandom(self):
"""
C{parseOptions} raises a C{UsageError} when C{--order} is passed along
with C{--random}.
"""
error = self.assertRaises(
UsageError,
self.options.parseOptions,
["--order", "alphabetical", "--random", "1234"])
self.assertEqual("You can't specify --random when using --order",
str(error))
class MakeRunnerTestCase(unittest.TestCase):
"""
Tests for the L{_makeRunner} helper.
"""
def setUp(self):
self.options = trial.Options()
def test_jobs(self):
"""
L{_makeRunner} returns a L{DistTrialRunner} instance when the C{--jobs}
option is passed, and passes the C{workerNumber} and C{workerArguments}
parameters to it.
"""
self.options.parseOptions(["--jobs", "4", "--force-gc"])
runner = trial._makeRunner(self.options)
self.assertIsInstance(runner, DistTrialRunner)
self.assertEqual(4, runner._workerNumber)
self.assertEqual(["--force-gc"], runner._workerArguments)
def test_dryRunWithJobs(self):
"""
L{_makeRunner} returns a L{TrialRunner} instance in C{DRY_RUN} mode
when the C{--dry-run} option is passed, even if C{--jobs} is set.
"""
self.options.parseOptions(["--jobs", "4", "--dry-run"])
runner = trial._makeRunner(self.options)
self.assertIsInstance(runner, TrialRunner)
self.assertEqual(TrialRunner.DRY_RUN, runner.mode)
def test_DebuggerNotFound(self):
namedAny = trial.reflect.namedAny
def namedAnyExceptdoNotFind(fqn):
if fqn == "doNotFind":
raise trial.reflect.ModuleNotFound(fqn)
return namedAny(fqn)
self.patch(trial.reflect, "namedAny", namedAnyExceptdoNotFind)
options = trial.Options()
options.parseOptions(["--debug", "--debugger", "doNotFind"])
self.assertRaises(trial._DebuggerNotFound, trial._makeRunner, options)
def test_exitfirst(self):
"""
Passing C{--exitfirst} wraps the reporter with a
L{reporter._ExitWrapper} that stops on any non-success.
"""
self.options.parseOptions(["--exitfirst"])
runner = trial._makeRunner(self.options)
self.assertTrue(runner._exitFirst)
class TestRun(unittest.TestCase):
"""
Tests for the L{run} function.
"""
def setUp(self):
# don't re-parse cmdline options, because if --reactor was passed to
# the test run trial will try to restart the (already running) reactor
self.patch(trial.Options, "parseOptions", lambda self: None)
def test_debuggerNotFound(self):
"""
When a debugger is not found, an error message is printed to the user.
"""
def _makeRunner(*args, **kwargs):
raise trial._DebuggerNotFound('foo')
self.patch(trial, "_makeRunner", _makeRunner)
try:
trial.run()
except SystemExit as e:
self.assertIn("foo", str(e))
else:
self.fail("Should have exited due to non-existent debugger!")
class TestArgumentOrderTests(unittest.TestCase):
"""
Tests for the order-preserving behavior on provided command-line tests.
"""
def setUp(self):
self.config = trial.Options()
self.loader = TestLoader()
def test_preserveArgumentOrder(self):
"""
Multiple tests passed on the command line are not reordered.
"""
tests = [
"twisted.trial.test.test_tests",
"twisted.trial.test.test_assertions",
"twisted.trial.test.test_deferreds",
]
self.config.parseOptions(tests)
suite = trial._getSuite(self.config)
names = testNames(suite)
expectedSuite = TestSuite(map(self.loader.loadByName, tests))
expectedNames = testNames(expectedSuite)
self.assertEqual(names, expectedNames)
class OrderTests(unittest.TestCase):
"""
Tests for the --order option.
"""
def setUp(self):
self.config = trial.Options()
def test_alphabetical(self):
"""
--order=alphabetical causes trial to run tests alphabetically within
each test case.
"""
self.config.parseOptions([
"--order", "alphabetical",
"twisted.trial.test.ordertests.FooTest"])
loader = trial._getLoader(self.config)
suite = loader.loadByNames(self.config['tests'])
self.assertEqual(
testNames(suite), [
'twisted.trial.test.ordertests.FooTest.test_first',
'twisted.trial.test.ordertests.FooTest.test_fourth',
'twisted.trial.test.ordertests.FooTest.test_second',
'twisted.trial.test.ordertests.FooTest.test_third'])
def test_alphabeticalModule(self):
"""
--order=alphabetical causes trial to run test classes within a given
module alphabetically.
"""
self.config.parseOptions([
"--order", "alphabetical", "twisted.trial.test.ordertests"])
loader = trial._getLoader(self.config)
suite = loader.loadByNames(self.config['tests'])
self.assertEqual(
testNames(suite), [
'twisted.trial.test.ordertests.BarTest.test_bar',
'twisted.trial.test.ordertests.BazTest.test_baz',
'twisted.trial.test.ordertests.FooTest.test_first',
'twisted.trial.test.ordertests.FooTest.test_fourth',
'twisted.trial.test.ordertests.FooTest.test_second',
'twisted.trial.test.ordertests.FooTest.test_third'])
def test_alphabeticalPackage(self):
"""
--order=alphabetical causes trial to run test modules within a given
package alphabetically, with tests within each module alphabetized.
"""
self.config.parseOptions([
"--order", "alphabetical", "twisted.trial.test"])
loader = trial._getLoader(self.config)
suite = loader.loadByNames(self.config['tests'])
names = testNames(suite)
self.assertTrue(names, msg="Failed to load any tests!")
self.assertEqual(names, sorted(names))
def test_toptobottom(self):
"""
--order=toptobottom causes trial to run test methods within a given
test case from top to bottom as they are defined in the body of the
class.
"""
self.config.parseOptions([
"--order", "toptobottom",
"twisted.trial.test.ordertests.FooTest"])
loader = trial._getLoader(self.config)
suite = loader.loadByNames(self.config['tests'])
self.assertEqual(
testNames(suite), [
'twisted.trial.test.ordertests.FooTest.test_first',
'twisted.trial.test.ordertests.FooTest.test_second',
'twisted.trial.test.ordertests.FooTest.test_third',
'twisted.trial.test.ordertests.FooTest.test_fourth'])
def test_toptobottomModule(self):
"""
--order=toptobottom causes trial to run test classes within a given
module from top to bottom as they are defined in the module's source.
"""
self.config.parseOptions([
"--order", "toptobottom", "twisted.trial.test.ordertests"])
loader = trial._getLoader(self.config)
suite = loader.loadByNames(self.config['tests'])
self.assertEqual(
testNames(suite), [
'twisted.trial.test.ordertests.FooTest.test_first',
'twisted.trial.test.ordertests.FooTest.test_second',
'twisted.trial.test.ordertests.FooTest.test_third',
'twisted.trial.test.ordertests.FooTest.test_fourth',
'twisted.trial.test.ordertests.BazTest.test_baz',
'twisted.trial.test.ordertests.BarTest.test_bar'])
def test_toptobottomPackage(self):
"""
--order=toptobottom causes trial to run test modules within a given
package alphabetically, with tests within each module run top to
bottom.
"""
self.config.parseOptions([
"--order", "toptobottom", "twisted.trial.test"])
loader = trial._getLoader(self.config)
suite = loader.loadByNames(self.config['tests'])
names = testNames(suite)
# twisted.trial.test.test_module, so split and key on the first 4 to
# get stable alphabetical sort on those
self.assertEqual(
names, sorted(names, key=lambda name : name.split(".")[:4]),
)
def test_toptobottomMissingSource(self):
"""
--order=toptobottom detects the source line of methods from modules
whose source file is missing.
"""
tempdir = self.mktemp().encode('utf-8')
package = FilePath(tempdir).child(b'twisted_toptobottom_temp')
package.makedirs()
package.child(b'__init__.py').setContent(b'')
package.child(b'test_missing.py').setContent(textwrap.dedent(b'''
from twisted.trial.unittest import TestCase
class TestMissing(TestCase):
def test_second(self): pass
def test_third(self): pass
def test_fourth(self): pass
def test_first(self): pass
'''))
pathEntry = package.parent().path.decode('utf-8')
sys.path.insert(0, pathEntry)
self.addCleanup(sys.path.remove, pathEntry)
from twisted_toptobottom_temp import test_missing
self.addCleanup(sys.modules.pop, 'twisted_toptobottom_temp')
self.addCleanup(sys.modules.pop, test_missing.__name__)
package.child(b'test_missing.py').remove()
self.config.parseOptions([
"--order", "toptobottom", "twisted.trial.test.ordertests"])
loader = trial._getLoader(self.config)
suite = loader.loadModule(test_missing)
self.assertEqual(
testNames(suite), [
'twisted_toptobottom_temp.test_missing.TestMissing.test_second',
'twisted_toptobottom_temp.test_missing.TestMissing.test_third',
'twisted_toptobottom_temp.test_missing.TestMissing.test_fourth',
'twisted_toptobottom_temp.test_missing.TestMissing.test_first'])
def test_unknownOrder(self):
"""
An unknown order passed to --order raises a L{UsageError}.
"""
self.assertRaises(
UsageError, self.config.parseOptions, ["--order", "I don't exist"])
class HelpOrderTests(unittest.TestCase):
"""
Tests for the --help-orders flag.
"""
def test_help_ordersPrintsSynopsisAndQuits(self):
"""
--help-orders prints each of the available orders and then exits.
"""
self.patch(sys, "stdout", StringIO.StringIO())
exc = self.assertRaises(
SystemExit, trial.Options().parseOptions, ["--help-orders"])
self.assertEqual(exc.code, 0)
output = sys.stdout.getvalue()
msg = "%r with its description not properly described in %r"
for orderName, (orderDesc, _) in trial._runOrders.items():
match = re.search(
"%s.*%s" % (re.escape(orderName), re.escape(orderDesc)),
output,
)
self.assertTrue(match, msg=msg % (orderName, output))

View file

@ -0,0 +1,162 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for warning suppression features of Trial.
"""
from __future__ import division, absolute_import
import unittest as pyunit
from twisted.trial import unittest
from twisted.trial.test import suppression
class SuppressionMixin(object):
"""
Tests for the warning suppression features of
L{twisted.trial.unittest.SynchronousTestCase}.
"""
def runTests(self, suite):
suite.run(pyunit.TestResult())
def _load(self, cls, methodName):
"""
Return a new L{unittest.TestSuite} with a single test method in it.
@param cls: A L{TestCase} subclass defining a test method.
@param methodName: The name of the test method from C{cls}.
"""
return pyunit.TestSuite([cls(methodName)])
def _assertWarnings(self, warnings, which):
"""
Assert that a certain number of warnings with certain messages were
emitted in a certain order.
@param warnings: A list of emitted warnings, as returned by
C{flushWarnings}.
@param which: A list of strings giving warning messages that should
appear in C{warnings}.
@raise self.failureException: If the warning messages given by C{which}
do not match the messages in the warning information in C{warnings},
or if they do not appear in the same order.
"""
self.assertEqual(
[warning['message'] for warning in warnings],
which)
def test_setUpSuppression(self):
"""
Suppressions defined by the test method being run are applied to any
warnings emitted while running the C{setUp} fixture.
"""
self.runTests(
self._load(self.TestSetUpSuppression, "testSuppressMethod"))
warningsShown = self.flushWarnings([
self.TestSetUpSuppression._emit])
self._assertWarnings(
warningsShown,
[suppression.CLASS_WARNING_MSG, suppression.MODULE_WARNING_MSG,
suppression.CLASS_WARNING_MSG, suppression.MODULE_WARNING_MSG])
def test_tearDownSuppression(self):
"""
Suppressions defined by the test method being run are applied to any
warnings emitted while running the C{tearDown} fixture.
"""
self.runTests(
self._load(self.TestTearDownSuppression, "testSuppressMethod"))
warningsShown = self.flushWarnings([
self.TestTearDownSuppression._emit])
self._assertWarnings(
warningsShown,
[suppression.CLASS_WARNING_MSG, suppression.MODULE_WARNING_MSG,
suppression.CLASS_WARNING_MSG, suppression.MODULE_WARNING_MSG])
def test_suppressMethod(self):
"""
A suppression set on a test method prevents warnings emitted by that
test method which the suppression matches from being emitted.
"""
self.runTests(
self._load(self.TestSuppression, "testSuppressMethod"))
warningsShown = self.flushWarnings([
self.TestSuppression._emit])
self._assertWarnings(
warningsShown,
[suppression.CLASS_WARNING_MSG, suppression.MODULE_WARNING_MSG])
def test_suppressClass(self):
"""
A suppression set on a L{SynchronousTestCase} subclass prevents warnings
emitted by any test methods defined on that class which match the
suppression from being emitted.
"""
self.runTests(
self._load(self.TestSuppression, "testSuppressClass"))
warningsShown = self.flushWarnings([
self.TestSuppression._emit])
self.assertEqual(
warningsShown[0]['message'], suppression.METHOD_WARNING_MSG)
self.assertEqual(
warningsShown[1]['message'], suppression.MODULE_WARNING_MSG)
self.assertEqual(len(warningsShown), 2)
def test_suppressModule(self):
"""
A suppression set on a module prevents warnings emitted by any test
mewthods defined in that module which match the suppression from being
emitted.
"""
self.runTests(
self._load(self.TestSuppression2, "testSuppressModule"))
warningsShown = self.flushWarnings([
self.TestSuppression._emit])
self.assertEqual(
warningsShown[0]['message'], suppression.METHOD_WARNING_MSG)
self.assertEqual(
warningsShown[1]['message'], suppression.CLASS_WARNING_MSG)
self.assertEqual(len(warningsShown), 2)
def test_overrideSuppressClass(self):
"""
The suppression set on a test method completely overrides a suppression
with wider scope; if it does not match a warning emitted by that test
method, the warning is emitted, even if a wider suppression matches.
"""
self.runTests(
self._load(self.TestSuppression, "testOverrideSuppressClass"))
warningsShown = self.flushWarnings([
self.TestSuppression._emit])
self.assertEqual(
warningsShown[0]['message'], suppression.METHOD_WARNING_MSG)
self.assertEqual(
warningsShown[1]['message'], suppression.CLASS_WARNING_MSG)
self.assertEqual(
warningsShown[2]['message'], suppression.MODULE_WARNING_MSG)
self.assertEqual(len(warningsShown), 3)
class SynchronousSuppressionTest(SuppressionMixin, unittest.SynchronousTestCase):
"""
@see: L{twisted.trial.test.test_tests}
"""
from twisted.trial.test.suppression import (
SynchronousTestSetUpSuppression as TestSetUpSuppression,
SynchronousTestTearDownSuppression as TestTearDownSuppression,
SynchronousTestSuppression as TestSuppression,
SynchronousTestSuppression2 as TestSuppression2)

View file

@ -0,0 +1,70 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Direct unit tests for L{twisted.trial.unittest.SynchronousTestCase} and
L{twisted.trial.unittest.TestCase}.
"""
from __future__ import division, absolute_import
from twisted.trial.unittest import SynchronousTestCase, TestCase
class TestCaseMixin(object):
"""
L{TestCase} tests.
"""
def setUp(self):
"""
Create a couple instances of C{MyTestCase}, each for the same test
method, to be used in the test methods of this class.
"""
self.first = self.MyTestCase('test_1')
self.second = self.MyTestCase('test_1')
def test_equality(self):
"""
In order for one test method to be runnable twice, two TestCase
instances with the same test method name must not compare as equal.
"""
self.assertTrue(self.first == self.first)
self.assertTrue(self.first != self.second)
self.assertFalse(self.first == self.second)
def test_hashability(self):
"""
In order for one test method to be runnable twice, two TestCase
instances with the same test method name should not have the same
hash value.
"""
container = {}
container[self.first] = None
container[self.second] = None
self.assertEqual(len(container), 2)
class SynchronousTestCaseTests(TestCaseMixin, SynchronousTestCase):
class MyTestCase(SynchronousTestCase):
"""
Some test methods which can be used to test behaviors of
L{SynchronousTestCase}.
"""
def test_1(self):
pass
# Yes, subclass SynchronousTestCase again. There are no interesting behaviors
# of self being tested below, only of self.MyTestCase.
class AsynchronousTestCaseTests(TestCaseMixin, SynchronousTestCase):
class MyTestCase(TestCase):
"""
Some test methods which can be used to test behaviors of
L{TestCase}.
"""
def test_1(self):
pass

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,780 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
#
"""
Tests for L{twisted.trial.util}
"""
from __future__ import division, absolute_import
import os, sys
from zope.interface import implementer
from twisted.python.compat import _PY3, NativeStringIO
from twisted.python import filepath
from twisted.internet.interfaces import IProcessTransport
from twisted.internet import defer
from twisted.internet.base import DelayedCall
from twisted.python.failure import Failure
from twisted.trial.unittest import SynchronousTestCase
from twisted.trial import util
from twisted.trial.util import (
DirtyReactorAggregateError, _Janitor, excInfoOrFailureToExcInfo,
acquireAttribute)
from twisted.trial.test import suppression
class TestMktemp(SynchronousTestCase):
"""
Tests for L{TestCase.mktemp}, a helper function for creating temporary file
or directory names.
"""
def test_name(self):
"""
The path name returned by C{mktemp} is directly beneath a directory
which identifies the test method which created the name.
"""
name = self.mktemp()
dirs = os.path.dirname(name).split(os.sep)[:-1]
self.assertEqual(
dirs, ['twisted.trial.test.test_util', 'TestMktemp', 'test_name'])
def test_unique(self):
"""
Repeated calls to C{mktemp} return different values.
"""
name = self.mktemp()
self.assertNotEqual(name, self.mktemp())
def test_created(self):
"""
The directory part of the path name returned by C{mktemp} exists.
"""
name = self.mktemp()
dirname = os.path.dirname(name)
self.assertTrue(os.path.exists(dirname))
self.assertFalse(os.path.exists(name))
def test_location(self):
"""
The path returned by C{mktemp} is beneath the current working directory.
"""
path = os.path.abspath(self.mktemp())
self.assertTrue(path.startswith(os.getcwd()))
class TestIntrospection(SynchronousTestCase):
def test_containers(self):
"""
When pased a test case, L{util.getPythonContainers} returns a list
including the test case and the module the test case is defined in.
"""
parents = util.getPythonContainers(
suppression.SynchronousTestSuppression2.testSuppressModule)
expected = [suppression.SynchronousTestSuppression2, suppression]
for a, b in zip(parents, expected):
self.assertEqual(a, b)
# Also, the function is deprecated.
warnings = self.flushWarnings([self.test_containers])
self.assertEqual(DeprecationWarning, warnings[0]['category'])
self.assertEqual(
"twisted.trial.util.getPythonContainers was deprecated in "
"Twisted 12.3.0: This function never worked correctly. "
"Implement lookup on your own.",
warnings[0]['message'])
self.assertEqual(1, len(warnings))
if _PY3:
test_containers.skip = "getPythonContainers is unsupported on Python 3."
class TestRunSequentially(SynchronousTestCase):
"""
Sometimes it is useful to be able to run an arbitrary list of callables,
one after the other.
When some of those callables can return Deferreds, things become complex.
"""
def assertDeferredResult(self, deferred, assertFunction, *args, **kwargs):
"""
Call the given assertion function against the current result of a
Deferred.
"""
result = []
deferred.addCallback(result.append)
assertFunction(result[0], *args, **kwargs)
def test_emptyList(self):
"""
When asked to run an empty list of callables, runSequentially returns a
successful Deferred that fires an empty list.
"""
d = util._runSequentially([])
self.assertDeferredResult(d, self.assertEqual, [])
def test_singleSynchronousSuccess(self):
"""
When given a callable that succeeds without returning a Deferred,
include the return value in the results list, tagged with a SUCCESS
flag.
"""
d = util._runSequentially([lambda: None])
self.assertDeferredResult(d, self.assertEqual, [(defer.SUCCESS, None)])
def test_singleSynchronousFailure(self):
"""
When given a callable that raises an exception, include a Failure for
that exception in the results list, tagged with a FAILURE flag.
"""
d = util._runSequentially([lambda: self.fail('foo')])
def check(results):
[(flag, fail)] = results
fail.trap(self.failureException)
self.assertEqual(fail.getErrorMessage(), 'foo')
self.assertEqual(flag, defer.FAILURE)
self.assertDeferredResult(d, check)
def test_singleAsynchronousSuccess(self):
"""
When given a callable that returns a successful Deferred, include the
result of the Deferred in the results list, tagged with a SUCCESS flag.
"""
d = util._runSequentially([lambda: defer.succeed(None)])
self.assertDeferredResult(d, self.assertEqual, [(defer.SUCCESS, None)])
def test_singleAsynchronousFailure(self):
"""
When given a callable that returns a failing Deferred, include the
failure the results list, tagged with a FAILURE flag.
"""
d = util._runSequentially([lambda: defer.fail(ValueError('foo'))])
def check(results):
[(flag, fail)] = results
fail.trap(ValueError)
self.assertEqual(fail.getErrorMessage(), 'foo')
self.assertEqual(flag, defer.FAILURE)
self.assertDeferredResult(d, check)
def test_callablesCalledInOrder(self):
"""
Check that the callables are called in the given order, one after the
other.
"""
log = []
deferreds = []
def append(value):
d = defer.Deferred()
log.append(value)
deferreds.append(d)
return d
util._runSequentially([lambda: append('foo'),
lambda: append('bar')])
# runSequentially should wait until the Deferred has fired before
# running the second callable.
self.assertEqual(log, ['foo'])
deferreds[-1].callback(None)
self.assertEqual(log, ['foo', 'bar'])
def test_continuesAfterError(self):
"""
If one of the callables raises an error, then runSequentially continues
to run the remaining callables.
"""
d = util._runSequentially([lambda: self.fail('foo'), lambda: 'bar'])
def check(results):
[(flag1, fail), (flag2, result)] = results
fail.trap(self.failureException)
self.assertEqual(flag1, defer.FAILURE)
self.assertEqual(fail.getErrorMessage(), 'foo')
self.assertEqual(flag2, defer.SUCCESS)
self.assertEqual(result, 'bar')
self.assertDeferredResult(d, check)
def test_stopOnFirstError(self):
"""
If the C{stopOnFirstError} option is passed to C{runSequentially}, then
no further callables are called after the first exception is raised.
"""
d = util._runSequentially([lambda: self.fail('foo'), lambda: 'bar'],
stopOnFirstError=True)
def check(results):
[(flag1, fail)] = results
fail.trap(self.failureException)
self.assertEqual(flag1, defer.FAILURE)
self.assertEqual(fail.getErrorMessage(), 'foo')
self.assertDeferredResult(d, check)
class DirtyReactorAggregateErrorTest(SynchronousTestCase):
"""
Tests for the L{DirtyReactorAggregateError}.
"""
def test_formatDelayedCall(self):
"""
Delayed calls are formatted nicely.
"""
error = DirtyReactorAggregateError(["Foo", "bar"])
self.assertEqual(str(error),
"""\
Reactor was unclean.
DelayedCalls: (set twisted.internet.base.DelayedCall.debug = True to debug)
Foo
bar""")
def test_formatSelectables(self):
"""
Selectables are formatted nicely.
"""
error = DirtyReactorAggregateError([], ["selectable 1", "selectable 2"])
self.assertEqual(str(error),
"""\
Reactor was unclean.
Selectables:
selectable 1
selectable 2""")
def test_formatDelayedCallsAndSelectables(self):
"""
Both delayed calls and selectables can appear in the same error.
"""
error = DirtyReactorAggregateError(["bleck", "Boozo"],
["Sel1", "Sel2"])
self.assertEqual(str(error),
"""\
Reactor was unclean.
DelayedCalls: (set twisted.internet.base.DelayedCall.debug = True to debug)
bleck
Boozo
Selectables:
Sel1
Sel2""")
class StubReactor(object):
"""
A reactor stub which contains enough functionality to be used with the
L{_Janitor}.
@ivar iterations: A list of the arguments passed to L{iterate}.
@ivar removeAllCalled: Number of times that L{removeAll} was called.
@ivar selectables: The value that will be returned from L{removeAll}.
@ivar delayedCalls: The value to return from L{getDelayedCalls}.
"""
def __init__(self, delayedCalls, selectables=None):
"""
@param delayedCalls: See L{StubReactor.delayedCalls}.
@param selectables: See L{StubReactor.selectables}.
"""
self.delayedCalls = delayedCalls
self.iterations = []
self.removeAllCalled = 0
if not selectables:
selectables = []
self.selectables = selectables
def iterate(self, timeout=None):
"""
Increment C{self.iterations}.
"""
self.iterations.append(timeout)
def getDelayedCalls(self):
"""
Return C{self.delayedCalls}.
"""
return self.delayedCalls
def removeAll(self):
"""
Increment C{self.removeAllCalled} and return C{self.selectables}.
"""
self.removeAllCalled += 1
return self.selectables
class StubErrorReporter(object):
"""
A subset of L{twisted.trial.itrial.IReporter} which records L{addError}
calls.
@ivar errors: List of two-tuples of (test, error) which were passed to
L{addError}.
"""
def __init__(self):
self.errors = []
def addError(self, test, error):
"""
Record parameters in C{self.errors}.
"""
self.errors.append((test, error))
class JanitorTests(SynchronousTestCase):
"""
Tests for L{_Janitor}!
"""
def test_cleanPendingSpinsReactor(self):
"""
During pending-call cleanup, the reactor will be spun twice with an
instant timeout. This is not a requirement, it is only a test for
current behavior. Hopefully Trial will eventually not do this kind of
reactor stuff.
"""
reactor = StubReactor([])
jan = _Janitor(None, None, reactor=reactor)
jan._cleanPending()
self.assertEqual(reactor.iterations, [0, 0])
def test_cleanPendingCancelsCalls(self):
"""
During pending-call cleanup, the janitor cancels pending timed calls.
"""
def func():
return "Lulz"
cancelled = []
delayedCall = DelayedCall(300, func, (), {},
cancelled.append, lambda x: None)
reactor = StubReactor([delayedCall])
jan = _Janitor(None, None, reactor=reactor)
jan._cleanPending()
self.assertEqual(cancelled, [delayedCall])
def test_cleanPendingReturnsDelayedCallStrings(self):
"""
The Janitor produces string representations of delayed calls from the
delayed call cleanup method. It gets the string representations
*before* cancelling the calls; this is important because cancelling the
call removes critical debugging information from the string
representation.
"""
delayedCall = DelayedCall(300, lambda: None, (), {},
lambda x: None, lambda x: None,
seconds=lambda: 0)
delayedCallString = str(delayedCall)
reactor = StubReactor([delayedCall])
jan = _Janitor(None, None, reactor=reactor)
strings = jan._cleanPending()
self.assertEqual(strings, [delayedCallString])
def test_cleanReactorRemovesSelectables(self):
"""
The Janitor will remove selectables during reactor cleanup.
"""
reactor = StubReactor([])
jan = _Janitor(None, None, reactor=reactor)
jan._cleanReactor()
self.assertEqual(reactor.removeAllCalled, 1)
def test_cleanReactorKillsProcesses(self):
"""
The Janitor will kill processes during reactor cleanup.
"""
@implementer(IProcessTransport)
class StubProcessTransport(object):
"""
A stub L{IProcessTransport} provider which records signals.
@ivar signals: The signals passed to L{signalProcess}.
"""
def __init__(self):
self.signals = []
def signalProcess(self, signal):
"""
Append C{signal} to C{self.signals}.
"""
self.signals.append(signal)
pt = StubProcessTransport()
reactor = StubReactor([], [pt])
jan = _Janitor(None, None, reactor=reactor)
jan._cleanReactor()
self.assertEqual(pt.signals, ["KILL"])
def test_cleanReactorReturnsSelectableStrings(self):
"""
The Janitor returns string representations of the selectables that it
cleaned up from the reactor cleanup method.
"""
class Selectable(object):
"""
A stub Selectable which only has an interesting string
representation.
"""
def __repr__(self):
return "(SELECTABLE!)"
reactor = StubReactor([], [Selectable()])
jan = _Janitor(None, None, reactor=reactor)
self.assertEqual(jan._cleanReactor(), ["(SELECTABLE!)"])
def test_postCaseCleanupNoErrors(self):
"""
The post-case cleanup method will return True and not call C{addError}
on the result if there are no pending calls.
"""
reactor = StubReactor([])
test = object()
reporter = StubErrorReporter()
jan = _Janitor(test, reporter, reactor=reactor)
self.assertTrue(jan.postCaseCleanup())
self.assertEqual(reporter.errors, [])
def test_postCaseCleanupWithErrors(self):
"""
The post-case cleanup method will return False and call C{addError} on
the result with a L{DirtyReactorAggregateError} Failure if there are
pending calls.
"""
delayedCall = DelayedCall(300, lambda: None, (), {},
lambda x: None, lambda x: None,
seconds=lambda: 0)
delayedCallString = str(delayedCall)
reactor = StubReactor([delayedCall], [])
test = object()
reporter = StubErrorReporter()
jan = _Janitor(test, reporter, reactor=reactor)
self.assertFalse(jan.postCaseCleanup())
self.assertEqual(len(reporter.errors), 1)
self.assertEqual(reporter.errors[0][1].value.delayedCalls,
[delayedCallString])
def test_postClassCleanupNoErrors(self):
"""
The post-class cleanup method will not call C{addError} on the result
if there are no pending calls or selectables.
"""
reactor = StubReactor([])
test = object()
reporter = StubErrorReporter()
jan = _Janitor(test, reporter, reactor=reactor)
jan.postClassCleanup()
self.assertEqual(reporter.errors, [])
def test_postClassCleanupWithPendingCallErrors(self):
"""
The post-class cleanup method call C{addError} on the result with a
L{DirtyReactorAggregateError} Failure if there are pending calls.
"""
delayedCall = DelayedCall(300, lambda: None, (), {},
lambda x: None, lambda x: None,
seconds=lambda: 0)
delayedCallString = str(delayedCall)
reactor = StubReactor([delayedCall], [])
test = object()
reporter = StubErrorReporter()
jan = _Janitor(test, reporter, reactor=reactor)
jan.postClassCleanup()
self.assertEqual(len(reporter.errors), 1)
self.assertEqual(reporter.errors[0][1].value.delayedCalls,
[delayedCallString])
def test_postClassCleanupWithSelectableErrors(self):
"""
The post-class cleanup method call C{addError} on the result with a
L{DirtyReactorAggregateError} Failure if there are selectables.
"""
selectable = "SELECTABLE HERE"
reactor = StubReactor([], [selectable])
test = object()
reporter = StubErrorReporter()
jan = _Janitor(test, reporter, reactor=reactor)
jan.postClassCleanup()
self.assertEqual(len(reporter.errors), 1)
self.assertEqual(reporter.errors[0][1].value.selectables,
[repr(selectable)])
class RemoveSafelyTests(SynchronousTestCase):
"""
Tests for L{util._removeSafely}.
"""
def test_removeSafelyNoTrialMarker(self):
"""
If a path doesn't contain a node named C{"_trial_marker"}, that path is
not removed by L{util._removeSafely} and a L{util._NoTrialMarker}
exception is raised instead.
"""
directory = self.mktemp().encode("utf-8")
os.mkdir(directory)
dirPath = filepath.FilePath(directory)
self.assertRaises(util._NoTrialMarker, util._removeSafely, dirPath)
def test_removeSafelyRemoveFailsMoveSucceeds(self):
"""
If an L{OSError} is raised while removing a path in
L{util._removeSafely}, an attempt is made to move the path to a new
name.
"""
def dummyRemove():
"""
Raise an C{OSError} to emulate the branch of L{util._removeSafely}
in which path removal fails.
"""
raise OSError()
# Patch stdout so we can check the print statements in _removeSafely
out = NativeStringIO()
self.patch(sys, 'stdout', out)
# Set up a trial directory with a _trial_marker
directory = self.mktemp().encode("utf-8")
os.mkdir(directory)
dirPath = filepath.FilePath(directory)
dirPath.child(b'_trial_marker').touch()
# Ensure that path.remove() raises an OSError
dirPath.remove = dummyRemove
util._removeSafely(dirPath)
self.assertIn("could not remove FilePath", out.getvalue())
def test_removeSafelyRemoveFailsMoveFails(self):
"""
If an L{OSError} is raised while removing a path in
L{util._removeSafely}, an attempt is made to move the path to a new
name. If that attempt fails, the L{OSError} is re-raised.
"""
def dummyRemove():
"""
Raise an C{OSError} to emulate the branch of L{util._removeSafely}
in which path removal fails.
"""
raise OSError("path removal failed")
def dummyMoveTo(path):
"""
Raise an C{OSError} to emulate the branch of L{util._removeSafely}
in which path movement fails.
"""
raise OSError("path movement failed")
# Patch stdout so we can check the print statements in _removeSafely
out = NativeStringIO()
self.patch(sys, 'stdout', out)
# Set up a trial directory with a _trial_marker
directory = self.mktemp().encode("utf-8")
os.mkdir(directory)
dirPath = filepath.FilePath(directory)
dirPath.child(b'_trial_marker').touch()
# Ensure that path.remove() and path.moveTo() both raise OSErrors
dirPath.remove = dummyRemove
dirPath.moveTo = dummyMoveTo
error = self.assertRaises(OSError, util._removeSafely, dirPath)
self.assertEqual(str(error), "path movement failed")
self.assertIn("could not remove FilePath", out.getvalue())
class ExcInfoTests(SynchronousTestCase):
"""
Tests for L{excInfoOrFailureToExcInfo}.
"""
def test_excInfo(self):
"""
L{excInfoOrFailureToExcInfo} returns exactly what it is passed, if it is
passed a tuple like the one returned by L{sys.exc_info}.
"""
info = (ValueError, ValueError("foo"), None)
self.assertTrue(info is excInfoOrFailureToExcInfo(info))
def test_failure(self):
"""
When called with a L{Failure} instance, L{excInfoOrFailureToExcInfo}
returns a tuple like the one returned by L{sys.exc_info}, with the
elements taken from the type, value, and traceback of the failure.
"""
try:
1 / 0
except:
f = Failure()
self.assertEqual((f.type, f.value, f.tb), excInfoOrFailureToExcInfo(f))
class AcquireAttributeTests(SynchronousTestCase):
"""
Tests for L{acquireAttribute}.
"""
def test_foundOnEarlierObject(self):
"""
The value returned by L{acquireAttribute} is the value of the requested
attribute on the first object in the list passed in which has that
attribute.
"""
self.value = value = object()
self.assertTrue(value is acquireAttribute([self, object()], "value"))
def test_foundOnLaterObject(self):
"""
The same as L{test_foundOnEarlierObject}, but for the case where the 2nd
element in the object list has the attribute and the first does not.
"""
self.value = value = object()
self.assertTrue(value is acquireAttribute([object(), self], "value"))
def test_notFoundException(self):
"""
If none of the objects passed in the list to L{acquireAttribute} have
the requested attribute, L{AttributeError} is raised.
"""
self.assertRaises(AttributeError, acquireAttribute, [object()], "foo")
def test_notFoundDefault(self):
"""
If none of the objects passed in the list to L{acquireAttribute} have
the requested attribute and a default value is given, the default value
is returned.
"""
default = object()
self.assertTrue(default is acquireAttribute([object()], "foo", default))
class TestListToPhrase(SynchronousTestCase):
"""
Input is transformed into a string representation of the list,
with each item separated by delimiter (defaulting to a comma) and the final
two being separated by a final delimiter.
"""
def test_empty(self):
"""
If things is empty, an empty string is returned.
"""
sample = []
expected = ''
result = util._listToPhrase(sample, 'and')
self.assertEqual(expected, result)
def test_oneWord(self):
"""
With a single item, the item is returned.
"""
sample = ['One']
expected = 'One'
result = util._listToPhrase(sample, 'and')
self.assertEqual(expected, result)
def test_twoWords(self):
"""
Two words are separated by the final delimiter.
"""
sample = ['One', 'Two']
expected = 'One and Two'
result = util._listToPhrase(sample, 'and')
self.assertEqual(expected, result)
def test_threeWords(self):
"""
With more than two words, the first two are separated by the delimiter.
"""
sample = ['One', 'Two', 'Three']
expected = 'One, Two, and Three'
result = util._listToPhrase(sample, 'and')
self.assertEqual(expected, result)
def test_fourWords(self):
"""
If a delimiter is specified, it is used instead of the default comma.
"""
sample = ['One', 'Two', 'Three', 'Four']
expected = 'One; Two; Three; or Four'
result = util._listToPhrase(sample, 'or', delimiter='; ')
self.assertEqual(expected, result)
def test_notString(self):
"""
If something in things is not a string, it is converted into one.
"""
sample = [1, 2, 'three']
expected = '1, 2, and three'
result = util._listToPhrase(sample, 'and')
self.assertEqual(expected, result)
def test_stringTypeError(self):
"""
If things is a string, a TypeError is raised.
"""
sample = "One, two, three"
error = self.assertRaises(TypeError, util._listToPhrase, sample, 'and')
self.assertEqual(str(error), "Things must be a list or a tuple")
def test_iteratorTypeError(self):
"""
If things is an iterator, a TypeError is raised.
"""
sample = iter([1, 2, 3])
error = self.assertRaises(TypeError, util._listToPhrase, sample, 'and')
self.assertEqual(str(error), "Things must be a list or a tuple")
def test_generatorTypeError(self):
"""
If things is a generator, a TypeError is raised.
"""
def sample():
for i in range(2):
yield i
error = self.assertRaises(TypeError, util._listToPhrase, sample, 'and')
self.assertEqual(str(error), "Things must be a list or a tuple")

View file

@ -0,0 +1,491 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for Trial's interaction with the Python warning system.
"""
from __future__ import division, absolute_import
import sys, warnings
from unittest import TestResult
from twisted.python.compat import NativeStringIO as StringIO
from twisted.python.filepath import FilePath
from twisted.trial.unittest import (
SynchronousTestCase, _collectWarnings, _setWarningRegistryToNone)
class Mask(object):
"""
Hide a test case definition from trial's automatic discovery mechanism.
"""
class MockTests(SynchronousTestCase):
"""
A test case which is used by L{FlushWarningsTests} to verify behavior
which cannot be verified by code inside a single test method.
"""
message = "some warning text"
category = UserWarning
def test_unflushed(self):
"""
Generate a warning and don't flush it.
"""
warnings.warn(self.message, self.category)
def test_flushed(self):
"""
Generate a warning and flush it.
"""
warnings.warn(self.message, self.category)
self.assertEqual(len(self.flushWarnings()), 1)
class FlushWarningsTests(SynchronousTestCase):
"""
Tests for C{flushWarnings}, an API for examining the warnings
emitted so far in a test.
"""
def assertDictSubset(self, set, subset):
"""
Assert that all the keys present in C{subset} are also present in
C{set} and that the corresponding values are equal.
"""
for k, v in subset.items():
self.assertEqual(set[k], v)
def assertDictSubsets(self, sets, subsets):
"""
For each pair of corresponding elements in C{sets} and C{subsets},
assert that the element from C{subsets} is a subset of the element from
C{sets}.
"""
self.assertEqual(len(sets), len(subsets))
for a, b in zip(sets, subsets):
self.assertDictSubset(a, b)
def test_none(self):
"""
If no warnings are emitted by a test, C{flushWarnings} returns an empty
list.
"""
self.assertEqual(self.flushWarnings(), [])
def test_several(self):
"""
If several warnings are emitted by a test, C{flushWarnings} returns a
list containing all of them.
"""
firstMessage = "first warning message"
firstCategory = UserWarning
warnings.warn(message=firstMessage, category=firstCategory)
secondMessage = "second warning message"
secondCategory = RuntimeWarning
warnings.warn(message=secondMessage, category=secondCategory)
self.assertDictSubsets(
self.flushWarnings(),
[{'category': firstCategory, 'message': firstMessage},
{'category': secondCategory, 'message': secondMessage}])
def test_repeated(self):
"""
The same warning triggered twice from the same place is included twice
in the list returned by C{flushWarnings}.
"""
message = "the message"
category = RuntimeWarning
for i in range(2):
warnings.warn(message=message, category=category)
self.assertDictSubsets(
self.flushWarnings(),
[{'category': category, 'message': message}] * 2)
def test_cleared(self):
"""
After a particular warning event has been returned by C{flushWarnings},
it is not returned by subsequent calls.
"""
message = "the message"
category = RuntimeWarning
warnings.warn(message=message, category=category)
self.assertDictSubsets(
self.flushWarnings(),
[{'category': category, 'message': message}])
self.assertEqual(self.flushWarnings(), [])
def test_unflushed(self):
"""
Any warnings emitted by a test which are not flushed are emitted to the
Python warning system.
"""
result = TestResult()
case = Mask.MockTests('test_unflushed')
case.run(result)
warningsShown = self.flushWarnings([Mask.MockTests.test_unflushed])
self.assertEqual(warningsShown[0]['message'], 'some warning text')
self.assertIdentical(warningsShown[0]['category'], UserWarning)
where = type(case).test_unflushed.__code__
filename = where.co_filename
# If someone edits MockTests.test_unflushed, the value added to
# firstlineno might need to change.
lineno = where.co_firstlineno + 4
self.assertEqual(warningsShown[0]['filename'], filename)
self.assertEqual(warningsShown[0]['lineno'], lineno)
self.assertEqual(len(warningsShown), 1)
def test_flushed(self):
"""
Any warnings emitted by a test which are flushed are not emitted to the
Python warning system.
"""
result = TestResult()
case = Mask.MockTests('test_flushed')
output = StringIO()
monkey = self.patch(sys, 'stdout', output)
case.run(result)
monkey.restore()
self.assertEqual(output.getvalue(), "")
def test_warningsConfiguredAsErrors(self):
"""
If a warnings filter has been installed which turns warnings into
exceptions, tests have an error added to the reporter for them for each
unflushed warning.
"""
class CustomWarning(Warning):
pass
result = TestResult()
case = Mask.MockTests('test_unflushed')
case.category = CustomWarning
originalWarnings = warnings.filters[:]
try:
warnings.simplefilter('error')
case.run(result)
self.assertEqual(len(result.errors), 1)
self.assertIdentical(result.errors[0][0], case)
self.assertTrue(
# Different python versions differ in whether they report the
# fully qualified class name or just the class name.
result.errors[0][1].splitlines()[-1].endswith(
"CustomWarning: some warning text"))
finally:
warnings.filters[:] = originalWarnings
def test_flushedWarningsConfiguredAsErrors(self):
"""
If a warnings filter has been installed which turns warnings into
exceptions, tests which emit those warnings but flush them do not have
an error added to the reporter.
"""
class CustomWarning(Warning):
pass
result = TestResult()
case = Mask.MockTests('test_flushed')
case.category = CustomWarning
originalWarnings = warnings.filters[:]
try:
warnings.simplefilter('error')
case.run(result)
self.assertEqual(result.errors, [])
finally:
warnings.filters[:] = originalWarnings
def test_multipleFlushes(self):
"""
Any warnings emitted after a call to C{flushWarnings} can be flushed by
another call to C{flushWarnings}.
"""
warnings.warn("first message")
self.assertEqual(len(self.flushWarnings()), 1)
warnings.warn("second message")
self.assertEqual(len(self.flushWarnings()), 1)
def test_filterOnOffendingFunction(self):
"""
The list returned by C{flushWarnings} includes only those
warnings which refer to the source of the function passed as the value
for C{offendingFunction}, if a value is passed for that parameter.
"""
firstMessage = "first warning text"
firstCategory = UserWarning
def one():
warnings.warn(firstMessage, firstCategory, stacklevel=1)
secondMessage = "some text"
secondCategory = RuntimeWarning
def two():
warnings.warn(secondMessage, secondCategory, stacklevel=1)
one()
two()
self.assertDictSubsets(
self.flushWarnings(offendingFunctions=[one]),
[{'category': firstCategory, 'message': firstMessage}])
self.assertDictSubsets(
self.flushWarnings(offendingFunctions=[two]),
[{'category': secondCategory, 'message': secondMessage}])
def test_functionBoundaries(self):
"""
Verify that warnings emitted at the very edges of a function are still
determined to be emitted from that function.
"""
def warner():
warnings.warn("first line warning")
warnings.warn("internal line warning")
warnings.warn("last line warning")
warner()
self.assertEqual(
len(self.flushWarnings(offendingFunctions=[warner])), 3)
def test_invalidFilter(self):
"""
If an object which is neither a function nor a method is included in the
C{offendingFunctions} list, C{flushWarnings} raises L{ValueError}. Such
a call flushes no warnings.
"""
warnings.warn("oh no")
self.assertRaises(ValueError, self.flushWarnings, [None])
self.assertEqual(len(self.flushWarnings()), 1)
def test_missingSource(self):
"""
Warnings emitted by a function the source code of which is not
available can still be flushed.
"""
package = FilePath(self.mktemp().encode('utf-8')).child(b'twisted_private_helper')
package.makedirs()
package.child(b'__init__.py').setContent(b'')
package.child(b'missingsourcefile.py').setContent(b'''
import warnings
def foo():
warnings.warn("oh no")
''')
pathEntry = package.parent().path.decode('utf-8')
sys.path.insert(0, pathEntry)
self.addCleanup(sys.path.remove, pathEntry)
from twisted_private_helper import missingsourcefile
self.addCleanup(sys.modules.pop, 'twisted_private_helper')
self.addCleanup(sys.modules.pop, missingsourcefile.__name__)
package.child(b'missingsourcefile.py').remove()
missingsourcefile.foo()
self.assertEqual(len(self.flushWarnings([missingsourcefile.foo])), 1)
def test_renamedSource(self):
"""
Warnings emitted by a function defined in a file which has been renamed
since it was initially compiled can still be flushed.
This is testing the code which specifically supports working around the
unfortunate behavior of CPython to write a .py source file name into
the .pyc files it generates and then trust that it is correct in
various places. If source files are renamed, .pyc files may not be
regenerated, but they will contain incorrect filenames.
"""
package = FilePath(self.mktemp().encode('utf-8')).child(b'twisted_private_helper')
package.makedirs()
package.child(b'__init__.py').setContent(b'')
package.child(b'module.py').setContent(b'''
import warnings
def foo():
warnings.warn("oh no")
''')
pathEntry = package.parent().path.decode('utf-8')
sys.path.insert(0, pathEntry)
self.addCleanup(sys.path.remove, pathEntry)
# Import it to cause pycs to be generated
from twisted_private_helper import module
# Clean up the state resulting from that import; we're not going to use
# this module, so it should go away.
del sys.modules['twisted_private_helper']
del sys.modules[module.__name__]
# Some Python versions have extra state related to the just
# imported/renamed package. Clean it up too. See also
# http://bugs.python.org/issue15912
try:
from importlib import invalidate_caches
except ImportError:
pass
else:
invalidate_caches()
# Rename the source directory
package.moveTo(package.sibling(b'twisted_renamed_helper'))
# Import the newly renamed version
from twisted_renamed_helper import module
self.addCleanup(sys.modules.pop, 'twisted_renamed_helper')
self.addCleanup(sys.modules.pop, module.__name__)
# Generate the warning
module.foo()
# Flush it
self.assertEqual(len(self.flushWarnings([module.foo])), 1)
class FakeWarning(Warning):
pass
class CollectWarningsTests(SynchronousTestCase):
"""
Tests for L{_collectWarnings}.
"""
def test_callsObserver(self):
"""
L{_collectWarnings} calls the observer with each emitted warning.
"""
firstMessage = "dummy calls observer warning"
secondMessage = firstMessage[::-1]
events = []
def f():
events.append('call')
warnings.warn(firstMessage)
warnings.warn(secondMessage)
events.append('returning')
_collectWarnings(events.append, f)
self.assertEqual(events[0], 'call')
self.assertEqual(events[1].message, firstMessage)
self.assertEqual(events[2].message, secondMessage)
self.assertEqual(events[3], 'returning')
self.assertEqual(len(events), 4)
def test_suppresses(self):
"""
Any warnings emitted by a call to a function passed to
L{_collectWarnings} are not actually emitted to the warning system.
"""
output = StringIO()
self.patch(sys, 'stdout', output)
_collectWarnings(lambda x: None, warnings.warn, "text")
self.assertEqual(output.getvalue(), "")
def test_callsFunction(self):
"""
L{_collectWarnings} returns the result of calling the callable passed to
it with the parameters given.
"""
arguments = []
value = object()
def f(*args, **kwargs):
arguments.append((args, kwargs))
return value
result = _collectWarnings(lambda x: None, f, 1, 'a', b=2, c='d')
self.assertEqual(arguments, [((1, 'a'), {'b': 2, 'c': 'd'})])
self.assertIdentical(result, value)
def test_duplicateWarningCollected(self):
"""
Subsequent emissions of a warning from a particular source site can be
collected by L{_collectWarnings}. In particular, the per-module
emitted-warning cache should be bypassed (I{__warningregistry__}).
"""
# Make sure the worst case is tested: if __warningregistry__ isn't in a
# module's globals, then the warning system will add it and start using
# it to avoid emitting duplicate warnings. Delete __warningregistry__
# to ensure that even modules which are first imported as a test is
# running still interact properly with the warning system.
global __warningregistry__
del __warningregistry__
def f():
warnings.warn("foo")
warnings.simplefilter('default')
f()
events = []
_collectWarnings(events.append, f)
self.assertEqual(len(events), 1)
self.assertEqual(events[0].message, "foo")
self.assertEqual(len(self.flushWarnings()), 1)
def test_immutableObject(self):
"""
L{_collectWarnings}'s behavior is not altered by the presence of an
object which cannot have attributes set on it as a value in
C{sys.modules}.
"""
key = object()
sys.modules[key] = key
self.addCleanup(sys.modules.pop, key)
self.test_duplicateWarningCollected()
def test_setWarningRegistryChangeWhileIterating(self):
"""
If the dictionary passed to L{_setWarningRegistryToNone} changes size
partway through the process, C{_setWarningRegistryToNone} continues to
set C{__warningregistry__} to C{None} on the rest of the values anyway.
This might be caused by C{sys.modules} containing something that's not
really a module and imports things on setattr. py.test does this, as
does L{twisted.python.deprecate.deprecatedModuleAttribute}.
"""
d = {}
class A(object):
def __init__(self, key):
self.__dict__['_key'] = key
def __setattr__(self, value, item):
d[self._key] = None
key1 = object()
key2 = object()
d[key1] = A(key2)
key3 = object()
key4 = object()
d[key3] = A(key4)
_setWarningRegistryToNone(d)
# If both key2 and key4 were added, then both A instanced were
# processed.
self.assertEqual(set([key1, key2, key3, key4]), set(d.keys()))

View file

@ -0,0 +1,23 @@
from __future__ import division, absolute_import
import unittest
from twisted.internet import defer
# Used in test_tests.TestUnhandledDeferred
class TestBleeding(unittest.TestCase):
"""This test creates an unhandled Deferred and leaves it in a cycle.
The Deferred is left in a cycle so that the garbage collector won't pick it
up immediately. We were having some problems where unhandled Deferreds in
one test were failing random other tests. (See #1507, #1213)
"""
def test_unhandledDeferred(self):
try:
1/0
except ZeroDivisionError:
f = defer.fail()
# these two lines create the cycle. don't remove them
l = [f]
l.append(l)