diff -r 71f15675e89f -r 7f51ab29a1a2 DebugClients/Python/coverage/xmlreport.py --- a/DebugClients/Python/coverage/xmlreport.py Fri Apr 11 18:37:22 2014 +0200 +++ b/DebugClients/Python/coverage/xmlreport.py Thu Apr 10 23:02:20 2014 +0200 @@ -4,29 +4,30 @@ import xml.dom.minidom from . import __url__, __version__ -from .backward import sorted # pylint: disable-msg=W0622 +from .backward import sorted, rpartition # pylint: disable=W0622 from .report import Reporter def rate(hit, num): - """Return the fraction of `hit`/`num`.""" - return hit / (num or 1.0) + """Return the fraction of `hit`/`num`, as a string.""" + return "%.4g" % (float(hit) / (num or 1.0)) 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 __init__(self, coverage, config): + super(XmlReporter, self).__init__(coverage, config) self.packages = None self.xml_out = None self.arcs = coverage.data.has_arcs() - def report(self, morfs, omit_prefixes=None, outfile=None): + def report(self, morfs, 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. + `morfs` is a list of modules or filenames. + + `outfile` is a file object to write the XML to. """ # Initial setup. @@ -52,44 +53,54 @@ # Call xml_file for each file in the data. self.packages = {} - self.report_files(self.xml_file, morfs, omit_prefixes=omit_prefixes) + self.report_files(self.xml_file, morfs) lnum_tot, lhits_tot = 0, 0 bnum_tot, bhits_tot = 0, 0 # Populate the XML DOM with the package info. - for pkg_name, pkg_data in self.packages.items(): + for pkg_name in sorted(self.packages.keys()): + pkg_data = self.packages[pkg_name] class_elts, lhits, lnum, bhits, bnum = pkg_data xpackage = self.xml_out.createElement("package") xpackages.appendChild(xpackage) xclasses = self.xml_out.createElement("classes") xpackage.appendChild(xclasses) - for className in sorted(class_elts.keys()): - xclasses.appendChild(class_elts[className]) + for class_name in sorted(class_elts.keys()): + xclasses.appendChild(class_elts[class_name]) xpackage.setAttribute("name", pkg_name.replace(os.sep, '.')) - xpackage.setAttribute("line-rate", str(rate(lhits, lnum))) - xpackage.setAttribute("branch-rate", str(rate(bhits, bnum))) - xpackage.setAttribute("complexity", "0.0") + xpackage.setAttribute("line-rate", rate(lhits, lnum)) + xpackage.setAttribute("branch-rate", rate(bhits, bnum)) + xpackage.setAttribute("complexity", "0") lnum_tot += lnum lhits_tot += lhits bnum_tot += bnum bhits_tot += bhits - xcoverage.setAttribute("line-rate", str(rate(lhits_tot, lnum_tot))) - xcoverage.setAttribute("branch-rate", str(rate(bhits_tot, bnum_tot))) + xcoverage.setAttribute("line-rate", rate(lhits_tot, lnum_tot)) + xcoverage.setAttribute("branch-rate", rate(bhits_tot, bnum_tot)) # Use the DOM to write the output file. outfile.write(self.xml_out.toprettyxml()) + # Return the total percentage. + denom = lnum_tot + bnum_tot + if denom == 0: + pct = 0.0 + else: + pct = 100.0 * (lhits_tot + bhits_tot) / denom + return pct + def xml_file(self, cu, analysis): """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 ]) + package_name = rpartition(cu.name, ".")[0] + className = cu.name + + package = self.packages.setdefault(package_name, [{}, 0, 0, 0, 0]) xclass = self.xml_out.createElement("class") @@ -97,53 +108,48 @@ xlines = self.xml_out.createElement("lines") xclass.appendChild(xlines) - className = fname.replace('.', '_') + xclass.setAttribute("name", className) - ext = os.path.splitext(cu.filename)[1] - xclass.setAttribute("filename", cu.name + ext) - xclass.setAttribute("complexity", "0.0") + filename = cu.file_locator.relative_filename(cu.filename) + xclass.setAttribute("filename", filename.replace("\\", "/")) + xclass.setAttribute("complexity", "0") - branch_lines = analysis.branch_lines() + branch_stats = analysis.branch_stats() # For each statement, create an XML 'line' element. - for line in analysis.statements: + for line in sorted(analysis.statements): xline = self.xml_out.createElement("line") xline.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. - xline.setAttribute("hits", str(int(not line in analysis.missing))) + xline.setAttribute("hits", str(int(line not in analysis.missing))) if self.arcs: - if line in branch_lines: + if line in branch_stats: + total, taken = branch_stats[line] xline.setAttribute("branch", "true") + xline.setAttribute("condition-coverage", + "%d%% (%d/%d)" % (100*taken/total, taken, total) + ) xlines.appendChild(xline) - class_lines = 1.0 * len(analysis.statements) + class_lines = len(analysis.statements) class_hits = class_lines - len(analysis.missing) if self.arcs: - # We assume here that every branch line has 2 exits, which is - # usually true. In theory, though, we could have a branch line - # with more exits.. - class_branches = 2.0 * len(branch_lines) - missed_branch_targets = analysis.missing_branch_arcs().values() - missing_branches = sum([len(b) for b in missed_branch_targets]) - class_branch_hits = class_branches - missing_branches + class_branches = sum([t for t,k in branch_stats.values()]) + missing_branches = sum([t-k for t,k in branch_stats.values()]) + class_br_hits = class_branches - missing_branches else: class_branches = 0.0 - class_branch_hits = 0.0 + class_br_hits = 0.0 # Finalize the statistics that are collected in the XML DOM. - line_rate = rate(class_hits, class_lines) - branch_rate = rate(class_branch_hits, class_branches) - xclass.setAttribute("line-rate", str(line_rate)) - xclass.setAttribute("branch-rate", str(branch_rate)) + xclass.setAttribute("line-rate", rate(class_hits, class_lines)) + xclass.setAttribute("branch-rate", rate(class_br_hits, class_branches)) package[0][className] = xclass package[1] += class_hits package[2] += class_lines - package[3] += class_branch_hits + package[3] += class_br_hits package[4] += class_branches - -# -# eflag: FileType = Python2