Commit bb02ecaf authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Added branch coverage checks

parent 42217e3d
......@@ -2958,6 +2958,7 @@ def decision(root, parent, context):
str(child.type), [dec.pos_x, dec.pos_y]])
# Make type checks to be sure that question and answers are compatible
covered_ranges = defaultdict(list)
qmin, qmax = 0, 0
need_else = False
for ans in dec.answers:
if ans.kind in ('constant', 'open_range'):
......@@ -3076,30 +3077,61 @@ def decision(root, parent, context):
dec=dec.inputString))
if (a0_val < qmin and a1_val < qmin) or (a0_val > qmax and
a1_val > qmax):
warnings.append('Decision "{dec}": Unreachable branch'
.format(dec=dec.inputString))
warnings.append('Decision "{dec}": Unreachable branch {l}:{h}'
.format(dec=dec.inputString,
l=a0_val, h=a1_val))
covered_ranges[ans].append((int(float(a0_basic.Min)),
int(float(a1_basic.Max))))
# Check the following:
# (1) no overlap between covered ranges in decision answers
# (2) no gap in the coverage of the decision possible values
# (3) ELSE branch, if present, can be reached
# (4) if an answer uses a non-ground expression an ELSE is there
q_ranges = [(qmin, qmax)] if is_numeric(dec.question.exprType) else []
for each in combinations(covered_ranges.viewitems(), 2):
for comb in combinations(
chain.from_iterable(val[1] for val in each), 2):
comb_overlap = (max(comb[0][0], comb[1][0]),
min(comb[0][1], comb[1][1]))
if comb_overlap[0] <= comb_overlap[1]:
errors.append('Non-determinism in decision "{d}": '
'answers {a1} and {a2} '
# (1) - check for overlaps
errors.append('Decision "{d}": answers {a1} and {a2} '
'are overlapping in range [{o1} .. {o2}]'
.format(d=dec.inputString,
a1=each[0][0].inputString,
a2=each[1][0].inputString,
o1=comb_overlap[0],
o2=comb_overlap[1]))
new_q_ranges = []
# for minq, maxq in q_ranges:
# (2) Check that decision range is fully covered
for ans_ref, ranges in covered_ranges.viewitems():
for mina, maxa in ranges:
for minq, maxq in q_ranges:
left = (minq, min(maxq, mina - 1))
right = (max(minq, maxa + 1), maxq)
if mina > minq and maxa < maxq:
new_q_ranges.extend([left, right])
elif mina <= minq and maxa >= maxq:
pass
elif mina <= minq:
new_q_ranges.append(right)
elif maxa >= maxq:
new_q_ranges.append(left)
q_ranges, new_q_ranges = new_q_ranges, []
if not has_else:
for minq, maxq in q_ranges:
errors.append('Decision "{}": No answer to cover range [{} .. {}]'
.format(dec.inputString, minq, maxq))
elif has_else and is_numeric(dec.question.exprType) and not q_ranges:
# (3) Check that ELSE branch is reachable
warnings.append('Decision "{}": ELSE branch is unreachable'
.format(dec.inputString))
if need_else and not has_else:
warnings.append('Missing ELSE branch in decision {}'
# (4) Answers use non-ground expression -> there should be an ELSE
warnings.append('Decision "{}": Missing ELSE branch'
.format(dec.inputString))
return dec, errors, warnings
......
......@@ -4,6 +4,8 @@ PROCESS myfunction;
dcl var1 t_Int32 := 0;
dcl var2 t_uint8 := 0;
dcl var3 t_uInt8 := 0;
/* CIF ENDTEXT */
/* CIF TEXT (36, 43), (360, 41) */
-- Test the branch coverage checker in decision answers
......@@ -14,29 +16,36 @@ dcl var2 t_uint8 := 0;
DECISION var1
/* CIF COMMENT (333, 349), (191, 35) */
COMMENT 'Check range overlapping';
/* CIF ANSWER (99, 412), (88, 23) */
/* CIF ANSWER (96, 412), (90, 24) */
(-500:500):
/* CIF ANSWER (198, 412), (70, 23) */
/* CIF ANSWER (198, 412), (70, 24) */
(=0):
/* CIF ANSWER (288, 412), (70, 23) */
/* CIF ANSWER (288, 412), (70, 24) */
(/=1):
/* CIF ANSWER (378, 412), (70, 23) */
/* CIF ANSWER (378, 412), (70, 24) */
(>0):
ENDDECISION;
/* CIF DECISION (243, 460), (70, 50) */
/* CIF DECISION (243, 470), (70, 50) */
DECISION var2
/* CIF COMMENT (333, 467), (241, 35) */
/* CIF COMMENT (333, 477), (241, 35) */
COMMENT 'Check unreachable branch check';
/* CIF ANSWER (117, 530), (52, 33) */
/* CIF ANSWER (115, 540), (53, 33) */
(<0):
/* CIF ANSWER (200, 530), (66, 33) */
/* CIF ANSWER (197, 540), (68, 33) */
(>300):
/* CIF ANSWER (286, 530), (72, 33) */
/* CIF ANSWER (286, 540), (72, 33) */
(-10:-5):
/* CIF ANSWER (372, 530), (83, 23) */
/* CIF ANSWER (369, 540), (86, 24) */
(256:300):
ENDDECISION;
/* CIF NEXTSTATE (243, 588), (70, 35) */
/* CIF DECISION (242, 602), (71, 50) */
DECISION var3;
/* CIF ANSWER (196, 672), (71, 24) */
(10:20):
/* CIF ANSWER (288, 672), (70, 24) */
(/=50):
ENDDECISION;
/* CIF NEXTSTATE (243, 716), (70, 35) */
NEXTSTATE wait;
/* CIF STATE (868, 313), (70, 35) */
STATE wait;
......
/* CIF PROCESS (200, 143), (150, 75) */
PROCESS myfunction;
/* CIF TEXT (36, 43), (360, 41) */
-- Test the branch coverage checker in decision answers
/* CIF ENDTEXT */
/* CIF TEXT (0, 142), (282, 128) */
dcl var1 t_Int32 := 0;
dcl var2 t_uint8 := 0;
/* CIF ENDTEXT */
/* CIF TEXT (36, 43), (360, 41) */
-- Test the branch coverage checker in decision answers
dcl var3 t_uInt8 := 0;
/* CIF ENDTEXT */
/* CIF START (243, 292), (70, 35) */
START;
......@@ -14,29 +16,36 @@ dcl var2 t_uint8 := 0;
DECISION var1
/* CIF COMMENT (333, 349), (191, 35) */
COMMENT 'Check range overlapping';
/* CIF ANSWER (99, 412), (88, 23) */
/* CIF ANSWER (95, 412), (90, 24) */
(-500:500):
/* CIF ANSWER (198, 412), (70, 23) */
/* CIF ANSWER (198, 412), (70, 24) */
(=0):
/* CIF ANSWER (288, 412), (70, 23) */
/* CIF ANSWER (288, 412), (70, 24) */
(/=1):
/* CIF ANSWER (378, 412), (70, 23) */
/* CIF ANSWER (378, 412), (70, 24) */
(>0):
ENDDECISION;
/* CIF DECISION (243, 460), (70, 50) */
/* CIF DECISION (243, 475), (70, 50) */
DECISION var2
/* CIF COMMENT (333, 467), (241, 35) */
/* CIF COMMENT (333, 482), (241, 35) */
COMMENT 'Check unreachable branch check';
/* CIF ANSWER (117, 530), (52, 33) */
/* CIF ANSWER (114, 545), (53, 33) */
(<0):
/* CIF ANSWER (200, 530), (66, 33) */
/* CIF ANSWER (196, 545), (68, 33) */
(>300):
/* CIF ANSWER (286, 530), (72, 33) */
/* CIF ANSWER (286, 545), (72, 33) */
(-10:-5):
/* CIF ANSWER (372, 530), (83, 23) */
/* CIF ANSWER (368, 545), (86, 24) */
(256:300):
ENDDECISION;
/* CIF NEXTSTATE (243, 588), (70, 35) */
/* CIF DECISION (242, 621), (71, 50) */
DECISION var3;
/* CIF ANSWER (195, 691), (71, 24) */
(10:20):
/* CIF ANSWER (288, 691), (70, 24) */
(/=50):
ENDDECISION;
/* CIF NEXTSTATE (243, 740), (70, 35) */
NEXTSTATE wait;
/* CIF STATE (868, 313), (70, 35) */
STATE wait;
......
all: test-ada
edit:
../../../opengeode.py og.pr system_structure.pr
test-parse:
../../../opengeode.py og.pr system_structure.pr --check
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment