annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/unittest/case.py @ 68:5028fdace37b

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