1040 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1040 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# Copyright (c) 2008-2011 testtools developers. See LICENSE for details.
 | 
						|
 | 
						|
"""Test case related stuff."""
 | 
						|
 | 
						|
__metaclass__ = type
 | 
						|
__all__ = [
 | 
						|
    'attr',
 | 
						|
    'clone_test_with_new_id',
 | 
						|
    'ExpectedException',
 | 
						|
    'gather_details',
 | 
						|
    'run_test_with',
 | 
						|
    'skip',
 | 
						|
    'skipIf',
 | 
						|
    'skipUnless',
 | 
						|
    'TestCase',
 | 
						|
    ]
 | 
						|
 | 
						|
import copy
 | 
						|
import functools
 | 
						|
import itertools
 | 
						|
import sys
 | 
						|
import types
 | 
						|
import warnings
 | 
						|
 | 
						|
from extras import (
 | 
						|
    safe_hasattr,
 | 
						|
    try_import,
 | 
						|
    try_imports,
 | 
						|
    )
 | 
						|
# To let setup.py work, make this a conditional import.
 | 
						|
unittest = try_imports(['unittest2', 'unittest'])
 | 
						|
 | 
						|
from testtools import (
 | 
						|
    content,
 | 
						|
    )
 | 
						|
from testtools.compat import (
 | 
						|
    advance_iterator,
 | 
						|
    reraise,
 | 
						|
    )
 | 
						|
from testtools.matchers import (
 | 
						|
    Annotate,
 | 
						|
    Contains,
 | 
						|
    Equals,
 | 
						|
    MatchesAll,
 | 
						|
    MatchesException,
 | 
						|
    MismatchError,
 | 
						|
    Is,
 | 
						|
    IsInstance,
 | 
						|
    Not,
 | 
						|
    Raises,
 | 
						|
    )
 | 
						|
from testtools.matchers._basic import _FlippedEquals
 | 
						|
from testtools.monkey import patch
 | 
						|
from testtools.runtest import RunTest
 | 
						|
from testtools.testresult import (
 | 
						|
    ExtendedToOriginalDecorator,
 | 
						|
    TestResult,
 | 
						|
    )
 | 
						|
 | 
						|
wraps = try_import('functools.wraps')
 | 
						|
 | 
						|
class TestSkipped(Exception):
 | 
						|
    """Raised within TestCase.run() when a test is skipped."""
 | 
						|
TestSkipped = try_import('unittest.case.SkipTest', TestSkipped)
 | 
						|
TestSkipped = try_import('unittest2.case.SkipTest', TestSkipped)
 | 
						|
 | 
						|
 | 
						|
class _UnexpectedSuccess(Exception):
 | 
						|
    """An unexpected success was raised.
 | 
						|
 | 
						|
    Note that this exception is private plumbing in testtools' testcase
 | 
						|
    module.
 | 
						|
    """
 | 
						|
_UnexpectedSuccess = try_import(
 | 
						|
    'unittest.case._UnexpectedSuccess', _UnexpectedSuccess)
 | 
						|
_UnexpectedSuccess = try_import(
 | 
						|
    'unittest2.case._UnexpectedSuccess', _UnexpectedSuccess)
 | 
						|
 | 
						|
class _ExpectedFailure(Exception):
 | 
						|
    """An expected failure occured.
 | 
						|
 | 
						|
    Note that this exception is private plumbing in testtools' testcase
 | 
						|
    module.
 | 
						|
    """
 | 
						|
_ExpectedFailure = try_import(
 | 
						|
    'unittest.case._ExpectedFailure', _ExpectedFailure)
 | 
						|
_ExpectedFailure = try_import(
 | 
						|
    'unittest2.case._ExpectedFailure', _ExpectedFailure)
 | 
						|
 | 
						|
 | 
						|
# Copied from unittest before python 3.4 release. Used to maintain
 | 
						|
# compatibility with unittest sub-test feature. Users should not use this
 | 
						|
# directly.
 | 
						|
def _expectedFailure(func):
 | 
						|
    @functools.wraps(func)
 | 
						|
    def wrapper(*args, **kwargs):
 | 
						|
        try:
 | 
						|
            func(*args, **kwargs)
 | 
						|
        except Exception:
 | 
						|
            raise _ExpectedFailure(sys.exc_info())
 | 
						|
        raise _UnexpectedSuccess
 | 
						|
    return wrapper
 | 
						|
 | 
						|
 | 
						|
def run_test_with(test_runner, **kwargs):
 | 
						|
    """Decorate a test as using a specific ``RunTest``.
 | 
						|
 | 
						|
    e.g.::
 | 
						|
 | 
						|
      @run_test_with(CustomRunner, timeout=42)
 | 
						|
      def test_foo(self):
 | 
						|
          self.assertTrue(True)
 | 
						|
 | 
						|
    The returned decorator works by setting an attribute on the decorated
 | 
						|
    function.  `TestCase.__init__` looks for this attribute when deciding on a
 | 
						|
    ``RunTest`` factory.  If you wish to use multiple decorators on a test
 | 
						|
    method, then you must either make this one the top-most decorator, or you
 | 
						|
    must write your decorators so that they update the wrapping function with
 | 
						|
    the attributes of the wrapped function.  The latter is recommended style
 | 
						|
    anyway.  ``functools.wraps``, ``functools.wrapper`` and
 | 
						|
    ``twisted.python.util.mergeFunctionMetadata`` can help you do this.
 | 
						|
 | 
						|
    :param test_runner: A ``RunTest`` factory that takes a test case and an
 | 
						|
        optional list of exception handlers.  See ``RunTest``.
 | 
						|
    :param kwargs: Keyword arguments to pass on as extra arguments to
 | 
						|
        'test_runner'.
 | 
						|
    :return: A decorator to be used for marking a test as needing a special
 | 
						|
        runner.
 | 
						|
    """
 | 
						|
    def decorator(function):
 | 
						|
        # Set an attribute on 'function' which will inform TestCase how to
 | 
						|
        # make the runner.
 | 
						|
        def _run_test_with(case, handlers=None, last_resort=None):
 | 
						|
            try:
 | 
						|
                return test_runner(
 | 
						|
                    case, handlers=handlers, last_resort=last_resort,
 | 
						|
                    **kwargs)
 | 
						|
            except TypeError:
 | 
						|
                # Backwards compat: if we can't call the constructor
 | 
						|
                # with last_resort, try without that.
 | 
						|
                return test_runner(case, handlers=handlers, **kwargs)
 | 
						|
        function._run_test_with = _run_test_with
 | 
						|
        return function
 | 
						|
    return decorator
 | 
						|
 | 
						|
 | 
						|
