# HG changeset patch # User cmlenz # Date 1129816488 0 # Node ID d83208ed2db9d08bb6ef50765bf96fc33d2bacb5 # Parent 86281f8eef44235ec8babd8bda45c65b2b46483f Change the way coverage statistics are collected, so that line number counting in covered and not covered files matches. Closes #67. diff --git a/bitten/build/pythontools.py b/bitten/build/pythontools.py --- a/bitten/build/pythontools.py +++ b/bitten/build/pythontools.py @@ -141,6 +141,43 @@ missing_files.append(filename) covered_modules = set() + def handle_file(elem, sourcefile, coverfile=None): + code_lines = set() + for lineno, linetype, line in loc.count(sourcefile): + if linetype == loc.CODE: + code_lines.add(lineno) + num_covered = 0 + lines = [] + if coverfile: + prev_hits = '0' + for idx, coverline in enumerate(coverfile): + match = coverage_line_re.search(coverline) + if match: + hits = match.group(1) + if hits: # Line covered + if hits != '0': + num_covered += 1 + lines.append(hits) + prev_hits = hits + elif coverline.startswith('>'): # Line not covered + lines.append('0') + prev_hits = '0' + elif idx not in code_lines: # Not a code line + lines.append('0') + prev_hits = '0' + else: # A code line not flagged by trace.py + if prev_hits != '0': + num_covered += 1 + lines.append(prev_hits) + + num_lines = len(lines) + percentage = int(round(num_covered / num_lines) * 100) + module.attr['percentage'] = str(percentage) + '%' + module.attr['lines'] = num_lines + module.append(xmlio.Element('line_hits')[' '.join(lines)]) + else: + module.attr['lines'] = len(code_lines) + try: summary_file = open(ctxt.resolve(summary), 'r') try: @@ -166,34 +203,22 @@ module = xmlio.Element('coverage', name=modname, file=filename.replace(os.sep, '/'), percentage=int(match.group(2))) - coverage_path = ctxt.resolve(coverdir, modname + '.cover') - if os.path.exists(coverage_path): - coverage_file = open(coverage_path, 'r') - lines = [] + sourcefile = file(ctxt.resolve(filename)) + try: + coverpath = ctxt.resolve(coverdir, modname + '.cover') + if os.path.isfile(coverpath): + coverfile = file(coverpath, 'r') + else: + log.warning('No coverage file for module %s at %s', + modname, coverpath) + coverfile = None try: - for coverage_line in coverage_file: - match = coverage_line_re.search(coverage_line) - if match: - hits = match.group(1) - if hits: - lines.append(hits) - else: - lines.append('0') + handle_file(module, sourcefile, coverfile) finally: - coverage_file.close() - module.attr['lines'] = len(lines) - module.append(xmlio.Element('line_hits')[ - ' '.join(lines) - ]) - else: - log.warning('No coverage file for module %s at %s', - modname, coverage_path) - - # Estimate total number of lines from covered lines and - # percentage - lines = int(match.group(1)) - percentage = int(match.group(2)) - module.attr['lines'] = lines * 100 / percentage + if coverfile: + coverfile.close() + finally: + sourcefile.close() coverage.append(module) for filename in missing_files: @@ -207,11 +232,7 @@ filepath = ctxt.resolve(filename) fileobj = file(filepath, 'r') try: - lines = 0 - for lineno, linetype, line in loc.count(fileobj): - if linetype == loc.CODE: - lines += 1 - module.attr['lines'] = lines + handle_file(module, fileobj) finally: fileobj.close() coverage.append(module) diff --git a/bitten/build/tests/pythontools.py b/bitten/build/tests/pythontools.py --- a/bitten/build/tests/pythontools.py +++ b/bitten/build/tests/pythontools.py @@ -74,8 +74,6 @@ self.assertEqual('coverage', child.name) self.assertEqual('test.module', child.attr['name']) self.assertEqual('test/module.py', child.attr['file']) - self.assertEqual(100, child.attr['percentage']) - self.assertEqual(60, child.attr['lines']) def test_summary_with_relative_path(self): self.summary.write(""" @@ -94,8 +92,6 @@ self.assertEqual('coverage', child.name) self.assertEqual('test.module', child.attr['name']) self.assertEqual('test/module.py', child.attr['file']) - self.assertEqual(100, child.attr['percentage']) - self.assertEqual(60, child.attr['lines']) class UnittestTestCase(unittest.TestCase):