def test_treat_non_integer_line_execution_count_as_zero(self): converter = LcovCobertura( 'SF:foo/file.ext\nDA:1,=====\nDA:2,2\nBRDA:1,1,1,1\nBRDA:1,1,2,0\nend_of_record\n' ) result = converter.parse() self.assertEqual(result['packages']['foo']['lines-covered'], 1) self.assertEqual(result['packages']['foo']['lines-total'], 2)
def test_generate_cobertura_xml(self): converter = LcovCobertura( 'TN:\nSF:foo/file.ext\nDA:1,1\nDA:2,0\nBRDA:1,1,1,1\nBRDA:1,1,2,0\nFN:1,(anonymous_1)\nFN:2,namedFn\nFNDA:1,(anonymous_1)\nend_of_record\n') parsed_lcov = {'packages': { 'foo': {'branches-covered': 1, 'line-rate': '0.5', 'branch-rate': '0.5', 'lines-covered': 1, 'branches-total': 2, 'lines-total': 2, 'classes': { 'Bar': {'branches-covered': 1, 'lines-covered': 1, 'branches-total': 2, 'methods': { '(anonymous_1)': '1', 'namedFn': '0' }, 'lines': { 1: {'hits': '1', 'branches-covered': 1, 'branches-total': 2, 'branch': 'true'}, 2: {'hits': '0', 'branches-covered': 0, 'branches-total': 0, 'branch': 'false'} }, 'lines-total': 2, 'name': 'file.ext'}}, }}, 'summary': {'branches-covered': 1, 'branches-total': 2, 'lines-covered': 1, 'lines-total': 2}, 'timestamp': '1346815648000'} xml = converter.generate_cobertura_xml(parsed_lcov) self.assertEqual(xml, '<?xml version="1.0" ?>\n<!DOCTYPE coverage\n SYSTEM \'http://cobertura.sourceforge.net/xml/coverage-03.dtd\'>\n<coverage branch-rate="0.5" branches-covered="1" branches-valid="2" complexity="0" line-rate="0.5" lines-valid="2" timestamp="1346815648000" version="1.9">\n\t<sources>\n\t\t<source>.</source>\n\t</sources>\n\t<packages>\n\t\t<package branch-rate="0.5" line-rate="0.5" name="foo">\n\t\t\t<classes>\n\t\t\t\t<class branch-rate="0.5" complexity="0" filename="Bar" line-rate="0.5" name="file.ext">\n\t\t\t\t\t<methods>\n\t\t\t\t\t\t<method hits="0" name="namedFn" signature=""/>\n\t\t\t\t\t\t<method hits="1" name="(anonymous_1)" signature=""/>\n\t\t\t\t\t</methods>\n\t\t\t\t\t<lines>\n\t\t\t\t\t\t<line branch="true" condition-coverage="50% (1/2)" hits="1" number="1"/>\n\t\t\t\t\t\t<line branch="false" hits="0" number="2"/>\n\t\t\t\t\t</lines>\n\t\t\t\t</class>\n\t\t\t</classes>\n\t\t</package>\n\t</packages>\n</coverage>\n')
def main(args): # Auto set arguments if none were provided # If no sourcefile was provided, find the test-coverage.info file. # This assumes that the first file found is the desired one, so if multiple # exist then the sourceFile must be specified on the command line. if not args.sourceFile: f = glob.glob('**/test-coverage.info', recursive=True) if f: sourceFile = f[0] else: sys.exit("No lcov output file found below current directory.") else: sourceFile = args.sourceFile # If no output file was provided, then place it in the same directory as # the source file. if not args.outFile: outFile = os.path.dirname(sourceFile) + '/test-coverage.xml' else: outFile = args.outFile # Read all the data from the lcov output file with open(sourceFile) as fr: data = fr.read() # Create a converter and convert coverage data converter = LcovCobertura(data) res = converter.convert() # Write all output data to the destination file. with open(outFile, 'w') as fw: fw.write(res)
def test_generate_cobertura_xml(self): converter = LcovCobertura( 'TN:\nSF:foo/file.ext\nDA:1,1\nDA:2,0\nBRDA:1,1,1,1\nBRDA:1,1,2,0\nFN:1,(anonymous_1)\nFN:2,namedFn\nFNDA:1,(anonymous_1)\nend_of_record\n') parsed_lcov = {'packages': { 'foo': {'branches-covered': 1, 'line-rate': '0.5', 'branch-rate': '0.5', 'lines-covered': 1, 'branches-total': 2, 'lines-total': 2, 'classes': { 'Bar': {'branches-covered': 1, 'lines-covered': 1, 'branches-total': 2, 'methods': { '(anonymous_1)': ['1', '1'], 'namedFn': ['2', '0'] }, 'lines': { 1: {'hits': '1', 'branches-covered': 1, 'branches-total': 2, 'branch': 'true'}, 2: {'hits': '0', 'branches-covered': 0, 'branches-total': 0, 'branch': 'false'} }, 'lines-total': 2, 'name': 'file.ext'}}, }}, 'summary': {'branches-covered': 1, 'branches-total': 2, 'lines-covered': 1, 'lines-total': 2}, 'timestamp': '1346815648000'} xml = converter.generate_cobertura_xml(parsed_lcov) self.assertEqual(xml, '<?xml version="1.0" ?>\n<!DOCTYPE coverage\n SYSTEM \'http://cobertura.sourceforge.net/xml/coverage-04.dtd\'>\n<coverage branch-rate="0.5" branches-covered="1" branches-valid="2" complexity="0" line-rate="0.5" lines-covered="1" lines-valid="2" timestamp="1346815648000" version="2.0.3">\n\t<sources>\n\t\t<source>.</source>\n\t</sources>\n\t<packages>\n\t\t<package branch-rate="0.5" complexity="0" line-rate="0.5" name="foo">\n\t\t\t<classes>\n\t\t\t\t<class branch-rate="0.5" complexity="0" filename="Bar" line-rate="0.5" name="file.ext">\n\t\t\t\t\t<methods>\n\t\t\t\t\t\t<method branch-rate="0.0" line-rate="0.0" name="namedFn" signature="">\n\t\t\t\t\t\t\t<lines>\n\t\t\t\t\t\t\t\t<line branch="false" hits="0" number="2"/>\n\t\t\t\t\t\t\t</lines>\n\t\t\t\t\t\t</method>\n\t\t\t\t\t\t<method branch-rate="1.0" line-rate="1.0" name="(anonymous_1)" signature="">\n\t\t\t\t\t\t\t<lines>\n\t\t\t\t\t\t\t\t<line branch="false" hits="1" number="1"/>\n\t\t\t\t\t\t\t</lines>\n\t\t\t\t\t\t</method>\n\t\t\t\t\t</methods>\n\t\t\t\t\t<lines>\n\t\t\t\t\t\t<line branch="true" condition-coverage="50% (1/2)" hits="1" number="1"/>\n\t\t\t\t\t\t<line branch="false" hits="0" number="2"/>\n\t\t\t\t\t</lines>\n\t\t\t\t</class>\n\t\t\t</classes>\n\t\t</package>\n\t</packages>\n</coverage>\n')
def test_parse_with_functions(self): converter = LcovCobertura( 'TN:\nSF:foo/file.ext\nDA:1,1\nDA:2,0\nFN:1,(anonymous_1)\nFN:2,namedFn\nFNDA:1,(anonymous_1)\nend_of_record\n') result = converter.parse() self.assertEqual(result['packages']['foo']['line-rate'], '0.5') self.assertEqual(result['packages']['foo']['lines-covered'], 1) self.assertEqual(result['packages']['foo']['lines-total'], 2) self.assertEqual(result['packages']['foo']['classes']['foo/file.ext']['methods']['(anonymous_1)'], ['1', '1']) self.assertEqual(result['packages']['foo']['classes']['foo/file.ext']['methods']['namedFn'], ['2', '0'])
def test_exclude_package_from_parser(self): converter = LcovCobertura( 'SF:foo/file.ext\nDA:1,1\nDA:2,0\nend_of_record\nSF:bar/file.ext\nDA:1,1\nDA:2,1\nend_of_record\n', '.', 'foo') result = converter.parse() self.assertTrue('foo' not in result['packages']) self.assertTrue('bar' in result['packages']) # Verify that excluded package did not skew line coverage totals self.assertEqual(result['packages']['bar']['line-rate'], '1.0')
def test_parse_with_functions(self): converter = LcovCobertura( 'TN:\nSF:foo/file.ext\nDA:1,1\nDA:2,0\nFN:1,(anonymous_1)\nFN:2,namedFn\nFNDA:1,(anonymous_1)\nend_of_record\n') result = converter.parse() self.assertEqual(result['packages']['foo']['line-rate'], '0.5') self.assertEqual(result['packages']['foo']['lines-covered'], 1) self.assertEqual(result['packages']['foo']['lines-total'], 2) self.assertEqual(result['packages']['foo']['classes']['foo/file.ext']['methods']['(anonymous_1)'], '1') self.assertEqual(result['packages']['foo']['classes']['foo/file.ext']['methods']['namedFn'], '0')
def test_generate_cobertura_xml(self): converter = LcovCobertura( 'TN:\nSF:foo/file.ext\nDA:1,1\nDA:2,0\nBRDA:1,1,1,1\nBRDA:1,1,2,0\nFN:1,(anonymous_1)\nFN:2,namedFn\nFNDA:1,(anonymous_1)\nend_of_record\n' ) parsed_lcov = { 'packages': { 'foo': { 'branches-covered': 1, 'line-rate': '0.5', 'branch-rate': '0.5', 'lines-covered': 1, 'branches-total': 2, 'lines-total': 2, 'classes': { 'Bar': { 'branches-covered': 1, 'lines-covered': 1, 'branches-total': 2, 'methods': { '(anonymous_1)': ['1', '1'], 'namedFn': ['2', '0'] }, 'lines': { 1: { 'hits': '1', 'branches-covered': 1, 'branches-total': 2, 'branch': 'true' }, 2: { 'hits': '0', 'branches-covered': 0, 'branches-total': 0, 'branch': 'false' } }, 'lines-total': 2, 'name': 'file.ext' } }, } }, 'summary': { 'branches-covered': 1, 'branches-total': 2, 'lines-covered': 1, 'lines-total': 2 }, 'timestamp': '1346815648000' } xml = converter.generate_cobertura_xml(parsed_lcov) with open('cobertura_reference.xml', 'r') as cobertura_reference: self.assertEqual(xml, cobertura_reference.read())
def test_parse(self): converter = LcovCobertura( 'SF:foo/file.ext\nDA:1,1\nDA:2,0\nend_of_record\n') result = converter.parse() self.assertTrue(result.has_key('packages')) self.assertTrue(result['packages'].has_key('foo')) self.assertEqual(result['packages']['foo']['branches-covered'], 0) self.assertEqual(result['packages']['foo']['branches-total'], 0) self.assertEqual(result['packages']['foo']['line-rate'], '0.5') self.assertEqual(result['packages']['foo']['lines-covered'], 1) self.assertEqual(result['packages']['foo']['lines-total'], 2)
def main(argv): """ Converts LCOV coverage data to Cobertura-compatible XML for reporting. Usage: lcov_cobertura.py lcov-file.dat lcov_cobertura.py lcov-file.dat -b src/dir -e test.lib -o path/out.xml By default, XML output will be written to ./coverage.xml """ parser = OptionParser() parser.usage = 'lcov_cobertura.py lcov-file.dat [-b source/dir] [-e <exclude packages regex>] [-o output.xml]' parser.description = 'Converts lcov output to cobertura-compatible XML' parser.add_option('-b', '--base-dir', action='store', help='Directory where source files are located', dest='base_dir', default='.') parser.add_option( '-e', '--excludes', help='Comma-separated list of regexes of packages to exclude', action='append', dest='excludes', default=[]) parser.add_option('-o', '--output', help='Path to store cobertura xml file', action='store', dest='output', default='coverage.xml') (options, args) = parser.parse_args(args=argv) if len(args) != 2: print((main.__doc__)) sys.exit(1) try: with open(args[1], 'r') as lcov_file: lcov_data = lcov_file.read() lcov_cobertura = LcovCobertura(lcov_data, options.base_dir, options.excludes) cobertura_xml = lcov_cobertura.convert() with open(options.output, mode='wt') as output_file: output_file.write(cobertura_xml) except IOError: sys.stderr.write("Unable to convert %s to Cobertura XML" % args[1])
def test_parse(self): converter = LcovCobertura( 'SF:foo/file.ext\nDA:1,1\nDA:2,0\nBRDA:1,1,1,1\nBRDA:1,1,2,0\nend_of_record\n') result = converter.parse() self.assertTrue('packages' in result) self.assertTrue('foo' in result['packages']) self.assertEqual(result['packages']['foo']['branches-covered'], 1) self.assertEqual(result['packages']['foo']['branches-total'], 2) self.assertEqual(result['packages']['foo']['branch-rate'], '0.5') self.assertEqual(result['packages']['foo']['line-rate'], '0.5') self.assertEqual(result['packages']['foo']['lines-covered'], 1) self.assertEqual(result['packages']['foo']['lines-total'], 2) self.assertEqual(result['packages']['foo']['classes']['foo/file.ext']['branches-covered'], 1) self.assertEqual(result['packages']['foo']['classes']['foo/file.ext']['branches-total'], 2) self.assertEqual(result['packages']['foo']['classes']['foo/file.ext']['methods'], {})
def test_generate_cobertura_xml(self): converter = LcovCobertura( 'SF:foo/file.ext\nDA:1,1\nDA:2,0\nend_of_record\n') parsed_lcov = {'packages': { 'foo': {'branches-covered': 0, 'line-rate': '0.5', 'lines-covered': 1, 'branches-total': 0, 'lines-total': 2, 'classes': { 'Bar': {'branches-covered': 0, 'lines-covered': 1, 'branches-total': 0, 'lines': { 1: {'hits': '1', 'branch-conditions-covered': 0, 'branch-conditions-total': 0, 'branch': 'false'}, 2: {'hits': '0', 'branch-conditions-covered': 0, 'branch-conditions-total': 0, 'branch': 'false'}}, 'lines-total': 2, 'name': 'file.ext'}}, 'branch-rate': '0.0'}}, 'summary': {'branches-covered': 0, 'branches-total': 0, 'lines-covered': 1, 'lines-total': 2}, 'timestamp': '1346815648'} xml = converter.generate_cobertura_xml(parsed_lcov) self.assertEqual(xml, '<?xml version="1.0" ?>\n<!DOCTYPE coverage\n SYSTEM \'http://cobertura.sourceforge.net/xml/coverage-03.dtd\'>\n<coverage branch-rate="0.0" branches-covered="0" branches-valid="0" complexity="0" line-rate="0.5" lines-valid="2" timestamp="1346815648" version="1.9">\n\t<sources/>\n\t<packages>\n\t\t<package branch-rate="0.0" line-rate="0.5" name="foo">\n\t\t\t<classes>\n\t\t\t\t<class branch-rate="0.0" complexity="0" filename="Bar" line-rate="0.5" name="file.ext">\n\t\t\t\t\t<lines>\n\t\t\t\t\t\t<line branch="false" hits="1" number="1"/>\n\t\t\t\t\t\t<line branch="false" hits="0" number="2"/>\n\t\t\t\t\t</lines>\n\t\t\t\t</class>\n\t\t\t</classes>\n\t\t</package>\n\t</packages>\n</coverage>\n')
def main(argv): """ Converts LCOV coverage data to Cobertura-compatible XML for reporting. Usage: lcov_cobertura.py lcov-file.dat lcov_cobertura.py lcov-file.dat -b src/dir -e test.lib -o path/out.xml By default, XML output will be written to ./coverage.xml """ parser = OptionParser() parser.usage = 'lcov_cobertura.py lcov-file.dat [-b source/dir] [-e <exclude packages regex>] [-o output.xml]' parser.description = 'Converts lcov output to cobertura-compatible XML' parser.add_option('-b', '--base-dir', action='store', help='Directory where source files are located', dest='base_dir', default='.') parser.add_option('-e', '--excludes', help='Comma-separated list of regexes of packages to exclude', action='append', dest='excludes', default=[]) parser.add_option('-o', '--output', help='Path to store cobertura xml file', action='store', dest='output', default='coverage.xml') (options, args) = parser.parse_args(args=argv) if len(args) != 2: print((main.__doc__)) sys.exit(1) try: with open(args[1], 'r') as lcov_file: lcov_data = lcov_file.read() lcov_cobertura = LcovCobertura(lcov_data, options.base_dir, options.excludes) cobertura_xml = lcov_cobertura.convert() with open(options.output, mode='wt') as output_file: output_file.write(cobertura_xml) except IOError: sys.stderr.write("Unable to convert %s to Cobertura XML" % args[1])
def parse_lcov_coverage_data(cov_data: str, toc: List[str]) -> types.CoverageData: converter = LcovCobertura(cov_data) cobertura_xml = converter.convert() return parse_xml_coverage_data(cobertura_xml, toc)
def collect(self): from lcov_cobertura import LcovCobertura # Check if file exists source = Path(self.config.source.value) if not source.exists(): raise FileNotFoundError( 'No such file or directory {}'.format(source) ) source = source.resolve() # Check if lcov is available lcov = which('lcov') if lcov is None: raise FileNotFoundError('lcov executable not found.') # Transform from list to something like # --rc setting1=value1 --rc setting2=value2 rc_overrides = '' if self.config.rc_overrides.value: rc_overrides = '--rc {}'.format( ' --rc '.join(self.config.rc_overrides.value) ) # Load remove patterns remove = self.config.remove.value for remove_file in self.config.remove_files.value: for pattern in load_filter_file(remove_file): if pattern not in remove: remove.append(pattern) # Load extract patterns extract = self.config.extract.value for extract_file in self.config.extract_files.value: for pattern in load_filter_file(extract_file): if pattern not in extract: extract.append(pattern) # Check if --derive-func-data is needed derive_func_data = '--derive-func-data' \ if self.config.derive_func_data.value else '' if source.is_dir(): # Create a temporary file. Close it, we just need the name. tmp_file = NamedTemporaryFile(suffix='.info') tmp_file.close() tracefile = Path(tmp_file.name) cmd = ( '{lcov} ' '{rc_overrides} ' '{derive_func_data} ' '--directory {directory} --capture ' '--output-file {tracefile}'.format( lcov=lcov, rc_overrides=rc_overrides, derive_func_data=derive_func_data, directory=source, tracefile=tracefile ) ) log.info('Gathering coverage info: "{}"'.format(cmd)) status = run(cmd) if status.returncode != 0: raise RuntimeError( 'Lcov failed capturing data:\n{}'.format(status.stderr) ) else: # Check file extension if source.suffix != '.info': raise ValueError( 'Unknown file extension "{}" ' 'for a tracefile. Must be ".info"'.format(source.suffix) ) tracefile = source result = { 'tracefile': str(tracefile), } # Remove files from patterns if remove: cmd = ( '{lcov} ' '{rc_overrides} ' '{derive_func_data} ' '--remove {tracefile} {remove} ' '--output-file {tracefile}'.format( lcov=lcov, rc_overrides=rc_overrides, derive_func_data=derive_func_data, tracefile=tracefile, remove=' '.join( '"{}"'.format(e) for e in remove ) ) ) log.info('Removing files: "{}"'.format(cmd)) status = run(cmd) if status.returncode != 0: raise RuntimeError( 'Lcov failed removing files from coverage:\n{}'.format( status.stderr ) ) # Extract files from patterns if extract: cmd = ( '{lcov} ' '{rc_overrides} ' '{derive_func_data} ' '--extract {tracefile} {extract} ' '--output-file {tracefile}'.format( lcov=lcov, rc_overrides=rc_overrides, derive_func_data=derive_func_data, tracefile=tracefile, extract=' '.join( '"{}"'.format(e) for e in extract ) ) ) log.info('Extracting files: "{}"'.format(cmd)) status = run(cmd) if status.returncode != 0: raise RuntimeError( 'Lcov failed extracting files from coverage:\n{}'.format( status.stderr ) ) # Create cobertura xml file and parse it converter = LcovCobertura(tracefile.open().read()) cobertura_xml = converter.convert() with NamedTemporaryFile(delete=False, suffix='.xml') as xml: xml.write(cobertura_xml.encode('utf-8')) cobertura_src = CoberturaSource( self._index, 'cobertura', self._id, config={ 'xmlpath': str(xml.name) } ) result.update(cobertura_src.collect()) return result
def test_treat_non_integer_line_execution_count_as_zero(self): converter = LcovCobertura( 'SF:foo/file.ext\nDA:1,=====\nDA:2,2\nBRDA:1,1,1,1\nBRDA:1,1,2,0\nend_of_record\n') result = converter.parse() self.assertEqual(result['packages']['foo']['lines-covered'], 1) self.assertEqual(result['packages']['foo']['lines-total'], 2)
def test_colon_in_function_name(self): converter = LcovCobertura( 'TN:\nSF:foo/file.ext\nDA:1,1\nDA:2,0\nBRDA:1,1,1,1\nBRDA:1,1,2,0\nFN:1,(anonymous_1)\nFN:2,[className namedFn: withColon:]\nFNDA:1,(anonymous_1)\nend_of_record\n') result = converter.parse() desired = result['packages']['foo']['classes']['foo/file.ext']['methods']['[className namedFn: withColon:]'] self.assertEqual(desired, '0')