def _copy_content(content_object):
 | 
						|
    """Make a copy of the given content object.
 | 
						|
 | 
						|
    The content within ``content_object`` is iterated and saved. This is
 | 
						|
    useful when the source of the content is volatile, a log file in a
 | 
						|
    temporary directory for example.
 | 
						|
 | 
						|
    :param content_object: A `content.Content` instance.
 | 
						|
    :return: A `content.Content` instance with the same mime-type as
 | 
						|
        ``content_object`` and a non-volatile copy of its content.
 | 
						|
    """
 | 
						|
    content_bytes = list(content_object.iter_bytes())
 | 
						|
    content_callback = lambda: content_bytes
 | 
						|
    return content.Content(content_object.content_type, content_callback)
 | 
						|
 | 
						|
 | 
						|
def gather_details(source_dict, target_dict):
 | 
						|
    """Merge the details from ``source_dict`` into ``target_dict``.
 | 
						|
 | 
						|
    ``gather_details`` evaluates all details in ``source_dict``. Do not use it
 | 
						|
    if the details are not ready to be evaluated.
 | 
						|
 | 
						|
    :param source_dict: A dictionary of details will be gathered.
 | 
						|
    :param target_dict: A dictionary into which details will be gathered.
 | 
						|
    """
 | 
						|
    for name, content_object in source_dict.items():
 | 
						|
        new_name = name
 | 
						|
        disambiguator = itertools.count(1)
 | 
						|
        while new_name in target_dict:
 | 
						|
            new_name = '%s-%d' % (name, advance_iterator(disambiguator))
 | 
						|
        name = new_name
 | 
						|
        target_dict[name] = _copy_content(content_object)
 | 
						|
 | 
						|
 | 
						|
