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