summaryrefslogtreecommitdiff
path: root/coverage/xml.py
blob: 55fdc973d95e2f0f559052b83876e77e4eb794e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
"""Cobertura reporting for coverage.py"""

import os, sys
import xml.dom.minidom

from coverage.report import Reporter


class XmlReporter(Reporter):
    """A reporter for writing Cobertura-style XML coverage results."""
    
    def __init__(self, coverage, ignore_errors=False):
        super(XmlReporter, self).__init__(coverage, ignore_errors)

    def report(self, morfs, omit_prefixes=None, outfile=None):
        """Generate a Cobertura report for `morfs`.
        
        `morfs` is a list of modules or filenames.  `directory` is where to put
        the Cobertura XML file. `omit_prefixes` is a list of strings, prefixes of
        modules to omit from the report.
        
        """
        # Initial setup.
        if not outfile:
            outfile = sys.stdout
        self.find_code_units(morfs, omit_prefixes)

        # Create the DOM that will store the data.
        impl = xml.dom.minidom.getDOMImplementation()
        docType = impl.createDocumentType(
            "coverage", None,
            "http://cobertura.sourceforge.net/xml/coverage-03.dtd" )
        doc = impl.createDocument(None, "coverage", docType)
        root = doc.documentElement

        packageXml = doc.createElement("packages")
        root.appendChild(packageXml)
        packages = {}

        errors = False
        for cu in self.code_units:
            # Create the 'lines' and 'package' XML elements, which
            # are populated later.  Note that a package == a directory.
            (dir, fname) = os.path.split(cu.name)
            print "HERE",dir,":",fname
            if dir is '':
                dir = '.'
            package = packages.setdefault(
                dir, [ doc.createElement("package"), {},
                    0, 0, 0, 0 ] )
            c = doc.createElement("class")
            lines = doc.createElement("lines")
            c.appendChild(lines)
            className = fname.replace('.', '_')
            c.setAttribute("name", className)
            c.setAttribute("filename", cu.name)
            c.setAttribute("complexity", "0.0")


            try:
                statements, _, missing, readable = self.coverage._analyze(cu)

                # For each statement, create an XML 'line' element.
                for line in statements:
                    l = doc.createElement("line")
                    l.setAttribute("number", str(line))

                    # Q: can we get info about the number of times
                    # a statement is executed?  If so, that should be
                    # recorded here.
                    if not line in missing:
                        l.setAttribute("hits", str(1))

                    # Q: can we get info about whether this statement
                    # is a branch?  If so, that data should be
                    # used here.
                    l.setAttribute("branch", "false")
                    lines.appendChild(l)
                class_lines = 1.0*len(statements)
                class_hits = class_lines - len(missing)
                class_branches = 0.0
                class_branch_hits = 0.0

                # Finalize the statistics that are collected
                # in the XML DOM.
                c.setAttribute("line-rate", str(class_hits / (class_lines or 1.0)))
                c.setAttribute( "branch-rate", str(class_branch_hits / (class_branches or 1.0)) )
                package[1][className] = c
                package[2] += class_hits
                package[3] += class_lines
                package[4] += class_branch_hits
                package[5] += class_branches
            except KeyboardInterrupt:                       #pragma: no cover
                raise
            except:
                if not self.ignore_errors:
                    typ, msg = sys.exc_info()[:2]
                    fmt_err = "%s   %s: %s\n"
                    outfile.write(fmt_err % (cu.name, typ.__name__, msg))
                    errors=True
   
        # Don't write the XML data if we've encountered errors.
        if errors:
            return

        # Populate the XML DOM with the package info.
        for packageName, packageData in packages.items():
            package = packageData[0];
            packageXml.appendChild(package)
            classes = doc.createElement("classes")
            package.appendChild(classes)
            classNames = packageData[1].keys()
            classNames.sort()
            for className in classNames:
                classes.appendChild(packageData[1][className])
            package.setAttribute("name", packageName.replace(os.sep, '.'))
            package.setAttribute("line-rate", str(packageData[2]/(packageData[3] or 1.0)))
            package.setAttribute( "branch-rate", str(packageData[4] / (packageData[5] or 1.0) ))
            package.setAttribute("complexity", "0.0")

        # Use the DOM to write the output file.
        outfile.write(doc.toprettyxml())