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