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
|
"""XML reporting for coverage.py"""
import os, sys
import xml.dom.minidom
from coverage import __url__, __version__
from coverage.backward import sorted # pylint: disable-msg=W0622
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)
self.packages = None
self.xml_out = None
def report(self, morfs, omit_prefixes=None, outfile=None):
"""Generate a Cobertura-compatible XML report for `morfs`.
`morfs` is a list of modules or filenames. `omit_prefixes` is a list
of strings, prefixes of modules to omit from the report.
"""
# Initial setup.
outfile = outfile or 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"
)
self.xml_out = impl.createDocument(None, "coverage", docType)
root = self.xml_out.documentElement
root.appendChild(self.xml_out.createComment(
" Generated by coverage.py %s: %s " % (__version__, __url__)
))
packageXml = self.xml_out.createElement("packages")
root.appendChild(packageXml)
self.packages = {}
errors = False
self.report_files(self.xml_file, morfs, omit_prefixes=omit_prefixes)
# 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 self.packages.items():
package = self.xml_out.createElement("package")
packageXml.appendChild(package)
classes = self.xml_out.createElement("classes")
package.appendChild(classes)
for className in sorted(packageData[0].keys()):
classes.appendChild(packageData[0][className])
package.setAttribute("name", packageName.replace(os.sep, '.'))
package.setAttribute("line-rate", str(packageData[1]/(packageData[2] or 1.0)))
package.setAttribute("branch-rate", str(packageData[3]/(packageData[4] or 1.0)))
package.setAttribute("complexity", "0.0")
# Use the DOM to write the output file.
outfile.write(self.xml_out.toprettyxml())
def xml_file(self, cu, statements, excluded, missing):
"""Add to the XML report for a single file."""
# Create the 'lines' and 'package' XML elements, which
# are populated later. Note that a package == a directory.
dirname, fname = os.path.split(cu.name)
dirname = dirname or '.'
package = self.packages.setdefault(dirname, [ {}, 0, 0, 0, 0 ])
c = self.xml_out.createElement("class")
lines = self.xml_out.createElement("lines")
c.appendChild(lines)
className = fname.replace('.', '_')
c.setAttribute("name", className)
c.setAttribute("filename", cu.filename)
c.setAttribute("complexity", "0.0")
# For each statement, create an XML 'line' element.
for line in statements:
l = self.xml_out.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.
l.setAttribute("hits", str(int(not line in missing)))
# 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.
line_rate = class_hits / (class_lines or 1.0)
branch_rate = class_branch_hits / (class_branches or 1.0)
c.setAttribute("line-rate", str(line_rate))
c.setAttribute("branch-rate", str(branch_rate))
package[0][className] = c
package[1] += class_hits
package[2] += class_lines
package[3] += class_branch_hits
package[4] += class_branches
|