#!/usr/bin/env python # # Copyright (c) 2011, 2012, Simon Howard # # 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. # from re import match from os import rename, popen, getcwd, chdir from os.path import exists, dirname, basename from os.path import join as path_join from glob import glob import sys def parse_stats(text): m = match(r"(.*)% of (.*)", text) pct = m.group(1) lines = int(m.group(2)) cov_lines = int(float(pct) * lines / 100 + 0.5) uncov_lines = lines - cov_lines return (pct + "%", uncov_lines, cov_lines, lines) def gcov(filename): # gcov must be run from within the same directory as the source # file that we are analysing. old_wd = getcwd() src_dir = dirname(filename) chdir(src_dir) s = popen("gcov %s" % basename(filename)) chdir(old_wd) # Process output from gcov. # This may cover multiple files when one .c file includes another. results = {} filename = None # File 'lha_file_header.c' # Lines executed:88.97% of 136 for line in s: m = match(r"File '(.*)'", line) if m: filename = m.group(1) m = match(r"Lines executed:(.*)", line) if m: full_path = path_join(src_dir, filename) results[full_path] = parse_stats(m.group(1)) s.close() return results def format_output(filename, stats): print " %-35s%7s%7s%7s%7s" % ((filename, ) + stats) print format_output("Filename", ("Percent", "Uncov", "Cov", "Total")) print " " + ("-" * 65) for filename in sorted(sys.argv[1:]): gcno = filename.replace(".c", ".gcno") gcda = filename.replace(".c", ".gcda") xgcno = glob(path_join(dirname(gcno), "*-" + basename(gcno))) xgcda = glob(path_join(dirname(gcda), "*-" + basename(gcda))) # Must rename eg. liblhasatest_a-foo.gcno to foo.gcno: if len(xgcno) > 0: rename(xgcno[0], gcno) if len(xgcda) > 0: rename(xgcda[0], gcda) if not exists(gcno) or not exists(gcda): continue # Run gcov and parse output: results = gcov(filename) if len(results) > 0: if filename in results: format_output(filename, results[filename]) else: format_output(filename, ("", "", "", "")) for subfile in sorted(results.keys()): if subfile.endswith(".h"): continue if subfile != filename: format_output(" -> " + subfile, results[subfile]) print