Skip to content

Instantly share code, notes, and snippets.

@briancroom
Last active December 9, 2016 08:34
Show Gist options
  • Save briancroom/936a54108de98a63d8cf to your computer and use it in GitHub Desktop.
Save briancroom/936a54108de98a63d8cf to your computer and use it in GitHub Desktop.
A pair of scripts to help with basic parsing of LLVM code-coverage output data, as produced by Xcode 7. The `cov-exclusions.txt` file can be used to exclude files and globs from the output
SCHEME=MyApp
PRODUCT_NAME=${SCHEME}
WORKSPACE=${SCHEME}.xcworkspace
SOURCE_ROOT=./
###
ABSOLUTE_SOURCE_ROOT=$(cd $SOURCE_ROOT; pwd)
BUILD_SETTINGS=`xcodebuild -workspace ${WORKSPACE} -scheme ${SCHEME} -sdk iphonesimulator -showBuildSettings`
# Project Temp Root ends up with /Build/Intermediates/
PROJECT_TEMP_ROOT=$(echo "${BUILD_SETTINGS}" | grep -m1 PROJECT_TEMP_ROOT | cut -d= -f2 | xargs)
PROFDATA=$(find ${PROJECT_TEMP_ROOT} -name "Coverage.profdata")
BINARY=$(find ${PROJECT_TEMP_ROOT} -path "*${PRODUCT_NAME}.app/${PRODUCT_NAME}")
if [[ -z $PROFDATA ]]; then
echo "ERROR: Unable to find Coverage.profdata. Be sure to execute tests before running this script."
exit 1
fi
find ${ABSOLUTE_SOURCE_ROOT} -type f \( -name "*.h" -or -name "*.m" -or -name "*.swift" \) -print0 | \
xargs -0 xcrun llvm-cov report -instr-profile ${PROFDATA} ${BINARY} | ./parse-llvm-cov-report.py
#!/usr/bin/python
import os
import sys
import fnmatch
currentFile = None
covResults = []
inFile = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin
try:
fileExclusions = open("cov-exclusions.txt").read().splitlines()
except IOError:
fileExclusions = []
def matchesexclusion(filePath):
basename = os.path.basename(filePath)
return any([(fnmatch.fnmatch(filePath, exclusion) or fnmatch.fnmatch(basename, exclusion)) for exclusion in fileExclusions])
for line in inFile:
lineComponents = line.split("'")
if len(lineComponents) == 3 and line.startswith("File '"):
filePath = lineComponents[1]
if not matchesexclusion(filePath):
currentFile = filePath
else:
currentFile = None
print "Skipping file: "+filePath
elif line.startswith("TOTAL") and currentFile != None:
lineComponents = line.split()
(fileTotalLines, fileMissedLines) = (float(lineComponents[4]), float(lineComponents[5]))
covPercentage = (fileTotalLines-fileMissedLines) / fileTotalLines
covResults.append((currentFile, covPercentage, fileTotalLines, fileMissedLines))
covResults.sort(key=lambda x: x[1], reverse=True)
# for (file, coverage, totalLines, missedLines) in covResults:
# print file + ": {0:.2%}".format(coverage)
totalLines = sum([x[2] for x in covResults])
missedLines = sum([x[3] for x in covResults])
covAverage = (totalLines-missedLines) / totalLines if totalLines>0 else 0
print "Total lines: %d" % totalLines
print "Hit lines: %d" % (totalLines-missedLines)
print "Coverage average is: {0:.2%}".format(covAverage)
@greg-burgoon
Copy link

Tools like this are seriously lacking in the community right now for llvm-cov, but this is exactly what I need/wanted for managing code coverage. Thank Brian!

Is there a particular reason you commented out the coverage output per file?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment