changeset 291:d83208ed2db9

Change the way coverage statistics are collected, so that line number counting in covered and not covered files matches. Closes #67.
author cmlenz
date Thu, 20 Oct 2005 13:54:48 +0000
parents 86281f8eef44
children 3b9d79ef560f
files bitten/build/pythontools.py bitten/build/tests/pythontools.py
diffstat 2 files changed, 52 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- 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)
--- 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):
Copyright (C) 2012-2017 Edgewall Software