blob: 4568e1044c398530cd9a9f4c66d887d90a8297c4 [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.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000221 """
222 desc = str(self)
223 doc_first_line = None
224
225 if self._testMethodDoc:
226 doc_first_line = self._testMethodDoc.split("\n")[0].strip()
227 if doc_first_line:
228 desc = '\n'.join((desc, doc_first_line))
229 return desc
230
231 def id(self):
232 return "%s.%s" % (util.strclass(self.__class__), self._testMethodName)
233
234 def __eq__(self, other):
235 if type(self) is not type(other):
236 return NotImplemented
237
238 return self._testMethodName == other._testMethodName
239
240 def __ne__(self, other):
241 return not self == other
242
243 def __hash__(self):
244 return hash((type(self), self._testMethodName))
245
246 def __str__(self):
247 return "%s (%s)" % (self._testMethodName, util.strclass(self.__class__))
248
249 def __repr__(self):
250 return "<%s testMethod=%s>" % \
251 (util.strclass(self.__class__), self._testMethodName)
252
253 def run(self, result=None):
254 orig_result = result
255 if result is None:
256 result = self.defaultTestResult()
257 startTestRun = getattr(result, 'startTestRun', None)
258 if startTestRun is not None:
259 startTestRun()
260
261 self._resultForDoCleanups = result
262 result.startTest(self)
263 if getattr(self.__class__, "__unittest_skip__", False):
264 # If the whole class was skipped.
265 try:
266 result.addSkip(self, self.__class__.__unittest_skip_why__)
267 finally:
268 result.stopTest(self)
269 return
270 testMethod = getattr(self, self._testMethodName)
271 try:
272 success = False
273 try:
274 self.setUp()
275 except SkipTest as e:
276 result.addSkip(self, str(e))
277 except Exception:
278 result.addError(self, sys.exc_info())
279 else:
280 try:
281 testMethod()
282 except self.failureException:
283 result.addFailure(self, sys.exc_info())
284 except _ExpectedFailure as e:
285 result.addExpectedFailure(self, e.exc_info)
286 except _UnexpectedSuccess:
287 result.addUnexpectedSuccess(self)
288 except SkipTest as e:
289 result.addSkip(self, str(e))
290 except Exception:
291 result.addError(self, sys.exc_info())
292 else:
293 success = True
294
295 try:
296 self.tearDown()
297 except Exception:
298 result.addError(self, sys.exc_info())
299 success = False
300
301 cleanUpSuccess = self.doCleanups()
302 success = success and cleanUpSuccess
303 if success:
304 result.addSuccess(self)
305 finally:
306 result.stopTest(self)
307 if orig_result is None:
308 stopTestRun = getattr(result, 'stopTestRun', None)
309 if stopTestRun is not None:
310 stopTestRun()
311
312 def doCleanups(self):
313 """Execute all cleanup functions. Normally called for you after
314 tearDown."""
315 result = self._resultForDoCleanups
316 ok = True
317 while self._cleanups:
318 function, args, kwargs = self._cleanups.pop(-1)
319 try:
320 function(*args, **kwargs)
321 except Exception:
322 ok = False
323 result.addError(self, sys.exc_info())
324 return ok
325
326 def __call__(self, *args, **kwds):
327 return self.run(*args, **kwds)
328
329 def debug(self):
330 """Run the test without collecting errors in a TestResult"""
331 self.setUp()
332 getattr(self, self._testMethodName)()
333 self.tearDown()
334
335 def skipTest(self, reason):
336 """Skip this test."""
337 raise SkipTest(reason)
338
339 def fail(self, msg=None):
340 """Fail immediately, with the given message."""
341 raise self.failureException(msg)
342
343 def assertFalse(self, expr, msg=None):
344 "Fail the test if the expression is true."
345 if expr:
346 msg = self._formatMessage(msg, "%r is not False" % expr)
347 raise self.failureException(msg)
348
349 def assertTrue(self, expr, msg=None):
350 """Fail the test unless the expression is true."""
351 if not expr:
352 msg = self._formatMessage(msg, "%r is not True" % expr)
353 raise self.failureException(msg)
354
355 def _formatMessage(self, msg, standardMsg):
356 """Honour the longMessage attribute when generating failure messages.
357 If longMessage is False this means:
358 * Use only an explicit message if it is provided
359 * Otherwise use the standard message for the assert
360
361 If longMessage is True:
362 * Use the standard message
363 * If an explicit message is provided, plus ' : ' and the explicit message
364 """
365 if not self.longMessage:
366 return msg or standardMsg
367 if msg is None:
368 return standardMsg
369 return standardMsg + ' : ' + msg
370
371
372 def assertRaises(self, excClass, callableObj=None, *args, **kwargs):
373 """Fail unless an exception of class excClass is thrown
374 by callableObj when invoked with arguments args and keyword
375 arguments kwargs. If a different type of exception is
376 thrown, it will not be caught, and the test case will be
377 deemed to have suffered an error, exactly as for an
378 unexpected exception.
379
380 If called with callableObj omitted or None, will return a
381 context object used like this::
382
Michael Foordd0edec32010-02-05 22:55:09 +0000383 with self.assertRaises(SomeException):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000384 do_something()
Michael Foordd0edec32010-02-05 22:55:09 +0000385
386 The context manager keeps a reference to the exception as
387 the exc_value attribute. This allows you to inspect the
388 exception after the assertion::
389
390 with self.assertRaises(SomeException) as cm:
391 do_something()
392 the_exception = cm.exc_value
Michael Foord757cc4d2010-02-05 23:22:37 +0000393 self.assertEqual(the_exception.error_code, 3)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000394 """
395 context = _AssertRaisesContext(excClass, self)
396 if callableObj is None:
397 return context
398 with context:
399 callableObj(*args, **kwargs)
400
401 def _getAssertEqualityFunc(self, first, second):
402 """Get a detailed comparison function for the types of the two args.
403
404 Returns: A callable accepting (first, second, msg=None) that will
405 raise a failure exception if first != second with a useful human
406 readable error message for those types.
407 """
408 #
409 # NOTE(gregory.p.smith): I considered isinstance(first, type(second))
410 # and vice versa. I opted for the conservative approach in case
411 # subclasses are not intended to be compared in detail to their super
412 # class instances using a type equality func. This means testing
413 # subtypes won't automagically use the detailed comparison. Callers
414 # should use their type specific assertSpamEqual method to compare
415 # subclasses if the detailed comparison is desired and appropriate.
416 # See the discussion in http://bugs.python.org/issue2578.
417 #
418 if type(first) is type(second):
419 asserter = self._type_equality_funcs.get(type(first))
420 if asserter is not None:
Benjamin Petersond46430b2009-11-29 22:26:26 +0000421 return asserter
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000422
423 return self._baseAssertEqual
424
425 def _baseAssertEqual(self, first, second, msg=None):
426 """The default assertEqual implementation, not type specific."""
427 if not first == second:
428 standardMsg = '%r != %r' % (first, second)
429 msg = self._formatMessage(msg, standardMsg)
430 raise self.failureException(msg)
431
432 def assertEqual(self, first, second, msg=None):
433 """Fail if the two objects are unequal as determined by the '=='
434 operator.
435 """
436 assertion_func = self._getAssertEqualityFunc(first, second)
437 assertion_func(first, second, msg=msg)
438
439 def assertNotEqual(self, first, second, msg=None):
440 """Fail if the two objects are equal as determined by the '=='
441 operator.
442 """
443 if not first != second:
444 msg = self._formatMessage(msg, '%r == %r' % (first, second))
445 raise self.failureException(msg)
446
447 def assertAlmostEqual(self, first, second, places=7, msg=None):
448 """Fail if the two objects are unequal as determined by their
449 difference rounded to the given number of decimal places
450 (default 7) and comparing to zero.
451
452 Note that decimal places (from zero) are usually not the same
453 as significant digits (measured from the most signficant digit).
Michael Foordc3f79372009-09-13 16:40:02 +0000454
455 If the two objects compare equal then they will automatically
456 compare almost equal.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000457 """
Michael Foordc3f79372009-09-13 16:40:02 +0000458 if first == second:
459 # shortcut for ite
460 return
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000461 if round(abs(second-first), places) != 0:
462 standardMsg = '%r != %r within %r places' % (first, second, places)
463 msg = self._formatMessage(msg, standardMsg)
464 raise self.failureException(msg)
465
466 def assertNotAlmostEqual(self, first, second, places=7, msg=None):
467 """Fail if the two objects are equal as determined by their
468 difference rounded to the given number of decimal places
469 (default 7) and comparing to zero.
470
471 Note that decimal places (from zero) are usually not the same
472 as significant digits (measured from the most signficant digit).
Michael Foordc3f79372009-09-13 16:40:02 +0000473
474 Objects that are equal automatically fail.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000475 """
Michael Foordc3f79372009-09-13 16:40:02 +0000476 if (first == second) or round(abs(second-first), places) == 0:
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000477 standardMsg = '%r == %r within %r places' % (first, second, places)
478 msg = self._formatMessage(msg, standardMsg)
479 raise self.failureException(msg)
480
481 # Synonyms for assertion methods
482
483 # The plurals are undocumented. Keep them that way to discourage use.
484 # Do not add more. Do not remove.
485 # Going through a deprecation cycle on these would annoy many people.
486 assertEquals = assertEqual
487 assertNotEquals = assertNotEqual
488 assertAlmostEquals = assertAlmostEqual
489 assertNotAlmostEquals = assertNotAlmostEqual
490 assert_ = assertTrue
491
492 # These fail* assertion method names are pending deprecation and will
493 # be a DeprecationWarning in 3.2; http://bugs.python.org/issue2578
494 def _deprecate(original_func):
495 def deprecated_func(*args, **kwargs):
496 warnings.warn(
497 'Please use {0} instead.'.format(original_func.__name__),
498 PendingDeprecationWarning, 2)
499 return original_func(*args, **kwargs)
500 return deprecated_func
501
502 failUnlessEqual = _deprecate(assertEqual)
503 failIfEqual = _deprecate(assertNotEqual)
504 failUnlessAlmostEqual = _deprecate(assertAlmostEqual)
505 failIfAlmostEqual = _deprecate(assertNotAlmostEqual)
506 failUnless = _deprecate(assertTrue)
507 failUnlessRaises = _deprecate(assertRaises)
508 failIf = _deprecate(assertFalse)
509
510 def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None):
511 """An equality assertion for ordered sequences (like lists and tuples).
512
R. David Murray05b41712010-01-29 19:35:39 +0000513 For the purposes of this function, a valid ordered sequence type is one
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000514 which can be indexed, has a length, and has an equality operator.
515
516 Args:
517 seq1: The first sequence to compare.
518 seq2: The second sequence to compare.
519 seq_type: The expected datatype of the sequences, or None if no
520 datatype should be enforced.
521 msg: Optional message to use on failure instead of a list of
522 differences.
523 """
524 if seq_type != None:
525 seq_type_name = seq_type.__name__
526 if not isinstance(seq1, seq_type):
527 raise self.failureException('First sequence is not a %s: %r'
528 % (seq_type_name, seq1))
529 if not isinstance(seq2, seq_type):
530 raise self.failureException('Second sequence is not a %s: %r'
531 % (seq_type_name, seq2))
532 else:
533 seq_type_name = "sequence"
534
535 differing = None
536 try:
537 len1 = len(seq1)
538 except (TypeError, NotImplementedError):
539 differing = 'First %s has no length. Non-sequence?' % (
540 seq_type_name)
541
542 if differing is None:
543 try:
544 len2 = len(seq2)
545 except (TypeError, NotImplementedError):
546 differing = 'Second %s has no length. Non-sequence?' % (
547 seq_type_name)
548
549 if differing is None:
550 if seq1 == seq2:
551 return
552
553 seq1_repr = repr(seq1)
554 seq2_repr = repr(seq2)
555 if len(seq1_repr) > 30:
556 seq1_repr = seq1_repr[:30] + '...'
557 if len(seq2_repr) > 30:
558 seq2_repr = seq2_repr[:30] + '...'
559 elements = (seq_type_name.capitalize(), seq1_repr, seq2_repr)
560 differing = '%ss differ: %s != %s\n' % elements
561
562 for i in xrange(min(len1, len2)):
563 try:
564 item1 = seq1[i]
565 except (TypeError, IndexError, NotImplementedError):
566 differing += ('\nUnable to index element %d of first %s\n' %
567 (i, seq_type_name))
568 break
569
570 try:
571 item2 = seq2[i]
572 except (TypeError, IndexError, NotImplementedError):
573 differing += ('\nUnable to index element %d of second %s\n' %
574 (i, seq_type_name))
575 break
576
577 if item1 != item2:
578 differing += ('\nFirst differing element %d:\n%s\n%s\n' %
579 (i, item1, item2))
580 break
581 else:
582 if (len1 == len2 and seq_type is None and
583 type(seq1) != type(seq2)):
584 # The sequences are the same, but have differing types.
585 return
586
587 if len1 > len2:
588 differing += ('\nFirst %s contains %d additional '
589 'elements.\n' % (seq_type_name, len1 - len2))
590 try:
591 differing += ('First extra element %d:\n%s\n' %
592 (len2, seq1[len2]))
593 except (TypeError, IndexError, NotImplementedError):
594 differing += ('Unable to index element %d '
595 'of first %s\n' % (len2, seq_type_name))
596 elif len1 < len2:
597 differing += ('\nSecond %s contains %d additional '
598 'elements.\n' % (seq_type_name, len2 - len1))
599 try:
600 differing += ('First extra element %d:\n%s\n' %
601 (len1, seq2[len1]))
602 except (TypeError, IndexError, NotImplementedError):
603 differing += ('Unable to index element %d '
604 'of second %s\n' % (len1, seq_type_name))
Georg Brandl46cc46a2009-10-01 20:11:14 +0000605 standardMsg = differing + '\n' + '\n'.join(
606 difflib.ndiff(pprint.pformat(seq1).splitlines(),
607 pprint.pformat(seq2).splitlines()))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000608 msg = self._formatMessage(msg, standardMsg)
609 self.fail(msg)
610
611 def assertListEqual(self, list1, list2, msg=None):
612 """A list-specific equality assertion.
613
614 Args:
615 list1: The first list to compare.
616 list2: The second list to compare.
617 msg: Optional message to use on failure instead of a list of
618 differences.
619
620 """
621 self.assertSequenceEqual(list1, list2, msg, seq_type=list)
622
623 def assertTupleEqual(self, tuple1, tuple2, msg=None):
624 """A tuple-specific equality assertion.
625
626 Args:
627 tuple1: The first tuple to compare.
628 tuple2: The second tuple to compare.
629 msg: Optional message to use on failure instead of a list of
630 differences.
631 """
632 self.assertSequenceEqual(tuple1, tuple2, msg, seq_type=tuple)
633
634 def assertSetEqual(self, set1, set2, msg=None):
635 """A set-specific equality assertion.
636
637 Args:
638 set1: The first set to compare.
639 set2: The second set to compare.
640 msg: Optional message to use on failure instead of a list of
641 differences.
642
643 For more general containership equality, assertSameElements will work
644 with things other than sets. This uses ducktyping to support
645 different types of sets, and is optimized for sets specifically
646 (parameters must support a difference method).
647 """
648 try:
649 difference1 = set1.difference(set2)
650 except TypeError, e:
651 self.fail('invalid type when attempting set difference: %s' % e)
652 except AttributeError, e:
653 self.fail('first argument does not support set difference: %s' % e)
654
655 try:
656 difference2 = set2.difference(set1)
657 except TypeError, e:
658 self.fail('invalid type when attempting set difference: %s' % e)
659 except AttributeError, e:
660 self.fail('second argument does not support set difference: %s' % e)
661
662 if not (difference1 or difference2):
663 return
664
665 lines = []
666 if difference1:
667 lines.append('Items in the first set but not the second:')
668 for item in difference1:
669 lines.append(repr(item))
670 if difference2:
671 lines.append('Items in the second set but not the first:')
672 for item in difference2:
673 lines.append(repr(item))
674
675 standardMsg = '\n'.join(lines)
676 self.fail(self._formatMessage(msg, standardMsg))
677
678 def assertIn(self, member, container, msg=None):
679 """Just like self.assertTrue(a in b), but with a nicer default message."""
680 if member not in container:
681 standardMsg = '%r not found in %r' % (member, container)
682 self.fail(self._formatMessage(msg, standardMsg))
683
684 def assertNotIn(self, member, container, msg=None):
685 """Just like self.assertTrue(a not in b), but with a nicer default message."""
686 if member in container:
687 standardMsg = '%r unexpectedly found in %r' % (member, container)
688 self.fail(self._formatMessage(msg, standardMsg))
689
690 def assertIs(self, expr1, expr2, msg=None):
691 """Just like self.assertTrue(a is b), but with a nicer default message."""
692 if expr1 is not expr2:
693 standardMsg = '%r is not %r' % (expr1, expr2)
694 self.fail(self._formatMessage(msg, standardMsg))
695
696 def assertIsNot(self, expr1, expr2, msg=None):
697 """Just like self.assertTrue(a is not b), but with a nicer default message."""
698 if expr1 is expr2:
699 standardMsg = 'unexpectedly identical: %r' % (expr1,)
700 self.fail(self._formatMessage(msg, standardMsg))
701
702 def assertDictEqual(self, d1, d2, msg=None):
703 self.assert_(isinstance(d1, dict), 'First argument is not a dictionary')
704 self.assert_(isinstance(d2, dict), 'Second argument is not a dictionary')
705
706 if d1 != d2:
707 standardMsg = ('\n' + '\n'.join(difflib.ndiff(
708 pprint.pformat(d1).splitlines(),
709 pprint.pformat(d2).splitlines())))
710 self.fail(self._formatMessage(msg, standardMsg))
711
712 def assertDictContainsSubset(self, expected, actual, msg=None):
713 """Checks whether actual is a superset of expected."""
714 missing = []
715 mismatched = []
716 for key, value in expected.iteritems():
717 if key not in actual:
718 missing.append(key)
719 elif value != actual[key]:
Georg Brandl46cc46a2009-10-01 20:11:14 +0000720 mismatched.append('%s, expected: %s, actual: %s' %
721 (key, value, actual[key]))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000722
723 if not (missing or mismatched):
724 return
725
726 standardMsg = ''
727 if missing:
728 standardMsg = 'Missing: %r' % ','.join(missing)
729 if mismatched:
730 if standardMsg:
731 standardMsg += '; '
732 standardMsg += 'Mismatched values: %s' % ','.join(mismatched)
733
734 self.fail(self._formatMessage(msg, standardMsg))
735
736 def assertSameElements(self, expected_seq, actual_seq, msg=None):
737 """An unordered sequence specific comparison.
738
739 Raises with an error message listing which elements of expected_seq
740 are missing from actual_seq and vice versa if any.
Michael Foordd0edec32010-02-05 22:55:09 +0000741
742 Duplicate elements are ignored when comparing *expected_seq* and
743 *actual_seq*. It is the equivalent of ``assertEqual(set(expected),
744 set(actual))`` but it works with sequences of unhashable objects as
745 well.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000746 """
747 try:
748 expected = set(expected_seq)
749 actual = set(actual_seq)
750 missing = list(expected.difference(actual))
751 unexpected = list(actual.difference(expected))
752 missing.sort()
753 unexpected.sort()
754 except TypeError:
755 # Fall back to slower list-compare if any of the objects are
756 # not hashable.
757 expected = list(expected_seq)
758 actual = list(actual_seq)
Antoine Pitroub9d49632010-01-04 23:22:44 +0000759 with warnings.catch_warnings():
760 if sys.py3kwarning:
761 # Silence Py3k warning
762 warnings.filterwarnings("ignore",
763 "dict inequality comparisons "
764 "not supported", DeprecationWarning)
765 expected.sort()
766 actual.sort()
767 missing, unexpected = util.sorted_list_difference(expected, actual)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000768 errors = []
769 if missing:
770 errors.append('Expected, but missing:\n %r' % missing)
771 if unexpected:
772 errors.append('Unexpected, but present:\n %r' % unexpected)
773 if errors:
774 standardMsg = '\n'.join(errors)
775 self.fail(self._formatMessage(msg, standardMsg))
776
777 def assertMultiLineEqual(self, first, second, msg=None):
778 """Assert that two multi-line strings are equal."""
779 self.assert_(isinstance(first, basestring), (
780 'First argument is not a string'))
781 self.assert_(isinstance(second, basestring), (
782 'Second argument is not a string'))
783
784 if first != second:
Georg Brandl46cc46a2009-10-01 20:11:14 +0000785 standardMsg = '\n' + ''.join(difflib.ndiff(first.splitlines(True),
786 second.splitlines(True)))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000787 self.fail(self._formatMessage(msg, standardMsg))
788
789 def assertLess(self, a, b, msg=None):
790 """Just like self.assertTrue(a < b), but with a nicer default message."""
791 if not a < b:
792 standardMsg = '%r not less than %r' % (a, b)
793 self.fail(self._formatMessage(msg, standardMsg))
794
795 def assertLessEqual(self, a, b, msg=None):
796 """Just like self.assertTrue(a <= b), but with a nicer default message."""
797 if not a <= b:
798 standardMsg = '%r not less than or equal to %r' % (a, b)
799 self.fail(self._formatMessage(msg, standardMsg))
800
801 def assertGreater(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 greater than %r' % (a, b)
805 self.fail(self._formatMessage(msg, standardMsg))
806
807 def assertGreaterEqual(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 greater than or equal to %r' % (a, b)
811 self.fail(self._formatMessage(msg, standardMsg))
812
813 def assertIsNone(self, obj, msg=None):
814 """Same as self.assertTrue(obj is None), with a nicer default message."""
815 if obj is not None:
816 standardMsg = '%r is not None' % obj
817 self.fail(self._formatMessage(msg, standardMsg))
818
819 def assertIsNotNone(self, obj, msg=None):
820 """Included for symmetry with assertIsNone."""
821 if obj is None:
822 standardMsg = 'unexpectedly None'
823 self.fail(self._formatMessage(msg, standardMsg))
824
Georg Brandlf895cf52009-10-01 20:59:31 +0000825 def assertIsInstance(self, obj, cls, msg=None):
826 """Same as self.assertTrue(isinstance(obj, cls)), with a nicer
827 default message."""
828 if not isinstance(obj, cls):
829 standardMsg = '%r is not an instance of %r' % (obj, cls)
830 self.fail(self._formatMessage(msg, standardMsg))
831
832 def assertNotIsInstance(self, obj, cls, msg=None):
833 """Included for symmetry with assertIsInstance."""
834 if isinstance(obj, cls):
835 standardMsg = '%r is an instance of %r' % (obj, cls)
836 self.fail(self._formatMessage(msg, standardMsg))
837
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000838 def assertRaisesRegexp(self, expected_exception, expected_regexp,
839 callable_obj=None, *args, **kwargs):
840 """Asserts that the message in a raised exception matches a regexp.
841
842 Args:
843 expected_exception: Exception class expected to be raised.
844 expected_regexp: Regexp (re pattern object or string) expected
845 to be found in error message.
846 callable_obj: Function to be called.
847 args: Extra args.
848 kwargs: Extra kwargs.
849 """
850 context = _AssertRaisesContext(expected_exception, self, expected_regexp)
851 if callable_obj is None:
852 return context
853 with context:
854 callable_obj(*args, **kwargs)
855
856 def assertRegexpMatches(self, text, expected_regex, msg=None):
857 if isinstance(expected_regex, basestring):
858 expected_regex = re.compile(expected_regex)
859 if not expected_regex.search(text):
860 msg = msg or "Regexp didn't match"
861 msg = '%s: %r not found in %r' % (msg, expected_regex.pattern, text)
862 raise self.failureException(msg)
863
864
865class FunctionTestCase(TestCase):
866 """A test case that wraps a test function.
867
868 This is useful for slipping pre-existing test functions into the
869 unittest framework. Optionally, set-up and tidy-up functions can be
870 supplied. As with TestCase, the tidy-up ('tearDown') function will
871 always be called if the set-up ('setUp') function ran successfully.
872 """
873
874 def __init__(self, testFunc, setUp=None, tearDown=None, description=None):
875 super(FunctionTestCase, self).__init__()
876 self._setUpFunc = setUp
877 self._tearDownFunc = tearDown
878 self._testFunc = testFunc
879 self._description = description
880
881 def setUp(self):
882 if self._setUpFunc is not None:
883 self._setUpFunc()
884
885 def tearDown(self):
886 if self._tearDownFunc is not None:
887 self._tearDownFunc()
888
889 def runTest(self):
890 self._testFunc()
891
892 def id(self):
893 return self._testFunc.__name__
894
895 def __eq__(self, other):
896 if not isinstance(other, self.__class__):
897 return NotImplemented
898
899 return self._setUpFunc == other._setUpFunc and \
900 self._tearDownFunc == other._tearDownFunc and \
901 self._testFunc == other._testFunc and \
902 self._description == other._description
903
904 def __ne__(self, other):
905 return not self == other
906
907 def __hash__(self):
908 return hash((type(self), self._setUpFunc, self._tearDownFunc,
909 self._testFunc, self._description))
910
911 def __str__(self):
912 return "%s (%s)" % (util.strclass(self.__class__),
913 self._testFunc.__name__)
914
915 def __repr__(self):
916 return "<%s testFunc=%s>" % (util.strclass(self.__class__),
917 self._testFunc)
918
919 def shortDescription(self):
920 if self._description is not None:
921 return self._description
922 doc = self._testFunc.__doc__
923 return doc and doc.split("\n")[0].strip() or None