class TestCase(unittest.TestCase):
 | 
						|
    """Extensions to the basic TestCase.
 | 
						|
 | 
						|
    :ivar exception_handlers: Exceptions to catch from setUp, runTest and
 | 
						|
        tearDown. This list is able to be modified at any time and consists of
 | 
						|
        (exception_class, handler(case, result, exception_value)) pairs.
 | 
						|
    :ivar force_failure: Force testtools.RunTest to fail the test after the
 | 
						|
        test has completed.
 | 
						|
    :cvar run_tests_with: A factory to make the ``RunTest`` to run tests with.
 | 
						|
        Defaults to ``RunTest``.  The factory is expected to take a test case
 | 
						|
        and an optional list of exception handlers.
 | 
						|
    """
 | 
						|
 | 
						|
    skipException = TestSkipped
 | 
						|
 | 
						|
    run_tests_with = RunTest
 | 
						|
 | 
						|
    def __init__(self, *args, **kwargs):
 | 
						|
        """Construct a TestCase.
 | 
						|
 | 
						|
        :param testMethod: The name of the method to run.
 | 
						|
        :keyword runTest: Optional class to use to execute the test. If not
 | 
						|
            supplied ``RunTest`` is used. The instance to be used is created
 | 
						|
            when run() is invoked, so will be fresh each time. Overrides
 | 
						|
            ``TestCase.run_tests_with`` if given.
 | 
						|
        """
 | 
						|
        runTest = kwargs.pop('runTest', None)
 | 
						|
        super(TestCase, self).__init__(*args, **kwargs)
 | 
						|
        self._reset()
 | 
						|
        test_method = self._get_test_method()
 | 
						|
        if runTest is None:
 | 
						|
            runTest = getattr(
 | 
						|
                test_method, '_run_test_with', self.run_tests_with)
 | 
						|
        self.__RunTest = runTest
 | 
						|
        if getattr(test_method, '__unittest_expecting_failure__', False):
 | 
						|
            setattr(self, self._testMethodName, _expectedFailure(test_method))
 | 
						|
        # Used internally for onException processing - used to gather extra
 | 
						|
        # data from exceptions.
 | 
						|
        self.__exception_handlers = []
 | 
						|
        # Passed to RunTest to map exceptions to result actions
 | 
						|
        self.exception_handlers = [
 | 
						|
            (self.skipException, self._report_skip),
 | 
						|
            (self.failureException, self._report_failure),
 | 
						|
            (_ExpectedFailure, self._report_expected_failure),
 | 
						|
            (_UnexpectedSuccess, self._report_unexpected_success),
 | 
						|
            (Exception, self._report_error),
 | 
						|
            ]
 | 
						|
 | 
						|
    def _reset(self):
 | 
						|
        """Reset the test case as if it had never been run."""
 | 
						|
        self._cleanups = []
 | 
						|
        self._unique_id_gen = itertools.count(1)
 | 
						|
        # Generators to ensure unique traceback ids.  Maps traceback label to
 | 
						|
        # iterators.
 | 
						|
        self._traceback_id_gens = {}
 | 
						|
        self.__setup_called = False
 | 
						|
        self.__teardown_called = False
 | 
						|
        # __details is lazy-initialized so that a constructed-but-not-run
 | 
						|
        # TestCase is safe to use with clone_test_with_new_id.
 | 
						|
        self.__details = None
 | 
						|
 | 
						|
    def __eq__(self, other):
 | 
						|
        eq = getattr(unittest.TestCase, '__eq__', None)
 | 
						|
        if eq is not None and not unittest.TestCase.__eq__(self, other):
 | 
						|
            return False
 | 
						|
        return self.__dict__ == other.__dict__
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        # We add id to the repr because it makes testing testtools easier.
 | 
						|
        return "<%s id=0x%0x>" % (self.id(), id(self))
 | 
						|
 | 
						|
    def addDetail(self, name, content_object):
 | 
						|
        """Add a detail to be reported with this test's outcome.
 | 
						|
 | 
						|
        For more details see pydoc testtools.TestResult.
 | 
						|
 | 
						|
        :param name: The name to give this detail.
 | 
						|
        :param content_object: The content object for this detail. See
 | 
						|
            testtools.content for more detail.
 | 
						|
        """
 | 
						|
        if self.__details is None:
 | 
						|
            self.__details = {}
 | 
						|
        self.__details[name] = content_object
 | 
						|
 | 
						|
    def getDetails(self):
 | 
						|
        """Get the details dict that will be reported with this test's outcome.
 | 
						|
 | 
						|
        For more details see pydoc testtools.TestResult.
 | 
						|
        """
 | 
						|
        if self.__details is None:
 | 
						|
            self.__details = {}
 | 
						|
        return self.__details
 | 
						|
 | 
						|
    def patch(self, obj, attribute, value):
 | 
						|
        """Monkey-patch 'obj.attribute' to 'value' while the test is running.
 | 
						|
 | 
						|
        If 'obj' has no attribute, then the monkey-patch will still go ahead,
 | 
						|
        and the attribute will be deleted instead of restored to its original
 | 
						|
        value.
 | 
						|
 | 
						|
        :param obj: The object to patch. Can be anything.
 | 
						|
        :param attribute: The attribute on 'obj' to patch.
 | 
						|
        :param value: The value to set 'obj.attribute' to.
 | 
						|
        """
 | 
						|
        self.addCleanup(patch(obj, attribute, value))
 | 
						|
 | 
						|
    def shortDescription(self):
 | 
						|
        return self.id()
 | 
						|
 | 
						|
    def skipTest(self, reason):
 | 
						|
        """Cause this test to be skipped.
 | 
						|
 | 
						|
        This raises self.skipException(reason). skipException is raised
 | 
						|
        to permit a skip to be triggered at any point (during setUp or the
 | 
						|
        testMethod itself). The run() method catches skipException and
 | 
						|
        translates that into a call to the result objects addSkip method.
 | 
						|
 | 
						|
        :param reason: The reason why the test is being skipped. This must
 | 
						|
            support being cast into a unicode string for reporting.
 | 
						|
        """
 | 
						|
        raise self.skipException(reason)
 | 
						|
 | 
						|
    def skip(self, reason):
 | 
						|
        """DEPRECATED: Use skipTest instead."""
 | 
						|
        warnings.warn(
 | 
						|
            'Only valid in 1.8.1 and earlier. Use skipTest instead.',
 | 
						|
            DeprecationWarning, stacklevel=2)
 | 
						|
        self.skipTest(reason)
 | 
						|
 | 
						|
    def _formatTypes(self, classOrIterable):
 | 
						|
        """Format a class or a bunch of classes for display in an error."""
 | 
						|
        className = getattr(classOrIterable, '__name__', None)
 | 
						|
        if className is None:
 | 
						|
            className = ', '.join(klass.__name__ for klass in classOrIterable)
 | 
						|
        return className
 | 
						|
 | 
						|
    def addCleanup(self, function, *arguments, **keywordArguments):
 | 
						|
        """Add a cleanup function to be called after tearDown.
 | 
						|
 | 
						|
        Functions added with addCleanup will be called in reverse order of
 | 
						|
        adding after tearDown, or after setUp if setUp raises an exception.
 | 
						|
 | 
						|
        If a function added with addCleanup raises an exception, the error
 | 
						|
        will be recorded as a test error, and the next cleanup will then be
 | 
						|
        run.
 | 
						|
 | 
						|
        Cleanup functions are always called before a test finishes running,
 | 
						|
        even if setUp is aborted by an exception.
 | 
						|
        """
 | 
						|
        self._cleanups.append((function, arguments, keywordArguments))
 | 
						|
 | 
						|
    def addOnException(self, handler):
 | 
						|
        """Add a handler to be called when an exception occurs in test code.
 | 
						|
 | 
						|
        This handler cannot affect what result methods are called, and is
 | 
						|
        called before any outcome is called on the result object. An example
 | 
						|
        use for it is to add some diagnostic state to the test details dict
 | 
						|
        which is expensive to calculate and not interesting for reporting in
 | 
						|
        the success case.
 | 
						|
 | 
						|
        Handlers are called before the outcome (such as addFailure) that
 | 
						|
        the exception has caused.
 | 
						|
 | 
						|
        Handlers are called in first-added, first-called order, and if they
 | 
						|
        raise an exception, that will propogate out of the test running
 | 
						|
        machinery, halting test processing. As a result, do not call code that
 | 
						|
        may unreasonably fail.
 | 
						|
        """
 | 
						|
        self.__exception_handlers.append(handler)
 | 
						|
 | 
						|
    def _add_reason(self, reason):
 | 
						|
        self.addDetail('reason', content.text_content(reason))
 | 
						|
 | 
						|
    def assertEqual(self, expected, observed, message=''):
 | 
						|
        """Assert that 'expected' is equal to 'observed'.
 | 
						|
 | 
						|
        :param expected: The expected value.
 | 
						|
        :param observed: The observed value.
 | 
						|
        :param message: An optional message to include in the error.
 | 
						|
        """
 | 
						|
        matcher = _FlippedEquals(expected)
 | 
						|
        self.assertThat(observed, matcher, message)
 | 
						|
 | 
						|
    failUnlessEqual = assertEquals = assertEqual
 | 
						|
 | 
						|
    def assertIn(self, needle, haystack, message=''):
 | 
						|
        """Assert that needle is in haystack."""
 | 
						|
        self.assertThat(haystack, Contains(needle), message)
 | 
						|
 | 
						|
    def assertIsNone(self, observed, message=''):
 | 
						|
        """Assert that 'observed' is equal to None.
 | 
						|
 | 
						|
        :param observed: The observed value.
 | 
						|
        :param message: An optional message describing the error.
 | 
						|
        """
 | 
						|
        matcher = Is(None)
 | 
						|
        self.assertThat(observed, matcher, message)
 | 
						|
 | 
						|
    def assertIsNotNone(self, observed, message=''):
 | 
						|
        """Assert that 'observed' is not equal to None.
 | 
						|
 | 
						|
        :param observed: The observed value.
 | 
						|
        :param message: An optional message describing the error.
 | 
						|
        """
 | 
						|
        matcher = Not(Is(None))
 | 
						|
        self.assertThat(observed, matcher, message)
 | 
						|
 | 
						|
    def assertIs(self, expected, observed, message=''):
 | 
						|
        """Assert that 'expected' is 'observed'.
 | 
						|
 | 
						|
        :param expected: The expected value.
 | 
						|
        :param observed: The observed value.
 | 
						|
        :param message: An optional message describing the error.
 | 
						|
        """
 | 
						|
        matcher = Is(expected)
 | 
						|
        self.assertThat(observed, matcher, message)
 | 
						|
 | 
						|
    def assertIsNot(self, expected, observed, message=''):
 | 
						|
        """Assert that 'expected' is not 'observed'."""
 | 
						|
        matcher = Not(Is(expected))
 | 
						|
        self.assertThat(observed, matcher, message)
 | 
						|
 | 
						|
    def assertNotIn(self, needle, haystack, message=''):
 | 
						|
        """Assert that needle is not in haystack."""
 | 
						|
        matcher = Not(Contains(needle))
 | 
						|
        self.assertThat(haystack, matcher, message)
 | 
						|
 | 
						|
    def assertIsInstance(self, obj, klass, msg=None):
 | 
						|
        if isinstance(klass, tuple):
 | 
						|
            matcher = IsInstance(*klass)
 | 
						|
        else:
 | 
						|
            matcher = IsInstance(klass)
 | 
						|
        self.assertThat(obj, matcher, msg)
 | 
						|
 | 
						|
    def assertRaises(self, excClass, callableObj, *args, **kwargs):
 | 
						|
        """Fail unless an exception of class excClass is thrown
 | 
						|
           by callableObj when invoked with arguments args and keyword
 | 
						|
           arguments kwargs. If a different type of exception is
 | 
						|
           thrown, it will not be caught, and the test case will be
 | 
						|
           deemed to have suffered an error, exactly as for an
 | 
						|
           unexpected exception.
 | 
						|
        """
 | 
						|
        class ReRaiseOtherTypes(object):
 | 
						|
            def match(self, matchee):
 | 
						|
                if not issubclass(matchee[0], excClass):
 | 
						|
                    reraise(*matchee)
 | 
						|
        class CaptureMatchee(object):
 | 
						|
            def match(self, matchee):
 | 
						|
                self.matchee = matchee[1]
 | 
						|
        capture = CaptureMatchee()
 | 
						|
        matcher = Raises(MatchesAll(ReRaiseOtherTypes(),
 | 
						|
                MatchesException(excClass), capture))
 | 
						|
        our_callable = Nullary(callableObj, *args, **kwargs)
 | 
						|
        self.assertThat(our_callable, matcher)
 | 
						|
        return capture.matchee
 | 
						|
    failUnlessRaises = assertRaises
 | 
						|
 | 
						|
    def assertThat(self, matchee, matcher, message='', verbose=False):
 | 
						|
        """Assert that matchee is matched by matcher.
 | 
						|
 | 
						|
        :param matchee: An object to match with matcher.
 | 
						|
        :param matcher: An object meeting the testtools.Matcher protocol.
 | 
						|
        :raises MismatchError: When matcher does not match thing.
 | 
						|
        """
 | 
						|
        mismatch_error = self._matchHelper(matchee, matcher, message, verbose)
 | 
						|
        if mismatch_error is not None:
 | 
						|
            raise mismatch_error
 | 
						|
 | 
						|
    def addDetailUniqueName(self, name, content_object):
 | 
						|
        """Add a detail to the test, but ensure it's name is unique.
 | 
						|
 | 
						|
        This method checks whether ``name`` conflicts with a detail that has
 | 
						|
        already been added to the test. If it does, it will modify ``name`` to
 | 
						|
        avoid the conflict.
 | 
						|
 | 
						|
        For more details see pydoc testtools.TestResult.
 | 
						|
 | 
						|
        :param name: The name to give this detail.
 | 
						|
        :param content_object: The content object for this detail. See
 | 
						|
            testtools.content for more detail.
 | 
						|
        """
 | 
						|
        existing_details = self.getDetails()
 | 
						|
        full_name = name
 | 
						|
        suffix = 1
 | 
						|
        while full_name in existing_details:
 | 
						|
            full_name = "%s-%d" % (name, suffix)
 | 
						|
            suffix += 1
 | 
						|
        self.addDetail(full_name, content_object)
 | 
						|
 | 
						|
    def expectThat(self, matchee, matcher, message='', verbose=False):
 | 
						|
        """Check that matchee is matched by matcher, but delay the assertion failure.
 | 
						|
 | 
						|
        This method behaves similarly to ``assertThat``, except that a failed
 | 
						|
        match does not exit the test immediately. The rest of the test code will
 | 
						|
        continue to run, and the test will be marked as failing after the test
 | 
						|
        has finished.
 | 
						|
 | 
						|
        :param matchee: An object to match with matcher.
 | 
						|
        :param matcher: An object meeting the testtools.Matcher protocol.
 | 
						|
        :param message: If specified, show this message with any failed match.
 | 
						|
        """
 | 
						|
        mismatch_error = self._matchHelper(matchee, matcher, message, verbose)
 | 
						|
 | 
						|
        if mismatch_error is not None:
 | 
						|
            self.addDetailUniqueName(
 | 
						|
                "Failed expectation",
 | 
						|
                content.StacktraceContent(
 | 
						|
                    postfix_content="MismatchError: " + str(mismatch_error)
 | 
						|
                )
 | 
						|
            )
 | 
						|
            self.force_failure = True
 | 
						|
 | 
						|
    def _matchHelper(self, matchee, matcher, message, verbose):
 | 
						|
        matcher = Annotate.if_message(message, matcher)
 | 
						|
        mismatch = matcher.match(matchee)
 | 
						|
        if not mismatch:
 | 
						|
            return
 | 
						|
        for (name, value) in mismatch.get_details().items():
 | 
						|
            self.addDetailUniqueName(name, value)
 | 
						|
        return MismatchError(matchee, matcher, mismatch, verbose)
 | 
						|
 | 
						|
    def defaultTestResult(self):
 | 
						|
        return TestResult()
 | 
						|
 | 
						|
    def expectFailure(self, reason, predicate, *args, **kwargs):
 | 
						|
        """Check that a test fails in a particular way.
 | 
						|
 | 
						|
        If the test fails in the expected way, a KnownFailure is caused. If it
 | 
						|
        succeeds an UnexpectedSuccess is caused.
 | 
						|
 | 
						|
        The expected use of expectFailure is as a barrier at the point in a
 | 
						|
        test where the test would fail. For example:
 | 
						|
        >>> def test_foo(self):
 | 
						|
        >>>    self.expectFailure("1 should be 0", self.assertNotEqual, 1, 0)
 | 
						|
        >>>    self.assertEqual(1, 0)
 | 
						|
 | 
						|
        If in the future 1 were to equal 0, the expectFailure call can simply
 | 
						|
        be removed. This separation preserves the original intent of the test
 | 
						|
        while it is in the expectFailure mode.
 | 
						|
        """
 | 
						|
        # TODO: implement with matchers.
 | 
						|
        self._add_reason(reason)
 | 
						|
        try:
 | 
						|
            predicate(*args, **kwargs)
 | 
						|
        except self.failureException:
 | 
						|
            # GZ 2010-08-12: Don't know how to avoid exc_info cycle as the new
 | 
						|
            #                unittest _ExpectedFailure wants old traceback
 | 
						|
            exc_info = sys.exc_info()
 | 
						|
            try:
 | 
						|
                self._report_traceback(exc_info)
 | 
						|
                raise _ExpectedFailure(exc_info)
 | 
						|
            finally:
 | 
						|
                del exc_info
 | 
						|
        else:
 | 
						|
            raise _UnexpectedSuccess(reason)
 | 
						|
 | 
						|
    def getUniqueInteger(self):
 | 
						|
        """Get an integer unique to this test.
 | 
						|
 | 
						|
        Returns an integer that is guaranteed to be unique to this instance.
 | 
						|
        Use this when you need an arbitrary integer in your test, or as a
 | 
						|
        helper for custom anonymous factory methods.
 | 
						|
        """
 | 
						|
        return advance_iterator(self._unique_id_gen)
 | 
						|
 | 
						|
    def getUniqueString(self, prefix=None):
 | 
						|
        """Get a string unique to this test.
 | 
						|
 | 
						|
        Returns a string that is guaranteed to be unique to this instance. Use
 | 
						|
        this when you need an arbitrary string in your test, or as a helper
 | 
						|
        for custom anonymous factory methods.
 | 
						|
 | 
						|
        :param prefix: The prefix of the string. If not provided, defaults
 | 
						|
            to the id of the tests.
 | 
						|
        :return: A bytestring of '<prefix>-<unique_int>'.
 | 
						|
        """
 | 
						|
        if prefix is None:
 | 
						|
            prefix = self.id()
 | 
						|
        return '%s-%d' % (prefix, self.getUniqueInteger())
 | 
						|
 | 
						|
    def onException(self, exc_info, tb_label='traceback'):
 | 
						|
        """Called when an exception propogates from test code.
 | 
						|
 | 
						|
        :seealso addOnException:
 | 
						|
        """
 | 
						|
        if exc_info[0] not in [
 | 
						|
                self.skipException, _UnexpectedSuccess, _ExpectedFailure]:
 | 
						|
            self._report_traceback(exc_info, tb_label=tb_label)
 | 
						|
        for handler in self.__exception_handlers:
 | 
						|
            handler(exc_info)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def _report_error(self, result, err):
 | 
						|
        result.addError(self, details=self.getDetails())
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def _report_expected_failure(self, result, err):
 | 
						|
        result.addExpectedFailure(self, details=self.getDetails())
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def _report_failure(self, result, err):
 | 
						|
        result.addFailure(self, details=self.getDetails())
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def _report_skip(self, result, err):
 | 
						|
        if err.args:
 | 
						|
            reason = err.args[0]
 | 
						|
        else:
 | 
						|
            reason = "no reason given."
 | 
						|
        self._add_reason(reason)
 | 
						|
        result.addSkip(self, details=self.getDetails())
 | 
						|
 | 
						|
    def _report_traceback(self, exc_info, tb_label='traceback'):
 | 
						|
        id_gen = self._traceback_id_gens.setdefault(
 | 
						|
            tb_label, itertools.count(0))
 | 
						|
        while True:
 | 
						|
            tb_id = advance_iterator(id_gen)
 | 
						|
            if tb_id:
 | 
						|
                tb_label = '%s-%d' % (tb_label, tb_id)
 | 
						|
            if tb_label not in self.getDetails():
 | 
						|
                break
 | 
						|
        self.addDetail(tb_label, content.TracebackContent(
 | 
						|
            exc_info, self, capture_locals=getattr(
 | 
						|
                self, '__testtools_tb_locals__', False)))
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def _report_unexpected_success(self, result, err):
 | 
						|
        result.addUnexpectedSuccess(self, details=self.getDetails())
 | 
						|
 | 
						|
    def run(self, result=None):
 | 
						|
        self._reset()
 | 
						|
        try:
 | 
						|
            run_test = self.__RunTest(
 | 
						|
                self, self.exception_handlers, last_resort=self._report_error)
 | 
						|
        except TypeError:
 | 
						|
            # Backwards compat: if we can't call the constructor
 | 
						|
            # with last_resort, try without that.
 | 
						|
            run_test = self.__RunTest(self, self.exception_handlers)
 | 
						|
        return run_test.run(result)
 | 
						|
 | 
						|
    def _run_setup(self, result):
 | 
						|
        """Run the setUp function for this test.
 | 
						|
 | 
						|
        :param result: A testtools.TestResult to report activity to.
 | 
						|
        :raises ValueError: If the base class setUp is not called, a
 | 
						|
            ValueError is raised.
 | 
						|
        """
 | 
						|
        ret = self.setUp()
 | 
						|
        if not self.__setup_called:
 | 
						|
            raise ValueError(
 | 
						|
                "In File: %s\n"
 | 
						|
                "TestCase.setUp was not called. Have you upcalled all the "
 | 
						|
                "way up the hierarchy from your setUp? e.g. Call "
 | 
						|
                "super(%s, self).setUp() from your setUp()."
 | 
						|
                % (sys.modules[self.__class__.__module__].__file__,
 | 
						|
                   self.__class__.__name__))
 | 
						|
        return ret
 | 
						|
 | 
						|
    def _run_teardown(self, result):
 | 
						|
        """Run the tearDown function for this test.
 | 
						|
 | 
						|
        :param result: A testtools.TestResult to report activity to.
 | 
						|
        :raises ValueError: If the base class tearDown is not called, a
 | 
						|
            ValueError is raised.
 | 
						|
        """
 | 
						|
        ret = self.tearDown()
 | 
						|
        if not self.__teardown_called:
 | 
						|
            raise ValueError(
 | 
						|
                "In File: %s\n"
 | 
						|
                "TestCase.tearDown was not called. Have you upcalled all the "
 | 
						|
                "way up the hierarchy from your tearDown? e.g. Call "
 | 
						|
                "super(%s, self).tearDown() from your tearDown()."
 | 
						|
                % (sys.modules[self.__class__.__module__].__file__,
 | 
						|
                   self.__class__.__name__))
 | 
						|
        return ret
 | 
						|
 | 
						|
    def _get_test_method(self):
 | 
						|
        method_name = getattr(self, '_testMethodName')
 | 
						|
        return getattr(self, method_name)
 | 
						|
 | 
						|
    def _run_test_method(self, result):
 | 
						|
        """Run the test method for this test.
 | 
						|
 | 
						|
        :param result: A testtools.TestResult to report activity to.
 | 
						|
        :return: None.
 | 
						|
        """
 | 
						|
        return self._get_test_method()()
 | 
						|
 | 
						|
    def useFixture(self, fixture):
 | 
						|
        """Use fixture in a test case.
 | 
						|
 | 
						|
        The fixture will be setUp, and self.addCleanup(fixture.cleanUp) called.
 | 
						|
 | 
						|
        :param fixture: The fixture to use.
 | 
						|
        :return: The fixture, after setting it up and scheduling a cleanup for
 | 
						|
           it.
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            fixture.setUp()
 | 
						|
        except:
 | 
						|
            exc_info = sys.exc_info()
 | 
						|
            try:
 | 
						|
                gather_details(fixture.getDetails(), self.getDetails())
 | 
						|
            except:
 | 
						|
                # Report the setUp exception, then raise the error during
 | 
						|
                # gather_details.
 | 
						|
                self._report_traceback(exc_info)
 | 
						|
                raise
 | 
						|
            else:
 | 
						|
                # Gather_details worked, so raise the exception setUp
 | 
						|
                # encountered.
 | 
						|
                reraise(*exc_info)
 | 
						|
        else:
 | 
						|
            self.addCleanup(fixture.cleanUp)
 | 
						|
            self.addCleanup(
 | 
						|
                gather_details, fixture.getDetails(), self.getDetails())
 | 
						|
            return fixture
 | 
						|
 | 
						|
    def setUp(self):
 | 
						|
        super(TestCase, self).setUp()
 | 
						|
        if self.__setup_called:
 | 
						|
            raise ValueError(
 | 
						|
                "In File: %s\n"
 | 
						|
                "TestCase.setUp was already called. Do not explicitly call "
 | 
						|
                "setUp from your tests. In your own setUp, use super to call "
 | 
						|
                "the base setUp."
 | 
						|
                % (sys.modules[self.__class__.__module__].__file__,))
 | 
						|
        self.__setup_called = True
 | 
						|
 | 
						|
    def tearDown(self):
 | 
						|
        super(TestCase, self).tearDown()
 | 
						|
        if self.__teardown_called:
 | 
						|
            raise ValueError(
 | 
						|
                "In File: %s\n"
 | 
						|
                "TestCase.tearDown was already called. Do not explicitly call "
 | 
						|
                "tearDown from your tests. In your own tearDown, use super to "
 | 
						|
                "call the base tearDown."
 | 
						|
                % (sys.modules[self.__class__.__module__].__file__,))
 | 
						|
        self.__teardown_called = True
 | 
						|
 | 
						|
 | 
						|
class PlaceHolder(object):
 | 
						|
    """A placeholder test.
 | 
						|
 | 
						|
    `PlaceHolder` implements much of the same interface as TestCase and is
 | 
						|
    particularly suitable for being added to TestResults.
 | 
						|
    """
 | 
						|
 | 
						|
    failureException = None
 | 
						|
 | 
						|
    def __init__(self, test_id, short_description=None, details=None,
 | 
						|
        outcome='addSuccess', error=None, tags=None, timestamps=(None, None)):
 | 
						|
        """Construct a `PlaceHolder`.
 | 
						|
 | 
						|
        :param test_id: The id of the placeholder test.
 | 
						|
        :param short_description: The short description of the place holder
 | 
						|
            test. If not provided, the id will be used instead.
 | 
						|
        :param details: Outcome details as accepted by addSuccess etc.
 | 
						|
        :param outcome: The outcome to call. Defaults to 'addSuccess'.
 | 
						|
        :param tags: Tags to report for the test.
 | 
						|
        :param timestamps: A two-tuple of timestamps for the test start and
 | 
						|
            finish. Each timestamp may be None to indicate it is not known.
 | 
						|
        """
 | 
						|
        self._test_id = test_id
 | 
						|
        self._short_description = short_description
 | 
						|
        self._details = details or {}
 | 
						|
        self._outcome = outcome
 | 
						|
        if error is not None:
 | 
						|
            self._details['traceback'] = content.TracebackContent(error, self)
 | 
						|
        tags = tags or frozenset()
 | 
						|
        self._tags = frozenset(tags)
 | 
						|
        self._timestamps = timestamps
 | 
						|
 | 
						|
    def __call__(self, result=None):
 | 
						|
        return self.run(result=result)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        internal = [self._outcome, self._test_id, self._details]
 | 
						|
        if self._short_description is not None:
 | 
						|
            internal.append(self._short_description)
 | 
						|
        return "<%s.%s(%s)>" % (
 | 
						|
            self.__class__.__module__,
 | 
						|
            self.__class__.__name__,
 | 
						|
            ", ".join(map(repr, internal)))
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return self.id()
 | 
						|
 | 
						|
    def countTestCases(self):
 | 
						|
        return 1
 | 
						|
 | 
						|
    def debug(self):
 | 
						|
        pass
 | 
						|
 | 
						|
    def id(self):
 | 
						|
        return self._test_id
 | 
						|
 | 
						|
    def _result(self, result):
 | 
						|
        if result is None:
 | 
						|
            return TestResult()
 | 
						|
        else:
 | 
						|
            return ExtendedToOriginalDecorator(result)
 | 
						|
 | 
						|
    def run(self, result=None):
 | 
						|
        result = self._result(result)
 | 
						|
        if self._timestamps[0] is not None:
 | 
						|
            result.time(self._timestamps[0])
 | 
						|
        result.tags(self._tags, set())
 | 
						|
        result.startTest(self)
 | 
						|
        if self._timestamps[1] is not None:
 | 
						|
            result.time(self._timestamps[1])
 | 
						|
        outcome = getattr(result, self._outcome)
 | 
						|
        outcome(self, details=self._details)
 | 
						|
        result.stopTest(self)
 | 
						|
        result.tags(set(), self._tags)
 | 
						|
 | 
						|
    def shortDescription(self):
 | 
						|
        if self._short_description is None:
 | 
						|
            return self.id()
 | 
						|
        else:
 | 
						|
            return self._short_description
 | 
						|
 | 
						|
 | 
						|
def ErrorHolder(test_id, error, short_description=None, details=None):
 | 
						|
    """Construct an `ErrorHolder`.
 | 
						|
 | 
						|
    :param test_id: The id of the test.
 | 
						|
    :param error: The exc info tuple that will be used as the test's error.
 | 
						|
        This is inserted into the details as 'traceback' - any existing key
 | 
						|
        will be overridden.
 | 
						|
    :param short_description: An optional short description of the test.
 | 
						|
    :param details: Outcome details as accepted by addSuccess etc.
 | 
						|
    """
 | 
						|
    return PlaceHolder(test_id, short_description=short_description,
 | 
						|
        details=details, outcome='addError', error=error)
 | 
						|
 | 
						|
 | 
						|
def _clone_test_id_callback(test, callback):
 | 
						|
    """Copy a `TestCase`, and make it call callback for its id().
 | 
						|
 | 
						|
    This is only expected to be used on tests that have been constructed but
 | 
						|
    not executed.
 | 
						|
 | 
						|
    :param test: A TestCase instance.
 | 
						|
    :param callback: A callable that takes no parameters and returns a string.
 | 
						|
    :return: A copy.copy of the test with id=callback.
 | 
						|
    """
 | 
						|
    newTest = copy.copy(test)
 | 
						|
    newTest.id = callback
 | 
						|
    return newTest
 | 
						|
 | 
						|
 | 
						|
def clone_test_with_new_id(test, new_id):
 | 
						|
    """Copy a `TestCase`, and give the copied test a new id.
 | 
						|
 | 
						|
    This is only expected to be used on tests that have been constructed but
 | 
						|
    not executed.
 | 
						|
    """
 | 
						|
    return _clone_test_id_callback(test, lambda: new_id)
 | 
						|
 | 
						|
 | 
						|
def attr(*args):
 | 
						|
    """Decorator for adding attributes to WithAttributes.
 | 
						|
 | 
						|
    :param args: The name of attributes to add.
 | 
						|
    :return: A callable that when applied to a WithAttributes will
 | 
						|
        alter its id to enumerate the added attributes.
 | 
						|
    """
 | 
						|
    def decorate(fn):
 | 
						|
        if not safe_hasattr(fn, '__testtools_attrs'):
 | 
						|
            fn.__testtools_attrs = set()
 | 
						|
        fn.__testtools_attrs.update(args)
 | 
						|
        return fn
 | 
						|
    return decorate
 | 
						|
 | 
						|
 | 
						|
class WithAttributes(object):
 | 
						|
    """A mix-in class for modifying test id by attributes.
 | 
						|
 | 
						|
    e.g.
 | 
						|
    >>> class MyTest(WithAttributes, TestCase):
 | 
						|
    ...    @attr('foo')
 | 
						|
    ...    def test_bar(self):
 | 
						|
    ...        pass
 | 
						|
    >>> MyTest('test_bar').id()
 | 
						|
    testtools.testcase.MyTest/test_bar[foo]
 | 
						|
    """
 | 
						|
 | 
						|
    def id(self):
 | 
						|
        orig = super(WithAttributes, self).id()
 | 
						|
        # Depends on testtools.TestCase._get_test_method, be nice to support
 | 
						|
        # plain unittest.
 | 
						|
        fn = self._get_test_method()
 | 
						|
        attributes = getattr(fn, '__testtools_attrs', None)
 | 
						|
        if not attributes:
 | 
						|
            return orig
 | 
						|
        return orig + '[' + ','.join(sorted(attributes)) + ']'
 | 
						|
 | 
						|
 | 
						|
def skip(reason):
 | 
						|
    """A decorator to skip unit tests.
 | 
						|
 | 
						|
    This is just syntactic sugar so users don't have to change any of their
 | 
						|
    unit tests in order to migrate to python 2.7, which provides the
 | 
						|
    @unittest.skip decorator.
 | 
						|
    """
 | 
						|
    def decorator(test_item):
 | 
						|
        # This attribute signals to RunTest._run_core that the entire test
 | 
						|
        # must be skipped - including setUp and tearDown. This makes us
 | 
						|
        # compatible with testtools.skip* functions, which set the same
 | 
						|
        # attributes.
 | 
						|
        test_item.__unittest_skip__ = True
 | 
						|
        test_item.__unittest_skip_why__ = reason
 | 
						|
        if wraps is not None:
 | 
						|
            @wraps(test_item)
 | 
						|
            def skip_wrapper(*args, **kwargs):
 | 
						|
                raise TestCase.skipException(reason)
 | 
						|
        else:
 | 
						|
            def skip_wrapper(test_item):
 | 
						|
                test_item.skip(reason)
 | 
						|
        return skip_wrapper
 | 
						|
    return decorator
 | 
						|
 | 
						|
 | 
						|
def skipIf(condition, reason):
 | 
						|
    """A decorator to skip a test if the condition is true."""
 | 
						|
    if condition:
 | 
						|
        return skip(reason)
 | 
						|
    def _id(obj):
 | 
						|
        return obj
 | 
						|
    return _id
 | 
						|
 | 
						|
 | 
						|
def skipUnless(condition, reason):
 | 
						|
    """A decorator to skip a test unless the condition is true."""
 | 
						|
    if not condition:
 | 
						|
        return skip(reason)
 | 
						|
    def _id(obj):
 | 
						|
        return obj
 | 
						|
    return _id
 | 
						|
 | 
						|
 | 
						|
class ExpectedException:
 | 
						|
    """A context manager to handle expected exceptions.
 | 
						|
 | 
						|
      def test_foo(self):
 | 
						|
          with ExpectedException(ValueError, 'fo.*'):
 | 
						|
              raise ValueError('foo')
 | 
						|
 | 
						|
    will pass.  If the raised exception has a type other than the specified
 | 
						|
    type, it will be re-raised.  If it has a 'str()' that does not match the
 | 
						|
    given regular expression, an AssertionError will be raised.  If no
 | 
						|
    exception is raised, an AssertionError will be raised.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, exc_type, value_re=None, msg=None):
 | 
						|
        """Construct an `ExpectedException`.
 | 
						|
 | 
						|
        :param exc_type: The type of exception to expect.
 | 
						|
        :param value_re: A regular expression to match against the
 | 
						|
            'str()' of the raised exception.
 | 
						|
        :param msg: An optional message explaining the failure.
 | 
						|
        """
 | 
						|
        self.exc_type = exc_type
 | 
						|
        self.value_re = value_re
 | 
						|
        self.msg = msg
 | 
						|
 | 
						|
    def __enter__(self):
 | 
						|
        pass
 | 
						|
 | 
						|
    def __exit__(self, exc_type, exc_value, traceback):
 | 
						|
        if exc_type is None:
 | 
						|
            error_msg = '%s not raised.' % self.exc_type.__name__
 | 
						|
            if self.msg:
 | 
						|
                error_msg = error_msg + ' : ' + self.msg
 | 
						|
            raise AssertionError(error_msg)
 | 
						|
        if exc_type != self.exc_type:
 | 
						|
            return False
 | 
						|
        if self.value_re:
 | 
						|
            matcher = MatchesException(self.exc_type, self.value_re)
 | 
						|
            if self.msg:
 | 
						|
                matcher = Annotate(self.msg, matcher)
 | 
						|
            mismatch = matcher.match((exc_type, exc_value, traceback))
 | 
						|
            if mismatch:
 | 
						|
                raise AssertionError(mismatch.describe())
 | 
						|
        return True
 | 
						|
 | 
						|
 | 
						|
