blob: d69a88bc9950409ab5bba04f5bfcce58603f5558 [file] [log] [blame]
#!/usr/bin/env bash
# vim: ts=4 sw=4 noet :
#==================================================================================
# Copyright (c) 2020 Nokia
# Copyright (c) 2020 AT&T Intellectual Property.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#==================================================================================
#
# Parse the .gcov file and discount any unexecuted lines which are in if()
# blocks which are testing the result of alloc/malloc calls, or testing for
# nil pointers. The feeling is that these might not be possible to drive
# and shoudn't contribute to coverage deficiencies.
#
# In verbose mode, the .gcov file is written to stdout and any unexecuted
# line which is discounted is marked with ===== replacing the ##### marking
# that gcov wrote.
#
# The return value is 0 for pass; non-zero for fail.
#
function discount_ck {
typeset f="$1"
mct=80 # force minimum coverage threshold for passing
if [[ ! -f $f ]]
then
if [[ -f ${f##*/} ]]
then
f=${f##*/}
else
echo "cant find: $f"
return
fi
fi
awk -v module_cov_target=$mct \
-v cfail=${cfail:-WARN} \
-v show_all=$show_all \
-v full_name="${1}" \
-v module="${f%.*}" \
-v chatty=$chatty \
-v replace_flags=$replace_flags \
'
function spit_line( ) {
if( chatty ) {
printf( "%s\n", $0 )
}
}
/-:/ { # skip unexecutable lines
spit_line()
seq++ # allow blank lines in a sequence group
next
}
{
nexec++ # number of executable lines
}
/#####:/ {
unexec++;
if( $2+0 != seq+1 ) {
prev_malloc = 0
prev_if = 0
seq = 0
spit_line()
next
}
if( prev_if && prev_malloc ) {
if( prev_malloc ) {
#printf( "allow discount: %s\n", $0 )
if( replace_flags ) {
gsub( "#####", " 1", $0 )
//gsub( "#####", "=====", $0 )
}
discount++;
}
}
seq++;;
spit_line()
next;
}
/if[(].*alloc.*{/ { # if( (x = malloc( ... )) != NULL ) or if( (p = sym_alloc(...)) != NULL )
seq = $2+0
prev_malloc = 1
prev_if = 1
spit_line()
next
}
/if[(].* == NULL/ { # a nil check likely not easily forced if it wasnt driven
prev_malloc = 1
prev_if = 1
spit_line()
seq = $2+0
next
}
/if[(]/ {
if( seq+1 == $2+0 && prev_malloc ) { // malloc on previous line
prev_if = 1
} else {
prev_malloc = 0
prev_if = 0
}
spit_line()
next
}
/alloc[(]/ {
seq = $2+0
prev_malloc = 1
spit_line()
next
}
{
spit_line()
}
END {
net = unexec - discount
orig_cov = ((nexec-unexec)/nexec)*100 # original coverage
adj_cov = ((nexec-net)/nexec)*100 # coverage after discount
pass_fail = adj_cov < module_cov_target ? cfail : "PASS"
rc = adj_cov < module_cov_target ? 1 : 0
if( pass_fail == cfail || show_all ) {
if( chatty ) {
printf( "[%s] %s executable=%d unexecuted=%d discounted=%d net_unex=%d cov=%d%% ==> %d%% target=%d%%\n",
pass_fail, full_name ? full_name : module, nexec, unexec, discount, net, orig_cov, adj_cov, module_cov_target )
} else {
printf( "[%s] %d%% (%d%%) %s\n", pass_fail, adj_cov, orig_cov, full_name ? full_name : module )
}
}
exit( rc )
}
' $f
}
# ----------------------------------------------------------------------
show_all=1 # turn off to hide passing modules (-q)
chatty=0 # -v turns on to provide more info when we do speak
while [[ $1 == "-"* ]]
do
case $1 in
-q) show_all=0;;
-v) chatty=1;;
*) echo "unrecognised option: $1"
echo "usage: $0 [-q] gcov-file-list"
exit 1
;;
esac
shift
done
while [[ -n $1 ]]
do
discount_ck $1
shift
done