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