blob: fca7e190d679def6677baa6308b7ff99640e33af [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
16class SkipTest(Exception):
17 """
18 Raise this exception in a test to skip it.
19
20 Usually you can use TestResult.skip() or one of the skipping decorators
21 instead of raising this directly.
22 """
23 pass
24
25class _ExpectedFailure(Exception):
26 """
27 Raise this when a test is expected to fail.
28
29 This is an implementation detail.
30 """
31
32 def __init__(self, exc_info):
33 super(_ExpectedFailure, self).__init__()
34 self.exc_info = exc_info
35
36class _UnexpectedSuccess(Exception):
37 """
38 The test was supposed to fail, but it didn't!
39 """
40 pass
41
42def _id(obj):
43 return obj
44
45def skip(reason):
46 """
47 Unconditionally skip a test.
48 """
49 def decorator(test_item):
Benjamin Peterson847a4112010-03-14 15:04:17 +000050 if not (isinstance(test_item, type) and issubclass(test_item, TestCase)):
51 @functools.wraps(test_item)
52 def skip_wrapper(*args, **kwargs):
53 raise SkipTest(reason)
54 test_item = skip_wrapper
55
56 test_item.__unittest_skip__ = True
57 test_item.__unittest_skip_why__ = reason
58 return test_item
Benjamin Petersonbed7d042009-07-19 21:01:52 +000059 return decorator
60
61def skipIf(condition, reason):
62 """
63 Skip a test if the condition is true.
64 """
65 if condition:
66 return skip(reason)
67 return _id
68
69def skipUnless(condition, reason):
70 """
71 Skip a test unless the condition is true.
72 """
73 if not condition:
74 return skip(reason)
75 return _id
76
77
78def expectedFailure(func):
79 @functools.wraps(func)
80 def wrapper(*args, **kwargs):
81 try:
82 func(*args, **kwargs)
83 except Exception:
84 raise _ExpectedFailure(sys.exc_info())
85 raise _UnexpectedSuccess
86 return wrapper
87
88
89class _AssertRaisesContext(object):
90 """A context manager used to implement TestCase.assertRaises* methods."""
91
92 def __init__(self, expected, test_case, callable_obj=None,
93 expected_regexp=None):
94 self.expected = expected
95 self.failureException = test_case.failureException
96 if callable_obj is not None:
97 try:
98 self.obj_name = callable_obj.__name__
99 except AttributeError:
100 self.obj_name = str(callable_obj)
101 else:
102 self.obj_name = None
Georg Brandl89fad142010-03-14 10:23:39 +0000103 self.expected_regexp = expected_regexp
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000104
105 def __enter__(self):
Ezio Melotti49008232010-02-08 21:57:48 +0000106 return self
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000107
108 def __exit__(self, exc_type, exc_value, tb):
109 if exc_type is None:
110 try:
111 exc_name = self.expected.__name__
112 except AttributeError:
113 exc_name = str(self.expected)
114 if self.obj_name:
115 raise self.failureException("{0} not raised by {1}"
116 .format(exc_name, self.obj_name))
117 else:
118 raise self.failureException("{0} not raised"
119 .format(exc_name))
120 if not issubclass(exc_type, self.expected):
121 # let unexpected exceptions pass through
122 return False
Ezio Melotti49008232010-02-08 21:57:48 +0000123 # store exception, without traceback, for later retrieval
124 self.exception = exc_value.with_traceback(None)
Georg Brandl89fad142010-03-14 10:23:39 +0000125 if self.expected_regexp is None:
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000126 return True
127
Georg Brandl89fad142010-03-14 10:23:39 +0000128 expected_regexp = self.expected_regexp
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000129 if isinstance(expected_regexp, (bytes, str)):
130 expected_regexp = re.compile(expected_regexp)
131 if not expected_regexp.search(str(exc_value)):
132 raise self.failureException('"%s" does not match "%s"' %
133 (expected_regexp.pattern, str(exc_value)))
134 return True
135
136
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000137class TestCase(object):
138 """A class whose instances are single test cases.
139
140 By default, the test code itself should be placed in a method named
141 'runTest'.
142
143 If the fixture may be used for many test cases, create as
144 many test methods as are needed. When instantiating such a TestCase
145 subclass, specify in the constructor arguments the name of the test method
146 that the instance is to execute.
147
148 Test authors should subclass TestCase for their own tests. Construction
149 and deconstruction of the test's environment ('fixture') can be
150 implemented by overriding the 'setUp' and 'tearDown' methods respectively.
151
152 If it is necessary to override the __init__ method, the base class
153 __init__ method must always be called. It is important that subclasses
154 should not change the signature of their __init__ method, since instances
155 of the classes are instantiated automatically by parts of the framework
156 in order to be run.
157 """
158
159 # This attribute determines which exception will be raised when
160 # the instance's assertion methods fail; test methods raising this
161 # exception will be deemed to have 'failed' rather than 'errored'
162
163 failureException = AssertionError
164
165 # This attribute determines whether long messages (including repr of
166 # objects used in assert methods) will be printed on failure in *addition*
167 # to any explicit message passed.
168
169 longMessage = False
170
Michael Foord085dfd32010-06-05 12:17:02 +0000171 # This attribute sets the maximum length of a diff in failure messsages
172 # by assert methods using difflib. It is looked up as an instance attribute
173 # so can be configured by individual tests if required.
174 maxDiff = 80*8
175
Benjamin Peterson847a4112010-03-14 15:04:17 +0000176 # Attribute used by TestSuite for classSetUp
177
178 _classSetupFailed = False
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000179
180 def __init__(self, methodName='runTest'):
181 """Create an instance of the class that will use the named test
182 method when executed. Raises a ValueError if the instance does
183 not have a method with the specified name.
184 """
185 self._testMethodName = methodName
186 self._resultForDoCleanups = None
187 try:
188 testMethod = getattr(self, methodName)
189 except AttributeError:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000190 raise ValueError("no such test method in %s: %s" %
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000191 (self.__class__, methodName))
192 self._testMethodDoc = testMethod.__doc__
193 self._cleanups = []
194
195 # Map types to custom assertEqual functions that will compare
196 # instances of said type in more detail to generate a more useful
197 # error message.
198 self._type_equality_funcs = {}
199 self.addTypeEqualityFunc(dict, self.assertDictEqual)
200 self.addTypeEqualityFunc(list, self.assertListEqual)
201 self.addTypeEqualityFunc(tuple, self.assertTupleEqual)
202 self.addTypeEqualityFunc(set, self.assertSetEqual)
203 self.addTypeEqualityFunc(frozenset, self.assertSetEqual)
Michael Foord02834952010-02-08 23:10:39 +0000204 self.addTypeEqualityFunc(str, self.assertMultiLineEqual)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000205
206 def addTypeEqualityFunc(self, typeobj, function):
207 """Add a type specific assertEqual style function to compare a type.
208
209 This method is for use by TestCase subclasses that need to register
210 their own type equality functions to provide nicer error messages.
211
212 Args:
213 typeobj: The data type to call this function on when both values
214 are of the same type in assertEqual().
215 function: The callable taking two arguments and an optional
216 msg= argument that raises self.failureException with a
217 useful error message when the two arguments are not equal.
218 """
Benjamin Peterson8f326b22009-12-13 02:10:36 +0000219 self._type_equality_funcs[typeobj] = function
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000220
221 def addCleanup(self, function, *args, **kwargs):
222 """Add a function, with arguments, to be called when the test is
223 completed. Functions added are called on a LIFO basis and are
224 called after tearDown on test failure or success.
225
226 Cleanup items are called even if setUp fails (unlike tearDown)."""
227 self._cleanups.append((function, args, kwargs))
228
229 def setUp(self):
230 "Hook method for setting up the test fixture before exercising it."
231 pass
232
233 def tearDown(self):
234 "Hook method for deconstructing the test fixture after testing it."
235 pass
236
Benjamin Peterson847a4112010-03-14 15:04:17 +0000237 @classmethod
238 def setUpClass(cls):
239 "Hook method for setting up class fixture before running tests in the class."
240
241 @classmethod
242 def tearDownClass(cls):
243 "Hook method for deconstructing the class fixture after running all tests in the class."
244
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000245 def countTestCases(self):
246 return 1
247
248 def defaultTestResult(self):
249 return result.TestResult()
250
251 def shortDescription(self):
Michael Foord34c94622010-02-10 15:51:42 +0000252 """Returns a one-line description of the test, or None if no
253 description has been provided.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000254
Michael Foord34c94622010-02-10 15:51:42 +0000255 The default implementation of this method returns the first line of
256 the specified test method's docstring.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000257 """
Michael Foord34c94622010-02-10 15:51:42 +0000258 doc = self._testMethodDoc
259 return doc and doc.split("\n")[0].strip() or None
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000260
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000261
262 def id(self):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000263 return "%s.%s" % (strclass(self.__class__), self._testMethodName)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000264
265 def __eq__(self, other):
266 if type(self) is not type(other):
267 return NotImplemented
268
269 return self._testMethodName == other._testMethodName
270
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000271 def __hash__(self):
272 return hash((type(self), self._testMethodName))
273
274 def __str__(self):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000275 return "%s (%s)" % (self._testMethodName, strclass(self.__class__))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000276
277 def __repr__(self):
278 return "<%s testMethod=%s>" % \
Benjamin Peterson847a4112010-03-14 15:04:17 +0000279 (strclass(self.__class__), self._testMethodName)
280
281 def _addSkip(self, result, reason):
282 addSkip = getattr(result, 'addSkip', None)
283 if addSkip is not None:
284 addSkip(self, reason)
285 else:
286 warnings.warn("TestResult has no addSkip method, skips not reported",
287 RuntimeWarning, 2)
288 result.addSuccess(self)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000289
290 def run(self, result=None):
291 orig_result = result
292 if result is None:
293 result = self.defaultTestResult()
294 startTestRun = getattr(result, 'startTestRun', None)
295 if startTestRun is not None:
296 startTestRun()
297
298 self._resultForDoCleanups = result
299 result.startTest(self)
Benjamin Peterson847a4112010-03-14 15:04:17 +0000300
301 testMethod = getattr(self, self._testMethodName)
302 if (getattr(self.__class__, "__unittest_skip__", False) or
303 getattr(testMethod, "__unittest_skip__", False)):
304 # If the class or method was skipped.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000305 try:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000306 skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
307 or getattr(testMethod, '__unittest_skip_why__', ''))
308 self._addSkip(result, skip_why)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000309 finally:
310 result.stopTest(self)
311 return
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000312 try:
313 success = False
314 try:
315 self.setUp()
316 except SkipTest as e:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000317 self._addSkip(result, str(e))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000318 except Exception:
319 result.addError(self, sys.exc_info())
320 else:
321 try:
322 testMethod()
323 except self.failureException:
324 result.addFailure(self, sys.exc_info())
325 except _ExpectedFailure as e:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000326 addExpectedFailure = getattr(result, 'addExpectedFailure', None)
327 if addExpectedFailure is not None:
328 addExpectedFailure(self, e.exc_info)
329 else:
330 warnings.warn("TestResult has no addExpectedFailure method, reporting as passes",
331 RuntimeWarning)
332 result.addSuccess(self)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000333 except _UnexpectedSuccess:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000334 addUnexpectedSuccess = getattr(result, 'addUnexpectedSuccess', None)
335 if addUnexpectedSuccess is not None:
336 addUnexpectedSuccess(self)
337 else:
338 warnings.warn("TestResult has no addUnexpectedSuccess method, reporting as failures",
339 RuntimeWarning)
340 result.addFailure(self, sys.exc_info())
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000341 except SkipTest as e:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000342 self._addSkip(result, str(e))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000343 except Exception:
344 result.addError(self, sys.exc_info())
345 else:
346 success = True
347
348 try:
349 self.tearDown()
350 except Exception:
351 result.addError(self, sys.exc_info())
352 success = False
353
354 cleanUpSuccess = self.doCleanups()
355 success = success and cleanUpSuccess
356 if success:
357 result.addSuccess(self)
358 finally:
359 result.stopTest(self)
360 if orig_result is None:
361 stopTestRun = getattr(result, 'stopTestRun', None)
362 if stopTestRun is not None:
363 stopTestRun()
364
365 def doCleanups(self):
366 """Execute all cleanup functions. Normally called for you after
367 tearDown."""
368 result = self._resultForDoCleanups
369 ok = True
370 while self._cleanups:
371 function, args, kwargs = self._cleanups.pop(-1)
372 try:
373 function(*args, **kwargs)
374 except Exception:
375 ok = False
376 result.addError(self, sys.exc_info())
377 return ok
378
379 def __call__(self, *args, **kwds):
380 return self.run(*args, **kwds)
381
382 def debug(self):
383 """Run the test without collecting errors in a TestResult"""
384 self.setUp()
385 getattr(self, self._testMethodName)()
386 self.tearDown()
387
388 def skipTest(self, reason):
389 """Skip this test."""
390 raise SkipTest(reason)
391
392 def fail(self, msg=None):
393 """Fail immediately, with the given message."""
394 raise self.failureException(msg)
395
396 def assertFalse(self, expr, msg=None):
397 "Fail the test if the expression is true."
398 if expr:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000399 msg = self._formatMessage(msg, "%s is not False" % safe_repr(expr))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000400 raise self.failureException(msg)
401
402 def assertTrue(self, expr, msg=None):
403 """Fail the test unless the expression is true."""
404 if not expr:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000405 msg = self._formatMessage(msg, "%s is not True" % safe_repr(expr))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000406 raise self.failureException(msg)
407
408 def _formatMessage(self, msg, standardMsg):
409 """Honour the longMessage attribute when generating failure messages.
410 If longMessage is False this means:
411 * Use only an explicit message if it is provided
412 * Otherwise use the standard message for the assert
413
414 If longMessage is True:
415 * Use the standard message
416 * If an explicit message is provided, plus ' : ' and the explicit message
417 """
418 if not self.longMessage:
419 return msg or standardMsg
420 if msg is None:
421 return standardMsg
Benjamin Peterson847a4112010-03-14 15:04:17 +0000422 try:
423 # don't switch to '{}' formatting in Python 2.X
424 # it changes the way unicode input is handled
425 return '%s : %s' % (standardMsg, msg)
426 except UnicodeDecodeError:
427 return '%s : %s' % (safe_repr(standardMsg), safe_repr(msg))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000428
429
430 def assertRaises(self, excClass, callableObj=None, *args, **kwargs):
431 """Fail unless an exception of class excClass is thrown
432 by callableObj when invoked with arguments args and keyword
433 arguments kwargs. If a different type of exception is
434 thrown, it will not be caught, and the test case will be
435 deemed to have suffered an error, exactly as for an
436 unexpected exception.
437
438 If called with callableObj omitted or None, will return a
439 context object used like this::
440
Michael Foord1c42b122010-02-05 22:58:21 +0000441 with self.assertRaises(SomeException):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000442 do_something()
Michael Foord1c42b122010-02-05 22:58:21 +0000443
444 The context manager keeps a reference to the exception as
Ezio Melotti49008232010-02-08 21:57:48 +0000445 the 'exception' attribute. This allows you to inspect the
Michael Foord1c42b122010-02-05 22:58:21 +0000446 exception after the assertion::
447
448 with self.assertRaises(SomeException) as cm:
449 do_something()
Ezio Melotti49008232010-02-08 21:57:48 +0000450 the_exception = cm.exception
Michael Foordb57ac6d2010-02-05 23:26:29 +0000451 self.assertEqual(the_exception.error_code, 3)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000452 """
453 context = _AssertRaisesContext(excClass, self, callableObj)
454 if callableObj is None:
455 return context
456 with context:
457 callableObj(*args, **kwargs)
458
459 def _getAssertEqualityFunc(self, first, second):
460 """Get a detailed comparison function for the types of the two args.
461
462 Returns: A callable accepting (first, second, msg=None) that will
463 raise a failure exception if first != second with a useful human
464 readable error message for those types.
465 """
466 #
467 # NOTE(gregory.p.smith): I considered isinstance(first, type(second))
468 # and vice versa. I opted for the conservative approach in case
469 # subclasses are not intended to be compared in detail to their super
470 # class instances using a type equality func. This means testing
471 # subtypes won't automagically use the detailed comparison. Callers
472 # should use their type specific assertSpamEqual method to compare
473 # subclasses if the detailed comparison is desired and appropriate.
474 # See the discussion in http://bugs.python.org/issue2578.
475 #
476 if type(first) is type(second):
477 asserter = self._type_equality_funcs.get(type(first))
478 if asserter is not None:
Benjamin Peterson8f326b22009-12-13 02:10:36 +0000479 return asserter
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000480
481 return self._baseAssertEqual
482
483 def _baseAssertEqual(self, first, second, msg=None):
484 """The default assertEqual implementation, not type specific."""
485 if not first == second:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000486 standardMsg = '%s != %s' % (safe_repr(first), safe_repr(second))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000487 msg = self._formatMessage(msg, standardMsg)
488 raise self.failureException(msg)
489
490 def assertEqual(self, first, second, msg=None):
491 """Fail if the two objects are unequal as determined by the '=='
492 operator.
493 """
494 assertion_func = self._getAssertEqualityFunc(first, second)
495 assertion_func(first, second, msg=msg)
496
497 def assertNotEqual(self, first, second, msg=None):
498 """Fail if the two objects are equal as determined by the '=='
499 operator.
500 """
501 if not first != second:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000502 msg = self._formatMessage(msg, '%s == %s' % (safe_repr(first),
503 safe_repr(second)))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000504 raise self.failureException(msg)
505
Benjamin Petersonb48af542010-04-11 20:43:16 +0000506 def assertAlmostEqual(self, first, second, *, places=None, msg=None,
507 delta=None):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000508 """Fail if the two objects are unequal as determined by their
509 difference rounded to the given number of decimal places
Benjamin Petersonb48af542010-04-11 20:43:16 +0000510 (default 7) and comparing to zero, or by comparing that the
511 between the two objects is more than the given delta.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000512
513 Note that decimal places (from zero) are usually not the same
514 as significant digits (measured from the most signficant digit).
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000515
516 If the two objects compare equal then they will automatically
517 compare almost equal.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000518 """
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000519 if first == second:
Benjamin Petersonb48af542010-04-11 20:43:16 +0000520 # shortcut
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000521 return
Benjamin Petersonb48af542010-04-11 20:43:16 +0000522 if delta is not None and places is not None:
523 raise TypeError("specify delta or places not both")
524
525 if delta is not None:
526 if abs(first - second) <= delta:
527 return
528
529 standardMsg = '%s != %s within %s delta' % (safe_repr(first),
530 safe_repr(second),
531 safe_repr(delta))
532 else:
533 if places is None:
534 places = 7
535
536 if round(abs(second-first), places) == 0:
537 return
538
Benjamin Peterson847a4112010-03-14 15:04:17 +0000539 standardMsg = '%s != %s within %r places' % (safe_repr(first),
540 safe_repr(second),
541 places)
Benjamin Petersonb48af542010-04-11 20:43:16 +0000542 msg = self._formatMessage(msg, standardMsg)
543 raise self.failureException(msg)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000544
Benjamin Petersonb48af542010-04-11 20:43:16 +0000545 def assertNotAlmostEqual(self, first, second, *, places=None, msg=None,
546 delta=None):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000547 """Fail if the two objects are equal as determined by their
548 difference rounded to the given number of decimal places
Benjamin Petersonb48af542010-04-11 20:43:16 +0000549 (default 7) and comparing to zero, or by comparing that the
550 between the two objects is less than the given delta.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000551
552 Note that decimal places (from zero) are usually not the same
553 as significant digits (measured from the most signficant digit).
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000554
555 Objects that are equal automatically fail.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000556 """
Benjamin Petersonb48af542010-04-11 20:43:16 +0000557 if delta is not None and places is not None:
558 raise TypeError("specify delta or places not both")
559 if delta is not None:
560 if not (first == second) and abs(first - second) > delta:
561 return
562 standardMsg = '%s == %s within %s delta' % (safe_repr(first),
563 safe_repr(second),
564 safe_repr(delta))
565 else:
566 if places is None:
567 places = 7
568 if not (first == second) and round(abs(second-first), places) != 0:
569 return
Benjamin Peterson847a4112010-03-14 15:04:17 +0000570 standardMsg = '%s == %s within %r places' % (safe_repr(first),
Benjamin Petersonb48af542010-04-11 20:43:16 +0000571 safe_repr(second),
572 places)
573
574 msg = self._formatMessage(msg, standardMsg)
575 raise self.failureException(msg)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000576
577 # Synonyms for assertion methods
578
579 # The plurals are undocumented. Keep them that way to discourage use.
580 # Do not add more. Do not remove.
581 # Going through a deprecation cycle on these would annoy many people.
582 assertEquals = assertEqual
583 assertNotEquals = assertNotEqual
584 assertAlmostEquals = assertAlmostEqual
585 assertNotAlmostEquals = assertNotAlmostEqual
Michael Foord0e31b992010-02-10 15:52:56 +0000586 assert_ = assertTrue
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000587
588 # These fail* assertion method names are pending deprecation and will
589 # be a DeprecationWarning in 3.2; http://bugs.python.org/issue2578
590 def _deprecate(original_func):
591 def deprecated_func(*args, **kwargs):
592 warnings.warn(
593 'Please use {0} instead.'.format(original_func.__name__),
594 DeprecationWarning, 2)
595 return original_func(*args, **kwargs)
596 return deprecated_func
597
598 failUnlessEqual = _deprecate(assertEqual)
599 failIfEqual = _deprecate(assertNotEqual)
600 failUnlessAlmostEqual = _deprecate(assertAlmostEqual)
601 failIfAlmostEqual = _deprecate(assertNotAlmostEqual)
602 failUnless = _deprecate(assertTrue)
603 failUnlessRaises = _deprecate(assertRaises)
604 failIf = _deprecate(assertFalse)
605
Michael Foord085dfd32010-06-05 12:17:02 +0000606 def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000607 """An equality assertion for ordered sequences (like lists and tuples).
608
R. David Murrayad13f222010-01-29 22:17:58 +0000609 For the purposes of this function, a valid ordered sequence type is one
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000610 which can be indexed, has a length, and has an equality operator.
611
612 Args:
613 seq1: The first sequence to compare.
614 seq2: The second sequence to compare.
615 seq_type: The expected datatype of the sequences, or None if no
616 datatype should be enforced.
617 msg: Optional message to use on failure instead of a list of
618 differences.
619 """
620 if seq_type != None:
621 seq_type_name = seq_type.__name__
622 if not isinstance(seq1, seq_type):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000623 raise self.failureException('First sequence is not a %s: %s'
624 % (seq_type_name, safe_repr(seq1)))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000625 if not isinstance(seq2, seq_type):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000626 raise self.failureException('Second sequence is not a %s: %s'
627 % (seq_type_name, safe_repr(seq2)))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000628 else:
629 seq_type_name = "sequence"
630
631 differing = None
632 try:
633 len1 = len(seq1)
634 except (TypeError, NotImplementedError):
635 differing = 'First %s has no length. Non-sequence?' % (
636 seq_type_name)
637
638 if differing is None:
639 try:
640 len2 = len(seq2)
641 except (TypeError, NotImplementedError):
642 differing = 'Second %s has no length. Non-sequence?' % (
643 seq_type_name)
644
645 if differing is None:
646 if seq1 == seq2:
647 return
648
Benjamin Peterson847a4112010-03-14 15:04:17 +0000649 seq1_repr = safe_repr(seq1)
650 seq2_repr = safe_repr(seq2)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000651 if len(seq1_repr) > 30:
652 seq1_repr = seq1_repr[:30] + '...'
653 if len(seq2_repr) > 30:
654 seq2_repr = seq2_repr[:30] + '...'
655 elements = (seq_type_name.capitalize(), seq1_repr, seq2_repr)
656 differing = '%ss differ: %s != %s\n' % elements
657
658 for i in range(min(len1, len2)):
659 try:
660 item1 = seq1[i]
661 except (TypeError, IndexError, NotImplementedError):
662 differing += ('\nUnable to index element %d of first %s\n' %
663 (i, seq_type_name))
664 break
665
666 try:
667 item2 = seq2[i]
668 except (TypeError, IndexError, NotImplementedError):
669 differing += ('\nUnable to index element %d of second %s\n' %
670 (i, seq_type_name))
671 break
672
673 if item1 != item2:
674 differing += ('\nFirst differing element %d:\n%s\n%s\n' %
675 (i, item1, item2))
676 break
677 else:
678 if (len1 == len2 and seq_type is None and
679 type(seq1) != type(seq2)):
680 # The sequences are the same, but have differing types.
681 return
682
683 if len1 > len2:
684 differing += ('\nFirst %s contains %d additional '
685 'elements.\n' % (seq_type_name, len1 - len2))
686 try:
687 differing += ('First extra element %d:\n%s\n' %
688 (len2, seq1[len2]))
689 except (TypeError, IndexError, NotImplementedError):
690 differing += ('Unable to index element %d '
691 'of first %s\n' % (len2, seq_type_name))
692 elif len1 < len2:
693 differing += ('\nSecond %s contains %d additional '
694 'elements.\n' % (seq_type_name, len2 - len1))
695 try:
696 differing += ('First extra element %d:\n%s\n' %
697 (len1, seq2[len1]))
698 except (TypeError, IndexError, NotImplementedError):
699 differing += ('Unable to index element %d '
700 'of second %s\n' % (len1, seq_type_name))
Michael Foord2034d9a2010-06-05 11:27:52 +0000701 standardMsg = differing
702 diffMsg = '\n' + '\n'.join(
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000703 difflib.ndiff(pprint.pformat(seq1).splitlines(),
704 pprint.pformat(seq2).splitlines()))
Michael Foord085dfd32010-06-05 12:17:02 +0000705
706 standardMsg = self._truncateMessage(standardMsg, diffMsg)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000707 msg = self._formatMessage(msg, standardMsg)
708 self.fail(msg)
709
Michael Foord085dfd32010-06-05 12:17:02 +0000710 def _truncateMessage(self, message, diff):
711 max_diff = self.maxDiff
712 if max_diff is None or len(diff) <= max_diff:
713 return message + diff
714 return message
715
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000716 def assertListEqual(self, list1, list2, msg=None):
717 """A list-specific equality assertion.
718
719 Args:
720 list1: The first list to compare.
721 list2: The second list to compare.
722 msg: Optional message to use on failure instead of a list of
723 differences.
724
725 """
726 self.assertSequenceEqual(list1, list2, msg, seq_type=list)
727
728 def assertTupleEqual(self, tuple1, tuple2, msg=None):
729 """A tuple-specific equality assertion.
730
731 Args:
732 tuple1: The first tuple to compare.
733 tuple2: The second tuple to compare.
734 msg: Optional message to use on failure instead of a list of
735 differences.
736 """
737 self.assertSequenceEqual(tuple1, tuple2, msg, seq_type=tuple)
738
739 def assertSetEqual(self, set1, set2, msg=None):
740 """A set-specific equality assertion.
741
742 Args:
743 set1: The first set to compare.
744 set2: The second set to compare.
745 msg: Optional message to use on failure instead of a list of
746 differences.
747
Michael Foord91c9da32010-03-20 17:21:27 +0000748 assertSetEqual uses ducktyping to support different types of sets, and
749 is optimized for sets specifically (parameters must support a
750 difference method).
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000751 """
752 try:
753 difference1 = set1.difference(set2)
754 except TypeError as e:
755 self.fail('invalid type when attempting set difference: %s' % e)
756 except AttributeError as e:
757 self.fail('first argument does not support set difference: %s' % e)
758
759 try:
760 difference2 = set2.difference(set1)
761 except TypeError as e:
762 self.fail('invalid type when attempting set difference: %s' % e)
763 except AttributeError as e:
764 self.fail('second argument does not support set difference: %s' % e)
765
766 if not (difference1 or difference2):
767 return
768
769 lines = []
770 if difference1:
771 lines.append('Items in the first set but not the second:')
772 for item in difference1:
773 lines.append(repr(item))
774 if difference2:
775 lines.append('Items in the second set but not the first:')
776 for item in difference2:
777 lines.append(repr(item))
778
779 standardMsg = '\n'.join(lines)
780 self.fail(self._formatMessage(msg, standardMsg))
781
782 def assertIn(self, member, container, msg=None):
783 """Just like self.assertTrue(a in b), but with a nicer default message."""
784 if member not in container:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000785 standardMsg = '%s not found in %s' % (safe_repr(member),
786 safe_repr(container))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000787 self.fail(self._formatMessage(msg, standardMsg))
788
789 def assertNotIn(self, member, container, msg=None):
790 """Just like self.assertTrue(a not in b), but with a nicer default message."""
791 if member in container:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000792 standardMsg = '%s unexpectedly found in %s' % (safe_repr(member),
793 safe_repr(container))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000794 self.fail(self._formatMessage(msg, standardMsg))
795
796 def assertIs(self, expr1, expr2, msg=None):
797 """Just like self.assertTrue(a is b), but with a nicer default message."""
798 if expr1 is not expr2:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000799 standardMsg = '%s is not %s' % (safe_repr(expr1),
800 safe_repr(expr2))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000801 self.fail(self._formatMessage(msg, standardMsg))
802
803 def assertIsNot(self, expr1, expr2, msg=None):
804 """Just like self.assertTrue(a is not b), but with a nicer default message."""
805 if expr1 is expr2:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000806 standardMsg = 'unexpectedly identical: %s' % (safe_repr(expr1),)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000807 self.fail(self._formatMessage(msg, standardMsg))
808
809 def assertDictEqual(self, d1, d2, msg=None):
810 self.assert_(isinstance(d1, dict), 'First argument is not a dictionary')
811 self.assert_(isinstance(d2, dict), 'Second argument is not a dictionary')
812
813 if d1 != d2:
Michael Foordcb11b252010-06-05 13:14:43 +0000814 standardMsg = '%s != %s' % (safe_repr(d1, True), safe_repr(d2, True))
Michael Foord085dfd32010-06-05 12:17:02 +0000815 diff = ('\n' + '\n'.join(difflib.ndiff(
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000816 pprint.pformat(d1).splitlines(),
817 pprint.pformat(d2).splitlines())))
Michael Foordcb11b252010-06-05 13:14:43 +0000818 standardMsg = self._truncateMessage(standardMsg, diff)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000819 self.fail(self._formatMessage(msg, standardMsg))
820
821 def assertDictContainsSubset(self, expected, actual, msg=None):
822 """Checks whether actual is a superset of expected."""
823 missing = []
824 mismatched = []
825 for key, value in expected.items():
826 if key not in actual:
827 missing.append(key)
828 elif value != actual[key]:
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000829 mismatched.append('%s, expected: %s, actual: %s' %
Benjamin Peterson847a4112010-03-14 15:04:17 +0000830 (safe_repr(key), safe_repr(value),
831 safe_repr(actual[key])))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000832
833 if not (missing or mismatched):
834 return
835
836 standardMsg = ''
837 if missing:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000838 standardMsg = 'Missing: %s' % ','.join(safe_repr(m) for m in
839 missing)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000840 if mismatched:
841 if standardMsg:
842 standardMsg += '; '
843 standardMsg += 'Mismatched values: %s' % ','.join(mismatched)
844
845 self.fail(self._formatMessage(msg, standardMsg))
846
847 def assertSameElements(self, expected_seq, actual_seq, msg=None):
848 """An unordered sequence specific comparison.
849
850 Raises with an error message listing which elements of expected_seq
851 are missing from actual_seq and vice versa if any.
Michael Foord1c42b122010-02-05 22:58:21 +0000852
853 Duplicate elements are ignored when comparing *expected_seq* and
854 *actual_seq*. It is the equivalent of ``assertEqual(set(expected),
855 set(actual))`` but it works with sequences of unhashable objects as
856 well.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000857 """
Michael Foord91c9da32010-03-20 17:21:27 +0000858 warnings.warn('assertSameElements is deprecated',
859 DeprecationWarning)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000860 try:
861 expected = set(expected_seq)
862 actual = set(actual_seq)
Benjamin Peterson847a4112010-03-14 15:04:17 +0000863 missing = sorted(expected.difference(actual))
864 unexpected = sorted(actual.difference(expected))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000865 except TypeError:
866 # Fall back to slower list-compare if any of the objects are
867 # not hashable.
868 expected = list(expected_seq)
869 actual = list(actual_seq)
870 try:
871 expected.sort()
872 actual.sort()
873 except TypeError:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000874 missing, unexpected = unorderable_list_difference(expected,
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000875 actual)
Benjamin Peterson847a4112010-03-14 15:04:17 +0000876 else:
877 missing, unexpected = sorted_list_difference(expected, actual)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000878 errors = []
879 if missing:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000880 errors.append('Expected, but missing:\n %s' %
881 safe_repr(missing))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000882 if unexpected:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000883 errors.append('Unexpected, but present:\n %s' %
884 safe_repr(unexpected))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000885 if errors:
886 standardMsg = '\n'.join(errors)
887 self.fail(self._formatMessage(msg, standardMsg))
888
Michael Foord8442a602010-03-20 16:58:04 +0000889
890 def assertItemsEqual(self, expected_seq, actual_seq, msg=None):
891 """An unordered sequence / set specific comparison. It asserts that
892 expected_seq and actual_seq contain the same elements. It is
893 the equivalent of::
894
895 self.assertEqual(sorted(expected_seq), sorted(actual_seq))
896
897 Raises with an error message listing which elements of expected_seq
898 are missing from actual_seq and vice versa if any.
899
900 Asserts that each element has the same count in both sequences.
901 Example:
902 - [0, 1, 1] and [1, 0, 1] compare equal.
903 - [0, 0, 1] and [0, 1] compare unequal.
904 """
905 try:
906 expected = sorted(expected_seq)
907 actual = sorted(actual_seq)
908 except TypeError:
909 # Unsortable items (example: set(), complex(), ...)
910 expected = list(expected_seq)
911 actual = list(actual_seq)
912 missing, unexpected = unorderable_list_difference(expected, actual)
913 else:
914 return self.assertSequenceEqual(expected, actual, msg=msg)
915
916 errors = []
917 if missing:
918 errors.append('Expected, but missing:\n %s' %
919 safe_repr(missing))
920 if unexpected:
921 errors.append('Unexpected, but present:\n %s' %
922 safe_repr(unexpected))
923 if errors:
924 standardMsg = '\n'.join(errors)
925 self.fail(self._formatMessage(msg, standardMsg))
926
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000927 def assertMultiLineEqual(self, first, second, msg=None):
928 """Assert that two multi-line strings are equal."""
929 self.assert_(isinstance(first, str), (
930 'First argument is not a string'))
931 self.assert_(isinstance(second, str), (
932 'Second argument is not a string'))
933
934 if first != second:
Michael Foordcb11b252010-06-05 13:14:43 +0000935 standardMsg = '%s != %s' % (safe_repr(d1, True), safe_repr(d2, True))
Michael Foord085dfd32010-06-05 12:17:02 +0000936 diff = '\n' + ''.join(difflib.ndiff(first.splitlines(True),
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000937 second.splitlines(True)))
Michael Foordcb11b252010-06-05 13:14:43 +0000938 standardMsg = self._truncateMessage(standardMsg, diff)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000939 self.fail(self._formatMessage(msg, standardMsg))
940
941 def assertLess(self, a, b, msg=None):
942 """Just like self.assertTrue(a < b), but with a nicer default message."""
943 if not a < b:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000944 standardMsg = '%s not less than %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000945 self.fail(self._formatMessage(msg, standardMsg))
946
947 def assertLessEqual(self, a, b, msg=None):
948 """Just like self.assertTrue(a <= b), but with a nicer default message."""
949 if not a <= b:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000950 standardMsg = '%s not less than or equal to %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000951 self.fail(self._formatMessage(msg, standardMsg))
952
953 def assertGreater(self, a, b, msg=None):
954 """Just like self.assertTrue(a > b), but with a nicer default message."""
955 if not a > b:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000956 standardMsg = '%s not greater than %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000957 self.fail(self._formatMessage(msg, standardMsg))
958
959 def assertGreaterEqual(self, a, b, msg=None):
960 """Just like self.assertTrue(a >= b), but with a nicer default message."""
961 if not a >= b:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000962 standardMsg = '%s not greater than or equal to %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000963 self.fail(self._formatMessage(msg, standardMsg))
964
965 def assertIsNone(self, obj, msg=None):
966 """Same as self.assertTrue(obj is None), with a nicer default message."""
967 if obj is not None:
Benjamin Peterson847a4112010-03-14 15:04:17 +0000968 standardMsg = '%s is not None' % (safe_repr(obj),)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000969 self.fail(self._formatMessage(msg, standardMsg))
970
971 def assertIsNotNone(self, obj, msg=None):
972 """Included for symmetry with assertIsNone."""
973 if obj is None:
974 standardMsg = 'unexpectedly None'
975 self.fail(self._formatMessage(msg, standardMsg))
976
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000977 def assertIsInstance(self, obj, cls, msg=None):
978 """Same as self.assertTrue(isinstance(obj, cls)), with a nicer
979 default message."""
980 if not isinstance(obj, cls):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000981 standardMsg = '%s is not an instance of %r' % (safe_repr(obj), cls)
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000982 self.fail(self._formatMessage(msg, standardMsg))
983
984 def assertNotIsInstance(self, obj, cls, msg=None):
985 """Included for symmetry with assertIsInstance."""
986 if isinstance(obj, cls):
Benjamin Peterson847a4112010-03-14 15:04:17 +0000987 standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls)
Benjamin Peterson6e8c7572009-10-04 20:19:21 +0000988 self.fail(self._formatMessage(msg, standardMsg))
989
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000990 def assertRaisesRegexp(self, expected_exception, expected_regexp,
991 callable_obj=None, *args, **kwargs):
992 """Asserts that the message in a raised exception matches a regexp.
993
994 Args:
995 expected_exception: Exception class expected to be raised.
996 expected_regexp: Regexp (re pattern object or string) expected
997 to be found in error message.
998 callable_obj: Function to be called.
999 args: Extra args.
1000 kwargs: Extra kwargs.
1001 """
1002 context = _AssertRaisesContext(expected_exception, self, callable_obj,
1003 expected_regexp)
1004 if callable_obj is None:
1005 return context
1006 with context:
1007 callable_obj(*args, **kwargs)
1008
Georg Brandl89fad142010-03-14 10:23:39 +00001009 def assertRegexpMatches(self, text, expected_regexp, msg=None):
Michael Foorde3ef5f12010-05-08 16:46:14 +00001010 """Fail the test unless the text matches the regular expression."""
Georg Brandl89fad142010-03-14 10:23:39 +00001011 if isinstance(expected_regexp, (str, bytes)):
1012 expected_regexp = re.compile(expected_regexp)
1013 if not expected_regexp.search(text):
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001014 msg = msg or "Regexp didn't match"
Georg Brandl89fad142010-03-14 10:23:39 +00001015 msg = '%s: %r not found in %r' % (msg, expected_regexp.pattern, text)
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001016 raise self.failureException(msg)
1017
Benjamin Petersonb48af542010-04-11 20:43:16 +00001018 def assertNotRegexpMatches(self, text, unexpected_regexp, msg=None):
Michael Foorde3ef5f12010-05-08 16:46:14 +00001019 """Fail the test if the text matches the regular expression."""
Benjamin Petersonb48af542010-04-11 20:43:16 +00001020 if isinstance(unexpected_regexp, (str, bytes)):
1021 unexpected_regexp = re.compile(unexpected_regexp)
1022 match = unexpected_regexp.search(text)
1023 if match:
1024 msg = msg or "Regexp matched"
1025 msg = '%s: %r matches %r in %r' % (msg,
1026 text[match.start():match.end()],
1027 unexpected_regexp.pattern,
1028 text)
1029 raise self.failureException(msg)
1030
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001031
1032class FunctionTestCase(TestCase):
1033 """A test case that wraps a test function.
1034
1035 This is useful for slipping pre-existing test functions into the
1036 unittest framework. Optionally, set-up and tidy-up functions can be
1037 supplied. As with TestCase, the tidy-up ('tearDown') function will
1038 always be called if the set-up ('setUp') function ran successfully.
1039 """
1040
1041 def __init__(self, testFunc, setUp=None, tearDown=None, description=None):
1042 super(FunctionTestCase, self).__init__()
1043 self._setUpFunc = setUp
1044 self._tearDownFunc = tearDown
1045 self._testFunc = testFunc
1046 self._description = description
1047
1048 def setUp(self):
1049 if self._setUpFunc is not None:
1050 self._setUpFunc()
1051
1052 def tearDown(self):
1053 if self._tearDownFunc is not None:
1054 self._tearDownFunc()
1055
1056 def runTest(self):
1057 self._testFunc()
1058
1059 def id(self):
1060 return self._testFunc.__name__
1061
1062 def __eq__(self, other):
1063 if not isinstance(other, self.__class__):
1064 return NotImplemented
1065
1066 return self._setUpFunc == other._setUpFunc and \
1067 self._tearDownFunc == other._tearDownFunc and \
1068 self._testFunc == other._testFunc and \
1069 self._description == other._description
1070
1071 def __ne__(self, other):
1072 return not self == other
1073
1074 def __hash__(self):
1075 return hash((type(self), self._setUpFunc, self._tearDownFunc,
1076 self._testFunc, self._description))
1077
1078 def __str__(self):
Benjamin Peterson847a4112010-03-14 15:04:17 +00001079 return "%s (%s)" % (strclass(self.__class__),
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001080 self._testFunc.__name__)
1081
1082 def __repr__(self):
Benjamin Peterson847a4112010-03-14 15:04:17 +00001083 return "<%s tec=%s>" % (strclass(self.__class__),
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001084 self._testFunc)
1085
1086 def shortDescription(self):
1087 if self._description is not None:
1088 return self._description
1089 doc = self._testFunc.__doc__
1090 return doc and doc.split("\n")[0].strip() or None