annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/unittest/case.py @ 69:33d812a61356

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