summaryrefslogtreecommitdiffstats
path: root/test/unittest/cover_to_html.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/unittest/cover_to_html.py')
-rwxr-xr-xtest/unittest/cover_to_html.py355
1 files changed, 355 insertions, 0 deletions
diff --git a/test/unittest/cover_to_html.py b/test/unittest/cover_to_html.py
new file mode 100755
index 0000000..2d69242
--- /dev/null
+++ b/test/unittest/cover_to_html.py
@@ -0,0 +1,355 @@
+#!/usr/bin/python
+
+#Copyright (c) 2005 Drew Smathers
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is furnished to do
+# so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+
+
+#From http://svn.xix.python-hosting.com/trunk/xix/utils/cover.py
+
+"""More things for working with coverage.py
+"""
+
+from UserList import UserList
+import sys, os
+import glob
+from StringIO import StringIO
+import lxml.etree as ET
+
+__author__ = 'Drew Smathers'
+__version__ = '$Revision$'[11:-2]
+
+class AnnotationLine:
+ def __init__(self, text, isexec=False, covered=False):
+ self.text = text
+ self.isexec = isexec
+ self.covered = covered
+ # hack
+ if self.text and self.text[-1] == '\n':
+ self.text = self.text[:-1]
+
+ def __repr__(self):
+ buf = ""
+ buf = buf + self.text + "\n"
+ return buf
+
+
+class Annotation(UserList):
+ pass
+
+class AnnotationParser:
+ """Parser for annotation files generated by coverage.
+ """
+ def parse(self, input):
+ fd = input
+ if not hasattr(input, 'read'):
+ fd = open(input)
+ annotation = Annotation()
+ for line in input:
+# print line
+ if not line or line[0] not in ('>', '!'):
+ annotation.append(AnnotationLine(line[2:], isexec=False))
+ elif line[0] == '>':
+ annotation.append(AnnotationLine(line[2:], isexec=True, covered=True))
+ elif line[0] == '!':
+ annotation.append(AnnotationLine(line[2:], isexec=True, covered=False))
+ else:
+ print >> sys.stderr, 'invalid annotation line: ' + line
+
+ return annotation
+
+def annotationToXML(annotation, tree=False):
+ """Transform annotation object to XML string or ElementTree instance
+ if tree is True.
+
+ @param annotation: Annotation instance
+ @param tree: set to true to return ElementTree instance.
+ """
+ etree = _annotationToXML(annotation)
+ if tree:
+ return etree
+ buffer = StringIO()
+ etree.write(buffer)
+ return buffer.getvalue()
+
+def _annotationToXML(annotation):
+ root = ET.Element('coverageAnnotation')
+ for line in annotation:
+ aline = ET.SubElement(root, 'line')
+ aline.attrib['executable'] = str(line.isexec).lower()
+ aline.attrib['covered'] = str(line.covered).lower()
+ aline.text = line.text
+ return ET.ElementTree(root)
+
+
+def annotationToHTML(annotation, xml=None, xslt=None, tree=False):
+ """Transform annotation object to HTML string or ElementTree instance
+ if tree is True.
+
+ @param annotation: Annotation instance
+ @param xslt: xslt source for transformation
+ @param tree: set to true to return ElementTree instance.
+ """
+ style = xslt or _XSLT
+# style = _XSLT
+ if not hasattr(style, 'read'):
+ style = StringIO(style)
+ style = ET.parse(style)
+ etree = _annotationToXML(annotation)
+ html = etree.xslt(style)
+ if tree:
+ return html
+ buffer = StringIO()
+ html.write(buffer)
+ return buffer.getvalue()
+
+###########################################
+# Coverage reports
+###########################################
+
+class CoverageReport(UserList):
+ package_name = None
+ summary = None
+
+class CoverageReportEntry:
+
+ def __init__(self, modname, statements, executed, coverage, missing):
+ self.modname = modname
+ self.statements = statements
+ self.executed = executed
+ self.coverage = coverage
+ self.missing = missing
+
+class CoverageReportParser:
+
+ def parse(self, input):
+ fd = input
+ if not hasattr(input, 'read'):
+ fd = open(input)
+ report = CoverageReport()
+ for line in fd.readlines()[2:]:
+ tokens = line.split()
+ try:
+ modname, stmts, execd, coverage = tokens[:4]
+ perc = coverage[:-1]
+ _stmts, _execd = int(stmts), int(execd)
+ except Exception, e:
+ continue
+ if modname == 'TOTAL':
+ report.summary = CoverageReportEntry(modname, stmts, execd, coverage, None)
+ break
+ modname = modname.replace(os.path.sep, '.')
+ missed = [ tk.replace(',','') for tk in tokens[4:] ]
+ report.append(CoverageReportEntry(modname, stmts, execd, coverage, missed))
+ return report
+
+
+def reportToXML(report, tree=False):
+ """Transform report object to XML representation as string or ElementTree
+ instance if tree arg is set to True.
+
+ @param report: report instance
+ @param tree: set to true to return ElementTree instance
+ """
+ etree = _reportToXML(report)
+ if tree:
+ return etree
+ buffer = StringIO()
+ etree.write(buffer)
+ return buffer.getvalue()
+
+def _reportToXML(report):
+ root = ET.Element('coverage-report')
+ elm = ET.SubElement(root, 'summary')
+ attr = elm.attrib
+ attr['statements'] = report.summary.statements
+ attr['executed'] = report.summary.executed
+ attr['coverage'] = report.summary.coverage
+ for entry in report:
+ elm = ET.SubElement(root, 'module')
+ attr = elm.attrib
+ attr['name'] = entry.modname
+ attr['statements'] = entry.statements
+ attr['coverage'] = entry.coverage
+ attr['executed'] = entry.executed
+ melm = ET.SubElement(elm, 'missing-ranges')
+ for missed in entry.missing:
+ start_end = missed.split('-')
+ if len(start_end) == 2:
+ start, end = start_end
+ else:
+ start = end = start_end[0]
+ relm = ET.SubElement(melm, 'range')
+ relm.attrib['start'] = start
+ relm.attrib['end'] = end
+ return ET.ElementTree(root)
+
+
+def gen_html(path_to_cover, path_for_html):
+ cover_files = glob.glob("%s/*,cover" % path_to_cover)
+
+ # write out the css file
+ f = open("coverage.css", "w")
+ f.write(_CSS)
+ f.close()
+
+ for cf in cover_files:
+ fd = open(cf, "r")
+ ann = AnnotationParser().parse(fd)
+ html = annotationToHTML(ann, xslt=_XSLT)
+ base_name = os.path.basename(cf)
+ source_name = base_name.split(',')[0]
+ html_name = "%s/%s.html" % (path_for_html, source_name)
+ f = open(html_name, "w")
+ f.write(html)
+ f.close()
+
+# fd = open("%s/cover.report" % path_to_cover)
+# crp = CoverageReportParser().parse(fd)
+
+
+_CSS = """
+body {
+ margin: 0px;
+}
+
+h2 {
+ padding: 3px;
+ margin: 0px;
+ background-color: #ddd;
+ border-bottom: 2px solid;
+}
+
+th {
+ text-align: left;
+ padding-right: 28px;
+}
+
+.report-column {
+ border-bottom: 1px dashed;
+ padding-right: 28px;
+}
+
+.summary {
+ background-color: #eed;
+ border-bottom: 0px;
+}
+
+a {
+ text-decoration: none;
+}
+
+.annotation-line {
+ font-style: italic;
+ font-weight: 700;
+ font-family: mono,arial;
+ border-left: 8px solid #aaa;
+ padding-left: 5px;
+}
+
+.covered {
+ border-left: 8px solid #3e3;
+ background-color: #cfc;
+}
+
+.uncovered {
+ border-left: 8px solid red;
+}
+
+pre {
+ margin: 1px;
+ display: inline;
+}
+
+.uncovered {
+ background: #ebb;
+}
+
+.non-exec {
+ border-left: 8px solid #aaa;
+ background-color: #eee;
+}
+
+.lineno {
+ margin-right: 5px;
+ background-color: #ef5;
+}
+
+#colophon {
+ border-top: 1px solid;
+ background-color: #eee;
+ display: block;
+ position: relative;
+ bottom: 0px;
+ padding: 8px;
+ float: bottom;
+ width: 100%;
+ margin-top: 20px;
+ font-size: 75%;
+ text-align: center;
+}
+
+"""
+
+
+_XSLT = '''<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:output method="html"/>
+<xsl:param name="modname"/>
+<xsl:template match="/">
+ <html><head><title>Coverage Results for <xsl:value-of select="$modname"/></title>
+ <link rel="stylesheet" type="text/css" href="coverage.css"/></head>
+ <body>
+ <h2>Coverage Results for <xsl:value-of select="$modname"/></h2>
+ <div class="annotated-source-code">
+ <table width="100%">
+ <xsl:for-each select="/coverageAnnotation/line">
+ <xsl:variable name="lineno" select="position()"/>
+ <xsl:choose>
+ <xsl:when test="@executable='false'">
+ <!--<div class="annotation-line non-exec">-->
+ <tr class="annotation-line non-exec">
+ <td class="non-exec"><xsl:value-of select="$lineno"/></td>
+ <td><pre><xsl:value-of select="."/></pre></td></tr>
+ </xsl:when>
+ <xsl:when test="@executable='true' and @covered='true'">
+ <tr class="annotation-line executable covered">
+ <td class="covered"><xsl:value-of select="$lineno"/></td>
+ <td><pre><xsl:value-of select="."/></pre></td></tr>
+ </xsl:when>
+ <xsl:otherwise>
+ <tr class="annotation-line executable uncovered">
+ <td class="uncovered"><xsl:value-of select="$lineno"/></td>
+ <td><pre><xsl:value-of select="."/></pre></td></tr>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </table>
+ </div></body></html>
+</xsl:template>
+</xsl:stylesheet>'''
+
+
+
+
+if __name__ == "__main__":
+ gen_html(sys.argv[1], sys.argv[2])
+
+