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