1"""Test case implementation"""
2
3import sys
4import collections
5import contextlib
6import difflib
7import logging
8import pprint
9import re
10import traceback2 as traceback
11import types
12import unittest
13import warnings
14
15import six
16from six.moves import range
17
18from unittest2 import result
19from unittest2.util import (
20    safe_repr, safe_str, strclass,
21    unorderable_list_difference, _common_shorten_repr
22)
23
24from unittest2.compatibility import (
25    wraps, with_context, catch_warnings, raise_from
26)
27
28__unittest = True
29
30
31DIFF_OMITTED = ('\nDiff is %s characters long. '
32                 'Set self.maxDiff to None to see it.')
33
34class SkipTest(Exception):
35    """
36    Raise this exception in a test to skip it.
37
38    Usually you can use TestCase.skipTest() or one of the skipping decorators
39    instead of raising this directly.
40    """
41
42class _ShouldStop(Exception):
43    """
44    The test should stop.
45    """
46
47class _UnexpectedSuccess(Exception):
48    """
49    The test was supposed to fail, but it didn't!
50    """
51
52class _Outcome(object):
53    def __init__(self, result=None):
54        self.expecting_failure = False
55        self.result = result
56        self.result_supports_subtests = hasattr(result, "addSubTest")
57        self.success = True
58        self.skipped = []
59        self.expectedFailure = None
60        self.errors = []
61
62    @contextlib.contextmanager
63    def testPartExecutor(self, test_case, isTest=False):
64        old_success = self.success
65        self.success = True
66        try:
67            yield
68        except KeyboardInterrupt:
69            raise
70        except SkipTest as e:
71            self.success = False
72            self.skipped.append((test_case, str(e)))
73        except _ShouldStop:
74            pass
75        except:
76            exc_info = sys.exc_info()
77            if self.expecting_failure:
78                self.expectedFailure = exc_info
79            else:
80                self.success = False
81                self.errors.append((test_case, exc_info))
82            # explicitly break a reference cycle:
83            # exc_info -> frame -> exc_info
84            exc_info = None
85        else:
86            if self.result_supports_subtests and self.success:
87                self.errors.append((test_case, None))
88        finally:
89            self.success = self.success and old_success
90
91def _id(obj):
92    return obj
93
94
95class_types = [type]
96if getattr(types, 'ClassType', None):
97    class_types.append(types.ClassType)
98class_types = tuple(class_types)
99
100
101def skip(reason):
102    """
103    Unconditionally skip a test.
104    """
105    def decorator(test_item):
106        if not isinstance(test_item, class_types):
107            @wraps(test_item)
108            def skip_wrapper(*args, **kwargs):
109                raise SkipTest(reason)
110            test_item = skip_wrapper
111
112        test_item.__unittest_skip__ = True
113        test_item.__unittest_skip_why__ = reason
114        return test_item
115    return decorator
116
117def skipIf(condition, reason):
118    """
119    Skip a test if the condition is true.
120    """
121    if condition:
122        return skip(reason)
123    return _id
124
125def skipUnless(condition, reason):
126    """
127    Skip a test unless the condition is true.
128    """
129    if not condition:
130        return skip(reason)
131    return _id
132
133
134def expectedFailure(test_item):
135    test_item.__unittest_expecting_failure__ = True
136    return test_item
137
138def _is_subtype(expected, basetype):
139    if isinstance(expected, tuple):
140        return all(_is_subtype(e, basetype) for e in expected)
141    return isinstance(expected, type) and issubclass(expected, basetype)
142
143class _BaseTestCaseContext:
144
145    def __init__(self, test_case):
146        self.test_case = test_case
147
148    def _raiseFailure(self, standardMsg):
149        msg = self.test_case._formatMessage(self.msg, standardMsg)
150        raise self.test_case.failureException(msg)
151
152
153class _AssertRaisesBaseContext(_BaseTestCaseContext):
154
155    def __init__(self, expected, test_case, expected_regex=None):
156        _BaseTestCaseContext.__init__(self, test_case)
157        self.expected = expected
158        self.failureException = test_case.failureException
159        if expected_regex is not None:
160            expected_regex = re.compile(expected_regex)
161        self.expected_regex = expected_regex
162        self.obj_name = None
163        self.msg = None
164
165    def handle(self, name, args, kwargs):
166        """
167        If args is empty, assertRaises/Warns is being used as a
168        context manager, so check for a 'msg' kwarg and return self.
169        If args is not empty, call a callable passing positional and keyword
170        arguments.
171        """
172        if not _is_subtype(self.expected, self._base_type):
173            raise TypeError('%s() arg 1 must be %s' %
174                            (name, self._base_type_str))
175        if args and args[0] is None:
176            warnings.warn("callable is None",
177                          DeprecationWarning, 3)
178            args = ()
179        if not args:
180            self.msg = kwargs.pop('msg', None)
181            if kwargs:
182                warnings.warn('%r is an invalid keyword argument for '
183                              'this function' % next(iter(kwargs)),
184                              DeprecationWarning, 3)
185            return self
186
187        callable_obj = args[0]
188        args = args[1:]
189        try:
190            self.obj_name = callable_obj.__name__
191        except AttributeError:
192            self.obj_name = str(callable_obj)
193        with self:
194            callable_obj(*args, **kwargs)
195
196
197class _AssertRaisesContext(_AssertRaisesBaseContext):
198    """A context manager used to implement TestCase.assertRaises* methods."""
199
200    _base_type = BaseException
201    _base_type_str = 'an exception type or tuple of exception types'
202
203    def __enter__(self):
204        return self
205
206    def __exit__(self, exc_type, exc_value, tb):
207        if exc_type is None:
208            try:
209                exc_name = self.expected.__name__
210            except AttributeError:
211                exc_name = str(self.expected)
212            if self.obj_name:
213                self._raiseFailure("{0} not raised by {1}".format(exc_name,
214                                                                  self.obj_name))
215            else:
216                self._raiseFailure("{0} not raised".format(exc_name))
217        else:
218            traceback.clear_frames(tb)
219        if not issubclass(exc_type, self.expected):
220            # let unexpected exceptions pass through
221            return False
222        self.exception = exc_value # store for later retrieval
223        if self.expected_regex is None:
224            return True
225
226        expected_regex = self.expected_regex
227        if not expected_regex.search(str(exc_value)):
228            raise self.failureException('"%s" does not match "%s"' %
229                     (expected_regex.pattern, str(exc_value)))
230        return True
231
232
233class _AssertWarnsContext(_AssertRaisesBaseContext):
234    """A context manager used to implement TestCase.assertWarns* methods."""
235
236    _base_type = Warning
237    _base_type_str = 'a warning type or tuple of warning types'
238
239    def __enter__(self):
240        # The __warningregistry__'s need to be in a pristine state for tests
241        # to work properly.
242        for v in sys.modules.values():
243            if getattr(v, '__warningregistry__', None):
244                v.__warningregistry__ = {}
245        self.warnings_manager = catch_warnings(record=True)
246        self.warnings = self.warnings_manager.__enter__()
247        warnings.simplefilter("always", self.expected)
248        return self
249
250    def __exit__(self, exc_type, exc_value, tb):
251        self.warnings_manager.__exit__(exc_type, exc_value, tb)
252        if exc_type is not None:
253            # let unexpected exceptions pass through
254            return
255        try:
256            exc_name = self.expected.__name__
257        except AttributeError:
258            exc_name = str(self.expected)
259        first_matching = None
260        for m in self.warnings:
261            w = m.message
262            if not isinstance(w, self.expected):
263                continue
264            if first_matching is None:
265                first_matching = w
266            if (self.expected_regex is not None and
267                not self.expected_regex.search(str(w))):
268                continue
269            # store warning for later retrieval
270            self.warning = w
271            self.filename = m.filename
272            self.lineno = m.lineno
273            return
274        # Now we simply try to choose a helpful failure message
275        if first_matching is not None:
276            raise self.failureException('%r does not match %r' %
277                     (self.expected_regex.pattern, str(first_matching)))
278        if self.obj_name:
279            raise self.failureException("%s not triggered by %s"
280                % (exc_name, self.obj_name))
281        else:
282            raise self.failureException("%s not triggered"
283                % exc_name )
284
285
286class _TypeEqualityDict(object):
287
288    def __init__(self, testcase):
289        self.testcase = testcase
290        self._store = {}
291
292    def __setitem__(self, key, value):
293        self._store[key] = value
294
295    def __getitem__(self, key):
296        value = self._store[key]
297        if isinstance(value, six.string_types):
298            return getattr(self.testcase, value)
299        return value
300
301    def get(self, key, default=None):
302        if key in self._store:
303            return self[key]
304        return default
305
306
307_LoggingWatcher = collections.namedtuple("_LoggingWatcher",
308                                         ["records", "output"])
309
310
311class _CapturingHandler(logging.Handler):
312    """
313    A logging handler capturing all (raw and formatted) logging output.
314    """
315
316    def __init__(self):
317        logging.Handler.__init__(self)
318        self.watcher = _LoggingWatcher([], [])
319
320    def flush(self):
321        pass
322
323    def emit(self, record):
324        self.watcher.records.append(record)
325        msg = self.format(record)
326        self.watcher.output.append(msg)
327
328
329
330class _AssertLogsContext(_BaseTestCaseContext):
331    """A context manager used to implement TestCase.assertLogs()."""
332
333    LOGGING_FORMAT = "%(levelname)s:%(name)s:%(message)s"
334
335    def __init__(self, test_case, logger_name, level):
336        _BaseTestCaseContext.__init__(self, test_case)
337        self.logger_name = logger_name
338        if level:
339            self.level = getattr(logging, str(level), level)
340        else:
341            self.level = logging.INFO
342        self.msg = None
343
344    def __enter__(self):
345        if isinstance(self.logger_name, logging.Logger):
346            logger = self.logger = self.logger_name
347        else:
348            logger = self.logger = logging.getLogger(self.logger_name)
349        formatter = logging.Formatter(self.LOGGING_FORMAT)
350        handler = _CapturingHandler()
351        handler.setFormatter(formatter)
352        self.watcher = handler.watcher
353        self.old_handlers = logger.handlers[:]
354        self.old_level = logger.level
355        self.old_propagate = logger.propagate
356        logger.handlers = [handler]
357        logger.setLevel(self.level)
358        logger.propagate = False
359        return handler.watcher
360
361    def __exit__(self, exc_type, exc_value, tb):
362        self.logger.handlers = self.old_handlers
363        self.logger.propagate = self.old_propagate
364        self.logger.setLevel(self.old_level)
365        if exc_type is not None:
366            # let unexpected exceptions pass through
367            return False
368        if len(self.watcher.records) == 0:
369            self._raiseFailure(
370                "no logs of level {0} or higher triggered on {1}"
371                .format(logging.getLevelName(self.level), self.logger.name))
372
373
374
375class TestCase(unittest.TestCase):
376    """A class whose instances are single test cases.
377
378    By default, the test code itself should be placed in a method named
379    'runTest'.
380
381    If the fixture may be used for many test cases, create as
382    many test methods as are needed. When instantiating such a TestCase
383    subclass, specify in the constructor arguments the name of the test method
384    that the instance is to execute.
385
386    Test authors should subclass TestCase for their own tests. Construction
387    and deconstruction of the test's environment ('fixture') can be
388    implemented by overriding the 'setUp' and 'tearDown' methods respectively.
389
390    If it is necessary to override the __init__ method, the base class
391    __init__ method must always be called. It is important that subclasses
392    should not change the signature of their __init__ method, since instances
393    of the classes are instantiated automatically by parts of the framework
394    in order to be run.
395
396    When subclassing TestCase, you can set these attributes:
397    * failureException: determines which exception will be raised when
398        the instance's assertion methods fail; test methods raising this
399        exception will be deemed to have 'failed' rather than 'errored'.
400    * longMessage: determines whether long messages (including repr of
401        objects used in assert methods) will be printed on failure in *addition*
402        to any explicit message passed.
403    * maxDiff: sets the maximum length of a diff in failure messages
404        by assert methods using difflib. It is looked up as an instance
405        attribute so can be configured by individual tests if required.
406    """
407
408    failureException = AssertionError
409
410    longMessage = True
411
412    maxDiff = 80*8
413
414    # If a string is longer than _diffThreshold, use normal comparison instead
415    # of difflib.  See #11763.
416    _diffThreshold = 2**16
417
418    # Attribute used by TestSuite for classSetUp
419
420    _classSetupFailed = False
421
422    def __init__(self, methodName='runTest'):
423        """Create an instance of the class that will use the named test
424           method when executed. Raises a ValueError if the instance does
425           not have a method with the specified name.
426        """
427        self._testMethodName = methodName
428        self._outcome = None
429        try:
430            testMethod = getattr(self, methodName)
431        except AttributeError:
432            raise ValueError("no such test method in %s: %s" % \
433                  (self.__class__, methodName))
434        self._testMethodDoc = testMethod.__doc__
435        self._cleanups = []
436        self._subtest = None
437
438        # Map types to custom assertEqual functions that will compare
439        # instances of said type in more detail to generate a more useful
440        # error message.
441        self._type_equality_funcs = _TypeEqualityDict(self)
442        self.addTypeEqualityFunc(dict, 'assertDictEqual')
443        self.addTypeEqualityFunc(list, 'assertListEqual')
444        self.addTypeEqualityFunc(tuple, 'assertTupleEqual')
445        self.addTypeEqualityFunc(set, 'assertSetEqual')
446        self.addTypeEqualityFunc(frozenset, 'assertSetEqual')
447        if six.PY2:
448            self.addTypeEqualityFunc(str, 'assertMultiLineEqual')
449        self.addTypeEqualityFunc(six.text_type, 'assertMultiLineEqual')
450
451    def addTypeEqualityFunc(self, typeobj, function):
452        """Add a type specific assertEqual style function to compare a type.
453
454        This method is for use by TestCase subclasses that need to register
455        their own type equality functions to provide nicer error messages.
456
457        Args:
458            typeobj: The data type to call this function on when both values
459                    are of the same type in assertEqual().
460            function: The callable taking two arguments and an optional
461                    msg= argument that raises self.failureException with a
462                    useful error message when the two arguments are not equal.
463        """
464        self._type_equality_funcs[typeobj] = function
465
466    def addCleanup(self, function, *args, **kwargs):
467        """Add a function, with arguments, to be called when the test is
468        completed. Functions added are called on a LIFO basis and are
469        called after tearDown on test failure or success.
470
471        Cleanup items are called even if setUp fails (unlike tearDown)."""
472        self._cleanups.append((function, args, kwargs))
473
474    @classmethod
475    def setUpClass(cls):
476        "Hook method for setting up class fixture before running tests in the class."
477
478    @classmethod
479    def tearDownClass(cls):
480        "Hook method for deconstructing the class fixture after running all tests in the class."
481
482    def defaultTestResult(self):
483        return result.TestResult()
484
485    def shortDescription(self):
486        """Returns a one-line description of the test, or None if no
487        description has been provided.
488
489        The default implementation of this method returns the first line of
490        the specified test method's docstring.
491        """
492        doc = self._testMethodDoc
493        return doc and doc.split("\n")[0].strip() or None
494
495
496    def id(self):
497        return "%s.%s" % (strclass(self.__class__), self._testMethodName)
498
499    def __eq__(self, other):
500        if type(self) is not type(other):
501            return NotImplemented
502
503        return self._testMethodName == other._testMethodName
504
505    def __ne__(self, other):
506        return not self == other
507
508    def __hash__(self):
509        return hash((type(self), self._testMethodName))
510
511    def __str__(self):
512        return "%s (%s)" % (self._testMethodName, strclass(self.__class__))
513
514    def __repr__(self):
515        return "<%s testMethod=%s>" % \
516               (strclass(self.__class__), self._testMethodName)
517
518    def _addSkip(self, result, test_case, reason):
519        addSkip = getattr(result, 'addSkip', None)
520        if addSkip is not None:
521            addSkip(test_case, reason)
522        else:
523            warnings.warn("TestResult has no addSkip method, skips not reported",
524                          RuntimeWarning, 2)
525            result.addSuccess(test_case)
526
527    @contextlib.contextmanager
528    def subTest(self, msg=None, **params):
529        """Return a context manager that will return the enclosed block
530        of code in a subtest identified by the optional message and
531        keyword parameters.  A failure in the subtest marks the test
532        case as failed but resumes execution at the end of the enclosed
533        block, allowing further test code to be executed.
534        """
535        if not self._outcome.result_supports_subtests:
536            yield
537            return
538        parent = self._subtest
539        if parent is None:
540            params_map = collections.ChainMap(params)
541        else:
542            params_map = parent.params.new_child(params)
543        self._subtest = _SubTest(self, msg, params_map)
544        try:
545            with self._outcome.testPartExecutor(self._subtest, isTest=True):
546                yield
547            if not self._outcome.success:
548                result = self._outcome.result
549                if result is not None and result.failfast:
550                    raise _ShouldStop
551            elif self._outcome.expectedFailure:
552                # If the test is expecting a failure, we really want to
553                # stop now and register the expected failure.
554                raise _ShouldStop
555        finally:
556            self._subtest = parent
557
558    def _feedErrorsToResult(self, result, errors):
559        for test, exc_info in errors:
560            if isinstance(test, _SubTest):
561                result.addSubTest(test.test_case, test, exc_info)
562            elif exc_info is not None:
563                if issubclass(exc_info[0], self.failureException):
564                    result.addFailure(test, exc_info)
565                else:
566                    result.addError(test, exc_info)
567
568    def _addExpectedFailure(self, result, exc_info):
569        try:
570            addExpectedFailure = result.addExpectedFailure
571        except AttributeError:
572            warnings.warn("TestResult has no addExpectedFailure method, reporting as passes",
573                          RuntimeWarning)
574            result.addSuccess(self)
575        else:
576            addExpectedFailure(self, exc_info)
577
578    def _addUnexpectedSuccess(self, result):
579        try:
580            addUnexpectedSuccess = result.addUnexpectedSuccess
581        except AttributeError:
582            warnings.warn("TestResult has no addUnexpectedSuccess method, reporting as failure",
583                          RuntimeWarning)
584            # We need to pass an actual exception and traceback to addFailure,
585            # otherwise the legacy result can choke.
586            try:
587                raise_from(_UnexpectedSuccess, None)
588            except _UnexpectedSuccess:
589                result.addFailure(self, sys.exc_info())
590        else:
591            addUnexpectedSuccess(self)
592
593    def run(self, result=None):
594        orig_result = result
595        if result is None:
596            result = self.defaultTestResult()
597            startTestRun = getattr(result, 'startTestRun', None)
598            if startTestRun is not None:
599                startTestRun()
600
601        result.startTest(self)
602
603        testMethod = getattr(self, self._testMethodName)
604        if (getattr(self.__class__, "__unittest_skip__", False) or
605            getattr(testMethod, "__unittest_skip__", False)):
606            # If the class or method was skipped.
607            try:
608                skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
609                            or getattr(testMethod, '__unittest_skip_why__', ''))
610                self._addSkip(result, self, skip_why)
611            finally:
612                result.stopTest(self)
613            return
614        expecting_failure = getattr(testMethod,
615                                    "__unittest_expecting_failure__", False)
616        outcome = _Outcome(result)
617        try:
618            self._outcome = outcome
619
620            with outcome.testPartExecutor(self):
621                self.setUp()
622            if outcome.success:
623                outcome.expecting_failure = expecting_failure
624                with outcome.testPartExecutor(self, isTest=True):
625                    testMethod()
626                outcome.expecting_failure = False
627                with outcome.testPartExecutor(self):
628                    self.tearDown()
629
630            self.doCleanups()
631            for test, reason in outcome.skipped:
632                self._addSkip(result, test, reason)
633            self._feedErrorsToResult(result, outcome.errors)
634            if outcome.success:
635                if expecting_failure:
636                    if outcome.expectedFailure:
637                        self._addExpectedFailure(result, outcome.expectedFailure)
638                    else:
639                        self._addUnexpectedSuccess(result)
640                else:
641                    result.addSuccess(self)
642            return result
643        finally:
644            result.stopTest(self)
645            if orig_result is None:
646                stopTestRun = getattr(result, 'stopTestRun', None)
647                if stopTestRun is not None:
648                    stopTestRun()
649
650            # explicitly break reference cycles:
651            # outcome.errors -> frame -> outcome -> outcome.errors
652            # outcome.expectedFailure -> frame -> outcome -> outcome.expectedFailure
653            del outcome.errors[:]
654            outcome.expectedFailure = None
655
656            # clear the outcome, no more needed
657            self._outcome = None
658
659    def doCleanups(self):
660        """Execute all cleanup functions. Normally called for you after
661        tearDown."""
662        outcome = self._outcome or _Outcome()
663        while self._cleanups:
664            function, args, kwargs = self._cleanups.pop()
665            with outcome.testPartExecutor(self):
666                function(*args, **kwargs)
667
668        # return this for backwards compatibility
669        # even though we no longer us it internally
670        return outcome.success
671
672    def __call__(self, *args, **kwds):
673        return self.run(*args, **kwds)
674
675    def debug(self):
676        """Run the test without collecting errors in a TestResult"""
677        self.setUp()
678        getattr(self, self._testMethodName)()
679        self.tearDown()
680        while self._cleanups:
681            function, args, kwargs = self._cleanups.pop(-1)
682            function(*args, **kwargs)
683
684    def skipTest(self, reason):
685        """Skip this test."""
686        raise SkipTest(reason)
687
688    def fail(self, msg=None):
689        """Fail immediately, with the given message."""
690        raise self.failureException(msg)
691
692    def assertFalse(self, expr, msg=None):
693        "Fail the test if the expression is true."
694        if expr:
695            msg = self._formatMessage(msg, "%s is not false" % safe_repr(expr))
696            raise self.failureException(msg)
697
698    def assertTrue(self, expr, msg=None):
699        """Fail the test unless the expression is true."""
700        if not expr:
701            msg = self._formatMessage(msg, "%s is not true" % safe_repr(expr))
702            raise self.failureException(msg)
703
704    def _formatMessage(self, msg, standardMsg):
705        """Honour the longMessage attribute when generating failure messages.
706        If longMessage is False this means:
707        * Use only an explicit message if it is provided
708        * Otherwise use the standard message for the assert
709
710        If longMessage is True:
711        * Use the standard message
712        * If an explicit message is provided, plus ' : ' and the explicit message
713        """
714        if not self.longMessage:
715            return msg or standardMsg
716        if msg is None:
717            return standardMsg
718        try:
719            return '%s : %s' % (standardMsg, msg)
720        except UnicodeDecodeError:
721            return '%s : %s' % (safe_str(standardMsg), safe_str(msg))
722
723
724    def assertRaises(self, expected_exception, *args, **kwargs):
725        """Fail unless an exception of class expected_exception is raised
726           by the callable when invoked with specified positional and
727           keyword arguments. If a different type of exception is
728           raised, it will not be caught, and the test case will be
729           deemed to have suffered an error, exactly as for an
730           unexpected exception.
731
732           If called with the callable and arguments omitted, will return a
733           context object used like this::
734
735                with self.assertRaises(SomeException):
736                    do_something()
737
738           The context manager keeps a reference to the exception as
739           the 'exception' attribute. This allows you to inspect the
740           exception after the assertion::
741
742               with self.assertRaises(SomeException) as cm:
743                   do_something()
744               the_exception = cm.exception
745               self.assertEqual(the_exception.error_code, 3)
746        """
747        context = _AssertRaisesContext(expected_exception, self)
748        return context.handle('assertRaises', args, kwargs)
749
750    def assertWarns(self, expected_warning, *args, **kwargs):
751        """Fail unless a warning of class warnClass is triggered
752           by the callable when invoked with specified positional and
753           keyword arguments.  If a different type of warning is
754           triggered, it will not be handled: depending on the other
755           warning filtering rules in effect, it might be silenced, printed
756           out, or raised as an exception.
757
758           If called with the callable and arguments omitted, will return a
759           context object used like this::
760
761                with self.assertWarns(SomeWarning):
762                    do_something()
763
764           The context manager keeps a reference to the first matching
765           warning as the 'warning' attribute; similarly, the 'filename'
766           and 'lineno' attributes give you information about the line
767           of Python code from which the warning was triggered.
768           This allows you to inspect the warning after the assertion::
769
770               with self.assertWarns(SomeWarning) as cm:
771                   do_something()
772               the_warning = cm.warning
773               self.assertEqual(the_warning.some_attribute, 147)
774        """
775        context = _AssertWarnsContext(expected_warning, self)
776        return context.handle('assertWarns', args, kwargs)
777
778    def assertLogs(self, logger=None, level=None):
779        """Fail unless a log message of level *level* or higher is emitted
780        on *logger_name* or its children.  If omitted, *level* defaults to
781        INFO and *logger* defaults to the root logger.
782
783        This method must be used as a context manager, and will yield
784        a recording object with two attributes: `output` and `records`.
785        At the end of the context manager, the `output` attribute will
786        be a list of the matching formatted log messages and the
787        `records` attribute will be a list of the corresponding LogRecord
788        objects.
789
790        Example::
791
792            with self.assertLogs('foo', level='INFO') as cm:
793                logging.getLogger('foo').info('first message')
794                logging.getLogger('foo.bar').error('second message')
795            self.assertEqual(cm.output, ['INFO:foo:first message',
796                                         'ERROR:foo.bar:second message'])
797        """
798        return _AssertLogsContext(self, logger, level)
799
800    def _getAssertEqualityFunc(self, first, second):
801        """Get a detailed comparison function for the types of the two args.
802
803        Returns: A callable accepting (first, second, msg=None) that will
804        raise a failure exception if first != second with a useful human
805        readable error message for those types.
806        """
807        #
808        # NOTE(gregory.p.smith): I considered isinstance(first, type(second))
809        # and vice versa.  I opted for the conservative approach in case
810        # subclasses are not intended to be compared in detail to their super
811        # class instances using a type equality func.  This means testing
812        # subtypes won't automagically use the detailed comparison.  Callers
813        # should use their type specific assertSpamEqual method to compare
814        # subclasses if the detailed comparison is desired and appropriate.
815        # See the discussion in http://bugs.python.org/issue2578.
816        #
817        if type(first) is type(second):
818            asserter = self._type_equality_funcs.get(type(first))
819            if asserter is not None:
820                return asserter
821
822        return self._baseAssertEqual
823
824    def _baseAssertEqual(self, first, second, msg=None):
825        """The default assertEqual implementation, not type specific."""
826        if not first == second:
827            standardMsg = '%s != %s' % _common_shorten_repr(first, second)
828            msg = self._formatMessage(msg, standardMsg)
829            raise self.failureException(msg)
830
831    def assertEqual(self, first, second, msg=None):
832        """Fail if the two objects are unequal as determined by the '=='
833           operator.
834        """
835        assertion_func = self._getAssertEqualityFunc(first, second)
836        assertion_func(first, second, msg=msg)
837
838    def assertNotEqual(self, first, second, msg=None):
839        """Fail if the two objects are equal as determined by the '!='
840           operator.
841        """
842        if not first != second:
843            msg = self._formatMessage(msg, '%s == %s' % (safe_repr(first),
844                                                           safe_repr(second)))
845            raise self.failureException(msg)
846
847    def assertAlmostEqual(self, first, second, places=None, msg=None, delta=None):
848        """Fail if the two objects are unequal as determined by their
849           difference rounded to the given number of decimal places
850           (default 7) and comparing to zero, or by comparing that the
851           between the two objects is more than the given delta.
852
853           Note that decimal places (from zero) are usually not the same
854           as significant digits (measured from the most signficant digit).
855
856           If the two objects compare equal then they will automatically
857           compare almost equal.
858        """
859        if first == second:
860            # shortcut
861            return
862        if delta is not None and places is not None:
863            raise TypeError("specify delta or places not both")
864
865        if delta is not None:
866            if abs(first - second) <= delta:
867                return
868
869            standardMsg = '%s != %s within %s delta' % (safe_repr(first),
870                                                        safe_repr(second),
871                                                        safe_repr(delta))
872        else:
873            if places is None:
874                places = 7
875
876            if round(abs(second-first), places) == 0:
877                return
878
879            standardMsg = '%s != %s within %r places' % (safe_repr(first),
880                                                          safe_repr(second),
881                                                          places)
882        msg = self._formatMessage(msg, standardMsg)
883        raise self.failureException(msg)
884
885    def assertNotAlmostEqual(self, first, second, places=None, msg=None, delta=None):
886        """Fail if the two objects are equal as determined by their
887           difference rounded to the given number of decimal places
888           (default 7) and comparing to zero, or by comparing that the
889           between the two objects is less than the given delta.
890
891           Note that decimal places (from zero) are usually not the same
892           as significant digits (measured from the most signficant digit).
893
894           Objects that are equal automatically fail.
895        """
896        if delta is not None and places is not None:
897            raise TypeError("specify delta or places not both")
898        if delta is not None:
899            if not (first == second) and abs(first - second) > delta:
900                return
901            standardMsg = '%s == %s within %s delta' % (safe_repr(first),
902                                                        safe_repr(second),
903                                                        safe_repr(delta))
904        else:
905            if places is None:
906                places = 7
907            if not (first == second) and round(abs(second-first), places) != 0:
908                return
909            standardMsg = '%s == %s within %r places' % (safe_repr(first),
910                                                         safe_repr(second),
911                                                         places)
912
913        msg = self._formatMessage(msg, standardMsg)
914        raise self.failureException(msg)
915
916
917    def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None):
918        """An equality assertion for ordered sequences (like lists and tuples).
919
920        For the purposes of this function, a valid ordered sequence type is one
921        which can be indexed, has a length, and has an equality operator.
922
923        Args:
924            seq1: The first sequence to compare.
925            seq2: The second sequence to compare.
926            seq_type: The expected datatype of the sequences, or None if no
927                    datatype should be enforced.
928            msg: Optional message to use on failure instead of a list of
929                    differences.
930        """
931        if seq_type is not None:
932            seq_type_name = seq_type.__name__
933            if not isinstance(seq1, seq_type):
934                raise self.failureException('First sequence is not a %s: %s'
935                                            % (seq_type_name, safe_repr(seq1)))
936            if not isinstance(seq2, seq_type):
937                raise self.failureException('Second sequence is not a %s: %s'
938                                            % (seq_type_name, safe_repr(seq2)))
939        else:
940            seq_type_name = "sequence"
941
942        differing = None
943        try:
944            len1 = len(seq1)
945        except (TypeError, NotImplementedError):
946            differing = 'First %s has no length.    Non-sequence?' % (
947                    seq_type_name)
948
949        if differing is None:
950            try:
951                len2 = len(seq2)
952            except (TypeError, NotImplementedError):
953                differing = 'Second %s has no length.    Non-sequence?' % (
954                        seq_type_name)
955
956        if differing is None:
957            if seq1 == seq2:
958                return
959
960            differing = '%ss differ: %s != %s\n' % (
961                    (seq_type_name.capitalize(),) +
962                    _common_shorten_repr(seq1, seq2))
963
964            for i in range(min(len1, len2)):
965                try:
966                    item1 = seq1[i]
967                except (TypeError, IndexError, NotImplementedError):
968                    differing += ('\nUnable to index element %d of first %s\n' %
969                                 (i, seq_type_name))
970                    break
971
972                try:
973                    item2 = seq2[i]
974                except (TypeError, IndexError, NotImplementedError):
975                    differing += ('\nUnable to index element %d of second %s\n' %
976                                 (i, seq_type_name))
977                    break
978
979                if item1 != item2:
980                    differing += ('\nFirst differing element %d:\n%s\n%s\n' %
981                                 (i, item1, item2))
982                    break
983            else:
984                if (len1 == len2 and seq_type is None and
985                    type(seq1) != type(seq2)):
986                    # The sequences are the same, but have differing types.
987                    return
988
989            if len1 > len2:
990                differing += ('\nFirst %s contains %d additional '
991                             'elements.\n' % (seq_type_name, len1 - len2))
992                try:
993                    differing += ('First extra element %d:\n%s\n' %
994                                  (len2, seq1[len2]))
995                except (TypeError, IndexError, NotImplementedError):
996                    differing += ('Unable to index element %d '
997                                  'of first %s\n' % (len2, seq_type_name))
998            elif len1 < len2:
999                differing += ('\nSecond %s contains %d additional '
1000                             'elements.\n' % (seq_type_name, len2 - len1))
1001                try:
1002                    differing += ('First extra element %d:\n%s\n' %
1003                                  (len1, seq2[len1]))
1004                except (TypeError, IndexError, NotImplementedError):
1005                    differing += ('Unable to index element %d '
1006                                  'of second %s\n' % (len1, seq_type_name))
1007        standardMsg = differing
1008        diffMsg = '\n' + '\n'.join(
1009            difflib.ndiff(pprint.pformat(seq1).splitlines(),
1010                          pprint.pformat(seq2).splitlines()))
1011
1012        standardMsg = self._truncateMessage(standardMsg, diffMsg)
1013        msg = self._formatMessage(msg, standardMsg)
1014        self.fail(msg)
1015
1016    def _truncateMessage(self, message, diff):
1017        max_diff = self.maxDiff
1018        if max_diff is None or len(diff) <= max_diff:
1019            return message + diff
1020        return message + (DIFF_OMITTED % len(diff))
1021
1022    def assertListEqual(self, list1, list2, msg=None):
1023        """A list-specific equality assertion.
1024
1025        Args:
1026            list1: The first list to compare.
1027            list2: The second list to compare.
1028            msg: Optional message to use on failure instead of a list of
1029                    differences.
1030
1031        """
1032        self.assertSequenceEqual(list1, list2, msg, seq_type=list)
1033
1034    def assertTupleEqual(self, tuple1, tuple2, msg=None):
1035        """A tuple-specific equality assertion.
1036
1037        Args:
1038            tuple1: The first tuple to compare.
1039            tuple2: The second tuple to compare.
1040            msg: Optional message to use on failure instead of a list of
1041                    differences.
1042        """
1043        self.assertSequenceEqual(tuple1, tuple2, msg, seq_type=tuple)
1044
1045    def assertSetEqual(self, set1, set2, msg=None):
1046        """A set-specific equality assertion.
1047
1048        Args:
1049            set1: The first set to compare.
1050            set2: The second set to compare.
1051            msg: Optional message to use on failure instead of a list of
1052                    differences.
1053
1054        assertSetEqual uses ducktyping to support
1055        different types of sets, and is optimized for sets specifically
1056        (parameters must support a difference method).
1057        """
1058        try:
1059            difference1 = set1.difference(set2)
1060        except TypeError:
1061            e = sys.exc_info()[1]
1062            self.fail('invalid type when attempting set difference: %s' % e)
1063        except AttributeError:
1064            e = sys.exc_info()[1]
1065            self.fail('first argument does not support set difference: %s' % e)
1066
1067        try:
1068            difference2 = set2.difference(set1)
1069        except TypeError:
1070            e = sys.exc_info()[1]
1071            self.fail('invalid type when attempting set difference: %s' % e)
1072        except AttributeError:
1073            e = sys.exc_info()[1]
1074            self.fail('second argument does not support set difference: %s' % e)
1075
1076        if not (difference1 or difference2):
1077            return
1078
1079        lines = []
1080        if difference1:
1081            lines.append('Items in the first set but not the second:')
1082            for item in difference1:
1083                lines.append(repr(item))
1084        if difference2:
1085            lines.append('Items in the second set but not the first:')
1086            for item in difference2:
1087                lines.append(repr(item))
1088
1089        standardMsg = '\n'.join(lines)
1090        self.fail(self._formatMessage(msg, standardMsg))
1091
1092    def assertIn(self, member, container, msg=None):
1093        """Just like self.assertTrue(a in b), but with a nicer default message."""
1094        if member not in container:
1095            standardMsg = '%s not found in %s' % (safe_repr(member),
1096                                                   safe_repr(container))
1097            self.fail(self._formatMessage(msg, standardMsg))
1098
1099    def assertNotIn(self, member, container, msg=None):
1100        """Just like self.assertTrue(a not in b), but with a nicer default message."""
1101        if member in container:
1102            standardMsg = '%s unexpectedly found in %s' % (safe_repr(member),
1103                                                            safe_repr(container))
1104            self.fail(self._formatMessage(msg, standardMsg))
1105
1106    def assertIs(self, expr1, expr2, msg=None):
1107        """Just like self.assertTrue(a is b), but with a nicer default message."""
1108        if expr1 is not expr2:
1109            standardMsg = '%s is not %s' % (safe_repr(expr1), safe_repr(expr2))
1110            self.fail(self._formatMessage(msg, standardMsg))
1111
1112    def assertIsNot(self, expr1, expr2, msg=None):
1113        """Just like self.assertTrue(a is not b), but with a nicer default message."""
1114        if expr1 is expr2:
1115            standardMsg = 'unexpectedly identical: %s' % (safe_repr(expr1),)
1116            self.fail(self._formatMessage(msg, standardMsg))
1117
1118    def assertDictEqual(self, d1, d2, msg=None):
1119        self.assertIsInstance(d1, dict, 'First argument is not a dictionary')
1120        self.assertIsInstance(d2, dict, 'Second argument is not a dictionary')
1121
1122        if d1 != d2:
1123            standardMsg = '%s != %s' % _common_shorten_repr(d1, d2)
1124            diff = ('\n' + '\n'.join(difflib.ndiff(
1125                           pprint.pformat(d1).splitlines(),
1126                           pprint.pformat(d2).splitlines())))
1127            standardMsg = self._truncateMessage(standardMsg, diff)
1128            self.fail(self._formatMessage(msg, standardMsg))
1129
1130    def assertDictContainsSubset(self, expected, actual, msg=None):
1131        """Checks whether actual is a superset of expected."""
1132        missing = []
1133        mismatched = []
1134        for key, value in expected.items():
1135            if key not in actual:
1136                missing.append(key)
1137            elif value != actual[key]:
1138                mismatched.append('%s, expected: %s, actual: %s' %
1139                                  (safe_repr(key), safe_repr(value),
1140                                   safe_repr(actual[key])))
1141
1142        if not (missing or mismatched):
1143            return
1144
1145        standardMsg = ''
1146        if missing:
1147            standardMsg = 'Missing: %s' % ','.join(safe_repr(m) for m in
1148                                                    missing)
1149        if mismatched:
1150            if standardMsg:
1151                standardMsg += '; '
1152            standardMsg += 'Mismatched values: %s' % ','.join(mismatched)
1153
1154        self.fail(self._formatMessage(msg, standardMsg))
1155
1156    def assertItemsEqual(self, expected_seq, actual_seq, msg=None):
1157        """An unordered sequence specific comparison. It asserts that
1158        expected_seq and actual_seq contain the same elements. It is
1159        the equivalent of::
1160
1161            self.assertEqual(sorted(expected_seq), sorted(actual_seq))
1162
1163        Raises with an error message listing which elements of expected_seq
1164        are missing from actual_seq and vice versa if any.
1165
1166        Asserts that each element has the same count in both sequences.
1167        Example:
1168            - [0, 1, 1] and [1, 0, 1] compare equal.
1169            - [0, 0, 1] and [0, 1] compare unequal.
1170        """
1171        try:
1172            expected = sorted(expected_seq)
1173            actual = sorted(actual_seq)
1174        except TypeError:
1175            # Unsortable items (example: set(), complex(), ...)
1176            expected = list(expected_seq)
1177            actual = list(actual_seq)
1178            missing, unexpected = unorderable_list_difference(
1179                expected, actual, ignore_duplicate=False
1180            )
1181        else:
1182            return self.assertSequenceEqual(expected, actual, msg=msg)
1183
1184        errors = []
1185        if missing:
1186            errors.append('Expected, but missing:\n    %s' %
1187                           safe_repr(missing))
1188        if unexpected:
1189            errors.append('Unexpected, but present:\n    %s' %
1190                           safe_repr(unexpected))
1191        if errors:
1192            standardMsg = '\n'.join(errors)
1193            self.fail(self._formatMessage(msg, standardMsg))
1194
1195    def assertMultiLineEqual(self, first, second, msg=None):
1196        """Assert that two multi-line strings are equal."""
1197        self.assertIsInstance(first, six.string_types, (
1198                'First argument is not a string'))
1199        self.assertIsInstance(second, six.string_types, (
1200                'Second argument is not a string'))
1201
1202        if first != second:
1203            # don't use difflib if the strings are too long
1204            if (len(first) > self._diffThreshold or
1205                len(second) > self._diffThreshold):
1206                self._baseAssertEqual(first, second, msg)
1207            firstlines = first.splitlines(True)
1208            secondlines = second.splitlines(True)
1209            if len(firstlines) == 1 and first.strip('\r\n') == first:
1210                firstlines = [first + '\n']
1211                secondlines = [second + '\n']
1212            standardMsg = '%s != %s' % _common_shorten_repr(first, second)
1213            diff = '\n' + ''.join(difflib.ndiff(firstlines, secondlines))
1214            standardMsg = self._truncateMessage(standardMsg, diff)
1215            self.fail(self._formatMessage(msg, standardMsg))
1216
1217    def assertLess(self, a, b, msg=None):
1218        """Just like self.assertTrue(a < b), but with a nicer default message."""
1219        if not a < b:
1220            standardMsg = '%s not less than %s' % (safe_repr(a), safe_repr(b))
1221            self.fail(self._formatMessage(msg, standardMsg))
1222
1223    def assertLessEqual(self, a, b, msg=None):
1224        """Just like self.assertTrue(a <= b), but with a nicer default message."""
1225        if not a <= b:
1226            standardMsg = '%s not less than or equal to %s' % (safe_repr(a), safe_repr(b))
1227            self.fail(self._formatMessage(msg, standardMsg))
1228
1229    def assertGreater(self, a, b, msg=None):
1230        """Just like self.assertTrue(a > b), but with a nicer default message."""
1231        if not a > b:
1232            standardMsg = '%s not greater than %s' % (safe_repr(a), safe_repr(b))
1233            self.fail(self._formatMessage(msg, standardMsg))
1234
1235    def assertGreaterEqual(self, a, b, msg=None):
1236        """Just like self.assertTrue(a >= b), but with a nicer default message."""
1237        if not a >= b:
1238            standardMsg = '%s not greater than or equal to %s' % (safe_repr(a), safe_repr(b))
1239            self.fail(self._formatMessage(msg, standardMsg))
1240
1241    def assertIsNone(self, obj, msg=None):
1242        """Same as self.assertTrue(obj is None), with a nicer default message."""
1243        if obj is not None:
1244            standardMsg = '%s is not None' % (safe_repr(obj),)
1245            self.fail(self._formatMessage(msg, standardMsg))
1246
1247    def assertIsNotNone(self, obj, msg=None):
1248        """Included for symmetry with assertIsNone."""
1249        if obj is None:
1250            standardMsg = 'unexpectedly None'
1251            self.fail(self._formatMessage(msg, standardMsg))
1252
1253    def assertIsInstance(self, obj, cls, msg=None):
1254        """Same as self.assertTrue(isinstance(obj, cls)), with a nicer
1255        default message."""
1256        if not isinstance(obj, cls):
1257            standardMsg = '%s is not an instance of %r' % (safe_repr(obj), cls)
1258            self.fail(self._formatMessage(msg, standardMsg))
1259
1260    def assertNotIsInstance(self, obj, cls, msg=None):
1261        """Included for symmetry with assertIsInstance."""
1262        if isinstance(obj, cls):
1263            standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls)
1264            self.fail(self._formatMessage(msg, standardMsg))
1265
1266    def assertRaisesRegex(self, expected_exception, expected_regex,
1267                          *args, **kwargs):
1268        """Asserts that the message in a raised exception matches a regex.
1269
1270        Args:
1271            expected_exception: Exception class expected to be raised.
1272            expected_regex: Regex (re pattern object or string) expected
1273                    to be found in error message.
1274            args: Function to be called and extra positional args.
1275            kwargs: Extra kwargs.
1276        """
1277        context = _AssertRaisesContext(expected_exception, self, expected_regex)
1278        return context.handle('assertRaisesRegex', args, kwargs)
1279
1280    def assertWarnsRegex(self, expected_warning, expected_regex,
1281                         *args, **kwargs):
1282        """Asserts that the message in a triggered warning matches a regex.
1283        Basic functioning is similar to assertWarns() with the addition
1284        that only warnings whose messages also match the regular expression
1285        are considered successful matches.
1286
1287        Args:
1288            expected_warning: Warning class expected to be triggered.
1289            expected_regex: Regex (re pattern object or string) expected
1290                    to be found in error message.
1291            args: Function to be called and extra positional args.
1292            kwargs: Extra kwargs.
1293        """
1294        context = _AssertWarnsContext(expected_warning, self, expected_regex)
1295        return context.handle('assertWarnsRegex', args, kwargs)
1296
1297    def assertRegex(self, text, expected_regex, msg=None):
1298        """Fail the test unless the text matches the regular expression."""
1299        if isinstance(expected_regex, six.string_types):
1300            expected_regex = re.compile(expected_regex)
1301        if not expected_regex.search(text):
1302            msg = msg or "Regex didn't match"
1303            msg = '%s: %r not found in %r' % (msg, expected_regex.pattern, text)
1304            raise self.failureException(msg)
1305
1306    def assertNotRegex(self, text, unexpected_regex, msg=None):
1307        """Fail the test if the text matches the regular expression."""
1308        if isinstance(unexpected_regex, six.string_types):
1309            unexpected_regex = re.compile(unexpected_regex)
1310        match = unexpected_regex.search(text)
1311        if match:
1312            msg = msg or "Regex matched"
1313            msg = '%s: %r matches %r in %r' % (msg,
1314                                               text[match.start():match.end()],
1315                                               unexpected_regex.pattern,
1316                                               text)
1317            raise self.failureException(msg)
1318
1319
1320    def _deprecate(original_func):
1321        def deprecated_func(*args, **kwargs):
1322            warnings.warn(
1323                ('Please use %s instead.' % original_func.__name__),
1324                PendingDeprecationWarning, 2)
1325            return original_func(*args, **kwargs)
1326        return deprecated_func
1327
1328    failUnlessEqual = assertEquals = _deprecate(assertEqual)
1329    failIfEqual = assertNotEquals = _deprecate(assertNotEqual)
1330    failUnlessAlmostEqual = assertAlmostEquals = _deprecate(assertAlmostEqual)
1331    failIfAlmostEqual = assertNotAlmostEquals = _deprecate(assertNotAlmostEqual)
1332    failUnless = assert_ = _deprecate(assertTrue)
1333    failUnlessRaises = _deprecate(assertRaises)
1334    failIf = _deprecate(assertFalse)
1335    assertRaisesRegexp = _deprecate(assertRaisesRegex)
1336    assertRegexpMatches = _deprecate(assertRegex)
1337    assertNotRegexpMatches = _deprecate(assertNotRegex)
1338
1339
1340class FunctionTestCase(TestCase):
1341    """A test case that wraps a test function.
1342
1343    This is useful for slipping pre-existing test functions into the
1344    unittest framework. Optionally, set-up and tidy-up functions can be
1345    supplied. As with TestCase, the tidy-up ('tearDown') function will
1346    always be called if the set-up ('setUp') function ran successfully.
1347    """
1348
1349    def __init__(self, testFunc, setUp=None, tearDown=None, description=None):
1350        super(FunctionTestCase, self).__init__()
1351        self._setUpFunc = setUp
1352        self._tearDownFunc = tearDown
1353        self._testFunc = testFunc
1354        self._description = description
1355
1356    def setUp(self):
1357        if self._setUpFunc is not None:
1358            self._setUpFunc()
1359
1360    def tearDown(self):
1361        if self._tearDownFunc is not None:
1362            self._tearDownFunc()
1363
1364    def runTest(self):
1365        self._testFunc()
1366
1367    def id(self):
1368        return self._testFunc.__name__
1369
1370    def __eq__(self, other):
1371        if not isinstance(other, self.__class__):
1372            return NotImplemented
1373
1374        return self._setUpFunc == other._setUpFunc and \
1375               self._tearDownFunc == other._tearDownFunc and \
1376               self._testFunc == other._testFunc and \
1377               self._description == other._description
1378
1379    def __ne__(self, other):
1380        return not self == other
1381
1382    def __hash__(self):
1383        return hash((type(self), self._setUpFunc, self._tearDownFunc,
1384                     self._testFunc, self._description))
1385
1386    def __str__(self):
1387        return "%s (%s)" % (strclass(self.__class__),
1388                            self._testFunc.__name__)
1389
1390    def __repr__(self):
1391        return "<%s testFunc=%s>" % (strclass(self.__class__),
1392                                     self._testFunc)
1393
1394    def shortDescription(self):
1395        if self._description is not None:
1396            return self._description
1397        doc = self._testFunc.__doc__
1398        return doc and doc.split("\n")[0].strip() or None
1399
1400
1401class _SubTest(TestCase):
1402
1403    def __init__(self, test_case, message, params):
1404        super(_SubTest, self).__init__()
1405        self._message = message
1406        self.test_case = test_case
1407        self.params = params
1408        self.failureException = test_case.failureException
1409
1410    def runTest(self):
1411        raise NotImplementedError("subtests cannot be run directly")
1412
1413    def _subDescription(self):
1414        parts = []
1415        if self._message:
1416            parts.append("[{0}]".format(self._message))
1417        if self.params:
1418            params_desc = ', '.join(
1419                "{0}={1!r}".format(k, v)
1420                for (k, v) in sorted(self.params.items()))
1421            parts.append("({0})".format(params_desc))
1422        return " ".join(parts) or '(<subtest>)'
1423
1424    def id(self):
1425        return "{0} {1}".format(self.test_case.id(), self._subDescription())
1426
1427    def shortDescription(self):
1428        """Returns a one-line description of the subtest, or None if no
1429        description has been provided.
1430        """
1431        return self.test_case.shortDescription()
1432
1433    def __str__(self):
1434        return "{0} {1}".format(self.test_case, self._subDescription())
1435