From: Derrick Stolee <dstolee@xxxxxxxxxxxxx> We have coverage targets in our Makefile for using gcov to display line coverage based on our test suite. The way I like to do it is to run: make coverage-test make coverage-report This leaves the repo in a state where every X.c file that was covered has an X.c.gcov file containing the coverage counts for every line, and "#####" at every uncovered line. There have been a few bugs in recent patches what would have been caught if the test suite covered those blocks (including a few of mine). I want to work towards a "sensible" amount of coverage on new topics. In my opinion, this means that any logic should be covered, but the 'die()' blocks in error cases do not need to be covered. It is important to not measure the coverage of the codebase by what old code is not covered. To help, I created the 'contrib/coverage-diff.sh' script. After creating the coverage statistics at a version (say, 'topic') you can then run contrib/coverage-diff.sh base topic to see the lines added between 'base' and 'topic' that are not covered by the test suite. The output uses 'git blame -c' format so you can find the commits responsible and view the line numbers for quick access to the context. Signed-off-by: Derrick Stolee <dstolee@xxxxxxxxxxxxx> --- contrib/coverage-diff.sh | 70 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100755 contrib/coverage-diff.sh diff --git a/contrib/coverage-diff.sh b/contrib/coverage-diff.sh new file mode 100755 index 0000000000..22acb13d38 --- /dev/null +++ b/contrib/coverage-diff.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +# Usage: 'contrib/coverage-diff.sh <version1> <version2> +# Outputs a list of new lines in version2 compared to version1 that are +# not covered by the test suite. Assumes you ran +# 'make coverage-test coverage-report' from root first, so .gcov files exist. + +V1=$1 +V2=$2 + +diff-lines() { + local path= + local line= + while read; do + esc=$'\033' + if [[ $REPLY =~ ---\ (a/)?.* ]]; then + continue + elif [[ $REPLY =~ \+\+\+\ (b/)?([^[:blank:]$esc]+).* ]]; then + path=${BASH_REMATCH[2]} + elif [[ $REPLY =~ @@\ -[0-9]+(,[0-9]+)?\ \+([0-9]+)(,[0-9]+)?\ @@.* ]]; then + line=${BASH_REMATCH[2]} + elif [[ $REPLY =~ ^($esc\[[0-9;]+m)*([\ +-]) ]]; then + echo "$path:$line:$REPLY" + if [[ ${BASH_REMATCH[2]} != - ]]; then + ((line++)) + fi + fi + done +} + +git diff --raw $V1 $V2 | grep \.c$ | awk 'NF>1{print $NF}' >files.txt + +for file in $(cat files.txt) +do + hash_file=${file//\//\#} + + git diff $V1 $V2 -- $file \ + | diff-lines \ + | grep ":+" \ + >"diff_file.txt" + + cat diff_file.txt \ + | sed -E 's/:/ /g' \ + | awk '{print $2}' \ + | sort \ + >new_lines.txt + + cat "$hash_file.gcov" \ + | grep \#\#\#\#\# \ + | sed 's/ #####: //g' \ + | sed 's/\:/ /g' \ + | awk '{print $1}' \ + | sort \ + >uncovered_lines.txt + + comm -12 uncovered_lines.txt new_lines.txt \ + | sed -e 's/$/\)/' \ + | sed -e 's/^/\t/' \ + >uncovered_new_lines.txt + + grep -q '[^[:space:]]' < uncovered_new_lines.txt && \ + echo $file && \ + git blame -c $file \ + | grep -f uncovered_new_lines.txt + + rm -f diff_file.txt new_lines.txt \ + uncovered_lines.txt uncovered_new_lines.txt +done + +rm -rf files.txt -- gitgitgadget