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