E. Scott Daniels | 4e4fb50 | 2020-03-24 12:28:06 -0400 | [diff] [blame^] | 1 | #!/usr/bin/env bash |
| 2 | # vim: ts=4 sw=4 noet : |
| 3 | |
| 4 | #================================================================================== |
| 5 | # Copyright (c) 2020 Nokia |
| 6 | # Copyright (c) 2020 AT&T Intellectual Property. |
| 7 | # |
| 8 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 9 | # you may not use this file except in compliance with the License. |
| 10 | # You may obtain a copy of the License at |
| 11 | # |
| 12 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 13 | # |
| 14 | # Unless required by applicable law or agreed to in writing, software |
| 15 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 17 | # See the License for the specific language governing permissions and |
| 18 | # limitations under the License. |
| 19 | #================================================================================== |
| 20 | |
| 21 | # |
| 22 | # Parse the .gcov file and discount any unexecuted lines which are in if() |
| 23 | # blocks which are testing the result of alloc/malloc calls, or testing for |
| 24 | # nil pointers. The feeling is that these might not be possible to drive |
| 25 | # and shoudn't contribute to coverage deficiencies. |
| 26 | # |
| 27 | # In verbose mode, the .gcov file is written to stdout and any unexecuted |
| 28 | # line which is discounted is marked with ===== replacing the ##### marking |
| 29 | # that gcov wrote. |
| 30 | # |
| 31 | # The return value is 0 for pass; non-zero for fail. |
| 32 | # |
| 33 | function discount_ck { |
| 34 | typeset f="$1" |
| 35 | |
| 36 | mct=80 # force minimum coverage threshold for passing |
| 37 | |
| 38 | if [[ ! -f $f ]] |
| 39 | then |
| 40 | if [[ -f ${f##*/} ]] |
| 41 | then |
| 42 | f=${f##*/} |
| 43 | else |
| 44 | echo "cant find: $f" |
| 45 | return |
| 46 | fi |
| 47 | fi |
| 48 | |
| 49 | awk -v module_cov_target=$mct \ |
| 50 | -v cfail=${cfail:-WARN} \ |
| 51 | -v show_all=$show_all \ |
| 52 | -v full_name="${1}" \ |
| 53 | -v module="${f%.*}" \ |
| 54 | -v chatty=$chatty \ |
| 55 | -v replace_flags=$replace_flags \ |
| 56 | ' |
| 57 | function spit_line( ) { |
| 58 | if( chatty ) { |
| 59 | printf( "%s\n", $0 ) |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | /-:/ { # skip unexecutable lines |
| 64 | spit_line() |
| 65 | seq++ # allow blank lines in a sequence group |
| 66 | next |
| 67 | } |
| 68 | |
| 69 | { |
| 70 | nexec++ # number of executable lines |
| 71 | } |
| 72 | |
| 73 | /#####:/ { |
| 74 | unexec++; |
| 75 | if( $2+0 != seq+1 ) { |
| 76 | prev_malloc = 0 |
| 77 | prev_if = 0 |
| 78 | seq = 0 |
| 79 | spit_line() |
| 80 | next |
| 81 | } |
| 82 | |
| 83 | if( prev_if && prev_malloc ) { |
| 84 | if( prev_malloc ) { |
| 85 | #printf( "allow discount: %s\n", $0 ) |
| 86 | if( replace_flags ) { |
| 87 | gsub( "#####", " 1", $0 ) |
| 88 | //gsub( "#####", "=====", $0 ) |
| 89 | } |
| 90 | discount++; |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | seq++;; |
| 95 | spit_line() |
| 96 | next; |
| 97 | } |
| 98 | |
| 99 | /if[(].*alloc.*{/ { # if( (x = malloc( ... )) != NULL ) or if( (p = sym_alloc(...)) != NULL ) |
| 100 | seq = $2+0 |
| 101 | prev_malloc = 1 |
| 102 | prev_if = 1 |
| 103 | spit_line() |
| 104 | next |
| 105 | } |
| 106 | |
| 107 | /if[(].* == NULL/ { # a nil check likely not easily forced if it wasnt driven |
| 108 | prev_malloc = 1 |
| 109 | prev_if = 1 |
| 110 | spit_line() |
| 111 | seq = $2+0 |
| 112 | next |
| 113 | } |
| 114 | |
| 115 | /if[(]/ { |
| 116 | if( seq+1 == $2+0 && prev_malloc ) { // malloc on previous line |
| 117 | prev_if = 1 |
| 118 | } else { |
| 119 | prev_malloc = 0 |
| 120 | prev_if = 0 |
| 121 | } |
| 122 | spit_line() |
| 123 | next |
| 124 | } |
| 125 | |
| 126 | /alloc[(]/ { |
| 127 | seq = $2+0 |
| 128 | prev_malloc = 1 |
| 129 | spit_line() |
| 130 | next |
| 131 | } |
| 132 | |
| 133 | { |
| 134 | spit_line() |
| 135 | } |
| 136 | |
| 137 | END { |
| 138 | net = unexec - discount |
| 139 | orig_cov = ((nexec-unexec)/nexec)*100 # original coverage |
| 140 | adj_cov = ((nexec-net)/nexec)*100 # coverage after discount |
| 141 | pass_fail = adj_cov < module_cov_target ? cfail : "PASS" |
| 142 | rc = adj_cov < module_cov_target ? 1 : 0 |
| 143 | if( pass_fail == cfail || show_all ) { |
| 144 | if( chatty ) { |
| 145 | printf( "[%s] %s executable=%d unexecuted=%d discounted=%d net_unex=%d cov=%d%% ==> %d%% target=%d%%\n", |
| 146 | pass_fail, full_name ? full_name : module, nexec, unexec, discount, net, orig_cov, adj_cov, module_cov_target ) |
| 147 | } else { |
| 148 | printf( "[%s] %d%% (%d%%) %s\n", pass_fail, adj_cov, orig_cov, full_name ? full_name : module ) |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | exit( rc ) |
| 153 | } |
| 154 | ' $f |
| 155 | } |
| 156 | |
| 157 | # ---------------------------------------------------------------------- |
| 158 | show_all=1 # turn off to hide passing modules (-q) |
| 159 | chatty=0 # -v turns on to provide more info when we do speak |
| 160 | |
| 161 | while [[ $1 == "-"* ]] |
| 162 | do |
| 163 | case $1 in |
| 164 | -q) show_all=0;; |
| 165 | -v) chatty=1;; |
| 166 | |
| 167 | *) echo "unrecognised option: $1" |
| 168 | echo "usage: $0 [-q] gcov-file-list" |
| 169 | exit 1 |
| 170 | ;; |
| 171 | esac |
| 172 | shift |
| 173 | done |
| 174 | |
| 175 | |
| 176 | while [[ -n $1 ]] |
| 177 | do |
| 178 | discount_ck $1 |
| 179 | shift |
| 180 | done |