Skip to content

Commit 08c743b

Browse files
author
Viviane Garese
committed
Merge branch 'assertion-coverage' into 'master'
Implementation of first two levels of assertion coverage See merge request eng/cov/gnatcoverage!48 See issue #7 Implement coverage for assertions for levels ATC and ATCC.
2 parents f64a4b3 + 6b6bc30 commit 08c743b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1669
-311
lines changed

testsuite/SCOV/internals/cnotes.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@
126126

127127
# cPartCov : independent effect of condition not demonstrated (=report)
128128

129+
# aNoCov : assertion never evaluated (=report)
130+
# atNoCov : assertion expression outcome TRUE never evaluated (=report)
131+
# acPartCov : assertion condition was never evaluated during an evaluation of
132+
# the decision to True (=report)
133+
129134
# xBlock0 : exempted block, 0 deviations (=report)
130135
# xBlock1 : exempted block, >0 deviations (=report)
131136
# xBlock2 : exempted block, >0 undetermined coverage items (=report)
@@ -168,8 +173,9 @@
168173
XotNoCov, XofNoCov, XoPartCov, XoNoCov,
169174
XcPartCov,
170175
Xr0, Xr0c,
176+
aNoCov, atNoCov, acPartCov,
171177
blockNote,
172-
xBlock0, xBlock1, xBlock2) = range(50)
178+
xBlock0, xBlock1, xBlock2) = range(53)
173179

174180
NK_image = {None: "None",
175181
lNoCode: "lNoCode", lNotCoverable: "lNotCoverable",
@@ -192,7 +198,8 @@
192198
XotNoCov: "XotNoCov", XofNoCov: "XofNoCov", XoPartCov: "XoPartCov",
193199
XoNoCov: "XoNoCov",
194200
XcPartCov: "XcPartCov",
195-
Xr0: "Xr0", Xr0c: "Xr0c"}
201+
Xr0: "Xr0", Xr0c: "Xr0c",
202+
aNoCov: "aNoCov", atNoCov: "atNoCov", acPartCov: "acPartCov"}
196203

197204

198205
# ===============================
@@ -221,6 +228,9 @@
221228
# MCDC violations
222229
cNoteKinds = (etNoCov, efNoCov, ePartCov, eNoCov, cPartCov, eUndetCov)
223230

231+
# Assertion violations
232+
aNoteKinds = (aNoCov, atNoCov, acPartCov)
233+
224234
# Exemption regions
225235
xNoteKinds = (xBlock0, xBlock1, xBlock2)
226236

@@ -247,6 +257,7 @@
247257
# if they could be emitted and report them as unmatched.
248258

249259
erNoteKinds = sNoteKinds+dNoteKinds+cNoteKinds+xNoteKinds+tNoteKinds+XNoteKinds
260+
erNoteKinds += aNoteKinds
250261
xrNoteKinds = erNoteKinds+rAntiKinds+XrAntiKinds
251262

252263

testsuite/SCOV/internals/driver.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,13 @@ def check_expectations(self):
936936
"stmt+decision": 2,
937937
"stmt+mcdc": 3,
938938
"stmt+uc_mcdc": 3,
939+
"stmt+atc": 1,
940+
"stmt+decision+atc": 2,
941+
"stmt+decision+atcc": 2,
942+
"stmt+mcdc+atc": 3,
943+
"stmt+mcdc+atcc": 3,
944+
"stmt+uc_mcdc+atc": 3,
945+
"stmt+uc_mcdc+atcc": 3,
939946
}
940947

941948
stricter_level = (
@@ -1164,6 +1171,43 @@ def _scofiles_list(self):
11641171
for soi in self.sources_of_interest())
11651172
if scof}
11661173

1174+
def wdbase_for(self, covlevel):
1175+
"""
1176+
Compute a short base prefix for the working directory that will
1177+
contain the output of coverage analysis for level covlevel.
1178+
1179+
Uses the first letter of the highest level ('s' for "stmt" or 'u' for
1180+
"stmt+uc_mcdc") and the full name of the assertion level if assertion
1181+
coverage is enabled.
1182+
"""
1183+
levels = covlevel.split("+")
1184+
1185+
if len(levels) == 1:
1186+
return "s_"
1187+
1188+
wdbase = levels[1][0]
1189+
wdbase += levels[-1] if self.assert_lvl else ""
1190+
1191+
return wdbase + "_"
1192+
1193+
def xcovlevel_for(self, wdname):
1194+
"""
1195+
Compute the source coverage level from the working directory prefix
1196+
by matching the first letter of the highest coverage level plus the
1197+
full name of the assertion level is enabled.
1198+
"""
1199+
res = "stmt"
1200+
wdbase = wdname.split('_')[0]
1201+
1202+
for lvl in ["decision", "mcdc", "uc_mcdc"]:
1203+
if wdbase[0] == lvl[0]:
1204+
res += "+" + lvl
1205+
1206+
if len(wdbase) > 1:
1207+
res += "+" + wdbase[1:]
1208+
1209+
return res
1210+
11671211

