Release 1.2.1
[ric-app/ts.git] / test / parse_gcov.sh
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 # 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
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