summaryrefslogtreecommitdiff
path: root/coverage/xml.py
blob: acbd7124843786aa497cdbab2579605ae5a3f5cd (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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
"""Cobertura reporting"""

import os
import sys
import xml.dom.minidom

from coverage.report import Reporter


class CoberturaReporter(Reporter):
    """A reporter for writing the summary report."""
    
    def __init__(self, coverage, ignore_errors=False):
        super(CoberturaReporter, 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() )