blob: d048303e2f2a11908aa2f29e3e0626486d9425a0 [file] [log] [blame]
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001"""Test case implementation"""
2
3import sys
4import functools
5import difflib
6import pprint
7import re
8import warnings
9
Benjamin Peterson847a4112010-03-14 15:04:17 +000010from . import result
11from .util import (strclass, safe_repr, sorted_list_difference,
12 unorderable_list_difference)
Benjamin Petersonbed7d042009-07-19 21:01:52 +000013
Benjamin Petersondccc1fc2010-03-22 00:15:53 +000014__unittest = True
Benjamin Petersonbed7d042009-07-19 21:01:52 +000015
Michael Foord9dad32e2010-06-05 13:49:56 +000016
17DIFF_OMITTED = ('\nDiff is %s characters long. '
18 'Set self.maxDiff to None to see it.')
19
Benjamin Petersonbed7d042009-07-19 21:01:52 +000020class SkipTest(Exception):
21 """
22 Raise this exception in a test to skip it.
23
24 Usually you can use TestResult.skip() or one of the skipping decorators
25 instead of raising this directly.
26 """
27 pass
28
29class _ExpectedFailure(Exception):
30 """
31 Raise this when a test is expected to fail.
32
33 This is an implementation detail.
34 """
35
36 def __init__(self, exc_info):
37 super(_ExpectedFailure, self).__init__()
38 self.exc_info = exc_info
39
40class _UnexpectedSuccess(Exception):
41 """
42 The test was supposed to fail, but it didn't!
43 """
44 pass
45
46def _id(obj):
47 return obj
48
49def skip(reason):
50 """
51 Unconditionally skip a test.
52 """
53 def decorator(test_item):
Benjamin Peterson847a4112010-03-14 15:04:17 +000054 if not (isinstance(test_item, type) and issubclass(test_item, TestCase)):
55 @functools.wraps(test_item)
56 def skip_wrapper(*args, **kwargs):
57 raise SkipTest(reason)
58 test_item = skip_wrapper
59
60 test_item.__unittest_skip__ = True
61 test_item.__unittest_skip_why__ = reason
62 return test_item
Benjamin Petersonbed7d042009-07-19 21:01:52 +000063 return decorator
64
65def skipIf(condition, reason):
66 """
67 Skip a test if the condition is true.
68 """
69 if condition:
70 return skip(reason)
71 return _id
72
73def skipUnless(condition, reason):
74 """
75 Skip a test unless the condition is true.
76 """
77 if not condition:
78 return skip(reason)
79 return _id
80
81
82def expectedFailure(func):
83 @functools.wraps(func)
84 def wrapper(*args, **kwargs):
85 try:
86 func(*args, **kwargs)
87 except Exception:
88 raise _ExpectedFailure(sys.exc_info())
89 raise _UnexpectedSuccess
90 return wrapper
91
92
93class _AssertRaisesContext(object):
94 """A context manager used to implement TestCase.assertRaises* methods."""
95
96 def __init__(self, expected, test_case, callable_obj=None,
97 expected_regexp=None):
98 self.expected = expected
99 self.failureException = test_case.failureException
100 if callable_obj is not None:
101 try:
102 self.obj_name = callable_obj.__name__
103 except AttributeError:
104 self.obj_name = str(callable_obj)
105 else:
106 self.obj_name = None
Georg Brandl89fad142010-03-14 10:23:39 +0000107 self.expected_regexp = expected_regexp
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000108
109 def __enter__(self):
Ezio Melotti49008232010-02-08 21:57:48 +0000110 return self
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000111
112 def __exit__(self, exc_type, exc_value, tb):
113 if exc_type is None:
114 try:
115 exc_name = self.expected.__name__
116 except AttributeError:
117 exc_name = str(self.expected)
118 if self.obj_name:
119 raise self.failureException("{0} not raised by {1}"
120 .format(exc_name, self.obj_name))
121 else:
122 raise self.failureException("{0} not raised"
123 .format(exc_name))
124 if not issubclass(exc_type, self.expected):
125 # let unexpected exceptions pass through
126 return False
Ezio Melotti49008232010-02-08 21:57:48 +0000127 # store exception, without traceback, for later retrieval
128 self.exception = exc_value.with_traceback(None)
Georg Brandl89fad142010-03-14 10:23:39 +0000129 if self.expected_regexp is None:
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000130 return True
131
Georg Brandl89fad142010-03-14 10:23:39 +0000132 expected_regexp = self.expected_regexp
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000133 if isinstance(expected_regexp, (bytes, str)):
134 expected_regexp = re.compile(expected_regexp)
135 if not expected_regexp.search(str(exc_value)):
136 raise self.failureException('"%s" does not match "%s"' %
137 (expected_regexp.pattern, str(exc_value)))
138 return True
139
140
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000141class TestCase(object):
142 """A class whose instances are single test cases.
143
144 By default, the test code itself should be placed in a method named
145 'runTest'.
146
147 If the fixture may be used for many test cases, create as
148 many test methods as are needed. When instantiating such a TestCase
149 subclass, specify in the constructor arguments the name of the test method
150 that the instance is to execute.
151
152 Test authors should subclass TestCase for their own tests. Construction
153 and deconstruction of the test's environment ('fixture') can be
154 implemented by overriding the 'setUp' and 'tearDown' methods respectively.
155
156 If it is necessary to override the __init__ method, the base class
157 __init__ method must always be called. It is important that subclasses
158 should not change the signature of their __init__ method, since instances
159 of the classes are instantiated automatically by parts of the framework
160 in order to be run.
161 """
162
163 # This attribute determines which exception will be raised when
164 # the instance's assertion methods fail; test methods raising this
165 # exception will be deemed to have 'failed' rather than 'errored'
166
167 failureException = AssertionError
168
169 # This attribute determines whether long messages (including repr of
170 # objects used in assert methods) will be printed on failure in *addition*
171 # to any explicit message passed.
172
173 longMessage = False
174
Michael Foord085dfd32010-06-05 12:17:02 +0000175 # This attribute sets the maximum length of a diff in failure messsages
176 # by assert methods using difflib. It is looked up as an instance attribute
177 # so can be configured by individual tests if required.
Michael Foordd50a6b92010-06-05 23:59:34 +0000178
Michael Foord085dfd32010-06-05 12:17:02 +0000179 maxDiff = 80*8
180
Benjamin Peterson847a4112010-03-14 15:04:17 +0000181 # Attribute used by TestSuite for classSetUp
182
183 _classSetupFailed = False
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000184
185 def __init__(self, methodName='runTest'):
186 """Create an instance of the class that will use the named test
187 method when executed. Raises a ValueError if the instance does
188 not have a method with the specified name.
189 """
190 self._testMethodName = methodName
191 self._resultForDoCleanups = None
192 try:
193 testMethod = getattr(self, methodName)
194 except AttributeError:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000195 raise ValueError("no such test method in %s: %s" %
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000196 (self.__class__, methodName))
197 self._testMethodDoc = testMethod.__doc__
198 self._cleanups = []
199
200 # Map types to custom assertEqual functions that will compare
201 # instances of said type in more detail to generate a more useful
202 # error message.
203 self._type_equality_funcs = {}
204 self.addTypeEqualityFunc(dict, self.assertDictEqual)
205 self.addTypeEqualityFunc(list, self.assertListEqual)
206 self.addTypeEqualityFunc(tuple, self.assertTupleEqual)
207 self.addTypeEqualityFunc(set, self.assertSetEqual)
208 self.addTypeEqualityFunc(frozenset, self.assertSetEqual)
Michael Foord02834952010-02-08 23:10:39 +0000209 self.addTypeEqualityFunc(str, self.assertMultiLineEqual)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000210
211 def addTypeEqualityFunc(self, typeobj, function):
212 """Add a type specific assertEqual style function to compare a type.
213
214 This method is for use by TestCase subclasses that need to register
215 their own type equality functions to provide nicer error messages.
216
217 Args:
218 typeobj: The data type to call this function on when both values
219 are of the same type in assertEqual().
220 function: The callable taking two arguments and an optional
221 msg= argument that raises self.failureException with a
222 useful error message when the two arguments are not equal.
223 """
Benjamin Peterson8f326b22009-12-13 02:10:36 +0000224 self._type_equality_funcs[typeobj] = function
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000225
226 def addCleanup(self, function, *args, **kwargs):
227 """Add a function, with arguments, to be called when the test is
228 completed. Functions added are called on a LIFO basis and are
229 called after tearDown on test failure or success.
230
231 Cleanup items are called even if setUp fails (unlike tearDown)."""
232 self._cleanups.append((function, args, kwargs))
233
234 def setUp(self):
235 "Hook method for setting up the test fixture before exercising it."
236 pass
237
238 def tearDown(self):
239 "Hook method for deconstructing the test fixture after testing it."
240 pass
241
Benjamin Peterson847a4112010-03-14 15:04:17 +0000242 @classmethod
243 def setUpClass(cls):
244 "Hook method for setting up class fixture before running tests in the class."
245
246 @classmethod
247 def tearDownClass(cls):
248 "Hook method for deconstructing the class fixture after running all tests in the class."
249
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000250 def countTestCases(self):
251 return 1
252
253 def defaultTestResult(self):
254 return result.TestResult()
255
256 def shortDescription(self):
Michael Foord34c94622010-02-10 15:51:42 +0000257 """Returns a one-line description of the test, or None if no
258 description has been provided.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000259
Michael Foord34c94622010-02-10 15:51:42 +0000260 The default implementation of this method returns the first line of
261 the specified test method's docstring.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000262 """
Michael Foord34c94622010-02-10 15:51:42 +0000263 doc = self._testMethodDoc
264 return doc and doc.split("\n")[0].strip() or None
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000265
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000266
267 def id(self):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000268 return "%s.%s" % (strclass(self.__class__), self._testMethodName)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000269
270 def __eq__(self, other):
271 if type(self) is not type(other):
272 return NotImplemented
273
274 return self._testMethodName == other._testMethodName
275
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000276 def __hash__(self):
277 return hash((type(self), self._testMethodName))
278
279 def __str__(self):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000280 return "%s (%s)" % (self._testMethodName, strclass(self.__class__))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000281
282 def __repr__(self):
283 return "<%s testMethod=%s>" % \
Benjamin Peterson847a4112010-03-14 15:04:17 +0000284 (strclass(self.__class__), self._testMethodName)
285
286 def _addSkip(self, result, reason):
287 addSkip = getattr(result, 'addSkip', None)
288 if addSkip is not None:
289 addSkip(self, reason)
290 else:
291 warnings.warn("TestResult has no addSkip method, skips not reported",
292 RuntimeWarning, 2)
293 result.addSuccess(self)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000294
295 def run(self, result=None):
296 orig_result = result
297 if result is None:
298 result = self.defaultTestResult()
299 startTestRun = getattr(result, 'startTestRun', None)
300 if startTestRun is not None:
301 startTestRun()
302
303 self._resultForDoCleanups = result
304 result.startTest(self)
Benjamin Peterson847a4112010-03-14 15:04:17 +0000305
306 testMethod = getattr(self, self._testMethodName)
307 if (getattr(self.__class__, "__unittest_skip__", False) or
308 getattr(testMethod, "__unittest_skip__", False)):
309 # If the class or method was skipped.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000310 try:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000311 skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
312 or getattr(testMethod, '__unittest_skip_why__', ''))
313 self._addSkip(result, skip_why)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000314 finally:
315 result.stopTest(self)
316 return
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000317 try:
318 success = False
319 try:
320 self.setUp()
321 except SkipTest as e:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000322 self._addSkip(result, str(e))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000323 except Exception:
324 result.addError(self, sys.exc_info())
325 else:
326 try:
327 testMethod()
328 except self.failureException:
329 result.addFailure(self, sys.exc_info())
330 except _ExpectedFailure as e:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000331 addExpectedFailure = getattr(result, 'addExpectedFailure', None)
332 if addExpectedFailure is not None:
333 addExpectedFailure(self, e.exc_info)
334 else:
335 warnings.warn("TestResult has no addExpectedFailure method, reporting as passes",
336 RuntimeWarning)
337 result.addSuccess(self)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000338 except _UnexpectedSuccess:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000339 addUnexpectedSuccess = getattr(result, 'addUnexpectedSuccess', None)
340 if addUnexpectedSuccess is not None:
341 addUnexpectedSuccess(self)
342 else:
343 warnings.warn("TestResult has no addUnexpectedSuccess method, reporting as failures",
344 RuntimeWarning)
345 result.addFailure(self, sys.exc_info())
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000346 except SkipTest as e:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000347 self._addSkip(result, str(e))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000348 except Exception:
349 result.addError(self, sys.exc_info())
350 else:
351 success = True
352
353 try:
354 self.tearDown()
355 except Exception:
356 result.addError(self, sys.exc_info())
357 success = False
358
359 cleanUpSuccess = self.doCleanups()
360 success = success and cleanUpSuccess
361 if success:
362 result.addSuccess(self)
363 finally:
364 result.stopTest(self)
365 if orig_result is None:
366 stopTestRun = getattr(result, 'stopTestRun', None)
367 if stopTestRun is not None:
368 stopTestRun()
369
370 def doCleanups(self):
371 """Execute all cleanup functions. Normally called for you after
372 tearDown."""
373 result = self._resultForDoCleanups
374 ok = True
375 while self._cleanups:
376 function, args, kwargs = self._cleanups.pop(-1)
377 try:
378 function(*args, **kwargs)
379 except Exception:
380 ok = False
381 result.addError(self, sys.exc_info())
382 return ok
383
384 def __call__(self, *args, **kwds):
385 return self.run(*args, **kwds)
386
387 def debug(self):
388 """Run the test without collecting errors in a TestResult"""
389 self.setUp()
390 getattr(self, self._testMethodName)()
391 self.tearDown()
392
393 def skipTest(self, reason):
394 """Skip this test."""
395 raise SkipTest(reason)
396
397 def fail(self, msg=None):
398 """Fail immediately, with the given message."""
399 raise self.failureException(msg)
400
401 def assertFalse(self, expr, msg=None):
402 "Fail the test if the expression is true."
403 if expr:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000404 msg = self._formatMessage(msg, "%s is not False" % safe_repr(expr))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000405 raise self.failureException(msg)
406
407 def assertTrue(self, expr, msg=None):
408 """Fail the test unless the expression is true."""
409 if not expr:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000410 msg = self._formatMessage(msg, "%s is not True" % safe_repr(expr))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000411 raise self.failureException(msg)
412
413 def _formatMessage(self, msg, standardMsg):
414 """Honour the longMessage attribute when generating failure messages.
415 If longMessage is False this means:
416 * Use only an explicit message if it is provided
417 * Otherwise use the standard message for the assert
418
419 If longMessage is True:
420 * Use the standard message
421 * If an explicit message is provided, plus ' : ' and the explicit message
422 """
423 if not self.longMessage:
424 return msg or standardMsg
425 if msg is None:
426 return standardMsg
Benjamin Peterson847a4112010-03-14 15:04:17 +0000427 try:
428 # don't switch to '{}' formatting in Python 2.X
429 # it changes the way unicode input is handled
430 return '%s : %s' % (standardMsg, msg)
431 except UnicodeDecodeError:
432 return '%s : %s' % (safe_repr(standardMsg), safe_repr(msg))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000433
434
435 def assertRaises(self, excClass, callableObj=None, *args, **kwargs):
436 """Fail unless an exception of class excClass is thrown
437 by callableObj when invoked with arguments args and keyword
438 arguments kwargs. If a different type of exception is
439 thrown, it will not be caught, and the test case will be
440 deemed to have suffered an error, exactly as for an
441 unexpected exception.
442
443 If called with callableObj omitted or None, will return a
444 context object used like this::
445
Michael Foord1c42b122010-02-05 22:58:21 +0000446 with self.assertRaises(SomeException):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000447 do_something()
Michael Foord1c42b122010-02-05 22:58:21 +0000448
449 The context manager keeps a reference to the exception as
Ezio Melotti49008232010-02-08 21:57:48 +0000450 the 'exception' attribute. This allows you to inspect the
Michael Foord1c42b122010-02-05 22:58:21 +0000451 exception after the assertion::
452
453 with self.assertRaises(SomeException) as cm:
454 do_something()
Ezio Melotti49008232010-02-08 21:57:48 +0000455 the_exception = cm.exception
Michael Foordb57ac6d2010-02-05 23:26:29 +0000456 self.assertEqual(the_exception.error_code, 3)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000457 """
458 context = _AssertRaisesContext(excClass, self, callableObj)
459 if callableObj is None:
460 return context
461 with context:
462 callableObj(*args, **kwargs)
463
464 def _getAssertEqualityFunc(self, first, second):
465 """Get a detailed comparison function for the types of the two args.
466
467 Returns: A callable accepting (first, second, msg=None) that will
468 raise a failure exception if first != second with a useful human
469 readable error message for those types.
470 """
471 #
472 # NOTE(gregory.p.smith): I considered isinstance(first, type(second))
473 # and vice versa. I opted for the conservative approach in case
474 # subclasses are not intended to be compared in detail to their super
475 # class instances using a type equality func. This means testing
476 # subtypes won't automagically use the detailed comparison. Callers
477 # should use their type specific assertSpamEqual method to compare
478 # subclasses if the detailed comparison is desired and appropriate.
479 # See the discussion in http://bugs.python.org/issue2578.
480 #
481 if type(first) is type(second):
482 asserter = self._type_equality_funcs.get(type(first))
483 if asserter is not None:
Benjamin Peterson8f326b22009-12-13 02:10:36 +0000484 return asserter
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000485
486 return self._baseAssertEqual
487
488 def _baseAssertEqual(self, first, second, msg=None):
489 """The default assertEqual implementation, not type specific."""
490 if not first == second:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000491 standardMsg = '%s != %s' % (safe_repr(first), safe_repr(second))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000492 msg = self._formatMessage(msg, standardMsg)
493 raise self.failureException(msg)
494
495 def assertEqual(self, first, second, msg=None):
496 """Fail if the two objects are unequal as determined by the '=='
497 operator.
498 """
499 assertion_func = self._getAssertEqualityFunc(first, second)
500 assertion_func(first, second, msg=msg)
501
502 def assertNotEqual(self, first, second, msg=None):
503 """Fail if the two objects are equal as determined by the '=='
504 operator.
505 """
506 if not first != second:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000507 msg = self._formatMessage(msg, '%s == %s' % (safe_repr(first),
508 safe_repr(second)))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000509 raise self.failureException(msg)
510
Benjamin Petersonb48af542010-04-11 20:43:16 +0000511 def assertAlmostEqual(self, first, second, *, places=None, msg=None,
512 delta=None):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000513 """Fail if the two objects are unequal as determined by their
514 difference rounded to the given number of decimal places
Benjamin Petersonb48af542010-04-11 20:43:16 +0000515 (default 7) and comparing to zero, or by comparing that the
516 between the two objects is more than the given delta.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000517
518 Note that decimal places (from zero) are usually not the same
519 as significant digits (measured from the most signficant digit).
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000520
521 If the two objects compare equal then they will automatically
522 compare almost equal.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000523 """
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000524 if first == second:
Benjamin Petersonb48af542010-04-11 20:43:16 +0000525 # shortcut
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000526 return
Benjamin Petersonb48af542010-04-11 20:43:16 +0000527 if delta is not None and places is not None:
528 raise TypeError("specify delta or places not both")
529
530 if delta is not None:
531 if abs(first - second) <= delta:
532 return
533
534 standardMsg = '%s != %s within %s delta' % (safe_repr(first),
535 safe_repr(second),
536 safe_repr(delta))
537 else:
538 if places is None:
539 places = 7
540
541 if round(abs(second-first), places) == 0:
542 return
543
Benjamin Peterson847a4112010-03-14 15:04:17 +0000544 standardMsg = '%s != %s within %r places' % (safe_repr(first),
545 safe_repr(second),
546 places)
Benjamin Petersonb48af542010-04-11 20:43:16 +0000547 msg = self._formatMessage(msg, standardMsg)
548 raise self.failureException(msg)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000549
Benjamin Petersonb48af542010-04-11 20:43:16 +0000550 def assertNotAlmostEqual(self, first, second, *, places=None, msg=None,
551 delta=None):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000552 """Fail if the two objects are equal as determined by their
553 difference rounded to the given number of decimal places
Benjamin Petersonb48af542010-04-11 20:43:16 +0000554 (default 7) and comparing to zero, or by comparing that the
555 between the two objects is less than the given delta.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000556
557 Note that decimal places (from zero) are usually not the same
558 as significant digits (measured from the most signficant digit).
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000559
560 Objects that are equal automatically fail.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000561 """
Benjamin Petersonb48af542010-04-11 20:43:16 +0000562 if delta is not None and places is not None:
563 raise TypeError("specify delta or places not both")
564 if delta is not None:
565 if not (first == second) and abs(first - second) > delta:
566 return
567 standardMsg = '%s == %s within %s delta' % (safe_repr(first),
568 safe_repr(second),
569 safe_repr(delta))
570 else:
571 if places is None:
572 places = 7
573 if not (first == second) and round(abs(second-first), places) != 0:
574 return
Benjamin Peterson847a4112010-03-14 15:04:17 +0000575 standardMsg = '%s == %s within %r places' % (safe_repr(first),
Benjamin Petersonb48af542010-04-11 20:43:16 +0000576 safe_repr(second),
577 places)
578
579 msg = self._formatMessage(msg, standardMsg)
580 raise self.failureException(msg)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000581
582 # Synonyms for assertion methods
583
584 # The plurals are undocumented. Keep them that way to discourage use.
585 # Do not add more. Do not remove.
586 # Going through a deprecation cycle on these would annoy many people.
587 assertEquals = assertEqual
588 assertNotEquals = assertNotEqual
589 assertAlmostEquals = assertAlmostEqual
590 assertNotAlmostEquals = assertNotAlmostEqual
Michael Foord0e31b992010-02-10 15:52:56 +0000591 assert_ = assertTrue
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000592
593 # These fail* assertion method names are pending deprecation and will
594 # be a DeprecationWarning in 3.2; http://bugs.python.org/issue2578
595 def _deprecate(original_func):
596 def deprecated_func(*args, **kwargs):
597 warnings.warn(
598 'Please use {0} instead.'.format(original_func.__name__),
599 DeprecationWarning, 2)
600 return original_func(*args, **kwargs)
601 return deprecated_func
602
603 failUnlessEqual = _deprecate(assertEqual)
604 failIfEqual = _deprecate(assertNotEqual)
605 failUnlessAlmostEqual = _deprecate(assertAlmostEqual)
606 failIfAlmostEqual = _deprecate(assertNotAlmostEqual)
607 failUnless = _deprecate(assertTrue)
608 failUnlessRaises = _deprecate(assertRaises)
609 failIf = _deprecate(assertFalse)
610
Michael Foord085dfd32010-06-05 12:17:02 +0000611 def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000612 """An equality assertion for ordered sequences (like lists and tuples).
613
R. David Murrayad13f222010-01-29 22:17:58 +0000614 For the purposes of this function, a valid ordered sequence type is one
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000615 which can be indexed, has a length, and has an equality operator.
616
617 Args:
618 seq1: The first sequence to compare.
619 seq2: The second sequence to compare.
620 seq_type: The expected datatype of the sequences, or None if no
621 datatype should be enforced.
622 msg: Optional message to use on failure instead of a list of
623 differences.
624 """
625 if seq_type != None:
626 seq_type_name = seq_type.__name__
627 if not isinstance(seq1, seq_type):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000628 raise self.failureException('First sequence is not a %s: %s'
629 % (seq_type_name, safe_repr(seq1)))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000630 if not isinstance(seq2, seq_type):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000631 raise self.failureException('Second sequence is not a %s: %s'
632 % (seq_type_name, safe_repr(seq2)))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000633 else:
634 seq_type_name = "sequence"
635
636 differing = None
637 try:
638 len1 = len(seq1)
639 except (TypeError, NotImplementedError):
640 differing = 'First %s has no length. Non-sequence?' % (
641 seq_type_name)
642
643 if differing is None:
644 try:
645 len2 = len(seq2)
646 except (TypeError, NotImplementedError):
647 differing = 'Second %s has no length. Non-sequence?' % (
648 seq_type_name)
649
650 if differing is None:
651 if seq1 == seq2:
652 return
653
Benjamin Peterson847a4112010-03-14 15:04:17 +0000654 seq1_repr = safe_repr(seq1)
655 seq2_repr = safe_repr(seq2)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000656 if len(seq1_repr) > 30:
657 seq1_repr = seq1_repr[:30] + '...'
658 if len(seq2_repr) > 30:
659 seq2_repr = seq2_repr[:30] + '...'
660 elements = (seq_type_name.capitalize(), seq1_repr, seq2_repr)
661 differing = '%ss differ: %s != %s\n' % elements
662
663 for i in range(min(len1, len2)):
664 try:
665 item1 = seq1[i]
666 except (TypeError, IndexError, NotImplementedError):
667 differing += ('\nUnable to index element %d of first %s\n' %
668 (i, seq_type_name))
669 break
670
671 try:
672 item2 = seq2[i]
673 except (TypeError, IndexError, NotImplementedError):
674 differing += ('\nUnable to index element %d of second %s\n' %
675 (i, seq_type_name))
676 break
677
678 if item1 != item2:
679 differing += ('\nFirst differing element %d:\n%s\n%s\n' %
680 (i, item1, item2))
681 break
682 else:
683 if (len1 == len2 and seq_type is None and
684 type(seq1) != type(seq2)):
685 # The sequences are the same, but have differing types.
686 return
687
688 if len1 > len2:
689 differing += ('\nFirst %s contains %d additional '
690 'elements.\n' % (seq_type_name, len1 - len2))
691 try:
692 differing += ('First extra element %d:\n%s\n' %
693 (len2, seq1[len2]))
694 except (TypeError, IndexError, NotImplementedError):
695 differing += ('Unable to index element %d '
696 'of first %s\n' % (len2, seq_type_name))
697 elif len1 < len2:
698 differing += ('\nSecond %s contains %d additional '
699 'elements.\n' % (seq_type_name, len2 - len1))
700 try:
701 differing += ('First extra element %d:\n%s\n' %
702 (len1, seq2[len1]))
703 except (TypeError, IndexError, NotImplementedError):
704 differing += ('Unable to index element %d '
705 'of second %s\n' % (len1, seq_type_name))
Michael Foord2034d9a2010-06-05 11:27:52 +0000706 standardMsg = differing
707 diffMsg = '\n' + '\n'.join(
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000708 difflib.ndiff(pprint.pformat(seq1).splitlines(),
709 pprint.pformat(seq2).splitlines()))
Michael Foord085dfd32010-06-05 12:17:02 +0000710
711 standardMsg = self._truncateMessage(standardMsg, diffMsg)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000712 msg = self._formatMessage(msg, standardMsg)
713 self.fail(msg)
714
Michael Foord085dfd32010-06-05 12:17:02 +0000715 def _truncateMessage(self, message, diff):
716 max_diff = self.maxDiff
717 if max_diff is None or len(diff) <= max_diff:
718 return message + diff
Michael Foord9dad32e2010-06-05 13:49:56 +0000719 return message + (DIFF_OMITTED % len(diff))
Michael Foord085dfd32010-06-05 12:17:02 +0000720
Benjamin Petersonbed7d042009-07-19 21:01:52 +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 Foord91c9da32010-03-20 17:21:27 +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 Petersonbed7d042009-07-19 21:01:52 +0000756 """
757 try:
758 difference1 = set1.difference(set2)
759 except TypeError as e:
760 self.fail('invalid type when attempting set difference: %s' % e)
761 except AttributeError as e:
762 self.fail('first argument does not support set difference: %s' % e)
763
764 try:
765 difference2 = set2.difference(set1)
766 except TypeError as e:
767 self.fail('invalid type when attempting set difference: %s' % e)
768 except AttributeError as 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:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000790 standardMsg = '%s not found in %s' % (safe_repr(member),
791 safe_repr(container))
Benjamin Petersonbed7d042009-07-19 21:01:52 +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:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000797 standardMsg = '%s unexpectedly found in %s' % (safe_repr(member),
798 safe_repr(container))
Benjamin Petersonbed7d042009-07-19 21:01:52 +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:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000804 standardMsg = '%s is not %s' % (safe_repr(expr1),
805 safe_repr(expr2))
Benjamin Petersonbed7d042009-07-19 21:01:52 +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:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000811 standardMsg = 'unexpectedly identical: %s' % (safe_repr(expr1),)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000812 self.fail(self._formatMessage(msg, standardMsg))
813
814 def assertDictEqual(self, d1, d2, msg=None):
815 self.assert_(isinstance(d1, dict), 'First argument is not a dictionary')
816 self.assert_(isinstance(d2, dict), 'Second argument is not a dictionary')
817
818 if d1 != d2:
Michael Foordcb11b252010-06-05 13:14:43 +0000819 standardMsg = '%s != %s' % (safe_repr(d1, True), safe_repr(d2, True))
Michael Foord085dfd32010-06-05 12:17:02 +0000820 diff = ('\n' + '\n'.join(difflib.ndiff(
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000821 pprint.pformat(d1).splitlines(),
822 pprint.pformat(d2).splitlines())))
Michael Foordcb11b252010-06-05 13:14:43 +0000823 standardMsg = self._truncateMessage(standardMsg, diff)
Benjamin Petersonbed7d042009-07-19 21:01:52 +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.items():
831 if key not in actual:
832 missing.append(key)
833 elif value != actual[key]:
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000834 mismatched.append('%s, expected: %s, actual: %s' %
Benjamin Peterson847a4112010-03-14 15:04:17 +0000835 (safe_repr(key), safe_repr(value),
836 safe_repr(actual[key])))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000837
838 if not (missing or mismatched):
839 return
840
841 standardMsg = ''
842 if missing:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000843 standardMsg = 'Missing: %s' % ','.join(safe_repr(m) for m in
844 missing)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000845 if mismatched:
846 if standardMsg:
847 standardMsg += '; '
848 standardMsg += 'Mismatched values: %s' % ','.join(mismatched)
849
850 self.fail(self._formatMessage(msg, standardMsg))
851
852 def assertSameElements(self, expected_seq, actual_seq, msg=None):
853 """An unordered sequence specific comparison.
854
855 Raises with an error message listing which elements of expected_seq
856 are missing from actual_seq and vice versa if any.
Michael Foord1c42b122010-02-05 22:58:21 +0000857
858 Duplicate elements are ignored when comparing *expected_seq* and
859 *actual_seq*. It is the equivalent of ``assertEqual(set(expected),
860 set(actual))`` but it works with sequences of unhashable objects as
861 well.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000862 """
Michael Foord91c9da32010-03-20 17:21:27 +0000863 warnings.warn('assertSameElements is deprecated',
864 DeprecationWarning)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000865 try:
866 expected = set(expected_seq)
867 actual = set(actual_seq)
Benjamin Peterson847a4112010-03-14 15:04:17 +0000868 missing = sorted(expected.difference(actual))
869 unexpected = sorted(actual.difference(expected))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000870 except TypeError:
871 # Fall back to slower list-compare if any of the objects are
872 # not hashable.
873 expected = list(expected_seq)
874 actual = list(actual_seq)
875 try:
876 expected.sort()
877 actual.sort()
878 except TypeError:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000879 missing, unexpected = unorderable_list_difference(expected,
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000880 actual)
Benjamin Peterson847a4112010-03-14 15:04:17 +0000881 else:
882 missing, unexpected = sorted_list_difference(expected, actual)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000883 errors = []
884 if missing:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000885 errors.append('Expected, but missing:\n %s' %
886 safe_repr(missing))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000887 if unexpected:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000888 errors.append('Unexpected, but present:\n %s' %
889 safe_repr(unexpected))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000890 if errors:
891 standardMsg = '\n'.join(errors)
892 self.fail(self._formatMessage(msg, standardMsg))
893
Michael Foord8442a602010-03-20 16:58:04 +0000894
895 def assertItemsEqual(self, expected_seq, actual_seq, msg=None):
896 """An unordered sequence / set specific comparison. It asserts that
897 expected_seq and actual_seq contain the same elements. It is
898 the equivalent of::
899
900 self.assertEqual(sorted(expected_seq), sorted(actual_seq))
901
902 Raises with an error message listing which elements of expected_seq
903 are missing from actual_seq and vice versa if any.
904
905 Asserts that each element has the same count in both sequences.
906 Example:
907 - [0, 1, 1] and [1, 0, 1] compare equal.
908 - [0, 0, 1] and [0, 1] compare unequal.
909 """
910 try:
911 expected = sorted(expected_seq)
912 actual = sorted(actual_seq)
913 except TypeError:
914 # Unsortable items (example: set(), complex(), ...)
915 expected = list(expected_seq)
916 actual = list(actual_seq)
917 missing, unexpected = unorderable_list_difference(expected, actual)
918 else:
919 return self.assertSequenceEqual(expected, actual, msg=msg)
920
921 errors = []
922 if missing:
923 errors.append('Expected, but missing:\n %s' %
924 safe_repr(missing))
925 if unexpected:
926 errors.append('Unexpected, but present:\n %s' %
927 safe_repr(unexpected))
928 if errors:
929 standardMsg = '\n'.join(errors)
930 self.fail(self._formatMessage(msg, standardMsg))
931
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000932 def assertMultiLineEqual(self, first, second, msg=None):
933 """Assert that two multi-line strings are equal."""
934 self.assert_(isinstance(first, str), (
935 'First argument is not a string'))
936 self.assert_(isinstance(second, str), (
937 'Second argument is not a string'))
938
939 if first != second:
Michael Foordac760742010-06-05 13:57:23 +0000940 standardMsg = '%s != %s' % (safe_repr(first, True), safe_repr(second, True))
Michael Foord085dfd32010-06-05 12:17:02 +0000941 diff = '\n' + ''.join(difflib.ndiff(first.splitlines(True),
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000942 second.splitlines(True)))
Michael Foordcb11b252010-06-05 13:14:43 +0000943 standardMsg = self._truncateMessage(standardMsg, diff)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000944 self.fail(self._formatMessage(msg, standardMsg))
945
946 def assertLess(self, a, b, msg=None):
947 """Just like self.assertTrue(a < b), but with a nicer default message."""
948 if not a < b:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000949 standardMsg = '%s not less than %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000950 self.fail(self._formatMessage(msg, standardMsg))
951
952 def assertLessEqual(self, a, b, msg=None):
953 """Just like self.assertTrue(a <= b), but with a nicer default message."""
954 if not a <= b:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000955 standardMsg = '%s not less than or equal to %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000956 self.fail(self._formatMessage(msg, standardMsg))
957
958 def assertGreater(self, a, b, msg=None):
959 """Just like self.assertTrue(a > b), but with a nicer default message."""
960 if not a > b:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000961 standardMsg = '%s not greater than %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000962 self.fail(self._formatMessage(msg, standardMsg))
963
964 def assertGreaterEqual(self, a, b, msg=None):
965 """Just like self.assertTrue(a >= b), but with a nicer default message."""
966 if not a >= b:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000967 standardMsg = '%s not greater than or equal to %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000968 self.fail(self._formatMessage(msg, standardMsg))
969
970 def assertIsNone(self, obj, msg=None):
971 """Same as self.assertTrue(obj is None), with a nicer default message."""
972 if obj is not None:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000973 standardMsg = '%s is not None' % (safe_repr(obj),)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000974 self.fail(self._formatMessage(msg, standardMsg))
975
976 def assertIsNotNone(self, obj, msg=None):
977 """Included for symmetry with assertIsNone."""
978 if obj is None:
979 standardMsg = 'unexpectedly None'
980 self.fail(self._formatMessage(msg, standardMsg))
981
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000982 def assertIsInstance(self, obj, cls, msg=None):
983 """Same as self.assertTrue(isinstance(obj, cls)), with a nicer
984 default message."""
985 if not isinstance(obj, cls):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000986 standardMsg = '%s is not an instance of %r' % (safe_repr(obj), cls)
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000987 self.fail(self._formatMessage(msg, standardMsg))
988
989 def assertNotIsInstance(self, obj, cls, msg=None):
990 """Included for symmetry with assertIsInstance."""
991 if isinstance(obj, cls):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000992 standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls)
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000993 self.fail(self._formatMessage(msg, standardMsg))
994
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000995 def assertRaisesRegexp(self, expected_exception, expected_regexp,
996 callable_obj=None, *args, **kwargs):
997 """Asserts that the message in a raised exception matches a regexp.
998
999 Args:
1000 expected_exception: Exception class expected to be raised.
1001 expected_regexp: Regexp (re pattern object or string) expected
1002 to be found in error message.
1003 callable_obj: Function to be called.
1004 args: Extra args.
1005 kwargs: Extra kwargs.
1006 """
1007 context = _AssertRaisesContext(expected_exception, self, callable_obj,
1008 expected_regexp)
1009 if callable_obj is None:
1010 return context
1011 with context:
1012 callable_obj(*args, **kwargs)
1013
Georg Brandl89fad142010-03-14 10:23:39 +00001014 def assertRegexpMatches(self, text, expected_regexp, msg=None):
Michael Foorde3ef5f12010-05-08 16:46:14 +00001015 """Fail the test unless the text matches the regular expression."""
Georg Brandl89fad142010-03-14 10:23:39 +00001016 if isinstance(expected_regexp, (str, bytes)):
1017 expected_regexp = re.compile(expected_regexp)
1018 if not expected_regexp.search(text):
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001019 msg = msg or "Regexp didn't match"
Georg Brandl89fad142010-03-14 10:23:39 +00001020 msg = '%s: %r not found in %r' % (msg, expected_regexp.pattern, text)
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001021 raise self.failureException(msg)
1022
Benjamin Petersonb48af542010-04-11 20:43:16 +00001023 def assertNotRegexpMatches(self, text, unexpected_regexp, msg=None):
Michael Foorde3ef5f12010-05-08 16:46:14 +00001024 """Fail the test if the text matches the regular expression."""
Benjamin Petersonb48af542010-04-11 20:43:16 +00001025 if isinstance(unexpected_regexp, (str, bytes)):
1026 unexpected_regexp = re.compile(unexpected_regexp)
1027 match = unexpected_regexp.search(text)
1028 if match:
1029 msg = msg or "Regexp matched"
1030 msg = '%s: %r matches %r in %r' % (msg,
1031 text[match.start():match.end()],
1032 unexpected_regexp.pattern,
1033 text)
1034 raise self.failureException(msg)
1035
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001036
1037class FunctionTestCase(TestCase):
1038 """A test case that wraps a test function.
1039
1040 This is useful for slipping pre-existing test functions into the
1041 unittest framework. Optionally, set-up and tidy-up functions can be
1042 supplied. As with TestCase, the tidy-up ('tearDown') function will
1043 always be called if the set-up ('setUp') function ran successfully.
1044 """
1045
1046 def __init__(self, testFunc, setUp=None, tearDown=None, description=None):
1047 super(FunctionTestCase, self).__init__()
1048 self._setUpFunc = setUp
1049 self._tearDownFunc = tearDown
1050 self._testFunc = testFunc
1051 self._description = description
1052
1053 def setUp(self):
1054 if self._setUpFunc is not None:
1055 self._setUpFunc()
1056
1057 def tearDown(self):
1058 if self._tearDownFunc is not None:
1059 self._tearDownFunc()
1060
1061 def runTest(self):
1062 self._testFunc()
1063
1064 def id(self):
1065 return self._testFunc.__name__
1066
1067 def __eq__(self, other):
1068 if not isinstance(other, self.__class__):
1069 return NotImplemented
1070
1071 return self._setUpFunc == other._setUpFunc and \
1072 self._tearDownFunc == other._tearDownFunc and \
1073 self._testFunc == other._testFunc and \
1074 self._description == other._description
1075
1076 def __ne__(self, other):
1077 return not self == other
1078
1079 def __hash__(self):
1080 return hash((type(self), self._setUpFunc, self._tearDownFunc,
1081 self._testFunc, self._description))
1082
1083 def __str__(self):
Benjamin Peterson847a4112010-03-14 15:04:17 +00001084 return "%s (%s)" % (strclass(self.__class__),
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001085 self._testFunc.__name__)
1086
1087 def __repr__(self):
Benjamin Peterson847a4112010-03-14 15:04:17 +00001088 return "<%s tec=%s>" % (strclass(self.__class__),
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001089 self._testFunc)
1090
1091 def shortDescription(self):
1092 if self._description is not None:
1093 return self._description
1094 doc = self._testFunc.__doc__
1095 return doc and doc.split("\n")[0].strip() or None