Index: Doc/library/unittest.rst =================================================================== --- Doc/library/unittest.rst (revision 70797) +++ Doc/library/unittest.rst (working copy) @@ -615,16 +615,25 @@ .. method:: assertEqual(first, second[, msg]) + assertEquals(first, second[, msg]) failUnlessEqual(first, second[, msg]) Test that *first* and *second* are equal. If the values do not compare equal, the test will fail with the explanation given by *msg*, or :const:`None`. Note that using :meth:`failUnlessEqual` improves upon doing the comparison as the first parameter to :meth:`failUnless`: the - default value for *msg* can be computed to include representations of both - *first* and *second*. + default value for *msg* include representations of both *first* and + *second*. + In addition, if *first* and *second* are the exact same type and one of + list, tuple, dict, set, or frozenset or any type that a subclass + registers :meth:`addTypeEqualityFunc` the type specific equality function + will be called in order to generate a more useful default error message. + .. versionchanged:: 2.7 + Added the automatic calling of type specific equality function. + + .. method:: assertNotEqual(first, second[, msg]) failIfEqual(first, second[, msg]) @@ -662,6 +671,125 @@ :const:`None`. + .. method:: assertGreater(first, second, msg=None) + assertGreaterEqual(first, second, msg=None) + assertLess(first, second, msg=None) + assertLessEqual(first, second, msg=None) + + Test that *first* is respectively >, >=, < or <= than *second* depending + on the method name. If not, the test will fail with the nice explanation + or with the explanation given by *msg*:: + + >>> self.assertGreaterEqual(3, 4) + AssertionError: "3" unexpectedly not greater than or equal to "4" + + .. versionadded:: 2.7 + + + .. method:: assertMultiLineEquals(self, first, second, msg=None) + + Test that the multiline string *first* is equal to the string *second*. + When not equal a diff of the two strings highlighting the differences + will be included in the error message. + + If specified *msg* will be used as the error message on failure. + + .. versionadded:: 2.7 + + + .. method:: assertRegexpMatches(text, regexp[, msg=None]): + + Verifies that a *regexp* search matches *text*. Fails with an error + message including the pattern and the *text*. *regexp* may be + a regular expression object or a string containing a regular expression + suitable for use by :func:`re.search`. + + .. versionadded:: 2.7 + + + .. method:: assertIn(first, second, msg=None) + assertNotIn(first, second, msg=None) + + Tests that *first* is or is not in *second* with a nice explanitory error + message as appropriate. + + If specified *msg* will be used as the error message on failure. + + .. versionadded:: 2.7 + + + .. method:: assertSameElements(expected, actual, msg=None) + + Test that sequence *expected* contains the same elements as *actual*. + When they don't an error message listing the differences between the + sequences will be generated. + + If specified *msg* will be used as the error message on failure. + + .. versionadded:: 2.7 + + + .. method:: assertSetEquals(set1, set2, msg=None) + + Tests that two sets are equal. If not, an error message is constructed + that lists the differences between the sets. + + Fails if either of *set1* or *set2* does not have a :meth:`set.difference` + method. + + If specified *msg* will be used as the error message on failure. + + .. versionadded:: 2.7 + + + .. method:: assertDictEquals(expected, actual, msg=None) + + Test that two dictionaries are equal. If not, an error message is + constructed that shows the differences in the dictionaries. + + If specified *msg* will be used as the error message on failure. + + .. versionadded:: 2.7 + + + .. method:: assertDictContainsSubset(expected, actual, msg=None) + + Tests whether the key value pairs in dictionary *actual* are a + superset of those in *expected*. If not, an error message listing + the missing keys and mismatched values is generated. + + If specified *msg* will be used as the error message on failure. + + .. versionadded:: 2.7 + + + .. method:: assertListEquals(list1, list2, msg=None) + assertTupleEquals(tuple1, tuple2, msg=None) + + Tests that two lists or tuples are equal. If not an error message is + constructed that shows only the differences between the two. An error + is also raised if either of the parameters are of the wrong type. + + If specified *msg* will be used as the error message on failure. + + .. versionadded:: 2.7 + + + .. method:: assertSequenceEquals(seq1, seq2, msg=None, seq_type=None) + + Tests that two sequences are equal. If a *seq_type* is supplied, both + *seq1* and *seq2* must be instances of *seq_type* or a failure will + be raised. If the sequences are different an error message is + constructed that shows the difference between the two. + + If specified *msg* will be used as the error message on failure. + + This method is used to implement :meth:`assertListEquals` and + :meth:`assertTupleEquals`. + + .. versionadded:: 2.7 + + .. method:: assertRaises(exception[, callable, ...]) failUnlessRaises(exception[, callable, ...]) @@ -682,6 +810,39 @@ Added the ability to use :meth:`assertRaises` as a context manager. + .. method:: assertRaisesRegexp(exception, regexp[, callable, ...]) + + Like :meth:`assertRaises` but also tests that *regexp* matches + on the string representation of the raised exception. *regexp* may be + a regular expression object or a string containing a regular expression + suitable for use by :func:`re.search`. Examples:: + + self.assertRaisesRegexp(ValueError, 'invalid literal for.*XYZ$', + int, 'XYZ') + + or:: + + with self.assertRaisesRegexp(ValueError, 'literal'): + int('XYZ') + + .. versionadded:: 2.7 + + + .. method:: assertIsNone(expr[, msg]) + + This signals a test failure if *expr* is not None. + + .. versionadded:: 2.7 + + + .. method:: assertIsNotNone(expr[, msg]) + + The inverse of the :meth:`assertIsNone` method. + This signals a test failure if *expr* is None. + + .. versionadded:: 2.7 + + .. method:: failIf(expr[, msg]) assertFalse(expr[, msg]) @@ -733,224 +894,248 @@ .. method:: shortDescription() - Returns a one-line description of the test, or :const:`None` if no - description has been provided. The default implementation of this method - returns the first line of the test method's docstring, if available, or - :const:`None`. + Returns a description of the test, or :const:`None` if no description + has been provided. The default implementation of this method + returns the first line of the test method's docstring, if available, + along with the method name. + .. versionchanged:: 2.7 -.. class:: FunctionTestCase(testFunc[, setUp[, tearDown[, description]]]) + In earlier versions this only returned the first line of the test + method's docstring, if available or the :const:`None`. That led to + undesirable behavior of not printing the test name when someone was + thoughtful enough to write a docstring. - This class implements the portion of the :class:`TestCase` interface which + + .. method:: addTypeEqualityFunc(typeobj, function) + + Registers a type specific :meth:`assertEquals` equality checking + function to be called by :meth:`assertEquals` when both objects it has + been asked to compare are exactly *typeobj* (not subclasses). + *function* must take two positional arguments and a third msg=None + keyword argument just as :meth:`assertEquals` does. It must raise + self.failureException when inequality between the first two + parameters is detected. + + One good use of custom equality checking functions for a type + is to raise self.failureException with an error message useful + for debugging the by explaining the inequalities in detail. + + .. versionadded:: 2.7 + + +.. class:: functiontestcase(testfunc[, setup[, teardown[, description]]]) + + this class implements the portion of the :class:`testcase` interface which allows the test runner to drive the test, but does not provide the methods which - test code can use to check and report errors. This is used to create test cases + test code can use to check and report errors. this is used to create test cases using legacy test code, allowing it to be integrated into a :mod:`unittest`\ -based test framework. .. _testsuite-objects: -Grouping tests +grouping tests ~~~~~~~~~~~~~~ -.. class:: TestSuite([tests]) +.. class:: testsuite([tests]) - This class represents an aggregation of individual tests cases and test suites. - The class presents the interface needed by the test runner to allow it to be run - as any other test case. Running a :class:`TestSuite` instance is the same as + this class represents an aggregation of individual tests cases and test suites. + the class presents the interface needed by the test runner to allow it to be run + as any other test case. running a :class:`testsuite` instance is the same as iterating over the suite, running each test individually. - If *tests* is given, it must be an iterable of individual test cases or other - test suites that will be used to build the suite initially. Additional methods + if *tests* is given, it must be an iterable of individual test cases or other + test suites that will be used to build the suite initially. additional methods are provided to add test cases and suites to the collection later on. - :class:`TestSuite` (including :class:`ClassTestSuite`) objects behave much - like :class:`TestCase` objects, except they do not actually implement a test. - Instead, they are used to aggregate tests into groups of tests that should be - run together. Some additional methods are available to add tests to - :class:`TestSuite` instances: + :class:`testsuite` (including :class:`classtestsuite`) objects behave much + like :class:`testcase` objects, except they do not actually implement a test. + instead, they are used to aggregate tests into groups of tests that should be + run together. some additional methods are available to add tests to + :class:`testsuite` instances: - .. method:: TestSuite.addTest(test) + .. method:: testsuite.addtest(test) - Add a :class:`TestCase` or :class:`TestSuite` to the suite. + add a :class:`testcase` or :class:`testsuite` to the suite. - .. method:: TestSuite.addTests(tests) + .. method:: testsuite.addtests(tests) - Add all the tests from an iterable of :class:`TestCase` and :class:`TestSuite` + add all the tests from an iterable of :class:`testcase` and :class:`testsuite` instances to this test suite. - This is equivalent to iterating over *tests*, calling :meth:`addTest` for each + this is equivalent to iterating over *tests*, calling :meth:`addtest` for each element. - :class:`TestSuite` shares the following methods with :class:`TestCase`: + :class:`testsuite` shares the following methods with :class:`testcase`: .. method:: run(result) - Run the tests associated with this suite, collecting the result into the - test result object passed as *result*. Note that unlike - :meth:`TestCase.run`, :meth:`TestSuite.run` requires the result object to + run the tests associated with this suite, collecting the result into the + test result object passed as *result*. note that unlike + :meth:`testcase.run`, :meth:`testsuite.run` requires the result object to be passed in. .. method:: debug() - Run the tests associated with this suite without collecting the - result. This allows exceptions raised by the test to be propagated to the + run the tests associated with this suite without collecting the + result. this allows exceptions raised by the test to be propagated to the caller and can be used to support running tests under a debugger. - .. method:: countTestCases() + .. method:: counttestcases() - Return the number of tests represented by this test object, including all + return the number of tests represented by this test object, including all individual tests and sub-suites. - In the typical usage of a :class:`TestSuite` object, the :meth:`run` method - is invoked by a :class:`TestRunner` rather than by the end-user test harness. + in the typical usage of a :class:`testsuite` object, the :meth:`run` method + is invoked by a :class:`testrunner` rather than by the end-user test harness. -.. class:: ClassTestSuite(tests, collected_from) +.. class:: classtestsuite(tests, collected_from) - This subclass of :class:`TestSuite` repesents an aggregation of individuals - tests from one :class:`TestCase` class. *tests* is an iterable of - :class:`TestCase` instances created from the class. *collected_from* is the + this subclass of :class:`testsuite` repesents an aggregation of individuals + tests from one :class:`testcase` class. *tests* is an iterable of + :class:`testcase` instances created from the class. *collected_from* is the class they came from. -Loading and running tests +loading and running tests ~~~~~~~~~~~~~~~~~~~~~~~~~ -.. class:: TestLoader() +.. class:: testloader() - The :class:`TestLoader` class is used to create test suites from classes and - modules. Normally, there is no need to create an instance of this class; the + the :class:`testloader` class is used to create test suites from classes and + modules. normally, there is no need to create an instance of this class; the :mod:`unittest` module provides an instance that can be shared as - ``unittest.defaultTestLoader``. Using a subclass or instance, however, allows + ``unittest.defaulttestloader``. using a subclass or instance, however, allows customization of some configurable properties. - :class:`TestLoader` objects have the following methods: + :class:`testloader` objects have the following methods: - .. method:: loadTestsFromTestCase(testCaseClass) + .. method:: loadtestsfromtestcase(testcaseclass) - Return a suite of all tests cases contained in the :class:`TestCase`\ -derived - :class:`testCaseClass`. + return a suite of all tests cases contained in the :class:`testcase`\ -derived + :class:`testcaseclass`. - .. method:: loadTestsFromModule(module) + .. method:: loadtestsfrommodule(module) - Return a suite of all tests cases contained in the given module. This - method searches *module* for classes derived from :class:`TestCase` and + return a suite of all tests cases contained in the given module. this + method searches *module* for classes derived from :class:`testcase` and creates an instance of the class for each test method defined for the class. .. warning:: - While using a hierarchy of :class:`TestCase`\ -derived classes can be + while using a hierarchy of :class:`testcase`\ -derived classes can be convenient in sharing fixtures and helper functions, defining test methods on base classes that are not intended to be instantiated - directly does not play well with this method. Doing so, however, can + directly does not play well with this method. doing so, however, can be useful when the fixtures are different and defined in subclasses. - .. method:: loadTestsFromName(name[, module]) + .. method:: loadtestsfromname(name[, module]) - Return a suite of all tests cases given a string specifier. + return a suite of all tests cases given a string specifier. - The specifier *name* is a "dotted name" that may resolve either to a + the specifier *name* is a "dotted name" that may resolve either to a module, a test case class, a test method within a test case class, a - :class:`TestSuite` instance, or a callable object which returns a - :class:`TestCase` or :class:`TestSuite` instance. These checks are + :class:`testsuite` instance, or a callable object which returns a + :class:`testcase` or :class:`testsuite` instance. these checks are applied in the order listed here; that is, a method on a possible test case class will be picked up as "a test method within a test case class", rather than "a callable object". - For example, if you have a module :mod:`SampleTests` containing a - :class:`TestCase`\ -derived class :class:`SampleTestCase` with three test + for example, if you have a module :mod:`sampletests` containing a + :class:`testcase`\ -derived class :class:`sampletestcase` with three test methods (:meth:`test_one`, :meth:`test_two`, and :meth:`test_three`), the - specifier ``'SampleTests.SampleTestCase'`` would cause this method to return a - suite which will run all three test methods. Using the specifier - ``'SampleTests.SampleTestCase.test_two'`` would cause it to return a test suite - which will run only the :meth:`test_two` test method. The specifier can refer + specifier ``'sampletests.sampletestcase'`` would cause this method to return a + suite which will run all three test methods. using the specifier + ``'sampletests.sampletestcase.test_two'`` would cause it to return a test suite + which will run only the :meth:`test_two` test method. the specifier can refer to modules and packages which have not been imported; they will be imported as a side-effect. - The method optionally resolves *name* relative to the given *module*. + the method optionally resolves *name* relative to the given *module*. - .. method:: loadTestsFromNames(names[, module]) + .. method:: loadtestsfromnames(names[, module]) - Similar to :meth:`loadTestsFromName`, but takes a sequence of names rather - than a single name. The return value is a test suite which supports all + similar to :meth:`loadtestsfromname`, but takes a sequence of names rather + than a single name. the return value is a test suite which supports all the tests defined for each name. - .. method:: getTestCaseNames(testCaseClass) + .. method:: gettestcasenames(testcaseclass) - Return a sorted sequence of method names found within *testCaseClass*; - this should be a subclass of :class:`TestCase`. + return a sorted sequence of method names found within *testcaseclass*; + this should be a subclass of :class:`testcase`. - The following attributes of a :class:`TestLoader` can be configured either by + the following attributes of a :class:`testloader` can be configured either by subclassing or assignment on an instance: - .. attribute:: testMethodPrefix + .. attribute:: testmethodprefix - String giving the prefix of method names which will be interpreted as test - methods. The default value is ``'test'``. + string giving the prefix of method names which will be interpreted as test + methods. the default value is ``'test'``. - This affects :meth:`getTestCaseNames` and all the :meth:`loadTestsFrom\*` + this affects :meth:`gettestcasenames` and all the :meth:`loadtestsfrom\*` methods. - .. attribute:: sortTestMethodsUsing + .. attribute:: sorttestmethodsusing - Function to be used to compare method names when sorting them in - :meth:`getTestCaseNames` and all the :meth:`loadTestsFrom\*` methods. The + function to be used to compare method names when sorting them in + :meth:`gettestcasenames` and all the :meth:`loadtestsfrom\*` methods. the default value is the built-in :func:`cmp` function; the attribute can also - be set to :const:`None` to disable the sort. + be set to :const:`none` to disable the sort. - .. attribute:: suiteClass + .. attribute:: suiteclass - Callable object that constructs a test suite from a list of tests. No - methods on the resulting object are needed. The default value is the - :class:`TestSuite` class. + callable object that constructs a test suite from a list of tests. no + methods on the resulting object are needed. the default value is the + :class:`testsuite` class. - This affects all the :meth:`loadTestsFrom\*` methods. + this affects all the :meth:`loadtestsfrom\*` methods. - .. attribute:: classSuiteClass + .. attribute:: classsuiteclass - Callable object that constructs a test suite for the tests cases from one - class. The default value is :class:`ClassTestSuite`. + callable object that constructs a test suite for the tests cases from one + class. the default value is :class:`classtestsuite`. -.. class:: TestResult +.. class:: testresult - This class is used to compile information about which tests have succeeded + this class is used to compile information about which tests have succeeded and which have failed. - A :class:`TestResult` object stores the results of a set of tests. The - :class:`TestCase` and :class:`TestSuite` classes ensure that results are + a :class:`testresult` object stores the results of a set of tests. the + :class:`testcase` and :class:`testsuite` classes ensure that results are properly recorded; test authors do not need to worry about recording the outcome of tests. - Testing frameworks built on top of :mod:`unittest` may want access to the - :class:`TestResult` object generated by running a set of tests for reporting - purposes; a :class:`TestResult` instance is returned by the - :meth:`TestRunner.run` method for this purpose. + testing frameworks built on top of :mod:`unittest` may want access to the + :class:`testresult` object generated by running a set of tests for reporting + purposes; a :class:`testresult` instance is returned by the + :meth:`testrunner.run` method for this purpose. - :class:`TestResult` instances have the following attributes that will be of + :class:`testresult` instances have the following attributes that will be of interest when inspecting the results of running a set of tests: .. attribute:: errors - A list containing 2-tuples of :class:`TestCase` instances and strings - holding formatted tracebacks. Each tuple represents a test which raised an + a list containing 2-tuples of :class:`testcase` instances and strings + holding formatted tracebacks. each tuple represents a test which raised an unexpected exception. .. versionchanged:: 2.2 Index: Lib/unittest.py =================================================================== --- Lib/unittest.py (revision 70797) +++ Lib/unittest.py (working copy) @@ -45,12 +45,15 @@ SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. ''' +import difflib +import functools +import os +import pprint +import re +import sys import time -import sys import traceback -import os import types -import functools ############################################################################## # Exported classes and functions @@ -253,10 +256,11 @@ class AssertRaisesContext(object): - def __init__(self, expected, test_case): + def __init__(self, expected, test_case, expected_regexp=None): self.expected = expected self.failureException = test_case.failureException - + self.expected_regex = expected_regexp + def __enter__(self): pass @@ -268,12 +272,22 @@ exc_name = str(self.expected) raise self.failureException( "{0} not raised".format(exc_name)) - if issubclass(exc_type, self.expected): + if not issubclass(exc_type, self.expected): + # let unexpexted exceptions pass through + return False + if self.expected_regex is None: return True - # Let unexpected exceptions skip through - return False + + expected_regexp = self.expected_regex + if isinstance(expected_regexp, basestring): + expected_regexp = re.compile(expected_regexp) + if not expected_regexp.search(str(exc_value)): + raise self.failureException('"%s" does not match "%s"' % + (expected_regexp.pattern, str(exc_value))) + return True + class TestCase(object): """A class whose instances are single test cases. @@ -315,6 +329,31 @@ (self.__class__, methodName)) self._testMethodDoc = testMethod.__doc__ + # Map types to custom assertEquals functions that will compare + # instances of said type in more detail to generate a more useful + # error message. + self.__type_equality_funcs = {} + self.addTypeEqualityFunc(dict, self.assertDictEquals) + self.addTypeEqualityFunc(list, self.assertListEquals) + self.addTypeEqualityFunc(tuple, self.assertTupleEquals) + self.addTypeEqualityFunc(set, self.assertSetEquals) + self.addTypeEqualityFunc(frozenset, self.assertSetEquals) + + def addTypeEqualityFunc(self, typeobj, function): + """Add a type specific assertEqual style function to compare a type. + + This method is for use by TestCase subclasses that need to register + their own type equality functions to provide nicer error messages. + + Args: + typeobj: The data type to call this function on when both values + are of the same type in assertEquals(). + function: The callable taking two arguments and an optional + msg= argument that raises self.failureException with a + useful error message when the two arguments are not equal. + """ + self.__type_equality_funcs[typeobj] = function + def setUp(self): "Hook method for setting up the test fixture before exercising it." pass @@ -330,15 +369,23 @@ return TestResult() def shortDescription(self): - """Returns a one-line description of the test, or None if no - description has been provided. + """Returns both the test method name and first line of its docstring. - The default implementation of this method returns the first line of - the specified test method's docstring. + If no docstring is given, only returns the method name. + + This method overrides unittest.TestCase.shortDescription(), which + only returns the first line of the docstring, obscuring the name + of the test upon failure. """ - doc = self._testMethodDoc - return doc and doc.split("\n")[0].strip() or None + desc = str(self) + doc_first_line = None + if self._testMethodDoc: + doc_first_line = self._testMethodDoc.split("\n")[0].strip() + if doc_first_line: + desc = '\n'.join((desc, doc_first_line)) + return desc + def id(self): return "%s.%s" % (_strclass(self.__class__), self._testMethodName) @@ -449,12 +496,39 @@ with context: callableObj(*args, **kwargs) + def _getAssertEqualityFunc(self, first, second): + """Get a detailed comparison function for the types of the two args. + + Returns: A callable accepting (first, second, msg=None) that will + raise a failure exception if first != second with a useful human + readable error message for those types. + """ + # + # NOTE(gregory.p.smith): I considered isinstance(first, type(second)) + # and vice versa. I opted for the conservative approach in case + # subclasses are not intended to be compared in detail to their super + # class instances using a type equality func. This means testing + # subtypes won't automagically use the detailed comparison. Callers + # should use their type specific assertSpamEquals method to compare + # subclasses if the detailed comparison is desired and appropriate. + # See the discussion in http://bugs.python.org/issue2578. + # + if type(first) is type(second): + return self.__type_equality_funcs.get(type(first), + self._baseAssertEquals) + return self._baseAssertEquals + + def _baseAssertEquals(self, first, second, msg=None): + """The default assertEquals implementation, not type specific.""" + if not first == second: + raise self.failureException(msg or '%r != %r' % (first, second)) + def failUnlessEqual(self, first, second, msg=None): """Fail if the two objects are unequal as determined by the '==' operator. """ - if not first == second: - raise self.failureException(msg or '%r != %r' % (first, second)) + assertion_func = self._getAssertEqualityFunc(first, second) + assertion_func(first, second, msg=msg) def failIfEqual(self, first, second, msg=None): """Fail if the two objects are equal as determined by the '==' @@ -504,7 +578,357 @@ assertFalse = failIf + def assertSequenceEquals(self, seq1, seq2, msg=None, seq_type=None): + """An equality assertion for ordered sequences (like lists and tuples). + For the purposes of this function, a valid orderd sequence type is one + which can be indexed, has a length, and has an equality operator. + + Args: + seq1: The first sequence to compare. + seq2: The second sequence to compare. + seq_type: The expected datatype of the sequences, or None if no + datatype should be enforced. + msg: Optional message to use on failure instead of a list of + differences. + """ + if seq_type != None: + seq_type_name = seq_type.__name__ + if not isinstance(seq1, seq_type): + raise self.failureException('First sequence is not a %s: %r' + % (seq_type_name, seq1)) + if not isinstance(seq2, seq_type): + raise self.failureException('Second sequence is not a %s: %r' + % (seq_type_name, seq2)) + else: + seq_type_name = "sequence" + + differing = None + try: + len1 = len(seq1) + except (TypeError, NotImplementedError): + differing = 'First %s has no length. Non-sequence?' % ( + seq_type_name) + + if differing is None: + try: + len2 = len(seq2) + except (TypeError, NotImplementedError): + differing = 'Second %s has no length. Non-sequence?' % ( + seq_type_name) + + if differing is None: + if seq1 == seq2: + return + + for i in xrange(min(len1, len2)): + try: + item1 = seq1[i] + except (TypeError, IndexError, NotImplementedError): + differing = ('Unable to index element %d of first %s\n' % + (i, seq_type_name)) + break + + try: + item2 = seq2[i] + except (TypeError, IndexError, NotImplementedError): + differing = ('Unable to index element %d of second %s\n' % + (i, seq_type_name)) + break + + if item1 != item2: + differing = ('First differing element %d:\n%s\n%s\n' % + (i, item1, item2)) + break + else: + if (len1 == len2 and seq_type is None and + type(seq1) != type(seq2)): + # The sequences are the same, but have differing types. + return + # A catch-all message for handling arbitrary user-defined + # sequences. + differing = '%ss differ:\n' % seq_type_name.capitalize() + if len1 > len2: + differing = ('First %s contains %d additional ' + 'elements.\n' % (seq_type_name, len1 - len2)) + try: + differing += ('First extra element %d:\n%s\n' % + (len2, seq1[len2])) + except (TypeError, IndexError, NotImplementedError): + differing += ('Unable to index element %d ' + 'of first %s\n' % (len2, seq_type_name)) + elif len1 < len2: + differing = ('Second %s contains %d additional ' + 'elements.\n' % (seq_type_name, len2 - len1)) + try: + differing += ('First extra element %d:\n%s\n' % + (len1, seq2[len1])) + except (TypeError, IndexError, NotImplementedError): + differing += ('Unable to index element %d ' + 'of second %s\n' % (len1, seq_type_name)) + if not msg: + msg = '\n'.join(difflib.ndiff(pprint.pformat(seq1).splitlines(), + pprint.pformat(seq2).splitlines())) + self.fail(differing + msg) + + def assertListEquals(self, list1, list2, msg=None): + """A list-specific equality assertion. + + Args: + list1: The first list to compare. + list2: The second list to compare. + msg: Optional message to use on failure instead of a list of + differences. + + """ + self.assertSequenceEquals(list1, list2, msg, seq_type=list) + + def assertTupleEquals(self, tuple1, tuple2, msg=None): + """A tuple-specific equality assertion. + + Args: + tuple1: The first tuple to compare. + tuple2: The second tuple to compare. + msg: Optional message to use on failure instead of a list of + differences. + """ + self.assertSequenceEquals(tuple1, tuple2, msg, seq_type=tuple) + + def assertSetEquals(self, set1, set2, msg=None): + """A set-specific equality assertion. + + Args: + set1: The first set to compare. + set2: The second set to compare. + msg: Optional message to use on failure instead of a list of + differences. + + For more general containership equality, assertSameElements will work + with things other than sets. This uses ducktyping to support + different types of sets, and is optimized for sets specifically + (parameters must support a difference method). + """ + try: + difference1 = set1.difference(set2) + except TypeError, e: + self.fail('invalid type when attempting set difference: %s' % e) + except AttributeError, e: + self.fail('first argument does not support set difference: %s' % e) + + try: + difference2 = set2.difference(set1) + except TypeError, e: + self.fail('invalid type when attempting set difference: %s' % e) + except AttributeError, e: + self.fail('second argument does not support set difference: %s' % e) + + if not (difference1 or difference2): + return + + if msg is not None: + self.fail(msg) + + lines = [] + if difference1: + lines.append('Items in the first set but not the second:') + for item in difference1: + lines.append(repr(item)) + if difference2: + lines.append('Items in the second set but not the first:') + for item in difference2: + lines.append(repr(item)) + self.fail('\n'.join(lines)) + + def assertIn(self, a, b, msg=None): + """Just like self.assert_(a in b), but with a nicer default message.""" + if msg is None: + msg = '"%s" not found in "%s"' % (a, b) + self.assert_(a in b, msg) + + def assertNotIn(self, a, b, msg=None): + """Just like self.assert_(a not in b), but with a nicer default message.""" + if msg is None: + msg = '"%s" unexpectedly found in "%s"' % (a, b) + self.assert_(a not in b, msg) + + def assertDictEquals(self, d1, d2, msg=None): + self.assert_(isinstance(d1, dict), 'First argument is not a dictionary') + self.assert_(isinstance(d2, dict), 'Second argument is not a dictionary') + + if d1 != d2: + self.fail(msg or ('\n' + '\n'.join(difflib.ndiff( + pprint.pformat(d1).splitlines(), + pprint.pformat(d2).splitlines())))) + + def assertDictContainsSubset(self, expected, actual, msg=None): + """Checks whether actual is a superset of expected.""" + missing = [] + mismatched = [] + for key, value in expected.iteritems(): + if key not in actual: + missing.append(key) + elif value != actual[key]: + mismatched.append('%s, expected: %s, actual: %s' % (key, value, + actual[key])) + + if not (missing or mismatched): + return + + missing_msg = mismatched_msg = '' + if missing: + missing_msg = 'Missing: %s' % ','.join(missing) + if mismatched: + mismatched_msg = 'Mismatched values: %s' % ','.join(mismatched) + + if msg: + msg = '%s: %s; %s' % (msg, missing_msg, mismatched_msg) + else: + msg = '%s; %s' % (missing_msg, mismatched_msg) + self.fail(msg) + + def assertSameElements(self, expected_seq, actual_seq, msg=None): + """An unordered sequence specific comparison. + + Raises with an error message listing which elements of expected_seq + are missing from actual_seq and vice versa if any. + """ + try: + expected = set(expected_seq) + actual = set(actual_seq) + missing = list(expected.difference(actual)) + unexpected = list(actual.difference(expected)) + missing.sort() + unexpected.sort() + except TypeError: + # Fall back to slower list-compare if any of the objects are + # not hashable. + expected = list(expected_seq) + actual = list(actual_seq) + expected.sort() + actual.sort() + missing, unexpected = _SortedListDifference(expected, actual) + errors = [] + if missing: + errors.append('Expected, but missing:\n %r\n' % missing) + if unexpected: + errors.append('Unexpected, but present:\n %r\n' % unexpected) + if errors: + self.fail(msg or ''.join(errors)) + + def assertMultiLineEquals(self, first, second, msg=None): + """Assert that two multi-line strings are equal.""" + self.assert_(isinstance(first, types.StringTypes), ( + 'First argument is not a string')) + self.assert_(isinstance(second, types.StringTypes), ( + 'Second argument is not a string')) + + if first != second: + raise self.failureException( + msg or '\n' + ''.join(difflib.ndiff(first.splitlines(True), + second.splitlines(True)))) + + def assertLess(self, a, b, msg=None): + """Just like self.assert_(a < b), but with a nicer default message.""" + if msg is None: + msg = '"%r" unexpectedly not less than "%r"' % (a, b) + self.assert_(a < b, msg) + + def assertLessEqual(self, a, b, msg=None): + """Just like self.assert_(a <= b), but with a nicer default message.""" + if msg is None: + msg = '"%r" unexpectedly not less than or equal to "%r"' % (a, b) + self.assert_(a <= b, msg) + + def assertGreater(self, a, b, msg=None): + """Just like self.assert_(a > b), but with a nicer default message.""" + if msg is None: + msg = '"%r" unexpectedly not greater than "%r"' % (a, b) + self.assert_(a > b, msg) + + def assertGreaterEqual(self, a, b, msg=None): + """Just like self.assert_(a >= b), but with a nicer default message.""" + if msg is None: + msg = '"%r" unexpectedly not greater than or equal to "%r"' % (a, b) + self.assert_(a >= b, msg) + + def assertIsNone(self, obj, msg=None): + """Same as self.assert_(obj is None), with a nicer default message.""" + if msg is None: + msg = '"%s" unexpectedly not None' % obj + self.assert_(obj is None, msg) + + def assertIsNotNone(self, obj, msg='unexpectedly None'): + """Included for symmetry with assertIsNone.""" + self.assert_(obj is not None, msg) + + def assertRaisesRegexp(self, expected_exception, expected_regexp, + callable_obj=None, *args, **kwargs): + """Asserts that the message in a raised exception matches a regexp. + + Args: + expected_exception: Exception class expected to be raised. + expected_regexp: Regexp (re pattern object or string) expected + to be found in error message. + callable_obj: Function to be called. + args: Extra args. + kwargs: Extra kwargs. + """ + context = AssertRaisesContext(expected_exception, self, expected_regexp) + if callable_obj is None: + return context + with context: + callable_obj(*args, **kwargs) + + def assertRegexpMatches(self, text, expected_regex, msg=None): + if isinstance(expected_regex, basestring): + expected_regex = re.compile(expected_regex) + if not expected_regex.search(text): + msg = msg or "Regexp didn't match" + msg = '%s: %r not found in %r' % (msg, expected_regex.pattern, text) + raise self.failureException(msg) + + +def _SortedListDifference(expected, actual): + """Finds elements in only one or the other of two, sorted input lists. + + Returns a two-element tuple of lists. The first list contains those + elements in the "expected" list but not in the "actual" list, and the + second contains those elements in the "actual" list but not in the + "expected" list. Duplicate elements in either input list are ignored. + """ + i = j = 0 + missing = [] + unexpected = [] + while True: + try: + e = expected[i] + a = actual[j] + if e < a: + missing.append(e) + i += 1 + while expected[i] == e: + i += 1 + elif e > a: + unexpected.append(a) + j += 1 + while actual[j] == a: + j += 1 + else: + i += 1 + try: + while expected[i] == e: + i += 1 + finally: + j += 1 + while actual[j] == a: + j += 1 + except IndexError: + missing.extend(expected[i:]) + unexpected.extend(actual[j:]) + break + return missing, unexpected + + class TestSuite(object): """A test suite is a composite test consisting of a number of TestCases. Index: Lib/test/test_gc.py =================================================================== --- Lib/test/test_gc.py (revision 70797) +++ Lib/test/test_gc.py (working copy) @@ -244,7 +244,7 @@ # - the call to assertEqual somehow avoids building its args tuple def test_get_count(self): # Avoid future allocation of method object - assertEqual = self.assertEqual + assertEqual = self._baseAssertEquals gc.collect() assertEqual(gc.get_count(), (0, 0, 0)) a = dict() Index: Lib/test/test_struct.py =================================================================== --- Lib/test/test_struct.py (revision 70797) +++ Lib/test/test_struct.py (working copy) @@ -227,6 +227,7 @@ BUGGY_RANGE_CHECK = "bBhHiIlL" def __init__(self, formatpair, bytesize): + super(IntTester, self).__init__(methodName='test_one') self.assertEqual(len(formatpair), 2) self.formatpair = formatpair for direction in "<>!=": Index: Lib/test/test_unittest.py =================================================================== --- Lib/test/test_unittest.py (revision 70797) +++ Lib/test/test_unittest.py (working copy) @@ -6,6 +6,7 @@ TestCase.{assert,fail}* methods (some are tested implicitly) """ +import re from test import test_support import unittest from unittest import TestCase @@ -70,7 +71,8 @@ def test_hash(self): for obj_1, obj_2 in self.eq_pairs: try: - assert hash(obj_1) == hash(obj_2) + if not hash(obj_1) == hash(obj_2): + raise AssertionError except KeyboardInterrupt: raise except AssertionError: @@ -80,7 +82,8 @@ for obj_1, obj_2 in self.ne_pairs: try: - assert hash(obj_1) != hash(obj_2) + if hash(obj_1) == hash(obj_2): + raise AssertionError except KeyboardInterrupt: raise except AssertionError: @@ -2237,39 +2240,6 @@ self.failUnless(isinstance(Foo().id(), basestring)) - # "Returns a one-line description of the test, or None if no description - # has been provided. The default implementation of this method returns - # the first line of the test method's docstring, if available, or None." - def test_shortDescription__no_docstring(self): - class Foo(unittest.TestCase): - def runTest(self): - pass - - self.assertEqual(Foo().shortDescription(), None) - - # "Returns a one-line description of the test, or None if no description - # has been provided. The default implementation of this method returns - # the first line of the test method's docstring, if available, or None." - def test_shortDescription__singleline_docstring(self): - class Foo(unittest.TestCase): - def runTest(self): - "this tests foo" - pass - - self.assertEqual(Foo().shortDescription(), "this tests foo") - - # "Returns a one-line description of the test, or None if no description - # has been provided. The default implementation of this method returns - # the first line of the test method's docstring, if available, or None." - def test_shortDescription__multiline_docstring(self): - class Foo(unittest.TestCase): - def runTest(self): - """this tests foo - blah, bar and baz are also tested""" - pass - - self.assertEqual(Foo().shortDescription(), "this tests foo") - # "If result is omitted or None, a temporary result object is created # and used, but is not made available to the caller" def test_run__uses_defaultTestResult(self): @@ -2288,7 +2258,408 @@ expected = ['startTest', 'test', 'addSuccess', 'stopTest'] self.assertEqual(events, expected) + def testShortDescriptionWithoutDocstring(self): + self.assertEqual( + self.shortDescription(), + 'testShortDescriptionWithoutDocstring (' + __name__ + + '.Test_TestCase)') + def testShortDescriptionWithOneLineDocstring(self): + """Tests shortDescription() for a method with a docstring.""" + self.assertEqual( + self.shortDescription(), + ('testShortDescriptionWithOneLineDocstring ' + '(' + __name__ + '.Test_TestCase)\n' + 'Tests shortDescription() for a method with a docstring.')) + + def testShortDescriptionWithMultiLineDocstring(self): + """Tests shortDescription() for a method with a longer docstring. + + This method ensures that only the first line of a docstring is + returned used in the short description, no matter how long the + whole thing is. + """ + self.assertEqual( + self.shortDescription(), + ('testShortDescriptionWithMultiLineDocstring ' + '(' + __name__ + '.Test_TestCase)\n' + 'Tests shortDescription() for a method with a longer ' + 'docstring.')) + + + def testAddTypeEqualityFunc(self): + class SadSnake(object): + """Dummy class for test_addTypeEqualityFunc.""" + s1, s2 = SadSnake(), SadSnake() + self.assertFalse(s1 == s2) + def AllSnakesCreatedEqual(a, b, msg=None): + return type(a) == type(b) == SadSnake + self.addTypeEqualityFunc(SadSnake, AllSnakesCreatedEqual) + self.assertEqual(s1, s2) + # No this doesn't clean up and remove the SadSnake equality func + # from this TestCase instance but since its a local nothing else + # will ever notice that. + + def testAssertIn(self): + animals = {'monkey': 'banana', 'cow': 'grass', 'seal': 'fish'} + + self.assertIn('a', 'abc') + self.assertIn(2, [1, 2, 3]) + self.assertIn('monkey', animals) + + self.assertNotIn('d', 'abc') + self.assertNotIn(0, [1, 2, 3]) + self.assertNotIn('otter', animals) + + self.assertRaises(self.failureException, self.assertIn, 'x', 'abc') + self.assertRaises(self.failureException, self.assertIn, 4, [1, 2, 3]) + self.assertRaises(self.failureException, self.assertIn, 'elephant', animals) + + self.assertRaises(self.failureException, self.assertNotIn, 'c', 'abc') + self.assertRaises(self.failureException, self.assertNotIn, 1, [1, 2, 3]) + self.assertRaises(self.failureException, self.assertNotIn, 'cow', animals) + + def testAssertDictContainsSubset(self): + self.assertDictContainsSubset({}, {}) + self.assertDictContainsSubset({}, {'a': 1}) + self.assertDictContainsSubset({'a': 1}, {'a': 1}) + self.assertDictContainsSubset({'a': 1}, {'a': 1, 'b': 2}) + self.assertDictContainsSubset({'a': 1, 'b': 2}, {'a': 1, 'b': 2}) + + self.assertRaises(unittest.TestCase.failureException, + self.assertDictContainsSubset, {'a': 2}, {'a': 1}, + '.*Mismatched values:.*') + + self.assertRaises(unittest.TestCase.failureException, + self.assertDictContainsSubset, {'c': 1}, {'a': 1}, + '.*Missing:.*') + + self.assertRaises(unittest.TestCase.failureException, + self.assertDictContainsSubset, {'a': 1, 'c': 1}, + {'a': 1}, '.*Missing:.*') + + self.assertRaises(unittest.TestCase.failureException, + self.assertDictContainsSubset, {'a': 1, 'c': 1}, + {'a': 1}, '.*Missing:.*Mismatched values:.*') + + def testAssertEqual(self): + equal_pairs = [ + ((), ()), + ({}, {}), + ([], []), + (set(), set()), + (frozenset(), frozenset())] + for a, b in equal_pairs: + # This mess of try excepts is to test the assertEqual behavior + # itself. + try: + self.assertEqual(a, b) + except self.failureException: + self.fail('assertEqual(%r, %r) failed' % (a, b)) + try: + self.assertEqual(a, b, msg='foo') + except self.failureException: + self.fail('assertEqual(%r, %r) with msg= failed' % (a, b)) + try: + self.assertEqual(a, b, 'foo') + except self.failureException: + self.fail('assertEqual(%r, %r) with third parameter failed' % + (a, b)) + + unequal_pairs = [ + ((), []), + ({}, set()), + (set([4,1]), frozenset([4,2])), + (frozenset([4,5]), set([2,3])), + (set([3,4]), set([5,4]))] + for a, b in unequal_pairs: + self.assertRaises(self.failureException, self.assertEqual, a, b) + self.assertRaises(self.failureException, self.assertEqual, a, b, + 'foo') + self.assertRaises(self.failureException, self.assertEqual, a, b, + msg='foo') + + def testEquality(self): + self.assertListEquals([], []) + self.assertTupleEquals((), ()) + self.assertSequenceEquals([], ()) + + a = [0, 'a', []] + b = [] + self.assertRaises(unittest.TestCase.failureException, + self.assertListEquals, a, b) + self.assertRaises(unittest.TestCase.failureException, + self.assertListEquals, tuple(a), tuple(b)) + self.assertRaises(unittest.TestCase.failureException, + self.assertSequenceEquals, a, tuple(b)) + + b.extend(a) + self.assertListEquals(a, b) + self.assertTupleEquals(tuple(a), tuple(b)) + self.assertSequenceEquals(a, tuple(b)) + self.assertSequenceEquals(tuple(a), b) + + self.assertRaises(self.failureException, self.assertListEquals, + a, tuple(b)) + self.assertRaises(self.failureException, self.assertTupleEquals, + tuple(a), b) + self.assertRaises(self.failureException, self.assertListEquals, None, b) + self.assertRaises(self.failureException, self.assertTupleEquals, None, + tuple(b)) + self.assertRaises(self.failureException, self.assertSequenceEquals, + None, tuple(b)) + self.assertRaises(self.failureException, self.assertListEquals, 1, 1) + self.assertRaises(self.failureException, self.assertTupleEquals, 1, 1) + self.assertRaises(self.failureException, self.assertSequenceEquals, + 1, 1) + + self.assertDictEquals({}, {}) + + c = { 'x': 1 } + d = {} + self.assertRaises(unittest.TestCase.failureException, + self.assertDictEquals, c, d) + + d.update(c) + self.assertDictEquals(c, d) + + d['x'] = 0 + self.assertRaises(unittest.TestCase.failureException, + self.assertDictEquals, c, d, 'These are unequal') + + self.assertRaises(self.failureException, self.assertDictEquals, None, d) + self.assertRaises(self.failureException, self.assertDictEquals, [], d) + self.assertRaises(self.failureException, self.assertDictEquals, 1, 1) + + self.assertSameElements([1, 2, 3], [3, 2, 1]) + self.assertSameElements([1, 2] + [3] * 100, [1] * 100 + [2, 3]) + self.assertSameElements(['foo', 'bar', 'baz'], ['bar', 'baz', 'foo']) + self.assertRaises(self.failureException, self.assertSameElements, + [10], [10, 11]) + self.assertRaises(self.failureException, self.assertSameElements, + [10, 11], [10]) + + # Test that sequences of unhashable objects can be tested for sameness: + self.assertSameElements([[1, 2], [3, 4]], [[3, 4], [1, 2]]) + self.assertSameElements([{'a': 1}, {'b': 2}], [{'b': 2}, {'a': 1}]) + self.assertRaises(self.failureException, self.assertSameElements, + [[1]], [[2]]) + + def testAssertSetEquals(self): + set1 = set() + set2 = set() + self.assertSetEquals(set1, set2) + + self.assertRaises(self.failureException, self.assertSetEquals, None, set2) + self.assertRaises(self.failureException, self.assertSetEquals, [], set2) + self.assertRaises(self.failureException, self.assertSetEquals, set1, None) + self.assertRaises(self.failureException, self.assertSetEquals, set1, []) + + set1 = set(['a']) + set2 = set() + self.assertRaises(self.failureException, self.assertSetEquals, set1, set2) + + set1 = set(['a']) + set2 = set(['a']) + self.assertSetEquals(set1, set2) + + set1 = set(['a']) + set2 = set(['a', 'b']) + self.assertRaises(self.failureException, self.assertSetEquals, set1, set2) + + set1 = set(['a']) + set2 = frozenset(['a', 'b']) + self.assertRaises(self.failureException, self.assertSetEquals, set1, set2) + + set1 = set(['a', 'b']) + set2 = frozenset(['a', 'b']) + self.assertSetEquals(set1, set2) + + set1 = set() + set2 = "foo" + self.assertRaises(self.failureException, self.assertSetEquals, set1, set2) + self.assertRaises(self.failureException, self.assertSetEquals, set2, set1) + + # make sure any string formatting is tuple-safe + set1 = set([(0, 1), (2, 3)]) + set2 = set([(4, 5)]) + self.assertRaises(self.failureException, self.assertSetEquals, set1, set2) + + def testInequality(self): + # Try ints + self.assertGreater(2, 1) + self.assertGreaterEqual(2, 1) + self.assertGreaterEqual(1, 1) + self.assertLess(1, 2) + self.assertLessEqual(1, 2) + self.assertLessEqual(1, 1) + self.assertRaises(self.failureException, self.assertGreater, 1, 2) + self.assertRaises(self.failureException, self.assertGreater, 1, 1) + self.assertRaises(self.failureException, self.assertGreaterEqual, 1, 2) + self.assertRaises(self.failureException, self.assertLess, 2, 1) + self.assertRaises(self.failureException, self.assertLess, 1, 1) + self.assertRaises(self.failureException, self.assertLessEqual, 2, 1) + + # Try Floats + self.assertGreater(1.1, 1.0) + self.assertGreaterEqual(1.1, 1.0) + self.assertGreaterEqual(1.0, 1.0) + self.assertLess(1.0, 1.1) + self.assertLessEqual(1.0, 1.1) + self.assertLessEqual(1.0, 1.0) + self.assertRaises(self.failureException, self.assertGreater, 1.0, 1.1) + self.assertRaises(self.failureException, self.assertGreater, 1.0, 1.0) + self.assertRaises(self.failureException, self.assertGreaterEqual, 1.0, 1.1) + self.assertRaises(self.failureException, self.assertLess, 1.1, 1.0) + self.assertRaises(self.failureException, self.assertLess, 1.0, 1.0) + self.assertRaises(self.failureException, self.assertLessEqual, 1.1, 1.0) + + # Try Strings + self.assertGreater('bug', 'ant') + self.assertGreaterEqual('bug', 'ant') + self.assertGreaterEqual('ant', 'ant') + self.assertLess('ant', 'bug') + self.assertLessEqual('ant', 'bug') + self.assertLessEqual('ant', 'ant') + self.assertRaises(self.failureException, self.assertGreater, 'ant', 'bug') + self.assertRaises(self.failureException, self.assertGreater, 'ant', 'ant') + self.assertRaises(self.failureException, self.assertGreaterEqual, 'ant', 'bug') + self.assertRaises(self.failureException, self.assertLess, 'bug', 'ant') + self.assertRaises(self.failureException, self.assertLess, 'ant', 'ant') + self.assertRaises(self.failureException, self.assertLessEqual, 'bug', 'ant') + + # Try Unicode + self.assertGreater(u'bug', u'ant') + self.assertGreaterEqual(u'bug', u'ant') + self.assertGreaterEqual(u'ant', u'ant') + self.assertLess(u'ant', u'bug') + self.assertLessEqual(u'ant', u'bug') + self.assertLessEqual(u'ant', u'ant') + self.assertRaises(self.failureException, self.assertGreater, u'ant', u'bug') + self.assertRaises(self.failureException, self.assertGreater, u'ant', u'ant') + self.assertRaises(self.failureException, self.assertGreaterEqual, u'ant', + u'bug') + self.assertRaises(self.failureException, self.assertLess, u'bug', u'ant') + self.assertRaises(self.failureException, self.assertLess, u'ant', u'ant') + self.assertRaises(self.failureException, self.assertLessEqual, u'bug', u'ant') + + # Try Mixed String/Unicode + self.assertGreater('bug', u'ant') + self.assertGreater(u'bug', 'ant') + self.assertGreaterEqual('bug', u'ant') + self.assertGreaterEqual(u'bug', 'ant') + self.assertGreaterEqual('ant', u'ant') + self.assertGreaterEqual(u'ant', 'ant') + self.assertLess('ant', u'bug') + self.assertLess(u'ant', 'bug') + self.assertLessEqual('ant', u'bug') + self.assertLessEqual(u'ant', 'bug') + self.assertLessEqual('ant', u'ant') + self.assertLessEqual(u'ant', 'ant') + self.assertRaises(self.failureException, self.assertGreater, 'ant', u'bug') + self.assertRaises(self.failureException, self.assertGreater, u'ant', 'bug') + self.assertRaises(self.failureException, self.assertGreater, 'ant', u'ant') + self.assertRaises(self.failureException, self.assertGreater, u'ant', 'ant') + self.assertRaises(self.failureException, self.assertGreaterEqual, 'ant', + u'bug') + self.assertRaises(self.failureException, self.assertGreaterEqual, u'ant', + 'bug') + self.assertRaises(self.failureException, self.assertLess, 'bug', u'ant') + self.assertRaises(self.failureException, self.assertLess, u'bug', 'ant') + self.assertRaises(self.failureException, self.assertLess, 'ant', u'ant') + self.assertRaises(self.failureException, self.assertLess, u'ant', 'ant') + self.assertRaises(self.failureException, self.assertLessEqual, 'bug', u'ant') + self.assertRaises(self.failureException, self.assertLessEqual, u'bug', 'ant') + + def testAssertMultiLineEquals(self): + sample_text = b"""\ +http://www.python.org/doc/2.3/lib/module-unittest.html +test case + A test case is the smallest unit of testing. [...] +""" + revised_sample_text = b"""\ +http://www.python.org/doc/2.4.1/lib/module-unittest.html +test case + A test case is the smallest unit of testing. [...] You may provide your + own implementation that does not subclass from TestCase, of course. +""" + sample_text_error = b""" +- http://www.python.org/doc/2.3/lib/module-unittest.html +? ^ ++ http://www.python.org/doc/2.4.1/lib/module-unittest.html +? ^^^ + test case +- A test case is the smallest unit of testing. [...] ++ A test case is the smallest unit of testing. [...] You may provide your +? +++++++++++++++++++++ ++ own implementation that does not subclass from TestCase, of course. +""" + + for modifier in (lambda x: x, lambda x: x.decode('utf8')): + try: + self.assertMultiLineEquals(modifier(sample_text), + modifier(revised_sample_text)) + except self.failureException, e: + # no fair testing ourself with ourself, use assertEqual.. + self.assertEqual(sample_text_error, str(e).encode('utf8')) + + def testAssertIsNone(self): + self.assertIsNone(None) + self.assertRaises(self.failureException, self.assertIsNone, False) + self.assertIsNotNone('DjZoPloGears on Rails') + self.assertRaises(self.failureException, self.assertIsNotNone, None) + + def testAssertRegexpMatches(self): + self.assertRegexpMatches('asdfabasdf', r'ab+') + self.assertRaises(self.failureException, self.assertRegexpMatches, + 'saaas', r'aaaa') + + def testAssertRaisesRegexp(self): + class ExceptionMock(Exception): + pass + + def Stub(): + raise ExceptionMock('We expect') + + self.assertRaisesRegexp(ExceptionMock, re.compile('expect$'), Stub) + self.assertRaisesRegexp(ExceptionMock, 'expect$', Stub) + self.assertRaisesRegexp(ExceptionMock, u'expect$', Stub) + + def testAssertNotRaisesRegexp(self): + self.assertRaisesRegexp( + self.failureException, '^Exception not raised$', + self.assertRaisesRegexp, Exception, re.compile('x'), + lambda: None) + self.assertRaisesRegexp( + self.failureException, '^Exception not raised$', + self.assertRaisesRegexp, Exception, 'x', + lambda: None) + self.assertRaisesRegexp( + self.failureException, '^Exception not raised$', + self.assertRaisesRegexp, Exception, u'x', + lambda: None) + + def testAssertRaisesRegexpMismatch(self): + def Stub(): + raise Exception('Unexpected') + + self.assertRaisesRegexp( + self.failureException, + r'"\^Expected\$" does not match "Unexpected"', + self.assertRaisesRegexp, Exception, '^Expected$', + Stub) + self.assertRaisesRegexp( + self.failureException, + r'"\^Expected\$" does not match "Unexpected"', + self.assertRaisesRegexp, Exception, u'^Expected$', + Stub) + self.assertRaisesRegexp( + self.failureException, + r'"\^Expected\$" does not match "Unexpected"', + self.assertRaisesRegexp, Exception, + re.compile('^Expected$'), Stub) + + class Test_TestSkipping(TestCase): def test_skipping(self): @@ -2386,20 +2757,20 @@ def test_AlmostEqual(self): self.failUnlessAlmostEqual(1.00000001, 1.0) self.failIfAlmostEqual(1.0000001, 1.0) - self.assertRaises(AssertionError, + self.assertRaises(self.failureException, self.failUnlessAlmostEqual, 1.0000001, 1.0) - self.assertRaises(AssertionError, + self.assertRaises(self.failureException, self.failIfAlmostEqual, 1.00000001, 1.0) self.failUnlessAlmostEqual(1.1, 1.0, places=0) - self.assertRaises(AssertionError, + self.assertRaises(self.failureException, self.failUnlessAlmostEqual, 1.1, 1.0, places=1) self.failUnlessAlmostEqual(0, .1+.1j, places=0) self.failIfAlmostEqual(0, .1+.1j, places=1) - self.assertRaises(AssertionError, + self.assertRaises(self.failureException, self.failUnlessAlmostEqual, 0, .1+.1j, places=1) - self.assertRaises(AssertionError, + self.assertRaises(self.failureException, self.failIfAlmostEqual, 0, .1+.1j, places=0) def test_assertRaises(self): @@ -2409,7 +2780,7 @@ self.assertRaises(KeyError, _raise, KeyError("key")) try: self.assertRaises(KeyError, lambda: None) - except AssertionError as e: + except self.failureException as e: self.assert_("KeyError not raised" in e, str(e)) else: self.fail("assertRaises() didn't fail") @@ -2426,7 +2797,7 @@ try: with self.assertRaises(KeyError): pass - except AssertionError as e: + except self.failureException as e: self.assert_("KeyError not raised" in e, str(e)) else: self.fail("assertRaises() didn't fail")