diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py index 993aaec1940748..9dde7249c44454 100644 --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -5,6 +5,7 @@ import difflib import logging import pprint +import pydoc import re import warnings import collections @@ -338,6 +339,20 @@ def __exit__(self, exc_type, exc_value, tb): .format(logging.getLevelName(self.level), self.logger.name)) +def _get_short_description(doc): + """ + Return the summary line from a docstring. + + If there is no summary line, return None. + """ + if not doc: + return None + + (synopsis, long_description) = pydoc.splitdoc(doc) + synopsis = synopsis.strip() + return synopsis + + class TestCase(object): """A class whose instances are single test cases. @@ -466,12 +481,10 @@ def shortDescription(self): """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 specified test method's docstring. + This method returns the summary line of + the specified test method's docstring, as per PEP-257. """ - doc = self._testMethodDoc - return doc and doc.split("\n")[0].strip() or None - + return _get_short_description(self._testMethodDoc) def id(self): return "%s.%s" % (strclass(self.__class__), self._testMethodName) @@ -1395,8 +1408,7 @@ def __repr__(self): def shortDescription(self): if self._description is not None: return self._description - doc = self._testFunc.__doc__ - return doc and doc.split("\n")[0].strip() or None + return _get_short_description(self._testFunc.__doc__) class _SubTest(TestCase): diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py index b84959150542bd..dc0484f72de400 100644 --- a/Lib/unittest/test/test_case.py +++ b/Lib/unittest/test/test_case.py @@ -577,7 +577,7 @@ def testShortDescriptionWithoutDocstring(self): @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") def testShortDescriptionWithOneLineDocstring(self): - """Tests shortDescription() for a method with a docstring.""" + """ Tests shortDescription() for a method with a docstring.""" self.assertEqual( self.shortDescription(), 'Tests shortDescription() for a method with a docstring.') @@ -585,7 +585,7 @@ def testShortDescriptionWithOneLineDocstring(self): @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") def testShortDescriptionWithMultiLineDocstring(self): - """Tests shortDescription() for a method with a longer docstring. + """ 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 @@ -596,6 +596,38 @@ def testShortDescriptionWithMultiLineDocstring(self): 'Tests shortDescription() for a method with a longer ' 'docstring.') + @unittest.skipIf( + sys.flags.optimize >= 2, + "Docstrings are omitted with -O2 and above") + def testShortDescriptionWithSurroundingNewlineOneLineDocstring(self): + """ + Surrounding newlines should be stripped to get the shortDescription. + """ + expected_description = ( + "Surrounding newlines should be stripped" + " to get the shortDescription.") + self.assertEqual(self.shortDescription(), expected_description) + + @unittest.skipIf( + sys.flags.optimize >= 2, + "Docstrings are omitted with -O2 and above") + def testShortDescriptionWithSurroundingNewlineMultiLineDocstring(self): + """ + Surrounding newlines should be stripped to get the shortDescription. + + The specification of how docstring space should be parsed is at + https://www.python.org/dev/peps/pep-0257/#handling-docstring-indentation + which requires that “Blank lines should be removed from the + beginning and end of the docstring.” + + The PEP 257 algorithm is implemented by `pydoc.splitdoc`. + + """ + expected_description = ( + "Surrounding newlines should be stripped" + " to get the shortDescription.") + self.assertEqual(self.shortDescription(), expected_description) + def testAddTypeEqualityFunc(self): class SadSnake(object): """Dummy class for test_addTypeEqualityFunc.""" diff --git a/Lib/unittest/test/test_functiontestcase.py b/Lib/unittest/test/test_functiontestcase.py index c5f2bcbe741b61..d1ec44254ce188 100644 --- a/Lib/unittest/test/test_functiontestcase.py +++ b/Lib/unittest/test/test_functiontestcase.py @@ -126,23 +126,65 @@ def test_id(self): self.assertIsInstance(test.id(), str) - # "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): + def test_shortDescription__no_description_no_docstring(self): + """ Should return None by default for shortDescription. """ test = unittest.FunctionTestCase(lambda: None) self.assertEqual(test.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): + def test_shortDescription__singleline_description(self): + """ Should use the specified description for shortDescription. """ desc = "this tests foo" test = unittest.FunctionTestCase(lambda: None, description=desc) self.assertEqual(test.shortDescription(), "this tests foo") + def test_shortDescription__no_description_singleline_docstring(self): + """ Should use the function docstring for the shortDescription. """ + test_function = (lambda: None) + test_function.__doc__ = """Should use the function docstring.""" + test = unittest.FunctionTestCase(test_function) + expected_description = "Should use the function docstring." + self.assertEqual(test.shortDescription(), expected_description) + + def test_shortDescription__singleline_docstring_space_surrounded(self): + """ Surrounding space should be stripped to get the shortDescription. """ + test_function = (lambda: None) + test_function.__doc__ = """ Surrounding space should be stripped. """ + test = unittest.FunctionTestCase(test_function) + expected_description = "Surrounding space should be stripped." + self.assertEqual(test.shortDescription(), expected_description) + + def test_shortDescription__singleline_docstring_newline_surrounded(self): + """ + Surrounding newlines should be stripped to get the shortDescription. + """ + test_function = (lambda: None) + test_function.__doc__ = """ + Surrounding newlines should be stripped. + """ + test = unittest.FunctionTestCase(test_function) + expected_description = "Surrounding newlines should be stripped." + self.assertEqual(test.shortDescription(), expected_description) + + def test_shortDescription__multiline_docstring_newline_surrounded(self): + """ + Surrounding newlines should be stripped to get the shortDescription. + """ + test_function = (lambda: None) + test_function.__doc__ = """ + Surrounding newlines should be stripped. + + The specification of how docstring space should be parsed is at + https://www.python.org/dev/peps/pep-0257/#handling-docstring-indentation + which requires that “Blank lines should be removed from the + beginning and end of the docstring.” + + """ + test = unittest.FunctionTestCase(test_function) + expected_description = "Surrounding newlines should be stripped." + self.assertEqual(test.shortDescription(), expected_description) + if __name__ == "__main__": unittest.main() diff --git a/Lib/unittest/test/test_result.py b/Lib/unittest/test/test_result.py index 0a615535637385..7778e9a8d5f92c 100644 --- a/Lib/unittest/test/test_result.py +++ b/Lib/unittest/test/test_result.py @@ -369,6 +369,7 @@ def testGetSubTestDescriptionWithOneLineDocstring(self): "Docstrings are omitted with -O2 and above") def testGetDescriptionWithMultiLineDocstring(self): """Tests getDescription() for a method with a longer docstring. + The second line of the docstring. """ result = unittest.TextTestResult(None, True, 1) @@ -383,6 +384,7 @@ def testGetDescriptionWithMultiLineDocstring(self): "Docstrings are omitted with -O2 and above") def testGetSubTestDescriptionWithMultiLineDocstring(self): """Tests getDescription() for a method with a longer docstring. + The second line of the docstring. """ result = unittest.TextTestResult(None, True, 1)