11681212
class SCOV_helper_bin_traces(SCOV_helper):
11691213
"""SCOV_helper specialization for the binary execution trace based mode."""

testsuite/SCOV/internals/rnexpanders.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111
from .cnotes import (
1212
xBlock0, xBlock1, sNoCov, sPartCov, sNotCoverable, dfAlways, dtAlways,
1313
dfNoCov, dtNoCov, dNoCov, dPartCov, efNoCov, etNoCov, eNoCov, ePartCov,
14-
cPartCov, Enote, KnoteDict, erNoteKinds, sUndetCov, dUndetCov, eUndetCov,
15-
xBlock2, XsNoCov, XsPartCov, XsNotCoverable, XsUndetCov, XotNoCov,
16-
XofNoCov, XoPartCov, XoNoCov, XcPartCov
14+
cPartCov, aNoCov, atNoCov, acPartCov, Enote, KnoteDict, erNoteKinds,
15+
sUndetCov, dUndetCov, eUndetCov, xBlock2, XsNoCov, XsPartCov,
16+
XsNotCoverable, XsUndetCov, XotNoCov, XofNoCov, XoPartCov, XoNoCov,
17+
XcPartCov
1718
)
1819
from .segments import Sloc, Sloc_from_match
1920
from .stags import Stag_from
@@ -79,7 +80,6 @@ def __init__(self, sloc, diag):
7980

8081

8182
def Rdiagline_from(text):
82-
8383
p = re.match(Rdiagline.re, text)
8484

