1#!/bin/sh
2
3# Usage: Run 'contrib/coverage-diff.sh <version1> <version2>' from source-root
4# after running
5#
6#     make coverage-test
7#     make coverage-report
8#
9# while checked out at <version2>. This script combines the *.gcov files
10# generated by the 'make' commands above with 'git diff <version1> <version2>'
11# to report new lines that are not covered by the test suite.
12
13V1=$1
14V2=$2
15
16diff_lines () {
17	perl -e '
18		my $line_num;
19		while (<>) {
20			# Hunk header?  Grab the beginning in postimage.
21			if (/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/) {
22				$line_num = $1;
23				next;
24			}
25
26			# Have we seen a hunk?  Ignore "diff --git" etc.
27			next unless defined $line_num;
28
29			# Deleted line? Ignore.
30			if (/^-/) {
31				next;
32			}
33
34			# Show only the line number of added lines.
35			if (/^\+/) {
36				print "$line_num\n";
37			}
38			# Either common context or added line appear in
39			# the postimage.  Count it.
40			$line_num++;
41		}
42	'
43}
44
45files=$(git diff --name-only "$V1" "$V2" -- \*.c)
46
47# create empty file
48>coverage-data.txt
49
50for file in $files
51do
52	git diff "$V1" "$V2" -- "$file" |
53	diff_lines |
54	sort >new_lines.txt
55
56	if ! test -s new_lines.txt
57	then
58		continue
59	fi
60
61	hash_file=$(echo $file | sed "s/\//\#/")
62
63	if ! test -s "$hash_file.gcov"
64	then
65		continue
66	fi
67
68	sed -ne '/#####:/{
69			s/    #####://
70			s/:.*//
71			s/ //g
72			p
73		}' "$hash_file.gcov" |
74	sort >uncovered_lines.txt
75
76	comm -12 uncovered_lines.txt new_lines.txt |
77	sed -e 's/$/\)/' |
78	sed -e 's/^/ /' >uncovered_new_lines.txt
79
80	grep -q '[^[:space:]]' <uncovered_new_lines.txt &&
81	echo $file >>coverage-data.txt &&
82	git blame -s "$V2" -- "$file" |
83	sed 's/\t//g' |
84	grep -f uncovered_new_lines.txt >>coverage-data.txt &&
85	echo >>coverage-data.txt
86
87	rm -f new_lines.txt uncovered_lines.txt uncovered_new_lines.txt
88done
89
90cat coverage-data.txt
91
92echo "Commits introducing uncovered code:"
93
94commit_list=$(cat coverage-data.txt |
95	grep -E '^[0-9a-f]{7,} ' |
96	awk '{print $1;}' |
97	sort |
98	uniq)
99
100(
101	for commit in $commit_list
102	do
103		git log --no-decorate --pretty=format:'%an      %h: %s' -1 $commit
104		echo
105	done
106) | sort
107
108rm coverage-data.txt
109