blob: 4f9c49665a315c41971bc271f1ddf41fcf273fe8 [file] [log] [blame]
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001"""Test case implementation"""
2
3import sys
4import functools
5import difflib
6import pprint
7import re
8import warnings
9
10from . import result, util
11
12
13class SkipTest(Exception):
14 """
15 Raise this exception in a test to skip it.
16
17 Usually you can use TestResult.skip() or one of the skipping decorators
18 instead of raising this directly.
19 """
20 pass
21
22class _ExpectedFailure(Exception):
23 """
24 Raise this when a test is expected to fail.
25
26 This is an implementation detail.
27 """
28
29 def __init__(self, exc_info):
30 super(_ExpectedFailure, self).__init__()
31 self.exc_info = exc_info
32
33class _UnexpectedSuccess(Exception):
34 """
35 The test was supposed to fail, but it didn't!
36 """
37 pass
38
39def _id(obj):
40 return obj
41
42def skip(reason):
43 """
44 Unconditionally skip a test.
45 """
46 def decorator(test_item):
47 if isinstance(test_item, type) and issubclass(test_item, TestCase):
48 test_item.__unittest_skip__ = True
49 test_item.__unittest_skip_why__ = reason
50 return test_item
51 @functools.wraps(test_item)
52 def skip_wrapper(*args, **kwargs):
53 raise SkipTest(reason)
54 return skip_wrapper
55 return decorator
56
57def skipIf(condition, reason):
58 """
59 Skip a test if the condition is true.
60 """
61 if condition:
62 return skip(reason)
63 return _id
64
65def skipUnless(condition, reason):
66 """
67 Skip a test unless the condition is true.
68 """
69 if not condition:
70 return skip(reason)
71 return _id
72
73
74def expectedFailure(func):
75 @functools.wraps(func)
76 def wrapper(*args, **kwargs):
77 try:
78 func(*args, **kwargs)
79 except Exception:
80 raise _ExpectedFailure(sys.exc_info())
81 raise _UnexpectedSuccess
82 return wrapper
83
84
85class _AssertRaisesContext(object):
86 """A context manager used to implement TestCase.assertRaises* methods."""
87
88 def __init__(self, expected, test_case, callable_obj=None,
89 expected_regexp=None):
90 self.expected = expected
91 self.failureException = test_case.failureException
92 if callable_obj is not None:
93 try:
94 self.obj_name = callable_obj.__name__
95 except AttributeError:
96 self.obj_name = str(callable_obj)
97 else:
98 self.obj_name = None
99 self.expected_regex = expected_regexp
100
101 def __enter__(self):
102 pass
103
104 def __exit__(self, exc_type, exc_value, tb):
105 if exc_type is None:
106 try:
107 exc_name = self.expected.__name__
108 except AttributeError:
109 exc_name = str(self.expected)
110 if self.obj_name:
111 raise self.failureException("{0} not raised by {1}"
112 .format(exc_name, self.obj_name))
113 else:
114 raise self.failureException("{0} not raised"
115 .format(exc_name))
116 if not issubclass(exc_type, self.expected):
117 # let unexpected exceptions pass through
118 return False
Kristján Valur Jónsson92a653a2009-11-13 16:10:13 +0000119 #store exception, without traceback, for later retrieval
Benjamin Peterson589c2d32009-11-13 22:09:10 +0000120 self.exc_value = exc_value.with_traceback(None)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000121 if self.expected_regex is None:
122 return True
123
124 expected_regexp = self.expected_regex
125 if isinstance(expected_regexp, (bytes, str)):
126 expected_regexp = re.compile(expected_regexp)
127 if not expected_regexp.search(str(exc_value)):
128 raise self.failureException('"%s" does not match "%s"' %
129 (expected_regexp.pattern, str(exc_value)))
130 return True
131
132
133class _AssertWrapper(object):
134 """Wrap entries in the _type_equality_funcs registry to make them deep
135 copyable."""
136
137 def __init__(self, function):
138 self.function = function
139
140 def __deepcopy__(self, memo):
141 memo[id(self)] = self
142
143
144class TestCase(object):
145 """A class whose instances are single test cases.
146
147 By default, the test code itself should be placed in a method named
148 'runTest'.
149
150 If the fixture may be used for many test cases, create as
151 many test methods as are needed. When instantiating such a TestCase
152 subclass, specify in the constructor arguments the name of the test method
153 that the instance is to execute.
154
155 Test authors should subclass TestCase for their own tests. Construction
156 and deconstruction of the test's environment ('fixture') can be
157 implemented by overriding the 'setUp' and 'tearDown' methods respectively.
158
159 If it is necessary to override the __init__ method, the base class
160 __init__ method must always be called. It is important that subclasses
161 should not change the signature of their __init__ method, since instances
162 of the classes are instantiated automatically by parts of the framework
163 in order to be run.
164 """
165
166 # This attribute determines which exception will be raised when
167 # the instance's assertion methods fail; test methods raising this
168 # exception will be deemed to have 'failed' rather than 'errored'
169
170 failureException = AssertionError
171
172 # This attribute determines whether long messages (including repr of
173 # objects used in assert methods) will be printed on failure in *addition*
174 # to any explicit message passed.
175
176 longMessage = False
177
178
179 def __init__(self, methodName='runTest'):
180 """Create an instance of the class that will use the named test
181 method when executed. Raises a ValueError if the instance does
182 not have a method with the specified name.
183 """
184 self._testMethodName = methodName
185 self._resultForDoCleanups = None
186 try:
187 testMethod = getattr(self, methodName)
188 except AttributeError:
189 raise ValueError("no such test method in %s: %s" % \
190 (self.__class__, methodName))
191 self._testMethodDoc = testMethod.__doc__
192 self._cleanups = []
193
194 # Map types to custom assertEqual functions that will compare
195 # instances of said type in more detail to generate a more useful
196 # error message.
197 self._type_equality_funcs = {}
198 self.addTypeEqualityFunc(dict, self.assertDictEqual)
199 self.addTypeEqualityFunc(list, self.assertListEqual)
200 self.addTypeEqualityFunc(tuple, self.assertTupleEqual)
201 self.addTypeEqualityFunc(set, self.assertSetEqual)
202 self.addTypeEqualityFunc(frozenset, self.assertSetEqual)
203
204 def addTypeEqualityFunc(self, typeobj, function):
205 """Add a type specific assertEqual style function to compare a type.
206
207 This method is for use by TestCase subclasses that need to register
208 their own type equality functions to provide nicer error messages.
209
210 Args:
211 typeobj: The data type to call this function on when both values
212 are of the same type in assertEqual().
213 function: The callable taking two arguments and an optional
214 msg= argument that raises self.failureException with a
215 useful error message when the two arguments are not equal.
216 """
217 self._type_equality_funcs[typeobj] = _AssertWrapper(function)
218
219 def addCleanup(self, function, *args, **kwargs):
220 """Add a function, with arguments, to be called when the test is
221 completed. Functions added are called on a LIFO basis and are
222 called after tearDown on test failure or success.
223
224 Cleanup items are called even if setUp fails (unlike tearDown)."""
225 self._cleanups.append((function, args, kwargs))
226
227 def setUp(self):
228 "Hook method for setting up the test fixture before exercising it."
229 pass
230
231 def tearDown(self):
232 "Hook method for deconstructing the test fixture after testing it."
233 pass
234
235 def countTestCases(self):
236 return 1
237
238 def defaultTestResult(self):
239 return result.TestResult()
240
241 def shortDescription(self):
242 """Returns both the test method name and first line of its docstring.
243
244 If no docstring is given, only returns the method name.
245
246 This method overrides unittest.TestCase.shortDescription(), which
247 only returns the first line of the docstring, obscuring the name
248 of the test upon failure.
249 """
250 desc = str(self)
251 doc_first_line = None
252
253 if self._testMethodDoc:
254 doc_first_line = self._testMethodDoc.split("\n")[0].strip()
255 if doc_first_line:
256 desc = '\n'.join((desc, doc_first_line))
257 return desc
258
259 def id(self):
260 return "%s.%s" % (util.strclass(self.__class__), self._testMethodName)
261
262 def __eq__(self, other):
263 if type(self) is not type(other):
264 return NotImplemented
265
266 return self._testMethodName == other._testMethodName
267
268 def __ne__(self, other):
269 return not self == other
270
271 def __hash__(self):
272 return hash((type(self), self._testMethodName))
273
274 def __str__(self):
275 return "%s (%s)" % (self._testMethodName, util.strclass(self.__class__))
276
277 def __repr__(self):
278 return "<%s testMethod=%s>" % \
279 (util.strclass(self.__class__), self._testMethodName)
280
281 def run(self, result=None):
282 orig_result = result
283 if result is None:
284 result = self.defaultTestResult()
285 startTestRun = getattr(result, 'startTestRun', None)
286 if startTestRun is not None:
287 startTestRun()
288
289 self._resultForDoCleanups = result
290 result.startTest(self)
291 if getattr(self.__class__, "__unittest_skip__", False):
292 # If the whole class was skipped.
293 try:
294 result.addSkip(self, self.__class__.__unittest_skip_why__)
295 finally:
296 result.stopTest(self)
297 return
298 testMethod = getattr(self, self._testMethodName)
299 try:
300 success = False
301 try:
302 self.setUp()
303 except SkipTest as e:
304 result.addSkip(self, str(e))
305 except Exception:
306 result.addError(self, sys.exc_info())
307 else:
308 try:
309 testMethod()
310 except self.failureException:
311 result.addFailure(self, sys.exc_info())
312 except _ExpectedFailure as e:
313 result.addExpectedFailure(self, e.exc_info)
314 except _UnexpectedSuccess:
315 result.addUnexpectedSuccess(self)
316 except SkipTest as e:
317 result.addSkip(self, str(e))
318 except Exception:
319 result.addError(self, sys.exc_info())
320 else:
321 success = True
322
323 try:
324 self.tearDown()
325 except Exception:
326 result.addError(self, sys.exc_info())
327 success = False
328
329 cleanUpSuccess = self.doCleanups()
330 success = success and cleanUpSuccess
331 if success:
332 result.addSuccess(self)
333 finally:
334 result.stopTest(self)
335 if orig_result is None:
336 stopTestRun = getattr(result, 'stopTestRun', None)
337 if stopTestRun is not None:
338 stopTestRun()
339
340 def doCleanups(self):
341 """Execute all cleanup functions. Normally called for you after
342 tearDown."""
343 result = self._resultForDoCleanups
344 ok = True
345 while self._cleanups:
346 function, args, kwargs = self._cleanups.pop(-1)
347 try:
348 function(*args, **kwargs)
349 except Exception:
350 ok = False
351 result.addError(self, sys.exc_info())
352 return ok
353
354 def __call__(self, *args, **kwds):
355 return self.run(*args, **kwds)
356
357 def debug(self):
358 """Run the test without collecting errors in a TestResult"""
359 self.setUp()
360 getattr(self, self._testMethodName)()
361 self.tearDown()
362
363 def skipTest(self, reason):
364 """Skip this test."""
365 raise SkipTest(reason)
366
367 def fail(self, msg=None):
368 """Fail immediately, with the given message."""
369 raise self.failureException(msg)
370
371 def assertFalse(self, expr, msg=None):
372 "Fail the test if the expression is true."
373 if expr:
374 msg = self._formatMessage(msg, "%r is not False" % expr)
375 raise self.failureException(msg)
376
377 def assertTrue(self, expr, msg=None):
378 """Fail the test unless the expression is true."""
379 if not expr:
380 msg = self._formatMessage(msg, "%r is not True" % expr)
381 raise self.failureException(msg)
382
383 def _formatMessage(self, msg, standardMsg):
384 """Honour the longMessage attribute when generating failure messages.
385 If longMessage is False this means:
386 * Use only an explicit message if it is provided
387 * Otherwise use the standard message for the assert
388
389 If longMessage is True:
390 * Use the standard message
391 * If an explicit message is provided, plus ' : ' and the explicit message
392 """
393 if not self.longMessage:
394 return msg or standardMsg
395 if msg is None:
396 return standardMsg
397 return standardMsg + ' : ' + msg
398
399
400 def assertRaises(self, excClass, callableObj=None, *args, **kwargs):
401 """Fail unless an exception of class excClass is thrown
402 by callableObj when invoked with arguments args and keyword
403 arguments kwargs. If a different type of exception is
404 thrown, it will not be caught, and the test case will be
405 deemed to have suffered an error, exactly as for an
406 unexpected exception.
407
408 If called with callableObj omitted or None, will return a
409 context object used like this::
410
411 with self.assertRaises(some_error_class):
412 do_something()
413 """
414 context = _AssertRaisesContext(excClass, self, callableObj)
415 if callableObj is None:
416 return context
417 with context:
418 callableObj(*args, **kwargs)
419
420 def _getAssertEqualityFunc(self, first, second):
421 """Get a detailed comparison function for the types of the two args.
422
423 Returns: A callable accepting (first, second, msg=None) that will
424 raise a failure exception if first != second with a useful human
425 readable error message for those types.
426 """
427 #
428 # NOTE(gregory.p.smith): I considered isinstance(first, type(second))
429 # and vice versa. I opted for the conservative approach in case
430 # subclasses are not intended to be compared in detail to their super
431 # class instances using a type equality func. This means testing
432 # subtypes won't automagically use the detailed comparison. Callers
433 # should use their type specific assertSpamEqual method to compare
434 # subclasses if the detailed comparison is desired and appropriate.
435 # See the discussion in http://bugs.python.org/issue2578.
436 #
437 if type(first) is type(second):
438 asserter = self._type_equality_funcs.get(type(first))
439 if asserter is not None:
440 return asserter.function
441
442 return self._baseAssertEqual
443
444 def _baseAssertEqual(self, first, second, msg=None):
445 """The default assertEqual implementation, not type specific."""
446 if not first == second:
447 standardMsg = '%r != %r' % (first, second)
448 msg = self._formatMessage(msg, standardMsg)
449 raise self.failureException(msg)
450
451 def assertEqual(self, first, second, msg=None):
452 """Fail if the two objects are unequal as determined by the '=='
453 operator.
454 """
455 assertion_func = self._getAssertEqualityFunc(first, second)
456 assertion_func(first, second, msg=msg)
457
458 def assertNotEqual(self, first, second, msg=None):
459 """Fail if the two objects are equal as determined by the '=='
460 operator.
461 """
462 if not first != second:
463 msg = self._formatMessage(msg, '%r == %r' % (first, second))
464 raise self.failureException(msg)
465
466 def assertAlmostEqual(self, first, second, *, places=7, msg=None):
467 """Fail if the two objects are unequal as determined by their
468 difference rounded to the given number of decimal places
469 (default 7) and comparing to zero.
470
471 Note that decimal places (from zero) are usually not the same
472 as significant digits (measured from the most signficant digit).
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000473
474 If the two objects compare equal then they will automatically
475 compare almost equal.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000476 """
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000477 if first == second:
478 # shortcut for ite
479 return
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000480 if round(abs(second-first), places) != 0:
481 standardMsg = '%r != %r within %r places' % (first, second, places)
482 msg = self._formatMessage(msg, standardMsg)
483 raise self.failureException(msg)
484
485 def assertNotAlmostEqual(self, first, second, *, places=7, msg=None):
486 """Fail if the two objects are equal as determined by their
487 difference rounded to the given number of decimal places
488 (default 7) and comparing to zero.
489
490 Note that decimal places (from zero) are usually not the same
491 as significant digits (measured from the most signficant digit).
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000492
493 Objects that are equal automatically fail.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000494 """
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000495 if (first == second) or round(abs(second-first), places) == 0:
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000496 standardMsg = '%r == %r within %r places' % (first, second, places)
497 msg = self._formatMessage(msg, standardMsg)
498 raise self.failureException(msg)
499
500 # Synonyms for assertion methods
501
502 # The plurals are undocumented. Keep them that way to discourage use.
503 # Do not add more. Do not remove.
504 # Going through a deprecation cycle on these would annoy many people.
505 assertEquals = assertEqual
506 assertNotEquals = assertNotEqual
507 assertAlmostEquals = assertAlmostEqual
508 assertNotAlmostEquals = assertNotAlmostEqual
509 assert_ = assertTrue
510
511 # These fail* assertion method names are pending deprecation and will
512 # be a DeprecationWarning in 3.2; http://bugs.python.org/issue2578
513 def _deprecate(original_func):
514 def deprecated_func(*args, **kwargs):
515 warnings.warn(
516 'Please use {0} instead.'.format(original_func.__name__),
517 DeprecationWarning, 2)
518 return original_func(*args, **kwargs)
519 return deprecated_func
520
521 failUnlessEqual = _deprecate(assertEqual)
522 failIfEqual = _deprecate(assertNotEqual)
523 failUnlessAlmostEqual = _deprecate(assertAlmostEqual)
524 failIfAlmostEqual = _deprecate(assertNotAlmostEqual)
525 failUnless = _deprecate(assertTrue)
526 failUnlessRaises = _deprecate(assertRaises)
527 failIf = _deprecate(assertFalse)
528
529 def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None):
530 """An equality assertion for ordered sequences (like lists and tuples).
531
532 For the purposes of this function, a valid orderd sequence type is one
533 which can be indexed, has a length, and has an equality operator.
534
535 Args:
536 seq1: The first sequence to compare.
537 seq2: The second sequence to compare.
538 seq_type: The expected datatype of the sequences, or None if no
539 datatype should be enforced.
540 msg: Optional message to use on failure instead of a list of
541 differences.
542 """
543 if seq_type != None:
544 seq_type_name = seq_type.__name__
545 if not isinstance(seq1, seq_type):
546 raise self.failureException('First sequence is not a %s: %r'
547 % (seq_type_name, seq1))
548 if not isinstance(seq2, seq_type):
549 raise self.failureException('Second sequence is not a %s: %r'
550 % (seq_type_name, seq2))
551 else:
552 seq_type_name = "sequence"
553
554 differing = None
555 try:
556 len1 = len(seq1)
557 except (TypeError, NotImplementedError):
558 differing = 'First %s has no length. Non-sequence?' % (
559 seq_type_name)
560
561 if differing is None:
562 try:
563 len2 = len(seq2)
564 except (TypeError, NotImplementedError):
565 differing = 'Second %s has no length. Non-sequence?' % (
566 seq_type_name)
567
568 if differing is None:
569 if seq1 == seq2:
570 return
571
572 seq1_repr = repr(seq1)
573 seq2_repr = repr(seq2)
574 if len(seq1_repr) > 30:
575 seq1_repr = seq1_repr[:30] + '...'
576 if len(seq2_repr) > 30:
577 seq2_repr = seq2_repr[:30] + '...'
578 elements = (seq_type_name.capitalize(), seq1_repr, seq2_repr)
579 differing = '%ss differ: %s != %s\n' % elements
580
581 for i in range(min(len1, len2)):
582 try:
583 item1 = seq1[i]
584 except (TypeError, IndexError, NotImplementedError):
585 differing += ('\nUnable to index element %d of first %s\n' %
586 (i, seq_type_name))
587 break
588
589 try:
590 item2 = seq2[i]
591 except (TypeError, IndexError, NotImplementedError):
592 differing += ('\nUnable to index element %d of second %s\n' %
593 (i, seq_type_name))
594 break
595
596 if item1 != item2:
597 differing += ('\nFirst differing element %d:\n%s\n%s\n' %
598 (i, item1, item2))
599 break
600 else:
601 if (len1 == len2 and seq_type is None and
602 type(seq1) != type(seq2)):
603 # The sequences are the same, but have differing types.
604 return
605
606 if len1 > len2:
607 differing += ('\nFirst %s contains %d additional '
608 'elements.\n' % (seq_type_name, len1 - len2))
609 try:
610 differing += ('First extra element %d:\n%s\n' %
611 (len2, seq1[len2]))
612 except (TypeError, IndexError, NotImplementedError):
613 differing += ('Unable to index element %d '
614 'of first %s\n' % (len2, seq_type_name))
615 elif len1 < len2:
616 differing += ('\nSecond %s contains %d additional '
617 'elements.\n' % (seq_type_name, len2 - len1))
618 try:
619 differing += ('First extra element %d:\n%s\n' %
620 (len1, seq2[len1]))
621 except (TypeError, IndexError, NotImplementedError):
622 differing += ('Unable to index element %d '
623 'of second %s\n' % (len1, seq_type_name))
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000624 standardMsg = differing + '\n' + '\n'.join(
625 difflib.ndiff(pprint.pformat(seq1).splitlines(),
626 pprint.pformat(seq2).splitlines()))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000627 msg = self._formatMessage(msg, standardMsg)
628 self.fail(msg)
629
630 def assertListEqual(self, list1, list2, msg=None):
631 """A list-specific equality assertion.
632
633 Args:
634 list1: The first list to compare.
635 list2: The second list to compare.
636 msg: Optional message to use on failure instead of a list of
637 differences.
638
639 """
640 self.assertSequenceEqual(list1, list2, msg, seq_type=list)
641
642 def assertTupleEqual(self, tuple1, tuple2, msg=None):
643 """A tuple-specific equality assertion.
644
645 Args:
646 tuple1: The first tuple to compare.
647 tuple2: The second tuple to compare.
648 msg: Optional message to use on failure instead of a list of
649 differences.
650 """
651 self.assertSequenceEqual(tuple1, tuple2, msg, seq_type=tuple)
652
653 def assertSetEqual(self, set1, set2, msg=None):
654 """A set-specific equality assertion.
655
656 Args:
657 set1: The first set to compare.
658 set2: The second set to compare.
659 msg: Optional message to use on failure instead of a list of
660 differences.
661
662 For more general containership equality, assertSameElements will work
663 with things other than sets. This uses ducktyping to support
664 different types of sets, and is optimized for sets specifically
665 (parameters must support a difference method).
666 """
667 try:
668 difference1 = set1.difference(set2)
669 except TypeError as e:
670 self.fail('invalid type when attempting set difference: %s' % e)
671 except AttributeError as e:
672 self.fail('first argument does not support set difference: %s' % e)
673
674 try:
675 difference2 = set2.difference(set1)
676 except TypeError as e:
677 self.fail('invalid type when attempting set difference: %s' % e)
678 except AttributeError as e:
679 self.fail('second argument does not support set difference: %s' % e)
680
681 if not (difference1 or difference2):
682 return
683
684 lines = []
685 if difference1:
686 lines.append('Items in the first set but not the second:')
687 for item in difference1:
688 lines.append(repr(item))
689 if difference2:
690 lines.append('Items in the second set but not the first:')
691 for item in difference2:
692 lines.append(repr(item))
693
694 standardMsg = '\n'.join(lines)
695 self.fail(self._formatMessage(msg, standardMsg))
696
697 def assertIn(self, member, container, msg=None):
698 """Just like self.assertTrue(a in b), but with a nicer default message."""
699 if member not in container:
700 standardMsg = '%r not found in %r' % (member, container)
701 self.fail(self._formatMessage(msg, standardMsg))
702
703 def assertNotIn(self, member, container, msg=None):
704 """Just like self.assertTrue(a not in b), but with a nicer default message."""
705 if member in container:
706 standardMsg = '%r unexpectedly found in %r' % (member, container)
707 self.fail(self._formatMessage(msg, standardMsg))
708
709 def assertIs(self, expr1, expr2, msg=None):
710 """Just like self.assertTrue(a is b), but with a nicer default message."""
711 if expr1 is not expr2:
712 standardMsg = '%r is not %r' % (expr1, expr2)
713 self.fail(self._formatMessage(msg, standardMsg))
714
715 def assertIsNot(self, expr1, expr2, msg=None):
716 """Just like self.assertTrue(a is not b), but with a nicer default message."""
717 if expr1 is expr2:
718 standardMsg = 'unexpectedly identical: %r' % (expr1,)
719 self.fail(self._formatMessage(msg, standardMsg))
720
721 def assertDictEqual(self, d1, d2, msg=None):
722 self.assert_(isinstance(d1, dict), 'First argument is not a dictionary')
723 self.assert_(isinstance(d2, dict), 'Second argument is not a dictionary')
724
725 if d1 != d2:
726 standardMsg = ('\n' + '\n'.join(difflib.ndiff(
727 pprint.pformat(d1).splitlines(),
728 pprint.pformat(d2).splitlines())))
729 self.fail(self._formatMessage(msg, standardMsg))
730
731 def assertDictContainsSubset(self, expected, actual, msg=None):
732 """Checks whether actual is a superset of expected."""
733 missing = []
734 mismatched = []
735 for key, value in expected.items():
736 if key not in actual:
737 missing.append(key)
738 elif value != actual[key]:
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000739 mismatched.append('%s, expected: %s, actual: %s' %
740 (key, value, actual[key]))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000741
742 if not (missing or mismatched):
743 return
744
745 standardMsg = ''
746 if missing:
747 standardMsg = 'Missing: %r' % ','.join(missing)
748 if mismatched:
749 if standardMsg:
750 standardMsg += '; '
751 standardMsg += 'Mismatched values: %s' % ','.join(mismatched)
752
753 self.fail(self._formatMessage(msg, standardMsg))
754
755 def assertSameElements(self, expected_seq, actual_seq, msg=None):
756 """An unordered sequence specific comparison.
757
758 Raises with an error message listing which elements of expected_seq
759 are missing from actual_seq and vice versa if any.
760 """
761 try:
762 expected = set(expected_seq)
763 actual = set(actual_seq)
764 missing = list(expected.difference(actual))
765 unexpected = list(actual.difference(expected))
766 missing.sort()
767 unexpected.sort()
768 except TypeError:
769 # Fall back to slower list-compare if any of the objects are
770 # not hashable.
771 expected = list(expected_seq)
772 actual = list(actual_seq)
773 try:
774 expected.sort()
775 actual.sort()
776 except TypeError:
777 missing, unexpected = util.unorderable_list_difference(expected,
778 actual)
779 else:
780 missing, unexpected = util.sorted_list_difference(expected,
781 actual)
782 errors = []
783 if missing:
784 errors.append('Expected, but missing:\n %r' % missing)
785 if unexpected:
786 errors.append('Unexpected, but present:\n %r' % unexpected)
787 if errors:
788 standardMsg = '\n'.join(errors)
789 self.fail(self._formatMessage(msg, standardMsg))
790
791 def assertMultiLineEqual(self, first, second, msg=None):
792 """Assert that two multi-line strings are equal."""
793 self.assert_(isinstance(first, str), (
794 'First argument is not a string'))
795 self.assert_(isinstance(second, str), (
796 'Second argument is not a string'))
797
798 if first != second:
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000799 standardMsg = '\n' + ''.join(difflib.ndiff(first.splitlines(True),
800 second.splitlines(True)))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000801 self.fail(self._formatMessage(msg, standardMsg))
802
803 def assertLess(self, a, b, msg=None):
804 """Just like self.assertTrue(a < b), but with a nicer default message."""
805 if not a < b:
806 standardMsg = '%r not less than %r' % (a, b)
807 self.fail(self._formatMessage(msg, standardMsg))
808
809 def assertLessEqual(self, a, b, msg=None):
810 """Just like self.assertTrue(a <= b), but with a nicer default message."""
811 if not a <= b:
812 standardMsg = '%r not less than or equal to %r' % (a, b)
813 self.fail(self._formatMessage(msg, standardMsg))
814
815 def assertGreater(self, a, b, msg=None):
816 """Just like self.assertTrue(a > b), but with a nicer default message."""
817 if not a > b:
818 standardMsg = '%r not greater than %r' % (a, b)
819 self.fail(self._formatMessage(msg, standardMsg))
820
821 def assertGreaterEqual(self, a, b, msg=None):
822 """Just like self.assertTrue(a >= b), but with a nicer default message."""
823 if not a >= b:
824 standardMsg = '%r not greater than or equal to %r' % (a, b)
825 self.fail(self._formatMessage(msg, standardMsg))
826
827 def assertIsNone(self, obj, msg=None):
828 """Same as self.assertTrue(obj is None), with a nicer default message."""
829 if obj is not None:
830 standardMsg = '%r is not None' % obj
831 self.fail(self._formatMessage(msg, standardMsg))
832
833 def assertIsNotNone(self, obj, msg=None):
834 """Included for symmetry with assertIsNone."""
835 if obj is None:
836 standardMsg = 'unexpectedly None'
837 self.fail(self._formatMessage(msg, standardMsg))
838
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000839 def assertIsInstance(self, obj, cls, msg=None):
840 """Same as self.assertTrue(isinstance(obj, cls)), with a nicer
841 default message."""
842 if not isinstance(obj, cls):
843 standardMsg = '%r is not an instance of %r' % (obj, cls)
844 self.fail(self._formatMessage(msg, standardMsg))
845
846 def assertNotIsInstance(self, obj, cls, msg=None):
847 """Included for symmetry with assertIsInstance."""
848 if isinstance(obj, cls):
849 standardMsg = '%r is an instance of %r' % (obj, cls)
850 self.fail(self._formatMessage(msg, standardMsg))
851
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000852 def assertRaisesRegexp(self, expected_exception, expected_regexp,
853 callable_obj=None, *args, **kwargs):
854 """Asserts that the message in a raised exception matches a regexp.
855
856 Args:
857 expected_exception: Exception class expected to be raised.
858 expected_regexp: Regexp (re pattern object or string) expected
859 to be found in error message.
860 callable_obj: Function to be called.
861 args: Extra args.
862 kwargs: Extra kwargs.
863 """
864 context = _AssertRaisesContext(expected_exception, self, callable_obj,
865 expected_regexp)
866 if callable_obj is None:
867 return context
868 with context:
869 callable_obj(*args, **kwargs)
870
871 def assertRegexpMatches(self, text, expected_regex, msg=None):
872 if isinstance(expected_regex, (str, bytes)):
873 expected_regex = re.compile(expected_regex)
874 if not expected_regex.search(text):
875 msg = msg or "Regexp didn't match"
876 msg = '%s: %r not found in %r' % (msg, expected_regex.pattern, text)
877 raise self.failureException(msg)
878
879
880class FunctionTestCase(TestCase):
881 """A test case that wraps a test function.
882
883 This is useful for slipping pre-existing test functions into the
884 unittest framework. Optionally, set-up and tidy-up functions can be
885 supplied. As with TestCase, the tidy-up ('tearDown') function will
886 always be called if the set-up ('setUp') function ran successfully.
887 """
888
889 def __init__(self, testFunc, setUp=None, tearDown=None, description=None):
890 super(FunctionTestCase, self).__init__()
891 self._setUpFunc = setUp
892 self._tearDownFunc = tearDown
893 self._testFunc = testFunc
894 self._description = description
895
896 def setUp(self):
897 if self._setUpFunc is not None:
898 self._setUpFunc()
899
900 def tearDown(self):
901 if self._tearDownFunc is not None:
902 self._tearDownFunc()
903
904 def runTest(self):
905 self._testFunc()
906
907 def id(self):
908 return self._testFunc.__name__
909
910 def __eq__(self, other):
911 if not isinstance(other, self.__class__):
912 return NotImplemented
913
914 return self._setUpFunc == other._setUpFunc and \
915 self._tearDownFunc == other._tearDownFunc and \
916 self._testFunc == other._testFunc and \
917 self._description == other._description
918
919 def __ne__(self, other):
920 return not self == other
921
922 def __hash__(self):
923 return hash((type(self), self._setUpFunc, self._tearDownFunc,
924 self._testFunc, self._description))
925
926 def __str__(self):
927 return "%s (%s)" % (util.strclass(self.__class__),
928 self._testFunc.__name__)
929
930 def __repr__(self):
931 return "<%s testFunc=%s>" % (util.strclass(self.__class__),
932 self._testFunc)
933
934 def shortDescription(self):
935 if self._description is not None:
936 return self._description
937 doc = self._testFunc.__doc__
938 return doc and doc.split("\n")[0].strip() or None