8585
return Rdiagline(sloc=Sloc_from_match(p),
@@ -207,7 +207,6 @@ def __init__(self, re_notes):
207207
self.enotes = []
208208

209209
def try_parse_enote(self, rline):
210-
211210
dline = Rdiagline_from(rline)
212211

213212
# If no match at all, punt.
@@ -570,6 +569,22 @@ def __init__(self):
570569
self.noteblocks.append(
571570
VIOsection(re_start="MCDC COVERAGE", re_notes=mcdc_notes))
572571

572+
# Assertion coverage
573+
574+
atc_notes = {
575+
"contract expression outcome TRUE never": atNoCov,
576+
"contract expression never evaluated": aNoCov,
577+
}
578+
self.noteblocks.append(
579+
VIOsection(re_start="ATC COVERAGE", re_notes=atc_notes))
580+
581+
atcc_notes = {
582+
"condition was never evaluated during an evaluation of the "
583+
"decision to True": acPartCov
584+
}
585+
self.noteblocks.append(
586+
VIOsection(re_start="ATCC COVERAGE", re_notes=atcc_notes))
587+
573588
# Non coverable items
574589

575590
nc_notes = {

testsuite/SCOV/internals/xnexpanders.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,10 +1203,25 @@ def __decode_note_choice(self, text):
12031203
or
12041204
[('stmt', 'l+'), ('stmt+decision', 'l+')]
12051205
"""
1206-
level_from_char = {"s": "stmt",
1207-
"d": "stmt+decision",
1208-
"m": "stmt+mcdc",
1209-
"u": "stmt+uc_mcdc"}
1206+
level_from_char = {"s": ["stmt"],
1207+
"d": ["stmt+decision"],
1208+
"m": ["stmt+mcdc"],
1209+
"u": ["stmt+uc_mcdc"]}
1210+
1211+
def make_assert_lvl_combinaison(assert_lvl):
1212+
"""
1213+
Add the assertion coverage level assert_lvl to other regular
1214+
coverage level combinaisons defined in level_from_char. Return the
1215+
list of combinaisons.
1216+
"""
1217+
return [level_from_char[c][0] + "+" + assert_lvl
1218+
for c in level_from_char]
1219+
1220+
assert_level_from_char = {"a": make_assert_lvl_combinaison("atc"),
1221+
"c": make_assert_lvl_combinaison("atcc")}
1222+
1223+
level_from_char.update(assert_level_from_char)
1224+
12101225
result = text.split("=>")
12111226

12121227
if len(result) == 1:
@@ -1220,7 +1235,12 @@ def __decode_note_choice(self, text):
12201235
note = result[1].lstrip(' ')
12211236
lev_list = result[0].rstrip(' ')
12221237

1223-
return [(level_from_char[lchar], note) for lchar in lev_list]
1238+
res = []
1239+
for lchar in lev_list:
1240+
for combinaison in level_from_char[lchar]:
1241+
res.append((combinaison, note))
1242+
1243+
return res
12241244

12251245
def __select_lnote(self, text):
12261246
"""Decode text to return the line note for the current

testsuite/SCOV/internals/xnotep.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
oPartCov, ofNoCov, otNoCov, r0, r0c, sNoCov, sNotCoverable, sPartCov,
1919
xBlock0, xBlock1, xBlock2, xNoteKinds, lUndetCov, sUndetCov, dUndetCov,
2020
eUndetCov, XsNoCov, XsPartCov, XsNotCoverable, XsUndetCov, XotNoCov,
21-
XofNoCov, XoPartCov, XoNoCov, XcPartCov, Xr0, Xr0c
21+
XofNoCov, XoPartCov, XoNoCov, XcPartCov, Xr0, Xr0c, aNoCov, atNoCov,
22+
acPartCov
2223
)
2324
from .segments import Line, Section, Segment
2425
from .stags import Stag_from
@@ -181,6 +182,7 @@ class XnoteP:
181182
'e?': eUndetCov,
182183
'oT-': otNoCov, 'oF-': ofNoCov, 'o!': oPartCov, 'o-': oNoCov,
183184
'c!': cPartCov,
185+
'a-': aNoCov, 'aT-': atNoCov, 'ac!': acPartCov,
184186
'x0': xBlock0, 'x+': xBlock1, 'x?': xBlock2,
185187
'0': r0, '0c': r0c,
186188
# Exempted notes

testsuite/SCOV/report.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from e3.fs import ls
1818

19+
from SCOV.internals.driver import SCOV_helper
1920
from SCOV.internals.cnotes import xNoteKinds
2021
from SCOV.internals.tfiles import Tfile
2122
from SUITE.tutils import XCOV, thistest, frame
@@ -139,15 +140,6 @@ def check(self):
139140
"stmt+uc_mcdc": ["STMT", "DECISION", "MCDC"]
140141
}
141142

142-
# Base prefix of the working subdirectory for each xcovlevel. ??? This is
143-
# relying too much on knowledge about how the testuite driver works ...
144-
xcovlevel_from = {
145-
"sc_": "stmt",
146-
"dc_": "stmt+decision",
147-
"mc_": "stmt+mcdc",
148-
"uc_": "stmt+uc_mcdc"
149-
}
150-
151143

152144
class ReportChecker:
153145
"""Whole report checker"""
@@ -301,7 +293,9 @@ def __process_one_test(self, qde):
301293
# applicable xcov-level
302294
self.__setup_expectations(
303295
ntraces=len(qde.drivers),
304-
xcovlevel=xcovlevel_from[os.path.basename(qde.wdir)[0:3]],
296+
xcovlevel=SCOV_helper.xcovlevel_for(self.tc,
297+
os.path.basename
298+
(qde.wdir)),
305299
xregions=xregions)
306300

307301
reports = ls(os.path.join(qde.wdir, "test.rep"))

testsuite/SCOV/tc.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def __drivers_from(self, cspec):
124124
return [drv for drv in self.all_drivers if re.search(drv_expr, drv)]
125125

126126
def __init__(self, extradrivers="", extracargs="", category=CAT.auto,
127-
tolerate_messages=None):
127+
tolerate_messages=None, assert_lvl=None):
128128
# By default, these test cases expect no error from subprocesses (xrun,
129129
# xcov, etc.)
130130
self.expect_failures = False
@@ -171,6 +171,8 @@ def __init__(self, extradrivers="", extracargs="", category=CAT.auto,
171171
if category == CAT.auto else
172172
category)
173173

174+
self.assert_lvl = assert_lvl
175+
174176
# - extra compilation arguments, added to what --cargs was provided to
175177
# the testsuite command line:
176178
self.extracargs = extracargs
@@ -191,19 +193,24 @@ def __xcovlevels(self):
191193
if thistest.options.xcov_level:
192194
return [thistest.options.xcov_level]
193195

