-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathcoverageGutter.py
More file actions
279 lines (228 loc) · 10.1 KB
/
coverageGutter.py
File metadata and controls
279 lines (228 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
class MCDCLineCoverage:
covered = 0
partially_covered = 1
uncovered = 2
def getMCDCLineDic(sourceObject):
"""
Returns a dictionary with the MCDC line coverage for each unit.
{unit_name: {line_number: MCDCLineCoverage}}
A line number can have the coverage states: covered, partially covered, uncovered (defined in MCDCLineCoverage).
"""
mcdc_unit_line_dic = dict()
temp_line_coverage_dic = dict()
unitFile = sourceObject.cover_data.name
unit = unitFile.rsplit(".", 1)[0]
all_decisions = []
covered_mcdc_pair_found = False
decision_has_covered_pairs_for_all_conditions = True
# If we overwrite a function, we need all "overwritten decisions"
for inst_file in sourceObject.instrumented_files:
all_decisions.extend(inst_file.mcdc_decisions)
for mcdc in all_decisions:
# If it s not a mcdc pair --> continue
if not mcdc.num_conditions:
continue
start_line = mcdc.start_line
# Per default, we set the line to be uncovered
temp_line_coverage_dic[start_line] = MCDCLineCoverage.uncovered
mcdc_unit_line_dic[unit] = temp_line_coverage_dic
for condition in mcdc.conditions:
covered_pair = condition.get_covered_pair()
# We have at least 1 covered mcdc pair
if(covered_pair == None):
decision_has_covered_pairs_for_all_conditions = False
else:
covered_mcdc_pair_found = True
if covered_mcdc_pair_found == True:
# We found covered and uncovered mcdc pairs --> Partially covered
if decision_has_covered_pairs_for_all_conditions == False:
temp_line_coverage_dic[start_line] = MCDCLineCoverage.partially_covered
else:
# We found only covered mcdc pairs --> Fully covered
temp_line_coverage_dic[start_line] = MCDCLineCoverage.covered
return mcdc_unit_line_dic
def handleStatementCoverage(line, coveredString, uncoveredString):
"""
Returns the coverage strings for Statement Coverage.
"""
metrics = line.metrics
if metrics.max_covered_statements > 0 or metrics.max_annotations_statements > 0:
coveredString += str(line.line_number) + ","
elif metrics.statements > 0:
uncoveredString += str(line.line_number) + ","
return coveredString, uncoveredString
def handleMcdcCoverage(
unit,
mcdc_line_dic,
line,
coveredString,
partiallyCoveredString,
uncoveredString,
):
"""
Returns the coverage strings for MCDC Coverage.
"""
metrics = line.metrics
line_number = line.line_number
# Since we only have mcdc lines and not statements, we first need to check whether our unit is in the dic first
unit_mcdc_lines = mcdc_line_dic.get(unit, {})
mcdc_line_coverage = unit_mcdc_lines.get(line_number, None)
if mcdc_line_coverage is not None:
# Decide whether to use mcdc_branches or fallback to normal branches (> 25 needs mcdc_branches)
use_mcdc = getattr(metrics, "mcdc_branches", 0) > 0
branch_total = metrics.mcdc_branches if use_mcdc else metrics.branches
covered_branches = (
metrics.max_covered_mcdc_branches + metrics.max_annotations_mcdc_branches
if use_mcdc
else metrics.max_covered_branches + metrics.max_annotations_branches
)
has_branch_coverage = covered_branches > 0
# First check for the branch coverage. If it has none, it can not be partially covered / covered
if has_branch_coverage:
mcdc_line_coverage = unit_mcdc_lines.get(
line_number, MCDCLineCoverage.uncovered
)
# To be fully mcdc covered: All Branches + All MCDC pairs
is_fully_mcdc_covered = (
covered_branches == branch_total
and mcdc_line_coverage == MCDCLineCoverage.covered
)
# If it's fully covered --> It's an mcdc line and fully covered --> green
if is_fully_mcdc_covered:
coveredString += f"{line.line_number},"
# Not everything is covered but we have at least 1 covered mcdc pair --> Partially covered mcdc line --> orange
elif metrics.covered_mcdc_pairs > 0:
partiallyCoveredString += f"{line.line_number},"
# If it has branches covered but not mcdc pair
else:
uncoveredString += f"{line.line_number},"
# It has no branch coverage but there are branches --> uncovered
elif branch_total > 0:
uncoveredString += str(line.line_number) + ","
return coveredString, partiallyCoveredString, uncoveredString
def handleStatementMcdcCoverage(
unit,
mcdc_line_dic,
line,
coveredString,
partiallyCoveredString,
uncoveredString,
):
"""
Returns the coverage strings for Statement + MCDC Coverage.
"""
metrics = line.metrics
line_number = line.line_number
has_coverage = (
metrics.max_covered_statements > 0 or metrics.max_annotations_statements > 0
)
# Check if it s an uncovered statement
if has_coverage:
# Check if the unit is in the dic
unit_mcdc_lines = mcdc_line_dic.get(unit, {})
mcdc_line_coverage = unit_mcdc_lines.get(line_number, None)
# Decide whether to use mcdc_branches or fallback to normal branches (> 25 needs mcdc_branches)
use_mcdc = getattr(metrics, "mcdc_branches", 0) > 0
branch_total = metrics.mcdc_branches if use_mcdc else metrics.branches
covered_branches = (
metrics.max_covered_mcdc_branches + metrics.max_annotations_mcdc_branches
if use_mcdc
else metrics.max_covered_branches + metrics.max_annotations_branches
)
# Determine statement coverage
covered_statements = (
metrics.max_covered_statements + metrics.max_annotations_statements
)
total_statements = metrics.statements
if mcdc_line_coverage is not None:
# To be fully mcdc covered: All Statements + All Branches + All MCDC pairs
# and the line either has to be flagged covered or partially covered from getMCDCLineDic
# here we find out if it's really 100% covered or only partially covered
is_fully_mcdc_covered = (
covered_statements == total_statements
and covered_branches == branch_total
and mcdc_line_coverage == MCDCLineCoverage.covered
)
# If it's fully covered --> It's an mcdc line and fully covered --> green
if is_fully_mcdc_covered:
coveredString += f"{line_number},"
# Not everything is covered but we have at least 1 covered mcdc pair --> Partially covered mcdc line --> orange
elif mcdc_line_coverage == MCDCLineCoverage.partially_covered:
partiallyCoveredString += f"{line_number},"
# a mcdc line that has no coverage --> Red
else:
uncoveredString += f"{line_number},"
# It's a fully covered statement and not a mcdc line --> green
elif covered_statements == total_statements:
coveredString += f"{line_number},"
# If it s no mcdc line is not covered but still has statements --> uncovered statement line --> red
elif metrics.statements > 0:
uncoveredString += f"{line_number},"
return coveredString, partiallyCoveredString, uncoveredString
def handleStatementBranchCoverage(
line,
coveredString,
partiallyCoveredString,
uncoveredString,
):
"""
Returns the coverage strings for Statement + Branch Coverage.
"""
metrics = line.metrics
if metrics.max_covered_statements > 0 or metrics.max_annotations_statements > 0:
# Check if it's a branch line
if metrics.branches > 0:
# If every branch is covered --> green
if (
metrics.max_covered_branches + metrics.max_annotations_branches
== metrics.branches
):
coveredString += str(line.line_number) + ","
# If only a part of the branch is covered --> orange
elif metrics.max_covered_branches + metrics.max_annotations_branches > 0:
partiallyCoveredString += str(line.line_number) + ","
# If it s a branch but nothing is covered --> red
else:
uncoveredString += str(line.line_number) + ","
# It's not a branch line but a fully covered statement line --> green
elif (
metrics.max_covered_statements + metrics.max_annotations_statements
== metrics.statements
):
coveredString += str(line.line_number) + ","
# It's a statement line but not covered --> red
elif metrics.statements > 0:
uncoveredString += str(line.line_number) + ","
return coveredString, partiallyCoveredString, uncoveredString
def handleBranchCoverage(
line,
functionLineList,
coveredString,
partiallyCoveredString,
uncoveredString,
):
"""
Returns the coverage strings for Branch Coverage.
"""
metrics = line.metrics
line_number = line.line_number
# Check if it's a branch line and filter out function lines
if metrics.branches > 0 and line_number not in functionLineList:
# If every branch is covered --> green
if (
metrics.max_covered_branches + metrics.max_annotations_branches
== metrics.branches
):
coveredString += str(line_number) + ","
# If only a part of the branch is covered --> orange
elif metrics.max_covered_branches + metrics.max_annotations_branches > 0:
partiallyCoveredString += str(line_number) + ","
# If it s a branch but nothing is covered --> red
else:
uncoveredString += str(line_number) + ","
return coveredString, partiallyCoveredString, uncoveredString
def main():
# This script is not designed to be executed directly from the command line.
pass
if __name__ == "__main__":
main()