diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e67ab81
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,16 @@
+ISC License
+
+Copyright (c) 2012-2015 Jason Cranmer, 2019-2025 Ole Henrik Dahle and Ann-Karin Kihle
+Included D3 library is also under the ISC license, Copyright 2010-2021 Mike Bostock
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..db6245a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+Various code coverage scripts, originally used for the Mozilla (browser) project by Joshua Cranmer.
+Forked from https://github.com/jcranmer/mozilla-coverage, since that project is no longer maintained.
+The Python scripts rely on lcov and d3.js to produce colored tables and treemaps to illustrate code coverage.
diff --git a/ccov.py b/ccov.py
index 4a43c90..e16831a 100755
--- a/ccov.py
+++ b/ccov.py
@@ -6,6 +6,7 @@
import shutil
import subprocess
import tempfile
+import sys
def format_set_difference(a, b):
if a == b:
@@ -35,7 +36,7 @@ def add_line_hit(self, line, hitcount):
def lines(self):
'''Returns an iterator over (line #, hit count) for this file.'''
- for i in xrange(len(self._lines)):
+ for i in range(len(self._lines)):
count = self._lines[i]
if count != -1:
yield (i, count)
@@ -53,8 +54,13 @@ def add_function_hit(self, name, hitcount, lineno=None):
def functions(self):
'''Returns an iterator over (function name, line #, hit count) for this
file.'''
- for func, fndata in self._funcs.iteritems():
- yield (func, fndata[0], fndata[1])
+ if sys.version_info[0] == 2:
+ # Python 2 has iteritems, Python 3 has items
+ for func, fndata in self._funcs.iteritems():
+ yield (func, fndata[0], fndata[1])
+ else:
+ for func, fndata in self._funcs.items():
+ yield (func, fndata[0], fndata[1])
def add_branch_hit(self, lineno, brno, targetid, count):
'''Note that the brno'th branch on the line number going to the targetid
@@ -65,10 +71,17 @@ def add_branch_hit(self, lineno, brno, targetid, count):
def branches(self):
'''Returns an iterator over (line #, branch #, [ids], [counts]) for this
file.'''
- for tup in self._branches.iteritems():
- items = tup[1].items()
- items.sort()
- yield (tup[0][0], tup[0][1], [x[0] for x in items], [x[1] for x in items])
+ if sys.version_info[0] == 2:
+ # Python 2 has iteritems, Python 3 has items
+ for tup in self._branches.iteritems():
+ items = tup[1].items()
+ items.sort()
+ yield (tup[0][0], tup[0][1], [x[0] for x in items], [x[1] for x in items])
+ else:
+ for tup in self._branches.items():
+ items = tup[1].items()
+ items.sort()
+ yield (tup[0][0], tup[0][1], [x[0] for x in items], [x[1] for x in items])
def write_lcov_output(self, fd):
'''Writes the record for this file to the file descriptor in the LCOV
@@ -201,7 +214,7 @@ def loadGcdaTree(self, testname, gcdaDir):
gcnodata.add_to_coverage(self, testname, dirpath)
return
for dirpath, dirnames, filenames in os.walk(gcdaDir):
- print 'Processing %s' % dirpath
+ print("Processing ", dirpath)
gcda_files = filter(lambda f: f.endswith('.gcda'), filenames)
gcno_files = [f[:-2] + 'no' for f in gcda_files]
filepairs = [(da, no) for (da, no) in zip(gcda_files, gcno_files)
@@ -301,7 +314,7 @@ def __init__(self, basedir, gcovtool='gcov', table={}):
self.table = table
def loadDirectory(self, directory, gcda_files):
- print 'Processing %s' % directory
+ print("Processing ", directory)
gcda_files = map(lambda f: os.path.join(directory, f), gcda_files)
gcovdir = tempfile.mktemp("gcovdir")
os.mkdir(gcovdir)
@@ -389,7 +402,7 @@ def main(argv):
coverage = CoverageData()
if opts.more_files == None: opts.more_files = []
for lcovFile in opts.more_files:
- print >> sys.stderr, "Reading file %s" % lcovFile
+ sys.stderr.write("Reading file ", lcovFile)
fd = open(lcovFile, 'r')
coverage.addFromLcovFile(fd)
@@ -404,7 +417,7 @@ def main(argv):
coverage.filterFilesByGlob(opts.extract_glob)
# Store it to output
if opts.outfile != None:
- print >> sys.stderr, "Writing to file %s" % opts.outfile
+ sys.stderr.write("Writing to file", opts.outfile)
outfd = open(opts.outfile, 'w')
else:
outfd = sys.stdout
diff --git a/make_ui.py b/make_ui.py
index 0c661ca..6616f7d 100755
--- a/make_ui.py
+++ b/make_ui.py
@@ -1,6 +1,5 @@
#!/usr/bin/python
-import cgi
import json
import os
import shutil
@@ -9,19 +8,27 @@
def main(argv):
from optparse import OptionParser
- o = OptionParser()
+ usage = "Usage: %prog [options] inputfile(s)"
+ o = OptionParser(usage)
o.add_option('-o', '--output', dest="outdir",
help="Directory to store all HTML files", metavar="DIRECTORY")
o.add_option('-s', '--source-dir', dest="basedir",
help="Base directory for source code", metavar="DIRECTORY")
+ o.add_option('-l', '--limits', dest="limits",
+ help="Custom limits for medium,high coverage")
(opts, args) = o.parse_args(argv)
if opts.outdir is None:
- print "Need to pass in -o!"
+ print("Need to pass in -o!")
sys.exit(1)
+ if len(args) < 2:
+ print("Need to specify at least one input file!")
+ sys.exit(1)
+
# Add in all the data
cov = CoverageData()
for lcovFile in args[1:]:
+ print("Reading coverage data from", lcovFile)
cov.addFromLcovFile(open(lcovFile, 'r'))
# Make the output directory
@@ -29,19 +36,20 @@ def main(argv):
os.makedirs(opts.outdir)
print ('Building UI...')
- builder = UiBuilder(cov, opts.outdir, opts.basedir)
+ builder = UiBuilder(cov, opts.outdir, opts.basedir, opts.limits)
builder.makeStaticOutput()
builder.makeDynamicOutput()
class UiBuilder(object):
- def __init__(self, covdata, outdir, basedir):
+ def __init__(self, covdata, outdir, basedir, limits):
self.data = covdata
self.flatdata = self.data.getFlatData()
self.outdir = outdir
self.uidir = os.path.dirname(__file__)
self.basedir = basedir
+ self.limits = limits
self.relsrc = None
- self.tests = ['all']
+ self.tests = []
def _loadGlobalData(self):
json_data = self.buildJSONData(self.flatdata)
@@ -126,7 +134,8 @@ def makeStaticOutput(self):
def makeDynamicOutput(self):
# Dump out JSON files
json_data = self._loadGlobalData()
- json.dump(json_data, open(os.path.join(self.outdir, 'all.json'), 'w'))
+ if 'all' in self.tests :
+ json.dump(json_data, open(os.path.join(self.outdir, 'all.json'), 'w'))
for test in self.data.getTests():
small_data = self.data.getTestData(test)
if len(small_data) == 0:
@@ -154,6 +163,14 @@ def _readTemplate(self, name):
def _makeDirectoryIndex(self, dirname, jsondata):
# Utility method for printing out rows of the table
+ mediumLimit = 75.0
+ highLimit = 90.0
+ if self.limits:
+ values = self.limits.split(",");
+ if len(values) == 2:
+ mediumLimit = float(values[0])
+ highLimit = float(values[1])
+
def summary_string(lhs, jsondata):
output = '