196+
assert not thistest.options.qualif_level
197+
194198
default_xcovlevels_for = {
195199
# Tests without categories should be ready for anything.
196200
# Exercise with the strictest possible mode:
197-
None: ["stmt+mcdc"],
201+
None: ["stmt+mcdc"],
198202

199-
CAT.stmt: ["stmt"],
203+
CAT.stmt: ["stmt"],
200204
CAT.decision: ["stmt+decision"],
201-
CAT.mcdc: ["stmt+mcdc", "stmt+uc_mcdc"]}
205+
CAT.mcdc: ["stmt+mcdc", "stmt+uc_mcdc"],
206+
}
202207

203-
defaults = default_xcovlevels_for[self.category]
204-
return ([defaults[0]]
205-
if thistest.options.qualif_level else
206-
defaults)
208+
# Add a "+" before the name of the assertion coverage level in order
209+
# to append it at the end of the the other specified coverage levels
210+
# passed to gnatcov.
211+
alvl = ("+" + self.assert_lvl) if self.assert_lvl else ""
212+
213+
return [d + alvl for d in default_xcovlevels_for[self.category]]
207214

208215
def __register_qde_for(self, drvo):
209216
"""
@@ -215,13 +222,6 @@ def __register_qde_for(self, drvo):
215222
drivers=drvo.drivers, xrnotes=drvo.xrnotes,
216223
wdir=os.path.normpath(drvo.awdir())))
217224

218-
# Base prefix for Working directories, per --level. Shared across
219-
# runs for multiples levels.
220-
_wdbase_for = {"stmt": "st_",
221-
"stmt+decision": "dc_",
222-
"stmt+mcdc": "mc_",
223-
"stmt+uc_mcdc": "uc_"}
224-
225225
def __run_one_covlevel(self, covlevel, covcontrol, subdirhint):
226226
"""
227227
Run this testcase individual drivers and consolidation tests with
@@ -236,7 +236,7 @@ def __run_one_covlevel(self, covlevel, covcontrol, subdirhint):
236236

237237
# Compute the Working directory base for this level, then run the test
238238
# for each indivdual driver.
239-
this_wdbase = self._wdbase_for[covlevel]
239+
this_wdbase = this_scov_helper.wdbase_for(self, covlevel)
240240

241241
wdctl = WdirControl(wdbase=this_wdbase, bdbase=self._available_bdbase,
242242
subdirhint=subdirhint)
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
pragma Assertion_Policy (Check);
2+
pragma Ada_2012;
3+
4+
package body Assertions is
5+
6+
---------
7+
-- Foo --
8+
---------
9+
10+
function Foo (I : Integer) return Integer
11+
is
12+
High : Integer := 3; -- # foo_hi_decl
13+
begin
14+
for J in 1 .. High loop -- # foo_loop_1
15+
pragma Loop_Invariant (J = J + 1 - 1 and then J < 4); -- # foo_inv_1
16+
end loop;
17+
18+
for J in 1 .. High loop -- # foo_loop_2
19+
pragma Loop_Invariant (J = J + 1 - 1 or else J < 4); -- # foo_inv_2
20+
end loop;
21+
return I; -- # foo_return
22+
end Foo;
23+
24+
----------
25+
-- Same --
26+
----------
27+
28+
function Same (A, B : Boolean) return Boolean
29+
is
30+
-- Subprogram body with aspect without prior declaration
31+
32+
function Id (C : Boolean) return Boolean
33+
with Pre => C or else (C or else not C), -- # id_pre
34+
Post => Id'Result = C -- # id_post
35+
is
36+
begin
37+
return C; -- # id_ret
38+
end Id;
39+
40+
begin
41+
-- Decision nested as parameter of a function call within an assertion.
42+
-- The function parameter should not be seen as a condition for the
43+
-- assertion decision.
44+
45+
-- Last two conditions are not evaluated
46+
47+
pragma Assert (Id (A or else B) or else A or else B); -- # nested_1
48+
49+
-- Last condition is not evaluated
50+
51+
pragma Assert (B or else A or else Id (A or else B)); -- # nested_2
52+
53+
-- All conditions are evaluated
54+
55+
pragma Assert (B or else Id (A or else B)); -- # nested_3
56+
return B; -- # same_ret
57+
end Same;
58+
59+
end Assertions;

0 commit comments

Comments
 (0)