Ron Shacham | e7dfeb8 | 2020-04-24 14:46:48 -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 | |
E. Scott Daniels | d846166 | 2021-01-22 08:16:05 -0500 | [diff] [blame] | 21 | # LICENSE NOTE: |
| 22 | # this code is based on the unit test code in the o-ran-sc RMR repositiory which |
| 23 | # is covered by the original license above, and thus that license governs this |
| 24 | # extension as well. |
| 25 | # --------------------------------------------------------------------------------- |
| 26 | |
Ron Shacham | e7dfeb8 | 2020-04-24 14:46:48 -0400 | [diff] [blame] | 27 | # |
| 28 | # Parse the .gcov file and discount any unexecuted lines which are in if() |
| 29 | # blocks which are testing the result of alloc/malloc calls, or testing for |
| 30 | # nil pointers. The feeling is that these might not be possible to drive |
| 31 | # and shoudn't contribute to coverage deficiencies. |
| 32 | # |
| 33 | # In verbose mode, the .gcov file is written to stdout and any unexecuted |
| 34 | # line which is discounted is marked with ===== replacing the ##### marking |
| 35 | # that gcov wrote. |
| 36 | # |
| 37 | # The return value is 0 for pass; non-zero for fail. |
| 38 | # |
| 39 | function discount_ck { |
| 40 | typeset f="$1" |
| 41 | |
| 42 | mct=80 # force minimum coverage threshold for passing |
| 43 | |
| 44 | if [[ ! -f $f ]] |
| 45 | then |
| 46 | if [[ -f ${f##*/} ]] |
| 47 | then |
| 48 | f=${f##*/} |
| 49 | else |
| 50 | echo "cant find: $f" |
| 51 | return |
| 52 | fi |
| 53 | fi |
| 54 | |
| 55 | awk -v module_cov_target=$mct \ |
| 56 | -v cfail=${cfail:-WARN} \ |
| 57 | -v show_all=$show_all \ |
| 58 | -v full_name="${1}" \ |
| 59 | -v module="${f%.*}" \ |
| 60 | -v chatty=$chatty \ |
| 61 | -v replace_flags=$replace_flags \ |
| 62 | ' |
| 63 | function spit_line( ) { |
| 64 | if( chatty ) { |
| 65 | printf( "%s\n", $0 ) |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | /-:/ { # skip unexecutable lines |
| 70 | spit_line() |
| 71 | seq++ # allow blank lines in a sequence group |
| 72 | next |
| 73 | } |
| 74 | |
| 75 | { |
| 76 | nexec++ # number of executable lines |
| 77 | } |
| 78 | |
| 79 | /#####:/ { |
| 80 | unexec++; |
| 81 | if( $2+0 != seq+1 ) { |
| 82 | prev_malloc = 0 |
| 83 | prev_if = 0 |
| 84 | seq = 0 |
| 85 | spit_line() |
| 86 | next |
| 87 | } |
| 88 | |
| 89 | if( prev_if && prev_malloc ) { |
| 90 | if( prev_malloc ) { |
| 91 | #printf( "allow discount: %s\n", $0 ) |
| 92 | if( replace_flags ) { |
| 93 | gsub( "#####", " 1", $0 ) |
| 94 | //gsub( "#####", "=====", $0 ) |
| 95 | } |
| 96 | discount++; |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | seq++;; |
| 101 | spit_line() |
| 102 | next; |
| 103 | } |
| 104 | |
| 105 | /if[(].*alloc.*{/ { # if( (x = malloc( ... )) != NULL ) or if( (p = sym_alloc(...)) != NULL ) |
| 106 | seq = $2+0 |
| 107 | prev_malloc = 1 |
| 108 | prev_if = 1 |
| 109 | spit_line() |
| 110 | next |
| 111 | } |
| 112 | |
| 113 | /if[(].* == NULL/ { # a nil check likely not easily forced if it wasnt driven |
| 114 | prev_malloc = 1 |
| 115 | prev_if = 1 |
| 116 | spit_line() |
| 117 | seq = $2+0 |
| 118 | next |
| 119 | } |
| 120 | |
| 121 | /if[(]/ { |
| 122 | if( seq+1 == $2+0 && prev_malloc ) { // malloc on previous line |
| 123 | prev_if = 1 |
| 124 | } else { |
| 125 | prev_malloc = 0 |
| 126 | prev_if = 0 |
| 127 | } |
| 128 | spit_line() |
| 129 | next |
| 130 | } |
| 131 | |
| 132 | /alloc[(]/ { |
| 133 | seq = $2+0 |
| 134 | prev_malloc = 1 |
| 135 | spit_line() |
| 136 | next |
| 137 | } |
| 138 | |
| 139 | { |
| 140 | spit_line() |
| 141 | } |
| 142 | |
| 143 | END { |
| 144 | net = unexec - discount |
| 145 | orig_cov = ((nexec-unexec)/nexec)*100 # original coverage |
| 146 | adj_cov = ((nexec-net)/nexec)*100 # coverage after discount |
| 147 | pass_fail = adj_cov < module_cov_target ? cfail : "PASS" |
| 148 | rc = adj_cov < module_cov_target ? 1 : 0 |
| 149 | if( pass_fail == cfail || show_all ) { |
| 150 | if( chatty ) { |
| 151 | printf( "[%s] %s executable=%d unexecuted=%d discounted=%d net_unex=%d cov=%d%% ==> %d%% target=%d%%\n", |
| 152 | pass_fail, full_name ? full_name : module, nexec, unexec, discount, net, orig_cov, adj_cov, module_cov_target ) |
| 153 | } else { |
| 154 | printf( "[%s] %d%% (%d%%) %s\n", pass_fail, adj_cov, orig_cov, full_name ? full_name : module ) |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | exit( rc ) |
| 159 | } |
| 160 | ' $f |
| 161 | } |
| 162 | |
| 163 | # ---------------------------------------------------------------------- |
| 164 | show_all=1 # turn off to hide passing modules (-q) |
| 165 | chatty=0 # -v turns on to provide more info when we do speak |
| 166 | |
| 167 | while [[ $1 == "-"* ]] |
| 168 | do |
| 169 | case $1 in |
| 170 | -q) show_all=0;; |
| 171 | -v) chatty=1;; |
| 172 | |
| 173 | *) echo "unrecognised option: $1" |
| 174 | echo "usage: $0 [-q] gcov-file-list" |
| 175 | exit 1 |
| 176 | ;; |
| 177 | esac |
| 178 | shift |
| 179 | done |
| 180 | |
| 181 | |
| 182 | while [[ -n $1 ]] |
| 183 | do |
| 184 | discount_ck $1 |
| 185 | shift |
| 186 | done |