blob: fcb756d3fbc9ddc9e936a4d65ff24833e1a78d2e [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.
178 maxDiff = 80*8
179
Benjamin Peterson847a4112010-03-14 15:04:17 +0000180 # Attribute used by TestSuite for classSetUp
181
182 _classSetupFailed = False
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000183
184 def __init__(self, methodName='runTest'):
185 """Create an instance of the class that will use the named test
186 method when executed. Raises a ValueError if the instance does
187 not have a method with the specified name.
188 """
189 self._testMethodName = methodName
190 self._resultForDoCleanups = None
191 try:
192 testMethod = getattr(self, methodName)
193 except AttributeError:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000194 raise ValueError("no such test method in %s: %s" %
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000195 (self.__class__, methodName))
196 self._testMethodDoc = testMethod.__doc__
197 self._cleanups = []
198
199 # Map types to custom assertEqual functions that will compare
200 # instances of said type in more detail to generate a more useful
201 # error message.
202 self._type_equality_funcs = {}
203 self.addTypeEqualityFunc(dict, self.assertDictEqual)
204 self.addTypeEqualityFunc(list, self.assertListEqual)
205 self.addTypeEqualityFunc(tuple, self.assertTupleEqual)
206 self.addTypeEqualityFunc(set, self.assertSetEqual)
207 self.addTypeEqualityFunc(frozenset, self.assertSetEqual)
Michael Foord02834952010-02-08 23:10:39 +0000208 self.addTypeEqualityFunc(str, self.assertMultiLineEqual)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000209
210 def addTypeEqualityFunc(self, typeobj, function):
211 """Add a type specific assertEqual style function to compare a type.
212
213 This method is for use by TestCase subclasses that need to register
214 their own type equality functions to provide nicer error messages.
215
216 Args:
217 typeobj: The data type to call this function on when both values
218 are of the same type in assertEqual().
219 function: The callable taking two arguments and an optional
220 msg= argument that raises self.failureException with a
221 useful error message when the two arguments are not equal.
222 """
Benjamin Peterson8f326b22009-12-13 02:10:36 +0000223 self._type_equality_funcs[typeobj] = function
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000224
225 def addCleanup(self, function, *args, **kwargs):
226 """Add a function, with arguments, to be called when the test is
227 completed. Functions added are called on a LIFO basis and are
228 called after tearDown on test failure or success.
229
230 Cleanup items are called even if setUp fails (unlike tearDown)."""
231 self._cleanups.append((function, args, kwargs))
232
233 def setUp(self):
234 "Hook method for setting up the test fixture before exercising it."
235 pass
236
237 def tearDown(self):
238 "Hook method for deconstructing the test fixture after testing it."
239 pass
240
Benjamin Peterson847a4112010-03-14 15:04:17 +0000241 @classmethod
242 def setUpClass(cls):
243 "Hook method for setting up class fixture before running tests in the class."
244
245 @classmethod
246 def tearDownClass(cls):
247 "Hook method for deconstructing the class fixture after running all tests in the class."
248
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000249 def countTestCases(self):
250 return 1
251
252 def defaultTestResult(self):
253 return result.TestResult()
254
255 def shortDescription(self):
Michael Foord34c94622010-02-10 15:51:42 +0000256 """Returns a one-line description of the test, or None if no
257 description has been provided.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000258
Michael Foord34c94622010-02-10 15:51:42 +0000259 The default implementation of this method returns the first line of
260 the specified test method's docstring.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000261 """
Michael Foord34c94622010-02-10 15:51:42 +0000262 doc = self._testMethodDoc
263 return doc and doc.split("\n")[0].strip() or None
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000264
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000265
266 def id(self):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000267 return "%s.%s" % (strclass(self.__class__), self._testMethodName)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000268
269 def __eq__(self, other):
270 if type(self) is not type(other):
271 return NotImplemented
272
273 return self._testMethodName == other._testMethodName
274
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000275 def __hash__(self):
276 return hash((type(self), self._testMethodName))
277
278 def __str__(self):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000279 return "%s (%s)" % (self._testMethodName, strclass(self.__class__))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000280
281 def __repr__(self):
282 return "<%s testMethod=%s>" % \
Benjamin Peterson847a4112010-03-14 15:04:17 +0000283 (strclass(self.__class__), self._testMethodName)
284
285 def _addSkip(self, result, reason):
286 addSkip = getattr(result, 'addSkip', None)
287 if addSkip is not None:
288 addSkip(self, reason)
289 else:
290 warnings.warn("TestResult has no addSkip method, skips not reported",
291 RuntimeWarning, 2)
292 result.addSuccess(self)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000293
294 def run(self, result=None):
295 orig_result = result
296 if result is None:
297 result = self.defaultTestResult()
298 startTestRun = getattr(result, 'startTestRun', None)
299 if startTestRun is not None:
300 startTestRun()
301
302 self._resultForDoCleanups = result
303 result.startTest(self)
Benjamin Peterson847a4112010-03-14 15:04:17 +0000304
305 testMethod = getattr(self, self._testMethodName)
306 if (getattr(self.__class__, "__unittest_skip__", False) or
307 getattr(testMethod, "__unittest_skip__", False)):
308 # If the class or method was skipped.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000309 try:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000310 skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
311 or getattr(testMethod, '__unittest_skip_why__', ''))
312 self._addSkip(result, skip_why)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000313 finally:
314 result.stopTest(self)
315 return
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000316 try:
317 success = False
318 try:
319 self.setUp()
320 except SkipTest as e:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000321 self._addSkip(result, str(e))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000322 except Exception:
323 result.addError(self, sys.exc_info())
324 else:
325 try:
326 testMethod()
327 except self.failureException:
328 result.addFailure(self, sys.exc_info())
329 except _ExpectedFailure as e:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000330 addExpectedFailure = getattr(result, 'addExpectedFailure', None)
331 if addExpectedFailure is not None:
332 addExpectedFailure(self, e.exc_info)
333 else:
334 warnings.warn("TestResult has no addExpectedFailure method, reporting as passes",
335 RuntimeWarning)
336 result.addSuccess(self)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000337 except _UnexpectedSuccess:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000338 addUnexpectedSuccess = getattr(result, 'addUnexpectedSuccess', None)
339 if addUnexpectedSuccess is not None:
340 addUnexpectedSuccess(self)
341 else:
342 warnings.warn("TestResult has no addUnexpectedSuccess method, reporting as failures",
343 RuntimeWarning)
344 result.addFailure(self, sys.exc_info())
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000345 except SkipTest as e:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000346 self._addSkip(result, str(e))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000347 except Exception:
348 result.addError(self, sys.exc_info())
349 else:
350 success = True
351
352 try:
353 self.tearDown()
354 except Exception:
355 result.addError(self, sys.exc_info())
356 success = False
357
358 cleanUpSuccess = self.doCleanups()
359 success = success and cleanUpSuccess
360 if success:
361 result.addSuccess(self)
362 finally:
363 result.stopTest(self)
364 if orig_result is None:
365 stopTestRun = getattr(result, 'stopTestRun', None)
366 if stopTestRun is not None:
367 stopTestRun()
368
369 def doCleanups(self):
370 """Execute all cleanup functions. Normally called for you after
371 tearDown."""
372 result = self._resultForDoCleanups
373 ok = True
374 while self._cleanups:
375 function, args, kwargs = self._cleanups.pop(-1)
376 try:
377 function(*args, **kwargs)
378 except Exception:
379 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()
391
392 def skipTest(self, reason):
393 """Skip this test."""
394 raise SkipTest(reason)
395
396 def fail(self, msg=None):
397 """Fail immediately, with the given message."""
398 raise self.failureException(msg)
399
400 def assertFalse(self, expr, msg=None):
401 "Fail the test if the expression is true."
402 if expr:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000403 msg = self._formatMessage(msg, "%s is not False" % safe_repr(expr))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000404 raise self.failureException(msg)
405
406 def assertTrue(self, expr, msg=None):
407 """Fail the test unless the expression is true."""
408 if not expr:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000409 msg = self._formatMessage(msg, "%s is not True" % safe_repr(expr))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000410 raise self.failureException(msg)
411
412 def _formatMessage(self, msg, standardMsg):
413 """Honour the longMessage attribute when generating failure messages.
414 If longMessage is False this means:
415 * Use only an explicit message if it is provided
416 * Otherwise use the standard message for the assert
417
418 If longMessage is True:
419 * Use the standard message
420 * If an explicit message is provided, plus ' : ' and the explicit message
421 """
422 if not self.longMessage:
423 return msg or standardMsg
424 if msg is None:
425 return standardMsg
Benjamin Peterson847a4112010-03-14 15:04:17 +0000426 try:
427 # don't switch to '{}' formatting in Python 2.X
428 # it changes the way unicode input is handled
429 return '%s : %s' % (standardMsg, msg)
430 except UnicodeDecodeError:
431 return '%s : %s' % (safe_repr(standardMsg), safe_repr(msg))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000432
433
434 def assertRaises(self, excClass, callableObj=None, *args, **kwargs):
435 """Fail unless an exception of class excClass is thrown
436 by callableObj when invoked with arguments args and keyword
437 arguments kwargs. If a different type of exception is
438 thrown, it will not be caught, and the test case will be
439 deemed to have suffered an error, exactly as for an
440 unexpected exception.
441
442 If called with callableObj omitted or None, will return a
443 context object used like this::
444
Michael Foord1c42b122010-02-05 22:58:21 +0000445 with self.assertRaises(SomeException):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000446 do_something()
Michael Foord1c42b122010-02-05 22:58:21 +0000447
448 The context manager keeps a reference to the exception as
Ezio Melotti49008232010-02-08 21:57:48 +0000449 the 'exception' attribute. This allows you to inspect the
Michael Foord1c42b122010-02-05 22:58:21 +0000450 exception after the assertion::
451
452 with self.assertRaises(SomeException) as cm:
453 do_something()
Ezio Melotti49008232010-02-08 21:57:48 +0000454 the_exception = cm.exception
Michael Foordb57ac6d2010-02-05 23:26:29 +0000455 self.assertEqual(the_exception.error_code, 3)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000456 """
457 context = _AssertRaisesContext(excClass, self, callableObj)
458 if callableObj is None:
459 return context
460 with context:
461 callableObj(*args, **kwargs)
462
463 def _getAssertEqualityFunc(self, first, second):
464 """Get a detailed comparison function for the types of the two args.
465
466 Returns: A callable accepting (first, second, msg=None) that will
467 raise a failure exception if first != second with a useful human
468 readable error message for those types.
469 """
470 #
471 # NOTE(gregory.p.smith): I considered isinstance(first, type(second))
472 # and vice versa. I opted for the conservative approach in case
473 # subclasses are not intended to be compared in detail to their super
474 # class instances using a type equality func. This means testing
475 # subtypes won't automagically use the detailed comparison. Callers
476 # should use their type specific assertSpamEqual method to compare
477 # subclasses if the detailed comparison is desired and appropriate.
478 # See the discussion in http://bugs.python.org/issue2578.
479 #
480 if type(first) is type(second):
481 asserter = self._type_equality_funcs.get(type(first))
482 if asserter is not None:
Benjamin Peterson8f326b22009-12-13 02:10:36 +0000483 return asserter
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000484
485 return self._baseAssertEqual
486
487 def _baseAssertEqual(self, first, second, msg=None):
488 """The default assertEqual implementation, not type specific."""
489 if not first == second:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000490 standardMsg = '%s != %s' % (safe_repr(first), safe_repr(second))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000491 msg = self._formatMessage(msg, standardMsg)
492 raise self.failureException(msg)
493
494 def assertEqual(self, first, second, msg=None):
495 """Fail if the two objects are unequal as determined by the '=='
496 operator.
497 """
498 assertion_func = self._getAssertEqualityFunc(first, second)
499 assertion_func(first, second, msg=msg)
500
501 def assertNotEqual(self, first, second, msg=None):
502 """Fail if the two objects are equal as determined by the '=='
503 operator.
504 """
505 if not first != second:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000506 msg = self._formatMessage(msg, '%s == %s' % (safe_repr(first),
507 safe_repr(second)))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000508 raise self.failureException(msg)
509
Benjamin Petersonb48af542010-04-11 20:43:16 +0000510 def assertAlmostEqual(self, first, second, *, places=None, msg=None,
511 delta=None):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000512 """Fail if the two objects are unequal as determined by their
513 difference rounded to the given number of decimal places
Benjamin Petersonb48af542010-04-11 20:43:16 +0000514 (default 7) and comparing to zero, or by comparing that the
515 between the two objects is more than the given delta.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000516
517 Note that decimal places (from zero) are usually not the same
518 as significant digits (measured from the most signficant digit).
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000519
520 If the two objects compare equal then they will automatically
521 compare almost equal.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000522 """
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000523 if first == second:
Benjamin Petersonb48af542010-04-11 20:43:16 +0000524 # shortcut
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000525 return
Benjamin Petersonb48af542010-04-11 20:43:16 +0000526 if delta is not None and places is not None:
527 raise TypeError("specify delta or places not both")
528
529 if delta is not None:
530 if abs(first - second) <= delta:
531 return
532
533 standardMsg = '%s != %s within %s delta' % (safe_repr(first),
534 safe_repr(second),
535 safe_repr(delta))
536 else:
537 if places is None:
538 places = 7
539
540 if round(abs(second-first), places) == 0:
541 return
542
Benjamin Peterson847a4112010-03-14 15:04:17 +0000543 standardMsg = '%s != %s within %r places' % (safe_repr(first),
544 safe_repr(second),
545 places)
Benjamin Petersonb48af542010-04-11 20:43:16 +0000546 msg = self._formatMessage(msg, standardMsg)
547 raise self.failureException(msg)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000548
Benjamin Petersonb48af542010-04-11 20:43:16 +0000549 def assertNotAlmostEqual(self, first, second, *, places=None, msg=None,
550 delta=None):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000551 """Fail if the two objects are equal as determined by their
552 difference rounded to the given number of decimal places
Benjamin Petersonb48af542010-04-11 20:43:16 +0000553 (default 7) and comparing to zero, or by comparing that the
554 between the two objects is less than the given delta.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000555
556 Note that decimal places (from zero) are usually not the same
557 as significant digits (measured from the most signficant digit).
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000558
559 Objects that are equal automatically fail.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000560 """
Benjamin Petersonb48af542010-04-11 20:43:16 +0000561 if delta is not None and places is not None:
562 raise TypeError("specify delta or places not both")
563 if delta is not None:
564 if not (first == second) and abs(first - second) > delta:
565 return
566 standardMsg = '%s == %s within %s delta' % (safe_repr(first),
567 safe_repr(second),
568 safe_repr(delta))
569 else:
570 if places is None:
571 places = 7
572 if not (first == second) and round(abs(second-first), places) != 0:
573 return
Benjamin Peterson847a4112010-03-14 15:04:17 +0000574 standardMsg = '%s == %s within %r places' % (safe_repr(first),
Benjamin Petersonb48af542010-04-11 20:43:16 +0000575 safe_repr(second),
576 places)
577
578 msg = self._formatMessage(msg, standardMsg)
579 raise self.failureException(msg)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000580
581 # Synonyms for assertion methods
582
583 # The plurals are undocumented. Keep them that way to discourage use.
584 # Do not add more. Do not remove.
585 # Going through a deprecation cycle on these would annoy many people.
586 assertEquals = assertEqual
587 assertNotEquals = assertNotEqual
588 assertAlmostEquals = assertAlmostEqual
589 assertNotAlmostEquals = assertNotAlmostEqual
Michael Foord0e31b992010-02-10 15:52:56 +0000590 assert_ = assertTrue
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000591
592 # These fail* assertion method names are pending deprecation and will
593 # be a DeprecationWarning in 3.2; http://bugs.python.org/issue2578
594 def _deprecate(original_func):
595 def deprecated_func(*args, **kwargs):
596 warnings.warn(
597 'Please use {0} instead.'.format(original_func.__name__),
598 DeprecationWarning, 2)
599 return original_func(*args, **kwargs)
600 return deprecated_func
601
602 failUnlessEqual = _deprecate(assertEqual)
603 failIfEqual = _deprecate(assertNotEqual)
604 failUnlessAlmostEqual = _deprecate(assertAlmostEqual)
605 failIfAlmostEqual = _deprecate(assertNotAlmostEqual)
606 failUnless = _deprecate(assertTrue)
607 failUnlessRaises = _deprecate(assertRaises)
608 failIf = _deprecate(assertFalse)
609
Michael Foord085dfd32010-06-05 12:17:02 +0000610 def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000611 """An equality assertion for ordered sequences (like lists and tuples).
612
R. David Murrayad13f222010-01-29 22:17:58 +0000613 For the purposes of this function, a valid ordered sequence type is one
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000614 which can be indexed, has a length, and has an equality operator.
615
616 Args:
617 seq1: The first sequence to compare.
618 seq2: The second sequence to compare.
619 seq_type: The expected datatype of the sequences, or None if no
620 datatype should be enforced.
621 msg: Optional message to use on failure instead of a list of
622 differences.
623 """
624 if seq_type != None:
625 seq_type_name = seq_type.__name__
626 if not isinstance(seq1, seq_type):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000627 raise self.failureException('First sequence is not a %s: %s'
628 % (seq_type_name, safe_repr(seq1)))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000629 if not isinstance(seq2, seq_type):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000630 raise self.failureException('Second sequence is not a %s: %s'
631 % (seq_type_name, safe_repr(seq2)))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000632 else:
633 seq_type_name = "sequence"
634
635 differing = None
636 try:
637 len1 = len(seq1)
638 except (TypeError, NotImplementedError):
639 differing = 'First %s has no length. Non-sequence?' % (
640 seq_type_name)
641
642 if differing is None:
643 try:
644 len2 = len(seq2)
645 except (TypeError, NotImplementedError):
646 differing = 'Second %s has no length. Non-sequence?' % (
647 seq_type_name)
648
649 if differing is None:
650 if seq1 == seq2:
651 return
652
Benjamin Peterson847a4112010-03-14 15:04:17 +0000653 seq1_repr = safe_repr(seq1)
654 seq2_repr = safe_repr(seq2)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000655 if len(seq1_repr) > 30:
656 seq1_repr = seq1_repr[:30] + '...'
657 if len(seq2_repr) > 30:
658 seq2_repr = seq2_repr[:30] + '...'
659 elements = (seq_type_name.capitalize(), seq1_repr, seq2_repr)
660 differing = '%ss differ: %s != %s\n' % elements
661
662 for i in range(min(len1, len2)):
663 try:
664 item1 = seq1[i]
665 except (TypeError, IndexError, NotImplementedError):
666 differing += ('\nUnable to index element %d of first %s\n' %
667 (i, seq_type_name))
668 break
669
670 try:
671 item2 = seq2[i]
672 except (TypeError, IndexError, NotImplementedError):
673 differing += ('\nUnable to index element %d of second %s\n' %
674 (i, seq_type_name))
675 break
676
677 if item1 != item2:
678 differing += ('\nFirst differing element %d:\n%s\n%s\n' %
679 (i, item1, item2))
680 break
681 else:
682 if (len1 == len2 and seq_type is None and
683 type(seq1) != type(seq2)):
684 # The sequences are the same, but have differing types.
685 return
686
687 if len1 > len2:
688 differing += ('\nFirst %s contains %d additional '
689 'elements.\n' % (seq_type_name, len1 - len2))
690 try:
691 differing += ('First extra element %d:\n%s\n' %
692 (len2, seq1[len2]))
693 except (TypeError, IndexError, NotImplementedError):
694 differing += ('Unable to index element %d '
695 'of first %s\n' % (len2, seq_type_name))
696 elif len1 < len2:
697 differing += ('\nSecond %s contains %d additional '
698 'elements.\n' % (seq_type_name, len2 - len1))
699 try:
700 differing += ('First extra element %d:\n%s\n' %
701 (len1, seq2[len1]))
702 except (TypeError, IndexError, NotImplementedError):
703 differing += ('Unable to index element %d '
704 'of second %s\n' % (len1, seq_type_name))
Michael Foord2034d9a2010-06-05 11:27:52 +0000705 standardMsg = differing
706 diffMsg = '\n' + '\n'.join(
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000707 difflib.ndiff(pprint.pformat(seq1).splitlines(),
708 pprint.pformat(seq2).splitlines()))
Michael Foord085dfd32010-06-05 12:17:02 +0000709
710 standardMsg = self._truncateMessage(standardMsg, diffMsg)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000711 msg = self._formatMessage(msg, standardMsg)
712 self.fail(msg)
713
Michael Foord085dfd32010-06-05 12:17:02 +0000714 def _truncateMessage(self, message, diff):
715 max_diff = self.maxDiff
716 if max_diff is None or len(diff) <= max_diff:
717 return message + diff
Michael Foord9dad32e2010-06-05 13:49:56 +0000718 return message + (DIFF_OMITTED % len(diff))
Michael Foord085dfd32010-06-05 12:17:02 +0000719
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000720 def assertListEqual(self, list1, list2, msg=None):
721 """A list-specific equality assertion.
722
723 Args:
724 list1: The first list to compare.
725 list2: The second list to compare.
726 msg: Optional message to use on failure instead of a list of
727 differences.
728
729 """
730 self.assertSequenceEqual(list1, list2, msg, seq_type=list)
731
732 def assertTupleEqual(self, tuple1, tuple2, msg=None):
733 """A tuple-specific equality assertion.
734
735 Args:
736 tuple1: The first tuple to compare.
737 tuple2: The second tuple to compare.
738 msg: Optional message to use on failure instead of a list of
739 differences.
740 """
741 self.assertSequenceEqual(tuple1, tuple2, msg, seq_type=tuple)
742
743 def assertSetEqual(self, set1, set2, msg=None):
744 """A set-specific equality assertion.
745
746 Args:
747 set1: The first set to compare.
748 set2: The second set to compare.
749 msg: Optional message to use on failure instead of a list of
750 differences.
751
Michael Foord91c9da32010-03-20 17:21:27 +0000752 assertSetEqual uses ducktyping to support different types of sets, and
753 is optimized for sets specifically (parameters must support a
754 difference method).
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000755 """
756 try:
757 difference1 = set1.difference(set2)
758 except TypeError as e:
759 self.fail('invalid type when attempting set difference: %s' % e)
760 except AttributeError as e:
761 self.fail('first argument does not support set difference: %s' % e)
762
763 try:
764 difference2 = set2.difference(set1)
765 except TypeError as e:
766 self.fail('invalid type when attempting set difference: %s' % e)
767 except AttributeError as e:
768 self.fail('second argument does not support set difference: %s' % e)
769
770 if not (difference1 or difference2):
771 return
772
773 lines = []
774 if difference1:
775 lines.append('Items in the first set but not the second:')
776 for item in difference1:
777 lines.append(repr(item))
778 if difference2:
779 lines.append('Items in the second set but not the first:')
780 for item in difference2:
781 lines.append(repr(item))
782
783 standardMsg = '\n'.join(lines)
784 self.fail(self._formatMessage(msg, standardMsg))
785
786 def assertIn(self, member, container, msg=None):
787 """Just like self.assertTrue(a in b), but with a nicer default message."""
788 if member not in container:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000789 standardMsg = '%s not found in %s' % (safe_repr(member),
790 safe_repr(container))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000791 self.fail(self._formatMessage(msg, standardMsg))
792
793 def assertNotIn(self, member, container, msg=None):
794 """Just like self.assertTrue(a not in b), but with a nicer default message."""
795 if member in container:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000796 standardMsg = '%s unexpectedly found in %s' % (safe_repr(member),
797 safe_repr(container))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000798 self.fail(self._formatMessage(msg, standardMsg))
799
800 def assertIs(self, expr1, expr2, msg=None):
801 """Just like self.assertTrue(a is b), but with a nicer default message."""
802 if expr1 is not expr2:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000803 standardMsg = '%s is not %s' % (safe_repr(expr1),
804 safe_repr(expr2))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000805 self.fail(self._formatMessage(msg, standardMsg))
806
807 def assertIsNot(self, expr1, expr2, msg=None):
808 """Just like self.assertTrue(a is not b), but with a nicer default message."""
809 if expr1 is expr2:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000810 standardMsg = 'unexpectedly identical: %s' % (safe_repr(expr1),)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000811 self.fail(self._formatMessage(msg, standardMsg))
812
813 def assertDictEqual(self, d1, d2, msg=None):
814 self.assert_(isinstance(d1, dict), 'First argument is not a dictionary')
815 self.assert_(isinstance(d2, dict), 'Second argument is not a dictionary')
816
817 if d1 != d2:
Michael Foordcb11b252010-06-05 13:14:43 +0000818 standardMsg = '%s != %s' % (safe_repr(d1, True), safe_repr(d2, True))
Michael Foord085dfd32010-06-05 12:17:02 +0000819 diff = ('\n' + '\n'.join(difflib.ndiff(
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000820 pprint.pformat(d1).splitlines(),
821 pprint.pformat(d2).splitlines())))
Michael Foordcb11b252010-06-05 13:14:43 +0000822 standardMsg = self._truncateMessage(standardMsg, diff)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000823 self.fail(self._formatMessage(msg, standardMsg))
824
825 def assertDictContainsSubset(self, expected, actual, msg=None):
826 """Checks whether actual is a superset of expected."""
827 missing = []
828 mismatched = []
829 for key, value in expected.items():
830 if key not in actual:
831 missing.append(key)
832 elif value != actual[key]:
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000833 mismatched.append('%s, expected: %s, actual: %s' %
Benjamin Peterson847a4112010-03-14 15:04:17 +0000834 (safe_repr(key), safe_repr(value),
835 safe_repr(actual[key])))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000836
837 if not (missing or mismatched):
838 return
839
840 standardMsg = ''
841 if missing:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000842 standardMsg = 'Missing: %s' % ','.join(safe_repr(m) for m in
843 missing)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000844 if mismatched:
845 if standardMsg:
846 standardMsg += '; '
847 standardMsg += 'Mismatched values: %s' % ','.join(mismatched)
848
849 self.fail(self._formatMessage(msg, standardMsg))
850
851 def assertSameElements(self, expected_seq, actual_seq, msg=None):
852 """An unordered sequence specific comparison.
853
854 Raises with an error message listing which elements of expected_seq
855 are missing from actual_seq and vice versa if any.
Michael Foord1c42b122010-02-05 22:58:21 +0000856
857 Duplicate elements are ignored when comparing *expected_seq* and
858 *actual_seq*. It is the equivalent of ``assertEqual(set(expected),
859 set(actual))`` but it works with sequences of unhashable objects as
860 well.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000861 """
Michael Foord91c9da32010-03-20 17:21:27 +0000862 warnings.warn('assertSameElements is deprecated',
863 DeprecationWarning)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000864 try:
865 expected = set(expected_seq)
866 actual = set(actual_seq)
Benjamin Peterson847a4112010-03-14 15:04:17 +0000867 missing = sorted(expected.difference(actual))
868 unexpected = sorted(actual.difference(expected))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000869 except TypeError:
870 # Fall back to slower list-compare if any of the objects are
871 # not hashable.
872 expected = list(expected_seq)
873 actual = list(actual_seq)
874 try:
875 expected.sort()
876 actual.sort()
877 except TypeError:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000878 missing, unexpected = unorderable_list_difference(expected,
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000879 actual)
Benjamin Peterson847a4112010-03-14 15:04:17 +0000880 else:
881 missing, unexpected = sorted_list_difference(expected, actual)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000882 errors = []
883 if missing:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000884 errors.append('Expected, but missing:\n %s' %
885 safe_repr(missing))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000886 if unexpected:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000887 errors.append('Unexpected, but present:\n %s' %
888 safe_repr(unexpected))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000889 if errors:
890 standardMsg = '\n'.join(errors)
891 self.fail(self._formatMessage(msg, standardMsg))
892
Michael Foord8442a602010-03-20 16:58:04 +0000893
894 def assertItemsEqual(self, expected_seq, actual_seq, msg=None):
895 """An unordered sequence / set specific comparison. It asserts that
896 expected_seq and actual_seq contain the same elements. It is
897 the equivalent of::
898
899 self.assertEqual(sorted(expected_seq), sorted(actual_seq))
900
901 Raises with an error message listing which elements of expected_seq
902 are missing from actual_seq and vice versa if any.
903
904 Asserts that each element has the same count in both sequences.
905 Example:
906 - [0, 1, 1] and [1, 0, 1] compare equal.
907 - [0, 0, 1] and [0, 1] compare unequal.
908 """
909 try:
910 expected = sorted(expected_seq)
911 actual = sorted(actual_seq)
912 except TypeError:
913 # Unsortable items (example: set(), complex(), ...)
914 expected = list(expected_seq)
915 actual = list(actual_seq)
916 missing, unexpected = unorderable_list_difference(expected, actual)
917 else:
918 return self.assertSequenceEqual(expected, actual, msg=msg)
919
920 errors = []
921 if missing:
922 errors.append('Expected, but missing:\n %s' %
923 safe_repr(missing))
924 if unexpected:
925 errors.append('Unexpected, but present:\n %s' %
926 safe_repr(unexpected))
927 if errors:
928 standardMsg = '\n'.join(errors)
929 self.fail(self._formatMessage(msg, standardMsg))
930
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000931 def assertMultiLineEqual(self, first, second, msg=None):
932 """Assert that two multi-line strings are equal."""
933 self.assert_(isinstance(first, str), (
934 'First argument is not a string'))
935 self.assert_(isinstance(second, str), (
936 'Second argument is not a string'))
937
938 if first != second:
Michael Foordcb11b252010-06-05 13:14:43 +0000939 standardMsg = '%s != %s' % (safe_repr(d1, True), safe_repr(d2, True))
Michael Foord085dfd32010-06-05 12:17:02 +0000940 diff = '\n' + ''.join(difflib.ndiff(first.splitlines(True),
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000941 second.splitlines(True)))
Michael Foordcb11b252010-06-05 13:14:43 +0000942 standardMsg = self._truncateMessage(standardMsg, diff)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000943 self.fail(self._formatMessage(msg, standardMsg))
944
945 def assertLess(self, a, b, msg=None):
946 """Just like self.assertTrue(a < b), but with a nicer default message."""
947 if not a < b:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000948 standardMsg = '%s not less than %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000949 self.fail(self._formatMessage(msg, standardMsg))
950
951 def assertLessEqual(self, a, b, msg=None):
952 """Just like self.assertTrue(a <= b), but with a nicer default message."""
953 if not a <= b:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000954 standardMsg = '%s not less than or equal to %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000955 self.fail(self._formatMessage(msg, standardMsg))
956
957 def assertGreater(self, a, b, msg=None):
958 """Just like self.assertTrue(a > b), but with a nicer default message."""
959 if not a > b:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000960 standardMsg = '%s not greater than %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000961 self.fail(self._formatMessage(msg, standardMsg))
962
963 def assertGreaterEqual(self, a, b, msg=None):
964 """Just like self.assertTrue(a >= b), but with a nicer default message."""
965 if not a >= b:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000966 standardMsg = '%s not greater than or equal to %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000967 self.fail(self._formatMessage(msg, standardMsg))
968
969 def assertIsNone(self, obj, msg=None):
970 """Same as self.assertTrue(obj is None), with a nicer default message."""
971 if obj is not None:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000972 standardMsg = '%s is not None' % (safe_repr(obj),)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000973 self.fail(self._formatMessage(msg, standardMsg))
974
975 def assertIsNotNone(self, obj, msg=None):
976 """Included for symmetry with assertIsNone."""
977 if obj is None:
978 standardMsg = 'unexpectedly None'
979 self.fail(self._formatMessage(msg, standardMsg))
980
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000981 def assertIsInstance(self, obj, cls, msg=None):
982 """Same as self.assertTrue(isinstance(obj, cls)), with a nicer
983 default message."""
984 if not isinstance(obj, cls):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000985 standardMsg = '%s is not an instance of %r' % (safe_repr(obj), cls)
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000986 self.fail(self._formatMessage(msg, standardMsg))
987
988 def assertNotIsInstance(self, obj, cls, msg=None):
989 """Included for symmetry with assertIsInstance."""
990 if isinstance(obj, cls):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000991 standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls)
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000992 self.fail(self._formatMessage(msg, standardMsg))
993
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000994 def assertRaisesRegexp(self, expected_exception, expected_regexp,
995 callable_obj=None, *args, **kwargs):
996 """Asserts that the message in a raised exception matches a regexp.
997
998 Args:
999 expected_exception: Exception class expected to be raised.
1000 expected_regexp: Regexp (re pattern object or string) expected
1001 to be found in error message.
1002 callable_obj: Function to be called.
1003 args: Extra args.
1004 kwargs: Extra kwargs.
1005 """
1006 context = _AssertRaisesContext(expected_exception, self, callable_obj,
1007 expected_regexp)
1008 if callable_obj is None:
1009 return context
1010 with context:
1011 callable_obj(*args, **kwargs)
1012
Georg Brandl89fad142010-03-14 10:23:39 +00001013 def assertRegexpMatches(self, text, expected_regexp, msg=None):
Michael Foorde3ef5f12010-05-08 16:46:14 +00001014 """Fail the test unless the text matches the regular expression."""
Georg Brandl89fad142010-03-14 10:23:39 +00001015 if isinstance(expected_regexp, (str, bytes)):
1016 expected_regexp = re.compile(expected_regexp)
1017 if not expected_regexp.search(text):
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001018 msg = msg or "Regexp didn't match"
Georg Brandl89fad142010-03-14 10:23:39 +00001019 msg = '%s: %r not found in %r' % (msg, expected_regexp.pattern, text)
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001020 raise self.failureException(msg)
1021
Benjamin Petersonb48af542010-04-11 20:43:16 +00001022 def assertNotRegexpMatches(self, text, unexpected_regexp, msg=None):
Michael Foorde3ef5f12010-05-08 16:46:14 +00001023 """Fail the test if the text matches the regular expression."""
Benjamin Petersonb48af542010-04-11 20:43:16 +00001024 if isinstance(unexpected_regexp, (str, bytes)):
1025 unexpected_regexp = re.compile(unexpected_regexp)
1026 match = unexpected_regexp.search(text)
1027 if match:
1028 msg = msg or "Regexp matched"
1029 msg = '%s: %r matches %r in %r' % (msg,
1030 text[match.start():match.end()],
1031 unexpected_regexp.pattern,
1032 text)
1033 raise self.failureException(msg)
1034
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001035
1036class FunctionTestCase(TestCase):
1037 """A test case that wraps a test function.
1038
1039 This is useful for slipping pre-existing test functions into the
1040 unittest framework. Optionally, set-up and tidy-up functions can be
1041 supplied. As with TestCase, the tidy-up ('tearDown') function will
1042 always be called if the set-up ('setUp') function ran successfully.
1043 """
1044
1045 def __init__(self, testFunc, setUp=None, tearDown=None, description=None):
1046 super(FunctionTestCase, self).__init__()
1047 self._setUpFunc = setUp
1048 self._tearDownFunc = tearDown
1049 self._testFunc = testFunc
1050 self._description = description
1051
1052 def setUp(self):
1053 if self._setUpFunc is not None:
1054 self._setUpFunc()
1055
1056 def tearDown(self):
1057 if self._tearDownFunc is not None:
1058 self._tearDownFunc()
1059
1060 def runTest(self):
1061 self._testFunc()
1062
1063 def id(self):
1064 return self._testFunc.__name__
1065
1066 def __eq__(self, other):
1067 if not isinstance(other, self.__class__):
1068 return NotImplemented
1069
1070 return self._setUpFunc == other._setUpFunc and \
1071 self._tearDownFunc == other._tearDownFunc and \
1072 self._testFunc == other._testFunc and \
1073 self._description == other._description
1074
1075 def __ne__(self, other):
1076 return not self == other
1077
1078 def __hash__(self):
1079 return hash((type(self), self._setUpFunc, self._tearDownFunc,
1080 self._testFunc, self._description))
1081
1082 def __str__(self):
Benjamin Peterson847a4112010-03-14 15:04:17 +00001083 return "%s (%s)" % (strclass(self.__class__),
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001084 self._testFunc.__name__)
1085
1086 def __repr__(self):
Benjamin Peterson847a4112010-03-14 15:04:17 +00001087 return "<%s tec=%s>" % (strclass(self.__class__),
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001088 self._testFunc)
1089
1090 def shortDescription(self):
1091 if self._description is not None:
1092 return self._description
1093 doc = self._testFunc.__doc__
1094 return doc and doc.split("\n")[0].strip() or None