class Nullary(object):
 | 
						|
    """Turn a callable into a nullary callable.
 | 
						|
 | 
						|
    The advantage of this over ``lambda: f(*args, **kwargs)`` is that it
 | 
						|
    preserves the ``repr()`` of ``f``.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, callable_object, *args, **kwargs):
 | 
						|
        self._callable_object = callable_object
 | 
						|
        self._args = args
 | 
						|
        self._kwargs = kwargs
 | 
						|
 | 
						|
    def __call__(self):
 | 
						|
        return self._callable_object(*self._args, **self._kwargs)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return repr(self._callable_object)
 | 
						|
 | 
						|
 | 
						|
class DecorateTestCaseResult(object):
 | 
						|
    """Decorate a TestCase and permit customisation of the result for runs."""
 | 
						|
 | 
						|
    def __init__(self, case, callout, before_run=None, after_run=None):
 | 
						|
        """Construct a DecorateTestCaseResult.
 | 
						|
 | 
						|
        :param case: The case to decorate.
 | 
						|
        :param callout: A callback to call when run/__call__/debug is called.
 | 
						|
            Must take a result parameter and return a result object to be used.
 | 
						|
            For instance: lambda result: result.
 | 
						|
        :param before_run: If set, call this with the decorated result before
 | 
						|
            calling into the decorated run/__call__ method.
 | 
						|
        :param before_run: If set, call this with the decorated result after
 | 
						|
            calling into the decorated run/__call__ method.
 | 
						|
        """
 | 
						|
        self.decorated = case
 | 
						|
        self.callout = callout
 | 
						|
        self.before_run = before_run
 | 
						|
        self.after_run = after_run
 | 
						|
 | 
						|
    def _run(self, result, run_method):
 | 
						|
        result = self.callout(result)
 | 
						|
        if self.before_run:
 | 
						|
            self.before_run(result)
 | 
						|
        try:
 | 
						|
            return run_method(result)
 | 
						|
        finally:
 | 
						|
            if self.after_run:
 | 
						|
                self.after_run(result)
 | 
						|
 | 
						|
    def run(self, result=None):
 | 
						|
        self._run(result, self.decorated.run)
 | 
						|
 | 
						|
    def __call__(self, result=None):
 | 
						|
        self._run(result, self.decorated)
 | 
						|
 | 
						|
    def __getattr__(self, name):
 | 
						|
        return getattr(self.decorated, name)
 | 
						|
 | 
						|
    def __delattr__(self, name):
 | 
						|
        delattr(self.decorated, name)
 | 
						|
 | 
						|
    def __setattr__(self, name, value):
 | 
						|
        if name in ('decorated', 'callout', 'before_run', 'after_run'):
 | 
						|
            self.__dict__[name] = value
 | 
						|
            return
 | 
						|
        setattr(self.decorated, name, value)
 | 
						|
 | 
						|
 | 
						|
# Signal that this is part of the testing framework, and that code from this
 | 
						|
# should not normally appear in tracebacks.
 | 
						|
__unittest = True
 |