blob: 33ab47a4b59625167f15a75c1bf3d9360c2e8a86 [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
Michael Foord225a0992010-02-18 20:30:09 +000010from . import result
Michael Foord98e7b762010-03-20 03:00:34 +000011from .util import (
12 strclass, safe_repr, sorted_list_difference, unorderable_list_difference
13)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000014
Michael Foordb1aa30f2010-03-22 00:06:30 +000015__unittest = True
Michael Foordb1aa30f2010-03-22 00:06:30 +000016
Michael Foord5fe21ff2010-06-05 13:38:16 +000017
18DIFF_OMITTED = ('\nDiff is %s characters long. '
19 'Set self.maxDiff to None to see it.')
20
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000021class SkipTest(Exception):
22 """
23 Raise this exception in a test to skip it.
24
25 Usually you can use TestResult.skip() or one of the skipping decorators
26 instead of raising this directly.
27 """
28 pass
29
30class _ExpectedFailure(Exception):
31 """
32 Raise this when a test is expected to fail.
33
34 This is an implementation detail.
35 """
36
37 def __init__(self, exc_info):
38 super(_ExpectedFailure, self).__init__()
39 self.exc_info = exc_info
40
41class _UnexpectedSuccess(Exception):
42 """
43 The test was supposed to fail, but it didn't!
44 """
45 pass
46
47def _id(obj):
48 return obj
49
50def skip(reason):
51 """
52 Unconditionally skip a test.
53 """
54 def decorator(test_item):
Michael Foord53e8eea2010-03-07 20:22:12 +000055 if not (isinstance(test_item, type) and issubclass(test_item, TestCase)):
56 @functools.wraps(test_item)
57 def skip_wrapper(*args, **kwargs):
58 raise SkipTest(reason)
59 test_item = skip_wrapper
60
61 test_item.__unittest_skip__ = True
62 test_item.__unittest_skip_why__ = reason
63 return test_item
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000064 return decorator
65
66def skipIf(condition, reason):
67 """
68 Skip a test if the condition is true.
69 """
70 if condition:
71 return skip(reason)
72 return _id
73
74def skipUnless(condition, reason):
75 """
76 Skip a test unless the condition is true.
77 """
78 if not condition:
79 return skip(reason)
80 return _id
81
82
83def expectedFailure(func):
84 @functools.wraps(func)
85 def wrapper(*args, **kwargs):
86 try:
87 func(*args, **kwargs)
88 except Exception:
89 raise _ExpectedFailure(sys.exc_info())
90 raise _UnexpectedSuccess
91 return wrapper
92
93
94class _AssertRaisesContext(object):
95 """A context manager used to implement TestCase.assertRaises* methods."""
96
97 def __init__(self, expected, test_case, expected_regexp=None):
98 self.expected = expected
99 self.failureException = test_case.failureException
Georg Brandlb0eb4d32010-02-07 11:34:15 +0000100 self.expected_regexp = expected_regexp
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000101
102 def __enter__(self):
Michael Foord2bd52dc2010-02-07 18:44:12 +0000103 return self
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000104
105 def __exit__(self, exc_type, exc_value, tb):
106 if exc_type is None:
107 try:
108 exc_name = self.expected.__name__
109 except AttributeError:
110 exc_name = str(self.expected)
111 raise self.failureException(
112 "{0} not raised".format(exc_name))
113 if not issubclass(exc_type, self.expected):
114 # let unexpected exceptions pass through
115 return False
Georg Brandldc3694b2010-02-07 17:02:22 +0000116 self.exception = exc_value # store for later retrieval
Georg Brandlb0eb4d32010-02-07 11:34:15 +0000117 if self.expected_regexp is None:
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000118 return True
119
Georg Brandlb0eb4d32010-02-07 11:34:15 +0000120 expected_regexp = self.expected_regexp
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000121 if isinstance(expected_regexp, basestring):
122 expected_regexp = re.compile(expected_regexp)
123 if not expected_regexp.search(str(exc_value)):
124 raise self.failureException('"%s" does not match "%s"' %
125 (expected_regexp.pattern, str(exc_value)))
126 return True
127
128
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000129class TestCase(object):
130 """A class whose instances are single test cases.
131
132 By default, the test code itself should be placed in a method named
133 'runTest'.
134
135 If the fixture may be used for many test cases, create as
136 many test methods as are needed. When instantiating such a TestCase
137 subclass, specify in the constructor arguments the name of the test method
138 that the instance is to execute.
139
140 Test authors should subclass TestCase for their own tests. Construction
141 and deconstruction of the test's environment ('fixture') can be
142 implemented by overriding the 'setUp' and 'tearDown' methods respectively.
143
144 If it is necessary to override the __init__ method, the base class
145 __init__ method must always be called. It is important that subclasses
146 should not change the signature of their __init__ method, since instances
147 of the classes are instantiated automatically by parts of the framework
148 in order to be run.
149 """
150
151 # This attribute determines which exception will be raised when
152 # the instance's assertion methods fail; test methods raising this
153 # exception will be deemed to have 'failed' rather than 'errored'
154
155 failureException = AssertionError
156
157 # This attribute determines whether long messages (including repr of
158 # objects used in assert methods) will be printed on failure in *addition*
159 # to any explicit message passed.
160
161 longMessage = False
162
Michael Foordae1bb9a2010-06-09 12:29:56 +0000163 # This attribute sets the maximum length of a diff in failure messages
Michael Foorde37d75f2010-06-05 12:10:52 +0000164 # by assert methods using difflib. It is looked up as an instance attribute
165 # so can be configured by individual tests if required.
Michael Foordc532c572010-06-05 23:58:40 +0000166
Michael Foorde37d75f2010-06-05 12:10:52 +0000167 maxDiff = 80*8
168
Michael Foord5ffa3252010-03-07 22:04:55 +0000169 # Attribute used by TestSuite for classSetUp
170
171 _classSetupFailed = False
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000172
173 def __init__(self, methodName='runTest'):
174 """Create an instance of the class that will use the named test
175 method when executed. Raises a ValueError if the instance does
176 not have a method with the specified name.
177 """
178 self._testMethodName = methodName
179 self._resultForDoCleanups = None
180 try:
181 testMethod = getattr(self, methodName)
182 except AttributeError:
Michael Foordc2294dd2010-02-18 21:37:07 +0000183 raise ValueError("no such test method in %s: %s" %
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000184 (self.__class__, methodName))
185 self._testMethodDoc = testMethod.__doc__
186 self._cleanups = []
187
188 # Map types to custom assertEqual functions that will compare
189 # instances of said type in more detail to generate a more useful
190 # error message.
191 self._type_equality_funcs = {}
192 self.addTypeEqualityFunc(dict, self.assertDictEqual)
193 self.addTypeEqualityFunc(list, self.assertListEqual)
194 self.addTypeEqualityFunc(tuple, self.assertTupleEqual)
195 self.addTypeEqualityFunc(set, self.assertSetEqual)
196 self.addTypeEqualityFunc(frozenset, self.assertSetEqual)
Michael Foordfe6349c2010-02-08 22:41:16 +0000197 self.addTypeEqualityFunc(unicode, self.assertMultiLineEqual)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000198
199 def addTypeEqualityFunc(self, typeobj, function):
200 """Add a type specific assertEqual style function to compare a type.
201
202 This method is for use by TestCase subclasses that need to register
203 their own type equality functions to provide nicer error messages.
204
205 Args:
206 typeobj: The data type to call this function on when both values
207 are of the same type in assertEqual().
208 function: The callable taking two arguments and an optional
209 msg= argument that raises self.failureException with a
210 useful error message when the two arguments are not equal.
211 """
Benjamin Petersond46430b2009-11-29 22:26:26 +0000212 self._type_equality_funcs[typeobj] = function
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000213
214 def addCleanup(self, function, *args, **kwargs):
215 """Add a function, with arguments, to be called when the test is
216 completed. Functions added are called on a LIFO basis and are
217 called after tearDown on test failure or success.
218
219 Cleanup items are called even if setUp fails (unlike tearDown)."""
220 self._cleanups.append((function, args, kwargs))
221
222 def setUp(self):
223 "Hook method for setting up the test fixture before exercising it."
224 pass
225
226 def tearDown(self):
227 "Hook method for deconstructing the test fixture after testing it."
228 pass
229
Michael Foord5ffa3252010-03-07 22:04:55 +0000230 @classmethod
231 def setUpClass(cls):
232 "Hook method for setting up class fixture before running tests in the class."
233
234 @classmethod
235 def tearDownClass(cls):
236 "Hook method for deconstructing the class fixture after running all tests in the class."
237
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000238 def countTestCases(self):
239 return 1
240
241 def defaultTestResult(self):
242 return result.TestResult()
243
244 def shortDescription(self):
Michael Foorddb43b5a2010-02-10 14:25:12 +0000245 """Returns a one-line description of the test, or None if no
246 description has been provided.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000247
Michael Foorddb43b5a2010-02-10 14:25:12 +0000248 The default implementation of this method returns the first line of
249 the specified test method's docstring.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000250 """
Michael Foorddb43b5a2010-02-10 14:25:12 +0000251 doc = self._testMethodDoc
252 return doc and doc.split("\n")[0].strip() or None
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000253
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000254
255 def id(self):
Michael Foord225a0992010-02-18 20:30:09 +0000256 return "%s.%s" % (strclass(self.__class__), self._testMethodName)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000257
258 def __eq__(self, other):
259 if type(self) is not type(other):
260 return NotImplemented
261
262 return self._testMethodName == other._testMethodName
263
264 def __ne__(self, other):
265 return not self == other
266
267 def __hash__(self):
268 return hash((type(self), self._testMethodName))
269
270 def __str__(self):
Michael Foord225a0992010-02-18 20:30:09 +0000271 return "%s (%s)" % (self._testMethodName, strclass(self.__class__))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000272
273 def __repr__(self):
274 return "<%s testMethod=%s>" % \
Michael Foord225a0992010-02-18 20:30:09 +0000275 (strclass(self.__class__), self._testMethodName)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000276
Michael Foordae3db0a2010-02-22 23:28:32 +0000277 def _addSkip(self, result, reason):
278 addSkip = getattr(result, 'addSkip', None)
279 if addSkip is not None:
280 addSkip(self, reason)
281 else:
282 warnings.warn("TestResult has no addSkip method, skips not reported",
283 RuntimeWarning, 2)
284 result.addSuccess(self)
285
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000286 def run(self, result=None):
287 orig_result = result
288 if result is None:
289 result = self.defaultTestResult()
290 startTestRun = getattr(result, 'startTestRun', None)
291 if startTestRun is not None:
292 startTestRun()
293
294 self._resultForDoCleanups = result
295 result.startTest(self)
Michael Foord53e8eea2010-03-07 20:22:12 +0000296
297 testMethod = getattr(self, self._testMethodName)
298 if (getattr(self.__class__, "__unittest_skip__", False) or
299 getattr(testMethod, "__unittest_skip__", False)):
300 # If the class or method was skipped.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000301 try:
Michael Foord53e8eea2010-03-07 20:22:12 +0000302 skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
303 or getattr(testMethod, '__unittest_skip_why__', ''))
304 self._addSkip(result, skip_why)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000305 finally:
306 result.stopTest(self)
307 return
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000308 try:
309 success = False
310 try:
311 self.setUp()
312 except SkipTest as e:
Michael Foordae3db0a2010-02-22 23:28:32 +0000313 self._addSkip(result, str(e))
Michael Foorda17f0762010-12-19 14:53:19 +0000314 except KeyboardInterrupt:
315 raise
316 except:
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000317 result.addError(self, sys.exc_info())
318 else:
319 try:
320 testMethod()
Michael Foorda17f0762010-12-19 14:53:19 +0000321 except KeyboardInterrupt:
322 raise
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000323 except self.failureException:
324 result.addFailure(self, sys.exc_info())
325 except _ExpectedFailure as e:
Michael Foordae3db0a2010-02-22 23:28:32 +0000326 addExpectedFailure = getattr(result, 'addExpectedFailure', None)
327 if addExpectedFailure is not None:
328 addExpectedFailure(self, e.exc_info)
329 else:
330 warnings.warn("TestResult has no addExpectedFailure method, reporting as passes",
331 RuntimeWarning)
332 result.addSuccess(self)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000333 except _UnexpectedSuccess:
Michael Foordae3db0a2010-02-22 23:28:32 +0000334 addUnexpectedSuccess = getattr(result, 'addUnexpectedSuccess', None)
335 if addUnexpectedSuccess is not None:
336 addUnexpectedSuccess(self)
337 else:
338 warnings.warn("TestResult has no addUnexpectedSuccess method, reporting as failures",
339 RuntimeWarning)
340 result.addFailure(self, sys.exc_info())
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000341 except SkipTest as e:
Michael Foordae3db0a2010-02-22 23:28:32 +0000342 self._addSkip(result, str(e))
Michael Foorda17f0762010-12-19 14:53:19 +0000343 except:
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000344 result.addError(self, sys.exc_info())
345 else:
346 success = True
347
348 try:
349 self.tearDown()
Michael Foorda17f0762010-12-19 14:53:19 +0000350 except KeyboardInterrupt:
351 raise
352 except:
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000353 result.addError(self, sys.exc_info())
354 success = False
355
356 cleanUpSuccess = self.doCleanups()
357 success = success and cleanUpSuccess
358 if success:
359 result.addSuccess(self)
360 finally:
361 result.stopTest(self)
362 if orig_result is None:
363 stopTestRun = getattr(result, 'stopTestRun', None)
364 if stopTestRun is not None:
365 stopTestRun()
366
367 def doCleanups(self):
368 """Execute all cleanup functions. Normally called for you after
369 tearDown."""
370 result = self._resultForDoCleanups
371 ok = True
372 while self._cleanups:
373 function, args, kwargs = self._cleanups.pop(-1)
374 try:
375 function(*args, **kwargs)
Michael Foorda17f0762010-12-19 14:53:19 +0000376 except KeyboardInterrupt:
377 raise
378 except:
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000379 ok = False
380 result.addError(self, sys.exc_info())
381 return ok
382
383 def __call__(self, *args, **kwds):
384 return self.run(*args, **kwds)
385
386 def debug(self):
387 """Run the test without collecting errors in a TestResult"""
388 self.setUp()
389 getattr(self, self._testMethodName)()
390 self.tearDown()
Michael Foord0fedb282010-06-08 22:44:52 +0000391 while self._cleanups:
392 function, args, kwargs = self._cleanups.pop(-1)
393 function(*args, **kwargs)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000394
395 def skipTest(self, reason):
396 """Skip this test."""
397 raise SkipTest(reason)
398
399 def fail(self, msg=None):
400 """Fail immediately, with the given message."""
401 raise self.failureException(msg)
402
403 def assertFalse(self, expr, msg=None):
Ezio Melottic139a562010-12-18 17:58:29 +0000404 """Check that the expression is false."""
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000405 if expr:
Ezio Melottic139a562010-12-18 17:58:29 +0000406 msg = self._formatMessage(msg, "%s is not false" % safe_repr(expr))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000407 raise self.failureException(msg)
408
409 def assertTrue(self, expr, msg=None):
Ezio Melottic139a562010-12-18 17:58:29 +0000410 """Check that the expression is true."""
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000411 if not expr:
Ezio Melottic139a562010-12-18 17:58:29 +0000412 msg = self._formatMessage(msg, "%s is not true" % safe_repr(expr))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000413 raise self.failureException(msg)
414
415 def _formatMessage(self, msg, standardMsg):
416 """Honour the longMessage attribute when generating failure messages.
417 If longMessage is False this means:
418 * Use only an explicit message if it is provided
419 * Otherwise use the standard message for the assert
420
421 If longMessage is True:
422 * Use the standard message
423 * If an explicit message is provided, plus ' : ' and the explicit message
424 """
425 if not self.longMessage:
426 return msg or standardMsg
427 if msg is None:
428 return standardMsg
Michael Foord53e8eea2010-03-07 20:22:12 +0000429 try:
430 # don't switch to '{}' formatting in Python 2.X
431 # it changes the way unicode input is handled
432 return '%s : %s' % (standardMsg, msg)
433 except UnicodeDecodeError:
434 return '%s : %s' % (safe_repr(standardMsg), safe_repr(msg))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000435
436
437 def assertRaises(self, excClass, callableObj=None, *args, **kwargs):
438 """Fail unless an exception of class excClass is thrown
439 by callableObj when invoked with arguments args and keyword
440 arguments kwargs. If a different type of exception is
441 thrown, it will not be caught, and the test case will be
442 deemed to have suffered an error, exactly as for an
443 unexpected exception.
444
445 If called with callableObj omitted or None, will return a
446 context object used like this::
447
Michael Foordd0edec32010-02-05 22:55:09 +0000448 with self.assertRaises(SomeException):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000449 do_something()
Michael Foordd0edec32010-02-05 22:55:09 +0000450
451 The context manager keeps a reference to the exception as
Ezio Melotticd4f6572010-02-08 21:52:08 +0000452 the 'exception' attribute. This allows you to inspect the
Michael Foordd0edec32010-02-05 22:55:09 +0000453 exception after the assertion::
454
455 with self.assertRaises(SomeException) as cm:
456 do_something()
Georg Brandldc3694b2010-02-07 17:02:22 +0000457 the_exception = cm.exception
Michael Foord757cc4d2010-02-05 23:22:37 +0000458 self.assertEqual(the_exception.error_code, 3)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000459 """
460 context = _AssertRaisesContext(excClass, self)
461 if callableObj is None:
462 return context
463 with context:
464 callableObj(*args, **kwargs)
465
466 def _getAssertEqualityFunc(self, first, second):
467 """Get a detailed comparison function for the types of the two args.
468
469 Returns: A callable accepting (first, second, msg=None) that will
470 raise a failure exception if first != second with a useful human
471 readable error message for those types.
472 """
473 #
474 # NOTE(gregory.p.smith): I considered isinstance(first, type(second))
475 # and vice versa. I opted for the conservative approach in case
476 # subclasses are not intended to be compared in detail to their super
477 # class instances using a type equality func. This means testing
478 # subtypes won't automagically use the detailed comparison. Callers
479 # should use their type specific assertSpamEqual method to compare
480 # subclasses if the detailed comparison is desired and appropriate.
481 # See the discussion in http://bugs.python.org/issue2578.
482 #
483 if type(first) is type(second):
484 asserter = self._type_equality_funcs.get(type(first))
485 if asserter is not None:
Benjamin Petersond46430b2009-11-29 22:26:26 +0000486 return asserter
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000487
488 return self._baseAssertEqual
489
490 def _baseAssertEqual(self, first, second, msg=None):
491 """The default assertEqual implementation, not type specific."""
492 if not first == second:
Michael Foord225a0992010-02-18 20:30:09 +0000493 standardMsg = '%s != %s' % (safe_repr(first), safe_repr(second))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000494 msg = self._formatMessage(msg, standardMsg)
495 raise self.failureException(msg)
496
497 def assertEqual(self, first, second, msg=None):
498 """Fail if the two objects are unequal as determined by the '=='
499 operator.
500 """
501 assertion_func = self._getAssertEqualityFunc(first, second)
502 assertion_func(first, second, msg=msg)
503
504 def assertNotEqual(self, first, second, msg=None):
505 """Fail if the two objects are equal as determined by the '=='
506 operator.
507 """
508 if not first != second:
Michael Foord225a0992010-02-18 20:30:09 +0000509 msg = self._formatMessage(msg, '%s == %s' % (safe_repr(first),
510 safe_repr(second)))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000511 raise self.failureException(msg)
512
Michael Foorda7e08fe2010-03-27 19:10:11 +0000513
514 def assertAlmostEqual(self, first, second, places=None, msg=None, delta=None):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000515 """Fail if the two objects are unequal as determined by their
516 difference rounded to the given number of decimal places
Michael Foorda7e08fe2010-03-27 19:10:11 +0000517 (default 7) and comparing to zero, or by comparing that the
518 between the two objects is more than the given delta.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000519
520 Note that decimal places (from zero) are usually not the same
521 as significant digits (measured from the most signficant digit).
Michael Foordc3f79372009-09-13 16:40:02 +0000522
523 If the two objects compare equal then they will automatically
524 compare almost equal.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000525 """
Michael Foordc3f79372009-09-13 16:40:02 +0000526 if first == second:
Michael Foorda7e08fe2010-03-27 19:10:11 +0000527 # shortcut
Michael Foordc3f79372009-09-13 16:40:02 +0000528 return
Michael Foorda7e08fe2010-03-27 19:10:11 +0000529 if delta is not None and places is not None:
530 raise TypeError("specify delta or places not both")
531
532 if delta is not None:
533 if abs(first - second) <= delta:
534 return
535
536 standardMsg = '%s != %s within %s delta' % (safe_repr(first),
537 safe_repr(second),
538 safe_repr(delta))
539 else:
540 if places is None:
541 places = 7
542
543 if round(abs(second-first), places) == 0:
544 return
545
Michael Foord225a0992010-02-18 20:30:09 +0000546 standardMsg = '%s != %s within %r places' % (safe_repr(first),
547 safe_repr(second),
548 places)
Michael Foorda7e08fe2010-03-27 19:10:11 +0000549 msg = self._formatMessage(msg, standardMsg)
550 raise self.failureException(msg)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000551
Michael Foorda7e08fe2010-03-27 19:10:11 +0000552 def assertNotAlmostEqual(self, first, second, places=None, msg=None, delta=None):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000553 """Fail if the two objects are equal as determined by their
554 difference rounded to the given number of decimal places
Michael Foorda7e08fe2010-03-27 19:10:11 +0000555 (default 7) and comparing to zero, or by comparing that the
556 between the two objects is less than the given delta.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000557
558 Note that decimal places (from zero) are usually not the same
559 as significant digits (measured from the most signficant digit).
Michael Foordc3f79372009-09-13 16:40:02 +0000560
561 Objects that are equal automatically fail.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000562 """
Michael Foorda7e08fe2010-03-27 19:10:11 +0000563 if delta is not None and places is not None:
564 raise TypeError("specify delta or places not both")
565 if delta is not None:
566 if not (first == second) and abs(first - second) > delta:
567 return
568 standardMsg = '%s == %s within %s delta' % (safe_repr(first),
569 safe_repr(second),
570 safe_repr(delta))
571 else:
572 if places is None:
573 places = 7
574 if not (first == second) and round(abs(second-first), places) != 0:
575 return
Michael Foord225a0992010-02-18 20:30:09 +0000576 standardMsg = '%s == %s within %r places' % (safe_repr(first),
Michael Foorda7e08fe2010-03-27 19:10:11 +0000577 safe_repr(second),
578 places)
579
580 msg = self._formatMessage(msg, standardMsg)
581 raise self.failureException(msg)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000582
583 # Synonyms for assertion methods
584
585 # The plurals are undocumented. Keep them that way to discourage use.
586 # Do not add more. Do not remove.
587 # Going through a deprecation cycle on these would annoy many people.
588 assertEquals = assertEqual
589 assertNotEquals = assertNotEqual
590 assertAlmostEquals = assertAlmostEqual
591 assertNotAlmostEquals = assertNotAlmostEqual
Michael Foord67dfc772010-02-10 14:31:30 +0000592 assert_ = assertTrue
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000593
594 # These fail* assertion method names are pending deprecation and will
595 # be a DeprecationWarning in 3.2; http://bugs.python.org/issue2578
596 def _deprecate(original_func):
597 def deprecated_func(*args, **kwargs):
598 warnings.warn(
599 'Please use {0} instead.'.format(original_func.__name__),
600 PendingDeprecationWarning, 2)
601 return original_func(*args, **kwargs)
602 return deprecated_func
603
604 failUnlessEqual = _deprecate(assertEqual)
605 failIfEqual = _deprecate(assertNotEqual)
606 failUnlessAlmostEqual = _deprecate(assertAlmostEqual)
607 failIfAlmostEqual = _deprecate(assertNotAlmostEqual)
608 failUnless = _deprecate(assertTrue)
609 failUnlessRaises = _deprecate(assertRaises)
610 failIf = _deprecate(assertFalse)
611
Michael Foorde37d75f2010-06-05 12:10:52 +0000612 def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000613 """An equality assertion for ordered sequences (like lists and tuples).
614
R. David Murray05b41712010-01-29 19:35:39 +0000615 For the purposes of this function, a valid ordered sequence type is one
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000616 which can be indexed, has a length, and has an equality operator.
617
618 Args:
619 seq1: The first sequence to compare.
620 seq2: The second sequence to compare.
621 seq_type: The expected datatype of the sequences, or None if no
622 datatype should be enforced.
623 msg: Optional message to use on failure instead of a list of
624 differences.
625 """
Florent Xicluna4a0f8b82010-03-21 10:50:44 +0000626 if seq_type is not None:
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000627 seq_type_name = seq_type.__name__
628 if not isinstance(seq1, seq_type):
Michael Foord225a0992010-02-18 20:30:09 +0000629 raise self.failureException('First sequence is not a %s: %s'
630 % (seq_type_name, safe_repr(seq1)))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000631 if not isinstance(seq2, seq_type):
Michael Foord225a0992010-02-18 20:30:09 +0000632 raise self.failureException('Second sequence is not a %s: %s'
633 % (seq_type_name, safe_repr(seq2)))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000634 else:
635 seq_type_name = "sequence"
636
637 differing = None
638 try:
639 len1 = len(seq1)
640 except (TypeError, NotImplementedError):
641 differing = 'First %s has no length. Non-sequence?' % (
642 seq_type_name)
643
644 if differing is None:
645 try:
646 len2 = len(seq2)
647 except (TypeError, NotImplementedError):
648 differing = 'Second %s has no length. Non-sequence?' % (
649 seq_type_name)
650
651 if differing is None:
652 if seq1 == seq2:
653 return
654
Michael Foord225a0992010-02-18 20:30:09 +0000655 seq1_repr = safe_repr(seq1)
656 seq2_repr = safe_repr(seq2)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000657 if len(seq1_repr) > 30:
658 seq1_repr = seq1_repr[:30] + '...'
659 if len(seq2_repr) > 30:
660 seq2_repr = seq2_repr[:30] + '...'
661 elements = (seq_type_name.capitalize(), seq1_repr, seq2_repr)
662 differing = '%ss differ: %s != %s\n' % elements
663
664 for i in xrange(min(len1, len2)):
665 try:
666 item1 = seq1[i]
667 except (TypeError, IndexError, NotImplementedError):
668 differing += ('\nUnable to index element %d of first %s\n' %
669 (i, seq_type_name))
670 break
671
672 try:
673 item2 = seq2[i]
674 except (TypeError, IndexError, NotImplementedError):
675 differing += ('\nUnable to index element %d of second %s\n' %
676 (i, seq_type_name))
677 break
678
679 if item1 != item2:
680 differing += ('\nFirst differing element %d:\n%s\n%s\n' %
681 (i, item1, item2))
682 break
683 else:
684 if (len1 == len2 and seq_type is None and
685 type(seq1) != type(seq2)):
686 # The sequences are the same, but have differing types.
687 return
688
689 if len1 > len2:
690 differing += ('\nFirst %s contains %d additional '
691 'elements.\n' % (seq_type_name, len1 - len2))
692 try:
693 differing += ('First extra element %d:\n%s\n' %
694 (len2, seq1[len2]))
695 except (TypeError, IndexError, NotImplementedError):
696 differing += ('Unable to index element %d '
697 'of first %s\n' % (len2, seq_type_name))
698 elif len1 < len2:
699 differing += ('\nSecond %s contains %d additional '
700 'elements.\n' % (seq_type_name, len2 - len1))
701 try:
702 differing += ('First extra element %d:\n%s\n' %
703 (len1, seq2[len1]))
704 except (TypeError, IndexError, NotImplementedError):
705 differing += ('Unable to index element %d '
706 'of second %s\n' % (len1, seq_type_name))
Michael Foord01007022010-06-05 11:23:51 +0000707 standardMsg = differing
708 diffMsg = '\n' + '\n'.join(
Georg Brandl46cc46a2009-10-01 20:11:14 +0000709 difflib.ndiff(pprint.pformat(seq1).splitlines(),
710 pprint.pformat(seq2).splitlines()))
Michael Foorde37d75f2010-06-05 12:10:52 +0000711 standardMsg = self._truncateMessage(standardMsg, diffMsg)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000712 msg = self._formatMessage(msg, standardMsg)
713 self.fail(msg)
714
Michael Foorde37d75f2010-06-05 12:10:52 +0000715 def _truncateMessage(self, message, diff):
716 max_diff = self.maxDiff
Michael Foorda4412872010-06-05 11:46:59 +0000717 if max_diff is None or len(diff) <= max_diff:
718 return message + diff
Michael Foord5fe21ff2010-06-05 13:38:16 +0000719 return message + (DIFF_OMITTED % len(diff))
Michael Foorda4412872010-06-05 11:46:59 +0000720
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000721 def assertListEqual(self, list1, list2, msg=None):
722 """A list-specific equality assertion.
723
724 Args:
725 list1: The first list to compare.
726 list2: The second list to compare.
727 msg: Optional message to use on failure instead of a list of
728 differences.
729
730 """
731 self.assertSequenceEqual(list1, list2, msg, seq_type=list)
732
733 def assertTupleEqual(self, tuple1, tuple2, msg=None):
734 """A tuple-specific equality assertion.
735
736 Args:
737 tuple1: The first tuple to compare.
738 tuple2: The second tuple to compare.
739 msg: Optional message to use on failure instead of a list of
740 differences.
741 """
742 self.assertSequenceEqual(tuple1, tuple2, msg, seq_type=tuple)
743
744 def assertSetEqual(self, set1, set2, msg=None):
745 """A set-specific equality assertion.
746
747 Args:
748 set1: The first set to compare.
749 set2: The second set to compare.
750 msg: Optional message to use on failure instead of a list of
751 differences.
752
Michael Foord98e7b762010-03-20 03:00:34 +0000753 assertSetEqual uses ducktyping to support different types of sets, and
754 is optimized for sets specifically (parameters must support a
755 difference method).
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000756 """
757 try:
758 difference1 = set1.difference(set2)
759 except TypeError, e:
760 self.fail('invalid type when attempting set difference: %s' % e)
761 except AttributeError, e:
762 self.fail('first argument does not support set difference: %s' % e)
763
764 try:
765 difference2 = set2.difference(set1)
766 except TypeError, e:
767 self.fail('invalid type when attempting set difference: %s' % e)
768 except AttributeError, e:
769 self.fail('second argument does not support set difference: %s' % e)
770
771 if not (difference1 or difference2):
772 return
773
774 lines = []
775 if difference1:
776 lines.append('Items in the first set but not the second:')
777 for item in difference1:
778 lines.append(repr(item))
779 if difference2:
780 lines.append('Items in the second set but not the first:')
781 for item in difference2:
782 lines.append(repr(item))
783
784 standardMsg = '\n'.join(lines)
785 self.fail(self._formatMessage(msg, standardMsg))
786
787 def assertIn(self, member, container, msg=None):
788 """Just like self.assertTrue(a in b), but with a nicer default message."""
789 if member not in container:
Michael Foord225a0992010-02-18 20:30:09 +0000790 standardMsg = '%s not found in %s' % (safe_repr(member),
791 safe_repr(container))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000792 self.fail(self._formatMessage(msg, standardMsg))
793
794 def assertNotIn(self, member, container, msg=None):
795 """Just like self.assertTrue(a not in b), but with a nicer default message."""
796 if member in container:
Michael Foord225a0992010-02-18 20:30:09 +0000797 standardMsg = '%s unexpectedly found in %s' % (safe_repr(member),
798 safe_repr(container))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000799 self.fail(self._formatMessage(msg, standardMsg))
800
801 def assertIs(self, expr1, expr2, msg=None):
802 """Just like self.assertTrue(a is b), but with a nicer default message."""
803 if expr1 is not expr2:
Michael Foord225a0992010-02-18 20:30:09 +0000804 standardMsg = '%s is not %s' % (safe_repr(expr1),
Michael Foordc2294dd2010-02-18 21:37:07 +0000805 safe_repr(expr2))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000806 self.fail(self._formatMessage(msg, standardMsg))
807
808 def assertIsNot(self, expr1, expr2, msg=None):
809 """Just like self.assertTrue(a is not b), but with a nicer default message."""
810 if expr1 is expr2:
Michael Foord225a0992010-02-18 20:30:09 +0000811 standardMsg = 'unexpectedly identical: %s' % (safe_repr(expr1),)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000812 self.fail(self._formatMessage(msg, standardMsg))
813
814 def assertDictEqual(self, d1, d2, msg=None):
Ezio Melotti2623a372010-11-21 13:34:58 +0000815 self.assertIsInstance(d1, dict, 'First argument is not a dictionary')
816 self.assertIsInstance(d2, dict, 'Second argument is not a dictionary')
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000817
818 if d1 != d2:
Michael Foord674648e2010-06-05 12:58:39 +0000819 standardMsg = '%s != %s' % (safe_repr(d1, True), safe_repr(d2, True))
Michael Foorde37d75f2010-06-05 12:10:52 +0000820 diff = ('\n' + '\n'.join(difflib.ndiff(
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000821 pprint.pformat(d1).splitlines(),
822 pprint.pformat(d2).splitlines())))
Michael Foord674648e2010-06-05 12:58:39 +0000823 standardMsg = self._truncateMessage(standardMsg, diff)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000824 self.fail(self._formatMessage(msg, standardMsg))
825
826 def assertDictContainsSubset(self, expected, actual, msg=None):
827 """Checks whether actual is a superset of expected."""
828 missing = []
829 mismatched = []
830 for key, value in expected.iteritems():
831 if key not in actual:
832 missing.append(key)
833 elif value != actual[key]:
Georg Brandl46cc46a2009-10-01 20:11:14 +0000834 mismatched.append('%s, expected: %s, actual: %s' %
Michael Foordc2294dd2010-02-18 21:37:07 +0000835 (safe_repr(key), safe_repr(value),
836 safe_repr(actual[key])))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000837
838 if not (missing or mismatched):
839 return
840
841 standardMsg = ''
842 if missing:
Michael Foord225a0992010-02-18 20:30:09 +0000843 standardMsg = 'Missing: %s' % ','.join(safe_repr(m) for m in
844 missing)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000845 if mismatched:
846 if standardMsg:
847 standardMsg += '; '
848 standardMsg += 'Mismatched values: %s' % ','.join(mismatched)
849
850 self.fail(self._formatMessage(msg, standardMsg))
851
Michael Foord98e7b762010-03-20 03:00:34 +0000852 def assertItemsEqual(self, expected_seq, actual_seq, msg=None):
853 """An unordered sequence / set specific comparison. It asserts that
854 expected_seq and actual_seq contain the same elements. It is
855 the equivalent of::
856
857 self.assertEqual(sorted(expected_seq), sorted(actual_seq))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000858
859 Raises with an error message listing which elements of expected_seq
860 are missing from actual_seq and vice versa if any.
Michael Foordd0edec32010-02-05 22:55:09 +0000861
Michael Foord98e7b762010-03-20 03:00:34 +0000862 Asserts that each element has the same count in both sequences.
863 Example:
864 - [0, 1, 1] and [1, 0, 1] compare equal.
865 - [0, 0, 1] and [0, 1] compare unequal.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000866 """
Florent Xicluna1f3b4e12010-03-07 12:14:25 +0000867 with warnings.catch_warnings():
868 if sys.py3kwarning:
869 # Silence Py3k warning raised during the sorting
Florent Xicluna4a0f8b82010-03-21 10:50:44 +0000870 for _msg in ["(code|dict|type) inequality comparisons",
Michael Foord98e7b762010-03-20 03:00:34 +0000871 "builtin_function_or_method order comparisons",
872 "comparing unequal types"]:
Michael Foorda7152552010-03-07 23:10:36 +0000873 warnings.filterwarnings("ignore", _msg, DeprecationWarning)
Florent Xicluna1f3b4e12010-03-07 12:14:25 +0000874 try:
Florent Xicluna1f3b4e12010-03-07 12:14:25 +0000875 expected = sorted(expected_seq)
876 actual = sorted(actual_seq)
Michael Foord98e7b762010-03-20 03:00:34 +0000877 except TypeError:
878 # Unsortable items (example: set(), complex(), ...)
879 expected = list(expected_seq)
880 actual = list(actual_seq)
881 missing, unexpected = unorderable_list_difference(
882 expected, actual, ignore_duplicate=False
883 )
884 else:
885 return self.assertSequenceEqual(expected, actual, msg=msg)
886
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000887 errors = []
888 if missing:
Michael Foord225a0992010-02-18 20:30:09 +0000889 errors.append('Expected, but missing:\n %s' %
Michael Foord98e7b762010-03-20 03:00:34 +0000890 safe_repr(missing))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000891 if unexpected:
Michael Foord225a0992010-02-18 20:30:09 +0000892 errors.append('Unexpected, but present:\n %s' %
Michael Foord98e7b762010-03-20 03:00:34 +0000893 safe_repr(unexpected))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000894 if errors:
895 standardMsg = '\n'.join(errors)
896 self.fail(self._formatMessage(msg, standardMsg))
897
898 def assertMultiLineEqual(self, first, second, msg=None):
899 """Assert that two multi-line strings are equal."""
Ezio Melotti2623a372010-11-21 13:34:58 +0000900 self.assertIsInstance(first, basestring,
901 'First argument is not a string')
902 self.assertIsInstance(second, basestring,
903 'Second argument is not a string')
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000904
905 if first != second:
Michael Foord94f071c2010-07-10 13:51:42 +0000906 firstlines = first.splitlines(True)
907 secondlines = second.splitlines(True)
908 if len(firstlines) == 1 and first.strip('\r\n') == first:
909 firstlines = [first + '\n']
910 secondlines = [second + '\n']
911 standardMsg = '%s != %s' % (safe_repr(first, True),
912 safe_repr(second, True))
913 diff = '\n' + ''.join(difflib.ndiff(firstlines, secondlines))
Michael Foord674648e2010-06-05 12:58:39 +0000914 standardMsg = self._truncateMessage(standardMsg, diff)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000915 self.fail(self._formatMessage(msg, standardMsg))
916
917 def assertLess(self, a, b, msg=None):
918 """Just like self.assertTrue(a < b), but with a nicer default message."""
919 if not a < b:
Michael Foord225a0992010-02-18 20:30:09 +0000920 standardMsg = '%s not less than %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000921 self.fail(self._formatMessage(msg, standardMsg))
922
923 def assertLessEqual(self, a, b, msg=None):
924 """Just like self.assertTrue(a <= b), but with a nicer default message."""
925 if not a <= b:
Michael Foord225a0992010-02-18 20:30:09 +0000926 standardMsg = '%s not less than or equal to %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000927 self.fail(self._formatMessage(msg, standardMsg))
928
929 def assertGreater(self, a, b, msg=None):
930 """Just like self.assertTrue(a > b), but with a nicer default message."""
931 if not a > b:
Michael Foord225a0992010-02-18 20:30:09 +0000932 standardMsg = '%s not greater than %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000933 self.fail(self._formatMessage(msg, standardMsg))
934
935 def assertGreaterEqual(self, a, b, msg=None):
936 """Just like self.assertTrue(a >= b), but with a nicer default message."""
937 if not a >= b:
Michael Foord225a0992010-02-18 20:30:09 +0000938 standardMsg = '%s not greater than or equal to %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000939 self.fail(self._formatMessage(msg, standardMsg))
940
941 def assertIsNone(self, obj, msg=None):
942 """Same as self.assertTrue(obj is None), with a nicer default message."""
943 if obj is not None:
Michael Foord225a0992010-02-18 20:30:09 +0000944 standardMsg = '%s is not None' % (safe_repr(obj),)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000945 self.fail(self._formatMessage(msg, standardMsg))
946
947 def assertIsNotNone(self, obj, msg=None):
948 """Included for symmetry with assertIsNone."""
949 if obj is None:
950 standardMsg = 'unexpectedly None'
951 self.fail(self._formatMessage(msg, standardMsg))
952
Georg Brandlf895cf52009-10-01 20:59:31 +0000953 def assertIsInstance(self, obj, cls, msg=None):
954 """Same as self.assertTrue(isinstance(obj, cls)), with a nicer
955 default message."""
956 if not isinstance(obj, cls):
Michael Foord225a0992010-02-18 20:30:09 +0000957 standardMsg = '%s is not an instance of %r' % (safe_repr(obj), cls)
Georg Brandlf895cf52009-10-01 20:59:31 +0000958 self.fail(self._formatMessage(msg, standardMsg))
959
960 def assertNotIsInstance(self, obj, cls, msg=None):
961 """Included for symmetry with assertIsInstance."""
962 if isinstance(obj, cls):
Michael Foord225a0992010-02-18 20:30:09 +0000963 standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls)
Georg Brandlf895cf52009-10-01 20:59:31 +0000964 self.fail(self._formatMessage(msg, standardMsg))
965
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000966 def assertRaisesRegexp(self, expected_exception, expected_regexp,
967 callable_obj=None, *args, **kwargs):
968 """Asserts that the message in a raised exception matches a regexp.
969
970 Args:
971 expected_exception: Exception class expected to be raised.
972 expected_regexp: Regexp (re pattern object or string) expected
973 to be found in error message.
974 callable_obj: Function to be called.
975 args: Extra args.
976 kwargs: Extra kwargs.
977 """
978 context = _AssertRaisesContext(expected_exception, self, expected_regexp)
979 if callable_obj is None:
980 return context
981 with context:
982 callable_obj(*args, **kwargs)
983
Georg Brandlb0eb4d32010-02-07 11:34:15 +0000984 def assertRegexpMatches(self, text, expected_regexp, msg=None):
Michael Foord959c16d2010-05-08 16:40:52 +0000985 """Fail the test unless the text matches the regular expression."""
Georg Brandlb0eb4d32010-02-07 11:34:15 +0000986 if isinstance(expected_regexp, basestring):
987 expected_regexp = re.compile(expected_regexp)
988 if not expected_regexp.search(text):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000989 msg = msg or "Regexp didn't match"
Georg Brandlb0eb4d32010-02-07 11:34:15 +0000990 msg = '%s: %r not found in %r' % (msg, expected_regexp.pattern, text)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000991 raise self.failureException(msg)
992
Michael Foorda04c7a02010-04-02 22:55:59 +0000993 def assertNotRegexpMatches(self, text, unexpected_regexp, msg=None):
Michael Foord959c16d2010-05-08 16:40:52 +0000994 """Fail the test if the text matches the regular expression."""
Michael Foorda04c7a02010-04-02 22:55:59 +0000995 if isinstance(unexpected_regexp, basestring):
996 unexpected_regexp = re.compile(unexpected_regexp)
997 match = unexpected_regexp.search(text)
998 if match:
999 msg = msg or "Regexp matched"
1000 msg = '%s: %r matches %r in %r' % (msg,
1001 text[match.start():match.end()],
1002 unexpected_regexp.pattern,
1003 text)
1004 raise self.failureException(msg)
1005
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00001006
1007class FunctionTestCase(TestCase):
1008 """A test case that wraps a test function.
1009
1010 This is useful for slipping pre-existing test functions into the
1011 unittest framework. Optionally, set-up and tidy-up functions can be
1012 supplied. As with TestCase, the tidy-up ('tearDown') function will
1013 always be called if the set-up ('setUp') function ran successfully.
1014 """
1015
1016 def __init__(self, testFunc, setUp=None, tearDown=None, description=None):
1017 super(FunctionTestCase, self).__init__()
1018 self._setUpFunc = setUp
1019 self._tearDownFunc = tearDown
1020 self._testFunc = testFunc
1021 self._description = description
1022
1023 def setUp(self):
1024 if self._setUpFunc is not None:
1025 self._setUpFunc()
1026
1027 def tearDown(self):
1028 if self._tearDownFunc is not None:
1029 self._tearDownFunc()
1030
1031 def runTest(self):
1032 self._testFunc()
1033
1034 def id(self):
1035 return self._testFunc.__name__
1036
1037 def __eq__(self, other):
1038 if not isinstance(other, self.__class__):
1039 return NotImplemented
1040
1041 return self._setUpFunc == other._setUpFunc and \
1042 self._tearDownFunc == other._tearDownFunc and \
1043 self._testFunc == other._testFunc and \
1044 self._description == other._description
1045
1046 def __ne__(self, other):
1047 return not self == other
1048
1049 def __hash__(self):
1050 return hash((type(self), self._setUpFunc, self._tearDownFunc,
1051 self._testFunc, self._description))
1052
1053 def __str__(self):
Michael Foord225a0992010-02-18 20:30:09 +00001054 return "%s (%s)" % (strclass(self.__class__),
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00001055 self._testFunc.__name__)
1056
1057 def __repr__(self):
Michael Foord225a0992010-02-18 20:30:09 +00001058 return "<%s tec=%s>" % (strclass(self.__class__),
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00001059 self._testFunc)
1060
1061 def shortDescription(self):
1062 if self._description is not None:
1063 return self._description
1064 doc = self._testFunc.__doc__
1065 return doc and doc.split("\n")[0].strip() or None