def test_extract_documentation_CPP(self): data = DocumentationExtractionTest.load_testdata("data.cpp") # No built-in documentation for C++. with self.assertRaises(KeyError): tuple(extract_documentation(data, "CPP", "default")) docstyle_CPP_doxygen = DocstyleDefinition.load("CPP", "doxygen") self.assertEqual( tuple(extract_documentation(data, "CPP", "doxygen")), (DocumentationComment(("\n" " This is the main function.\n" " @returns Exit code.\n" " Or any other number.\n"), docstyle_CPP_doxygen.markers[0], TextRange.from_values(4, 1, 8, 4)), DocumentationComment( (" foobar\n" " @param xyz\n"), docstyle_CPP_doxygen.markers[0], TextRange.from_values(15, 1, 17, 4)), DocumentationComment(" Some alternate style of documentation\n", docstyle_CPP_doxygen.markers[4], TextRange.from_values(22, 1, 23, 1)), DocumentationComment(" ends instantly", docstyle_CPP_doxygen.markers[0], TextRange.from_values(26, 5, 26, 26)), DocumentationComment((" Should work\n" "\n" " even without a function standing below.\n" "\n" " @param foo WHAT PARAM PLEASE!?\n"), docstyle_CPP_doxygen.markers[4], TextRange.from_values(32, 1, 37, 1))))
def test_extract_documentation_CPP(self): data = load_testdata('data.cpp') # No built-in documentation for C++. with self.assertRaises(KeyError): tuple(extract_documentation(data, 'CPP', 'default')) docstyle_CPP_doxygen = DocstyleDefinition.load('CPP', 'doxygen') self.assertEqual( tuple(extract_documentation(data, 'CPP', 'doxygen')), (DocumentationComment( ('\n' ' This is the main function.\n' ' @returns Exit code.\n' ' Or any other number.\n'), docstyle_CPP_doxygen, '', docstyle_CPP_doxygen.markers[0], TextPosition(4, 1)), DocumentationComment( (' foobar\n' ' @param xyz\n'), docstyle_CPP_doxygen, '', docstyle_CPP_doxygen.markers[0], TextPosition(15, 1)), DocumentationComment(' Some alternate style of documentation\n', docstyle_CPP_doxygen, '', docstyle_CPP_doxygen.markers[4], TextPosition(22, 1)), DocumentationComment(' ends instantly', docstyle_CPP_doxygen, '\t', docstyle_CPP_doxygen.markers[0], TextPosition(26, 2)), DocumentationComment( (' Should work\n' '\n' ' even without a function standing below.\n' '\n' ' @param foo WHAT PARAM PLEASE!?\n'), docstyle_CPP_doxygen, '', docstyle_CPP_doxygen.markers[4], TextPosition(32, 1))))
def test_extract_documentation_PYTHON3(self): data = DocumentationExtractionTest.load_testdata("data.py") docstyle_PYTHON3_default = DocstyleDefinition.load( "PYTHON3", "default") docstyle_PYTHON3_doxygen = DocstyleDefinition.load( "PYTHON3", "doxygen") expected = (DocumentationComment(("\n" "Module description.\n" "\n" "Some more foobar-like text.\n"), docstyle_PYTHON3_default.markers[0], TextRange.from_values(1, 1, 5, 4)), DocumentationComment( ("\n" "A nice and neat way of documenting code.\n" ":param radius: The explosion radius.\n"), docstyle_PYTHON3_default.markers[0], TextRange.from_values(8, 5, 11, 8)), DocumentationComment( ("\n" "Docstring with layouted text.\n" "\n" " layouts inside docs are preserved for these " "documentation styles.\n" "this is intended.\n"), docstyle_PYTHON3_default.markers[0], TextRange.from_values(14, 1, 19, 4)), DocumentationComment( (" Docstring directly besides triple quotes.\n" " Continues here. "), docstyle_PYTHON3_default.markers[0], TextRange.from_values(21, 1, 22, 24)), DocumentationComment(("super\n" " nicely\n" "short"), docstyle_PYTHON3_default.markers[0], TextRange.from_values(35, 1, 37, 9))) self.assertEqual( tuple(extract_documentation(data, "PYTHON3", "default")), expected) # Change only the docstyle in expected results. expected = list( DocumentationComment(r.documentation, r.marker, r.range) for r in expected) expected.insert( 4, DocumentationComment( (" Alternate documentation style in doxygen.\n" " Subtext\n" " More subtext (not correctly aligned)\n" " sub-sub-text\n" "\n"), docstyle_PYTHON3_doxygen.markers[1], TextRange.from_values(25, 1, 30, 1))) self.assertEqual( list(extract_documentation(data, "PYTHON3", "doxygen")), expected)
def test_python_doxygen(self): data = load_testdata("doxygen.py") parsed_docs = [ doc.parse() for doc in extract_documentation(data, "python", "doxygen") ] expected = [ [ self.Description( desc=' @package pyexample\n Documentation for' ' this module.\n\n More details.\n') ], [ self.Description( desc=' Documentation for a class.\n\n More details.\n') ], [self.Description(desc=' The constructor.\n')], [ self.Description(desc=' Documentation for a method.\n'), self.Parameter(name='self', desc='The object pointer.\n') ], [self.Description(desc=' A class variable.\n')], [self.Description(desc=' @var _memVar\n a member variable\n')], [ self.Description(desc=' This is the best docstring ever!\n\n'), self.Parameter(name='param1', desc='Parameter 1\n'), self.Parameter(name='param2', desc='Parameter 2\n'), self.ReturnValue(desc='Nothing\n') ] ] self.assertEqual(parsed_docs, expected)
def test_python_doxygen(self): data = load_testdata('doxygen.py') parsed_docs = [doc.parse() for doc in extract_documentation(data, 'python', 'doxygen')] expected = [ [self.Description(desc=' @package pyexample\n Documentation for' ' this module.\n\n More details.\n')], [self.Description( desc=' Documentation for a class.\n\n More details.\n')], [self.Description(desc=' The constructor.\n')], [self.Description(desc=' Documentation for a method.\n'), self.Parameter(name='self', desc='The object pointer.\n')], [self.Description(desc=' A class variable.\n')], [self.Description(desc=' @var _memVar\n a member variable\n')], [self.Description(desc=' This is the best docstring ever!\n\n'), self.Parameter(name='param1', desc='Parameter 1\n'), self.Parameter(name='param2', desc='Parameter 2\n'), self.ReturnValue(desc='Nothing\n')], [self.Description(desc=' This is dummy docstring find ' 'function.\n\n'), self.Parameter(name='filename', desc='contains filename\n'), self.ExceptionValue(name='FileNotFoundError', desc='raises when filename is not found\n'), self.ReturnValue(desc='nothing\n')], ] self.assertEqual(parsed_docs, expected)
def test_python_default(self): data = load_testdata("default.py") parsed_docs = [doc.parse() for doc in extract_documentation(data, "python", "default")] expected = [ [self.Description(desc='\nModule description.\n\n' 'Some more foobar-like text.\n')], [self.Description(desc='\nA nice and neat way of ' 'documenting code.\n'), self.Parameter(name='radius', desc=' The explosion radius. ')], [self.Description(desc='A function that returns 55.')], [self.Description(desc='\nDocstring with layouted text.\n\n ' 'layouts inside docs are preserved.' '\nthis is intended.\n')], [self.Description(desc=' Docstring inline with triple quotes.\n' ' Continues here. ')], [self.Description(desc='\nThis is the best docstring ever!\n\n'), self.Parameter(name='param1', desc='\n Very Very Long Parameter ' 'description.\n'), self.Parameter(name='param2', desc='\n Short Param description.\n\n'), self.ReturnValue(desc=' Long Return Description That Makes No ' 'Sense And Will\n Cut to the Next' ' Line.\n')]] self.assertEqual(parsed_docs, expected)
def test_python_default(self): data = load_testdata('default.py') parsed_docs = [doc.parse() for doc in extract_documentation(data, 'python', 'default')] expected = [ [self.Description(desc='\nModule description.\n\n' 'Some more foobar-like text.\n')], [self.Description(desc='\nA nice and neat way of ' 'documenting code.\n'), self.Parameter(name='radius', desc=' The explosion radius. ')], [self.Description(desc='A function that returns 55.')], [self.Description(desc='\nDocstring with layouted text.\n\n ' 'layouts inside docs are preserved.' '\nthis is intended.\n')], [self.Description(desc=' Docstring inline with triple quotes.\n' ' Continues here. ')], [self.Description(desc='\nThis is the best docstring ever!\n\n'), self.Parameter(name='param1', desc='\n Very Very Long Parameter ' 'description.\n'), self.Parameter(name='param2', desc='\n Short Param description.\n\n'), self.ReturnValue(desc=' Long Return Description That Makes No ' 'Sense And Will\n Cut to the Next' ' Line.\n')]] self.assertEqual(parsed_docs, expected)
def test_extract_documentation_C(self): data = load_testdata("data.c") # No built-in documentation for C. with self.assertRaises(KeyError): tuple(extract_documentation(data, "C", "default")) docstyle_C_doxygen = DocstyleDefinition.load("C", "doxygen") expected_results = (DocumentationComment( ("\n" " This is the main function.\n" "\n" " @returns Your favorite number.\n"), docstyle_C_doxygen, "", docstyle_C_doxygen.markers[0], TextRange.from_values(3, 1, 7, 4)), DocumentationComment( ("\n" " Preserves alignment\n" " - Main item\n" " - sub item\n" " - sub sub item\n"), docstyle_C_doxygen, "", docstyle_C_doxygen.markers[2], TextRange.from_values(15, 1, 20, 4)), DocumentationComment( (" ABC\n" " Another type of comment\n" "\n" " ..."), docstyle_C_doxygen, "", docstyle_C_doxygen.markers[1], TextRange.from_values(23, 1, 26, 11)), DocumentationComment( (" foobar = barfoo.\n" " @param x whatever...\n"), docstyle_C_doxygen, "", docstyle_C_doxygen.markers[0], TextRange.from_values(28, 1, 30, 4))) self.assertEqual(tuple( extract_documentation(data, "C", "doxygen")), expected_results)
def test_extract_documentation_C(self): data = load_testdata('data.c') # No built-in documentation for C. with self.assertRaises(KeyError): tuple(extract_documentation(data, 'C', 'default')) docstyle_C_doxygen = DocstyleDefinition.load('C', 'doxygen') expected_results = (DocumentationComment( ('\n' ' This is the main function.\n' '\n' ' @returns Your favorite number.\n'), docstyle_C_doxygen, '', docstyle_C_doxygen.markers[0], TextRange.from_values(3, 1, 7, 4)), DocumentationComment( ('\n' ' Preserves alignment\n' ' - Main item\n' ' - sub item\n' ' - sub sub item\n'), docstyle_C_doxygen, '', docstyle_C_doxygen.markers[2], TextRange.from_values(15, 1, 20, 4)), DocumentationComment( (' ABC\n' ' Another type of comment\n' '\n' ' ...'), docstyle_C_doxygen, '', docstyle_C_doxygen.markers[1], TextRange.from_values(23, 1, 26, 11)), DocumentationComment( (' foobar = barfoo.\n' ' @param x whatever...\n'), docstyle_C_doxygen, '', docstyle_C_doxygen.markers[0], TextRange.from_values(28, 1, 30, 4))) self.assertEqual(tuple( extract_documentation(data, 'C', 'doxygen')), expected_results)
def test_extract_documentation_CPP(self): data = load_testdata("data.cpp") # No built-in documentation for C++. with self.assertRaises(KeyError): tuple(extract_documentation(data, "CPP", "default")) docstyle_CPP_doxygen = DocstyleDefinition.load("CPP", "doxygen") self.assertEqual(tuple(extract_documentation(data, "CPP", "doxygen")), (DocumentationComment( ("\n" " This is the main function.\n" " @returns Exit code.\n" " Or any other number.\n"), docstyle_CPP_doxygen, "", docstyle_CPP_doxygen.markers[0], TextRange.from_values(4, 1, 8, 4)), DocumentationComment( (" foobar\n" " @param xyz\n"), docstyle_CPP_doxygen, "", docstyle_CPP_doxygen.markers[0], TextRange.from_values(15, 1, 17, 4)), DocumentationComment( " Some alternate style of documentation\n", docstyle_CPP_doxygen, "", docstyle_CPP_doxygen.markers[4], TextRange.from_values(22, 1, 23, 1)), DocumentationComment( " ends instantly", docstyle_CPP_doxygen, "\t", docstyle_CPP_doxygen.markers[0], TextRange.from_values(26, 2, 26, 23)), DocumentationComment( (" Should work\n" "\n" " even without a function standing below.\n" "\n" " @param foo WHAT PARAM PLEASE!?\n"), docstyle_CPP_doxygen, "", docstyle_CPP_doxygen.markers[4], TextRange.from_values(32, 1, 37, 1))))
def test_extract_documentation_C_2(self): data = ['/** my main description\n', ' * continues here */'] docstyle_C_doxygen = DocstyleDefinition.load('C', 'doxygen') self.assertEqual(list(extract_documentation(data, 'C', 'doxygen')), [ DocumentationComment( ' my main description\n continues here', docstyle_C_doxygen, '', docstyle_C_doxygen.markers[0], TextPosition(1, 1)) ])
def test_extract_documentation_CPP_2(self): data = DocumentationExtractionTest.load_testdata("data2.cpp") docstyle_CPP_doxygen = DocstyleDefinition.load("CPP", "doxygen") self.assertEqual(tuple(extract_documentation( data, "CPP", "doxygen")), (DocumentationComment( ("module comment\n" " hello world\n"), docstyle_CPP_doxygen.markers[0], TextRange.from_values(1, 1, 3, 4)), ))
def test_extract_documentation_CPP_2(self): data = load_testdata('data2.cpp') docstyle_CPP_doxygen = DocstyleDefinition.load('CPP', 'doxygen') self.assertEqual(tuple(extract_documentation( data, 'CPP', 'doxygen')), (DocumentationComment( ('module comment\n' ' hello world\n'), docstyle_CPP_doxygen, '', docstyle_CPP_doxygen.markers[0], TextPosition(1, 1)), ))
def test_extract_documentation_CPP(self): data = load_testdata('data.cpp') # No built-in documentation for C++. with self.assertRaises(KeyError): tuple(extract_documentation(data, 'CPP', 'default')) docstyle_CPP_doxygen = DocstyleDefinition.load('CPP', 'doxygen') self.assertEqual(tuple(extract_documentation(data, 'CPP', 'doxygen')), (DocumentationComment( ('\n' ' This is the main function.\n' ' @returns Exit code.\n' ' Or any other number.\n'), docstyle_CPP_doxygen, '', docstyle_CPP_doxygen.markers[0], TextRange.from_values(4, 1, 8, 4)), DocumentationComment( (' foobar\n' ' @param xyz\n'), docstyle_CPP_doxygen, '', docstyle_CPP_doxygen.markers[0], TextRange.from_values(15, 1, 17, 4)), DocumentationComment( ' Some alternate style of documentation\n', docstyle_CPP_doxygen, '', docstyle_CPP_doxygen.markers[4], TextRange.from_values(22, 1, 23, 1)), DocumentationComment( ' ends instantly', docstyle_CPP_doxygen, '\t', docstyle_CPP_doxygen.markers[0], TextRange.from_values(26, 2, 26, 23)), DocumentationComment( (' Should work\n' '\n' ' even without a function standing below.\n' '\n' ' @param foo WHAT PARAM PLEASE!?\n'), docstyle_CPP_doxygen, '', docstyle_CPP_doxygen.markers[4], TextRange.from_values(32, 1, 37, 1))))
def test_extract_documentation_C_2(self): data = ['/** my main description\n', ' * continues here */'] docstyle_C_doxygen = DocstyleDefinition.load("C", "doxygen") self.assertEqual( list(extract_documentation(data, "C", "doxygen")), [DocumentationComment(" my main description\n continues here", docstyle_C_doxygen.markers[0], TextRange.from_values(1, 1, 2, 21))])
def test_extract_documentation_C_2(self): data = ['/** my main description\n', ' * continues here */'] docstyle_C_doxygen = DocstyleDefinition.load("C", "doxygen") self.assertEqual(list(extract_documentation(data, "C", "doxygen")), [ DocumentationComment(" my main description\n continues here", "C", "doxygen", "", docstyle_C_doxygen.markers[0], TextRange.from_values(1, 1, 2, 21)) ])
def test_extract_documentation_CPP_2(self): data = DocumentationExtractionTest.load_testdata("data2.cpp") docstyle_CPP_doxygen = DocstyleDefinition.load("CPP", "doxygen") self.assertEqual(tuple(extract_documentation(data, "CPP", "doxygen")), (DocumentationComment( ("module comment\n" " hello world\n"), docstyle_CPP_doxygen.markers[0], TextRange.from_values(1, 1, 3, 4)),))
def test_extract_documentation_PYTHON3_2(self): data = ['\n', '""" documentation in single line """\n', 'print(1)\n'] docstyle_PYTHON3_default = DocstyleDefinition.load("PYTHON3", "default") self.assertEqual( list(extract_documentation(data, "PYTHON3", "default")), [DocumentationComment(" documentation in single line ", docstyle_PYTHON3_default.markers[0], TextRange.from_values(2, 1, 2, 38))])
def test_extract_documentation_PYTHON3_3(self): data = ['## documentation in single line without return at end.'] docstyle_PYTHON3_doxygen = DocstyleDefinition.load("PYTHON3", "doxygen") self.assertEqual( list(extract_documentation(data, "PYTHON3", "doxygen")), [DocumentationComment(" documentation in single line without " "return at end.", docstyle_PYTHON3_doxygen.markers[1], TextRange.from_values(1, 1, 1, 55))])
def test_extract_documentation_CPP_2(self): data = load_testdata('data2.cpp') docstyle_CPP_doxygen = DocstyleDefinition.load('CPP', 'doxygen') self.assertEqual(tuple(extract_documentation(data, 'CPP', 'doxygen')), (DocumentationComment( ('module comment\n' ' hello world\n'), docstyle_CPP_doxygen, '', docstyle_CPP_doxygen.markers[0], TextRange.from_values(1, 1, 3, 4)),))
def test_extract_documentation_PYTHON3_4(self): data = [ '\n', 'triple_quote_string_test = """\n', 'This is not a docstring\n', '"""\n' ] docstyle_PYTHON3_default = DocstyleDefinition.load( 'PYTHON3', 'default') # Nothing is yielded as triple quote string literals are being # ignored. self.assertEqual( list(extract_documentation(data, 'PYTHON3', 'default')), [])
def test_extract_documentation_PYTHON3_3(self): data = ['## documentation in single line without return at end.'] docstyle_PYTHON3_doxygen = DocstyleDefinition.load( 'PYTHON3', 'doxygen') self.assertEqual( list(extract_documentation(data, 'PYTHON3', 'doxygen')), [ DocumentationComment( ' documentation in single line without ' 'return at end.', docstyle_PYTHON3_doxygen, '', docstyle_PYTHON3_doxygen.markers[1], TextPosition(1, 1)) ])
def test_extract_documentation_PYTHON3_2(self): data = ['\n', '""" documentation in single line """\n', 'print(1)\n'] docstyle_PYTHON3_default = DocstyleDefinition.load( 'PYTHON3', 'default') self.assertEqual( list(extract_documentation(data, 'PYTHON3', 'default')), [ DocumentationComment(' documentation in single line ', docstyle_PYTHON3_default, '', docstyle_PYTHON3_default.markers[0], TextPosition(2, 1)) ])
def test_extract_documentation_C(self): data = load_testdata('data.c') # No built-in documentation for C. with self.assertRaises(KeyError): tuple(extract_documentation(data, 'C', 'default')) docstyle_C_doxygen = DocstyleDefinition.load('C', 'doxygen') expected_results = (DocumentationComment( ('\n' ' This is the main function.\n' '\n' ' @returns Your favorite number.\n'), docstyle_C_doxygen, '', docstyle_C_doxygen.markers[0], TextRange.from_values(3, 1, 7, 4)), DocumentationComment( ('\n' ' Preserves alignment\n' ' - Main item\n' ' - sub item\n' ' - sub sub item\n'), docstyle_C_doxygen, '', docstyle_C_doxygen.markers[2], TextRange.from_values(15, 1, 20, 4)), DocumentationComment( (' ABC\n' ' Another type of comment\n' '\n' ' ...'), docstyle_C_doxygen, '', docstyle_C_doxygen.markers[1], TextRange.from_values(23, 1, 26, 11)), DocumentationComment( (' foobar = barfoo.\n' ' @param x whatever...\n'), docstyle_C_doxygen, '', docstyle_C_doxygen.markers[0], TextRange.from_values(28, 1, 30, 4))) self.assertEqual(tuple(extract_documentation(data, 'C', 'doxygen')), expected_results)
def test_from_metadata(self): data = load_testdata("default.py") original = list(extract_documentation(data, "python", "default")) parsed_docs = [(doc.parse(), doc.marker, doc.indent, doc.range) for doc in original] docstyle_definition = DocstyleDefinition.load("python", "default") assembled_docs = [DocumentationComment.from_metadata( doc[0], docstyle_definition, doc[1], doc[2], doc[3]) for doc in parsed_docs] self.assertEqual(assembled_docs, original)
def test_go_default(self): data = load_testdata('default.go') parsed_docs = [doc.parse() for doc in extract_documentation(data, 'golang', 'golang')] expected = [['\n', 'Comments may span\n', 'multiple lines\n'], ['A class comment\n', 'that also spans\n', 'multiple lines\n'], ['More documentation for everyone, but in one line\n']] self.assertEqual(expected, parsed_docs)
def test_from_metadata(self): data = load_testdata('default.py') original = list(extract_documentation(data, 'python', 'default')) parsed_docs = [(doc.parse(), doc.marker, doc.indent, doc.position) for doc in original] docstyle_definition = DocstyleDefinition.load('python', 'default') assembled_docs = [DocumentationComment.from_metadata( doc[0], docstyle_definition, doc[1], doc[2], doc[3]) for doc in parsed_docs] self.assertEqual(assembled_docs, original)
def test_java_default(self): data = load_testdata('default.java') parsed_docs = [doc.parse() for doc in extract_documentation(data, 'java', 'default')] expected = [[self.Description( desc='\n Returns an String that says Hello with the name' ' argument.\n\n'), self.Parameter(name='name', desc='the name to which to say hello\n'), self.ReturnValue( desc=' the concatenated string\n')]] self.assertEqual(expected, parsed_docs)
def test_java_default(self): data = load_testdata("default.java") parsed_docs = [doc.parse() for doc in extract_documentation(data, "java", "default")] expected = [[self.Description( desc='\n Returns an String that says Hello with the name' ' argument.\n\n'), self.Parameter(name='name', desc='the name to which to say hello\n'), self.ReturnValue( desc=' the concatenated string\n')]] self.assertEqual(expected, parsed_docs)
def test_python_default(self): data = load_testdata('default.py') parsed_docs = [doc.parse() for doc in extract_documentation(data, 'python', 'default')] expected = [ [self.Description(desc='\nModule description.\n\n' 'Some more foobar-like text.\n')], [self.Description(desc='\nA nice and neat way of ' 'documenting code.\n'), self.Parameter(name='radius', desc=' The explosion radius. ')], [self.Description(desc='A function that returns 55.')], [self.Description(desc='\nDocstring with layouted text.\n\n ' 'layouts inside docs are preserved.' '\nthis is intended.\n')], [self.Description(desc=' Docstring inline with triple quotes.\n' ' Continues here. ')], [self.Description(desc='\nThis is the best docstring ever!\n\n'), self.Parameter(name='param1', desc='\n Very Very Long Parameter ' 'description.\n'), self.Parameter(name='param2', desc='\n Short Param description.\n\n'), self.ReturnValue(desc=' Long Return Description That Makes No ' 'Sense And Will\n Cut to the Next' ' Line.\n')], [self.Description(desc='\nThis is dummy docstring find ' 'function.\n\n'), self.Parameter(name='filename', desc='\n contains filename\n'), self.ExceptionValue(name='FileNotFoundError', desc='\n raised when the given ' 'file name was not found\n\n'), self.ReturnValue(desc=' returns all possible docstrings' ' in a file\n')], [self.Description(desc='\nThis returns perimeter ' 'of a triangle. \n\n'), self.Parameter(name='side_A', desc='\n length of side_A \n'), self.Parameter(name='side_B', desc='\n length of side_B \n'), self.Parameter(name='side_C', desc='\n length of side_C \n\n'), self.ReturnValue(desc=' returns perimeter\n')], ] self.assertEqual(parsed_docs, expected)
def test_python_doxygen(self): data = load_testdata("doxygen.py") parsed_docs = [doc.parse() for doc in extract_documentation(data, "python", "doxygen")] expected = [ [self.Description(desc=' @package pyexample\n Documentation for' ' this module.\n\n More details.\n')], [self.Description( desc=' Documentation for a class.\n\n More details.\n')], [self.Description(desc=' The constructor.\n')], [self.Description(desc=' Documentation for a method.\n'), self.Parameter(name='self', desc='The object pointer.\n')], [self.Description(desc=' A class variable.\n')], [self.Description(desc=' @var _memVar\n a member variable\n')], [self.Description(desc=' This is the best docstring ever!\n\n'), self.Parameter(name='param1', desc='Parameter 1\n'), self.Parameter(name='param2', desc='Parameter 2\n'), self.ReturnValue(desc='Nothing\n')]] self.assertEqual(parsed_docs, expected)
def test_python_assembly(self): data = load_testdata('default.py') docs = ''.join(data) for doc in extract_documentation(data, 'python', 'default'): self.assertIn(doc.assemble(), docs)
def test_extract_documentation_invalid_input(self): with self.assertRaises(FileNotFoundError): tuple(extract_documentation('', 'PYTHON', 'INVALID'))
def test_extract_documentation_PYTHON3(self): data = load_testdata('data.py') docstyle_PYTHON3_default = DocstyleDefinition.load('PYTHON3', 'default') docstyle_PYTHON3_doxygen = DocstyleDefinition.load('PYTHON3', 'doxygen') expected = (DocumentationComment( ('\n' 'Module description.\n' '\n' 'Some more foobar-like text.\n'), docstyle_PYTHON3_default, '', docstyle_PYTHON3_default.markers[0], TextRange.from_values(1, 1, 5, 4)), DocumentationComment( ('\n' 'A nice and neat way of documenting code.\n' ':param radius: The explosion radius.\n'), docstyle_PYTHON3_default, ' ' * 4, docstyle_PYTHON3_default.markers[0], TextRange.from_values(8, 5, 11, 8)), DocumentationComment( '\nA function that returns 55.\n', docstyle_PYTHON3_default, ' ' * 8, docstyle_PYTHON3_default.markers[0], TextRange.from_values(13, 9, 15, 12)), DocumentationComment( ('\n' 'Docstring with layouted text.\n' '\n' ' layouts inside docs are preserved for these ' 'documentation styles.\n' 'this is intended.\n'), docstyle_PYTHON3_default, '', docstyle_PYTHON3_default.markers[0], TextRange.from_values(19, 1, 24, 4)), DocumentationComment( (' Docstring directly besides triple quotes.\n' ' Continues here. '), docstyle_PYTHON3_default, '', docstyle_PYTHON3_default.markers[0], TextRange.from_values(26, 1, 27, 24)), DocumentationComment( ('super\n' ' nicely\n' 'short'), docstyle_PYTHON3_default, '', docstyle_PYTHON3_default.markers[0], TextRange.from_values(40, 1, 42, 9))) self.assertEqual( tuple(extract_documentation(data, 'PYTHON3', 'default')), expected) # Change only the docstyle in expected results. expected = list(DocumentationComment(r.documentation, docstyle_PYTHON3_doxygen, r.indent, r.marker, r.range) for r in expected) expected.insert(5, DocumentationComment( (' Alternate documentation style in doxygen.\n' ' Subtext\n' ' More subtext (not correctly aligned)\n' ' sub-sub-text\n' '\n'), docstyle_PYTHON3_doxygen, '', docstyle_PYTHON3_doxygen.markers[1], TextRange.from_values(30, 1, 35, 1))) self.assertEqual( list(extract_documentation(data, 'PYTHON3', 'doxygen')), expected)
def test_c_assembly(self): data = load_testdata('default.c') docs = ''.join(data) for doc in extract_documentation(data, 'c', 'doxygen'): self.assertIn(doc.assemble(), docs)
def test_doxygen_assembly(self): data = load_testdata('doxygen.py') docs = ''.join(data) for doc in extract_documentation(data, 'python', 'doxygen'): self.assertIn(doc.assemble(), docs)
def run(self, filename, file, language: str, docstyle: str = 'default', allow_missing_func_desc: str = False, indent_size: int = 4): """ Checks for certain in-code documentation styles. It currently checks for the following style: :: The first line needs to have no indentation. - Following lines can have indentation :param x: 4 space indent :return: also 4 space indent following lines are also 4 space indented :param language: The programming language of the file(s). :param docstyle: The docstyle to use. For example ``default`` or ``doxygen``. Docstyles are language dependent, meaning not every language is supported by a certain docstyle. :param allow_missing_func_desc: When set ``True`` this will allow functions with missing descriptions, allowing functions to start with params. :param indent_size: Number of spaces per indentation level. """ for doc_comment in extract_documentation(file, language, docstyle): parsed = doc_comment.parse() metadata = iter(parsed) # Assuming that the first element is always the only main # description. main_description = next(metadata) if main_description.desc == '\n' and not allow_missing_func_desc: warning_desc = """ Missing function description. Please set allow_missing_func_desc = True to ignore this warning. """ else: warning_desc = 'Documentation does not have correct style.' # one empty line shall follow main description (except it's empty # or no annotations follow). if main_description.desc.strip() != '': main_description = main_description._replace( desc='\n' + main_description.desc.strip() + '\n' * (1 if len(parsed) == 1 else 2)) new_metadata = [main_description] for m in metadata: # Split newlines and remove leading and trailing whitespaces. stripped_desc = list(map(str.strip, m.desc.splitlines())) if len(stripped_desc) == 0: # Annotations should be on their own line, though no # further description follows. stripped_desc.append('') else: # Wrap parameter description onto next line if it follows # annotation directly. if stripped_desc[0] != '': stripped_desc.insert(0, '') # Indent with 4 spaces. stripped_desc = ('' if line == '' else ' ' * indent_size + line for line in stripped_desc) new_desc = '\n'.join(stripped_desc) # Strip away trailing whitespaces and obsolete newlines (except # one newline which is mandatory). new_desc = new_desc.rstrip() + '\n' new_metadata.append(m._replace(desc=new_desc.lstrip(' '))) new_comment = DocumentationComment.from_metadata( new_metadata, doc_comment.docstyle_definition, doc_comment.marker, doc_comment.indent, doc_comment.position) if new_comment != doc_comment: # Something changed, let's apply a result. diff = Diff(file) # We need to update old comment positions, as `assemble()` # prepends indentation for first line. old_range = TextRange.from_values(doc_comment.range.start.line, 1, doc_comment.range.end.line, doc_comment.range.end.column) diff.replace(old_range, new_comment.assemble()) yield Result(origin=self, message=warning_desc, affected_code=(diff.range(filename), ), diffs={filename: diff})
def test_extract_documentation_PYTHON3(self): data = load_testdata('data.py') docstyle_PYTHON3_default = DocstyleDefinition.load( 'PYTHON3', 'default') docstyle_PYTHON3_doxygen = DocstyleDefinition.load( 'PYTHON3', 'doxygen') expected = ( DocumentationComment(('\n' 'Module description.\n' '\n' 'Some more foobar-like text.\n'), docstyle_PYTHON3_default, '', docstyle_PYTHON3_default.markers[0], TextPosition(1, 1)), DocumentationComment(('\n' 'A nice and neat way of documenting code.\n' ':param radius: The explosion radius.\n'), docstyle_PYTHON3_default, ' ' * 4, docstyle_PYTHON3_default.markers[0], TextPosition(8, 5)), DocumentationComment('\nA function that returns 55.\n', docstyle_PYTHON3_default, ' ' * 8, docstyle_PYTHON3_default.markers[0], TextPosition(13, 9)), DocumentationComment( ('\n' 'Docstring with layouted text.\n' '\n' ' layouts inside docs are preserved for these ' 'documentation styles.\n' 'this is intended.\n'), docstyle_PYTHON3_default, '', docstyle_PYTHON3_default.markers[0], TextPosition(19, 1)), DocumentationComment( (' Docstring directly besides triple quotes.\n' ' Continues here. '), docstyle_PYTHON3_default, '', docstyle_PYTHON3_default.markers[0], TextPosition(26, 1)), DocumentationComment(('super\n' ' nicely\n' 'short'), docstyle_PYTHON3_default, '', docstyle_PYTHON3_default.markers[0], TextPosition(40, 1)), DocumentationComment(('\n' 'A bad indented docstring\n' ' Improper indentation.\n' ':param impact: The force of Impact.\n'), docstyle_PYTHON3_default, ' ' * 4, docstyle_PYTHON3_default.markers[0], TextPosition(45, 5)), ) self.assertEqual( tuple(extract_documentation(data, 'PYTHON3', 'default')), expected) # Change only the docstyle in expected results. expected = list( DocumentationComment(r.documentation, docstyle_PYTHON3_doxygen, r.indent, r.marker, r.position) for r in expected) expected.insert( 5, DocumentationComment( (' Alternate documentation style in doxygen.\n' ' Subtext\n' ' More subtext (not correctly aligned)\n' ' sub-sub-text\n' '\n'), docstyle_PYTHON3_doxygen, '', docstyle_PYTHON3_doxygen.markers[1], TextPosition(30, 1))) self.assertEqual( list(extract_documentation(data, 'PYTHON3', 'doxygen')), expected)
def test_c_assembly(self): data = load_testdata("default.c") docs = "".join(data) for doc in extract_documentation(data, "c", "doxygen"): self.assertIn(doc.assemble(), docs)
def test_extract_documentation_invalid_input(self): with self.assertRaises(FileNotFoundError): tuple(extract_documentation("", "PYTHON", "INVALID"))
def test_python_assembly(self): data = load_testdata("default.py") docs = "".join(data) for doc in extract_documentation(data, "python", "default"): self.assertIn(doc.assemble(), docs)
def test_extract_documentation_PYTHON3(self): data = DocumentationExtractionTest.load_testdata("data.py") docstyle_PYTHON3_default = DocstyleDefinition.load("PYTHON3", "default") docstyle_PYTHON3_doxygen = DocstyleDefinition.load("PYTHON3", "doxygen") expected = (DocumentationComment( ("\n" "Module description.\n" "\n" "Some more foobar-like text.\n"), docstyle_PYTHON3_default.markers[0], TextRange.from_values(1, 1, 5, 4)), DocumentationComment( ("\n" "A nice and neat way of documenting code.\n" ":param radius: The explosion radius.\n"), docstyle_PYTHON3_default.markers[0], TextRange.from_values(8, 5, 11, 8)), DocumentationComment( ("\n" "Docstring with layouted text.\n" "\n" " layouts inside docs are preserved for these " "documentation styles.\n" "this is intended.\n"), docstyle_PYTHON3_default.markers[0], TextRange.from_values(14, 1, 19, 4)), DocumentationComment( (" Docstring directly besides triple quotes.\n" " Continues here. "), docstyle_PYTHON3_default.markers[0], TextRange.from_values(21, 1, 22, 24)), DocumentationComment( ("super\n" " nicely\n" "short"), docstyle_PYTHON3_default.markers[0], TextRange.from_values(35, 1, 37, 9))) self.assertEqual( tuple(extract_documentation(data, "PYTHON3", "default")), expected) # Change only the docstyle in expected results. expected = list(DocumentationComment(r.documentation, r.marker, r.range) for r in expected) expected.insert(4, DocumentationComment( (" Alternate documentation style in doxygen.\n" " Subtext\n" " More subtext (not correctly aligned)\n" " sub-sub-text\n" "\n"), docstyle_PYTHON3_doxygen.markers[1], TextRange.from_values(25, 1, 30, 1))) self.assertEqual( list(extract_documentation(data, "PYTHON3", "doxygen")), expected)