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