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

Check coverage of boolean decisions

parent a838c2d8
...@@ -3472,7 +3472,7 @@ def decision(root, parent, context): ...@@ -3472,7 +3472,7 @@ def decision(root, parent, context):
covered_ranges = defaultdict(list) covered_ranges = defaultdict(list)
qmin, qmax = 0, 0 qmin, qmax = 0, 0
need_else = False need_else = False
is_enum = False is_enum, is_bool = False, False
for ans in dec.answers: for ans in dec.answers:
if dec.kind in ('informal_text', 'any'): if dec.kind in ('informal_text', 'any'):
break break
...@@ -3495,6 +3495,12 @@ def decision(root, parent, context): ...@@ -3495,6 +3495,12 @@ def decision(root, parent, context):
continue continue
covered_ranges[ans].append(ans.inputString) covered_ranges[ans].append(ans.inputString)
is_enum = True is_enum = True
elif q_basic.kind == 'BooleanType':
covered_ranges[ans].append(ans.inputString)
is_bool = True
if not ans.constant.is_raw:
need_else = True
continue
if not q_basic.kind.startswith(('Integer', 'Real')): if not q_basic.kind.startswith(('Integer', 'Real')):
# Check numeric questions - ignore others # Check numeric questions - ignore others
continue continue
...@@ -3648,7 +3654,7 @@ def decision(root, parent, context): ...@@ -3648,7 +3654,7 @@ def decision(root, parent, context):
new_q_ranges = [] new_q_ranges = []
# (2) Check that decision range is fully covered # (2) Check that decision range is fully covered
for ans_ref, ranges in covered_ranges.viewitems(): for ans_ref, ranges in covered_ranges.viewitems():
if is_enum: if is_enum or is_bool:
continue continue
for mina, maxa in ranges: for mina, maxa in ranges:
for minq, maxq in q_ranges: for minq, maxq in q_ranges:
...@@ -3683,7 +3689,7 @@ def decision(root, parent, context): ...@@ -3683,7 +3689,7 @@ def decision(root, parent, context):
.format(dec.inputString)) .format(dec.inputString))
# (5) check coverage of enumerated types # (5) check coverage of enumerated types
if is_enum: if is_enum or is_bool:
# check duplicate answers # check duplicate answers
answers = [a.lower() answers = [a.lower()
for a in chain.from_iterable(covered_ranges.viewvalues())] for a in chain.from_iterable(covered_ranges.viewvalues())]
...@@ -3691,8 +3697,12 @@ def decision(root, parent, context): ...@@ -3691,8 +3697,12 @@ def decision(root, parent, context):
if dupl: if dupl:
qerr.append('Decision "{}": duplicate answers "{}"' qerr.append('Decision "{}": duplicate answers "{}"'
.format(dec.inputString, '", "'.join(dupl))) .format(dec.inputString, '", "'.join(dupl)))
enumerants = [en.replace('-', '_').lower() if is_bool:
for en in q_basic.EnumValues.keys()] # Boolean special case: values are just True and False
enumerants = ['true', 'false']
else:
enumerants = [en.replace('-', '_').lower()
for en in q_basic.EnumValues.keys()]
# check for missing answers # check for missing answers
if set(answers) != set(enumerants) and not has_else: if set(answers) != set(enumerants) and not has_else:
qerr.append('Decision "{}": Missing branches for answer(s) "{}"' qerr.append('Decision "{}": Missing branches for answer(s) "{}"'
......
...@@ -3,9 +3,12 @@ ...@@ -3,9 +3,12 @@
[ERROR] Decision "var6": No answer to cover range 10.0 .. 10.5 [ERROR] Decision "var6": No answer to cover range 10.0 .. 10.5
[ERROR] Decision "var6": No answer to cover value 10.0 [ERROR] Decision "var6": No answer to cover value 10.0
[ERROR] Decision "var6": answers >=10.0 and <=10.0 are overlapping in range 10.0 .. 10.0 [ERROR] Decision "var6": answers >=10.0 and <=10.0 are overlapping in range 10.0 .. 10.0
[ERROR] Decision "varbool": Missing branches for answer(s) "false"
[ERROR] Decision "varbool": Missing branches for answer(s) "false"
[ERROR] Too many errors, cannot generate code [ERROR] Too many errors, cannot generate code
[INFO] Checking ['myfunction.pr', 'system_structure.pr'] [INFO] Checking ['myfunction.pr', 'system_structure.pr']
[INFO] Parsing complete. Summary, found 2 warnings and 5 errors [INFO] Parsing complete. Summary, found 3 warnings and 7 errors
[INFO] myfunction.pr [INFO] myfunction.pr
[WARNING] Decision "var6": Range -10.0 .. -5.0 is unreachable [WARNING] Decision "var6": Range -10.0 .. -5.0 is unreachable
[WARNING] Decision "var6": Range 100.0 .. 150.0 is unreachable [WARNING] Decision "var6": Range 100.0 .. 150.0 is unreachable
[WARNING] Decision "varbool": Missing ELSE branch
...@@ -2,74 +2,111 @@ ...@@ -2,74 +2,111 @@
PROCESS myfunction; PROCESS myfunction;
/* CIF TEXT (78, 142), (282, 268) */ /* CIF TEXT (78, 142), (282, 268) */
dcl var6 T_Real := 5.0; dcl var6 T_Real := 5.0;
dcl varbool T_Boolean := false;
/* CIF ENDTEXT */ /* CIF ENDTEXT */
/* CIF TEXT (0, 43), (449, 41) */ /* CIF TEXT (0, 43), (449, 41) */
-- Test the branch coverage checker in decision answers -- Test the branch coverage checker in decision answers
/* CIF ENDTEXT */ /* CIF ENDTEXT */
/* CIF START (525, 71), (70, 35) */ /* CIF START (525, 71), (70, 35) */
START; START;
/* CIF DECISION (523, 121), (73, 50) */ /* CIF DECISION (511, 121), (98, 50) */
DECISION varbool
/* CIF COMMENT (629, 128), (262, 35) */
COMMENT 'check branch false is missing';
/* CIF ANSWER (484, 198), (73, 28) */
(true):
ENDDECISION;
/* CIF DECISION (511, 241), (98, 50) */
DECISION varbool
/* CIF COMMENT (629, 248), (262, 35) */
COMMENT 'check there is no error';
/* CIF ANSWER (439, 318), (73, 28) */
(true):
/* CIF ANSWER (531, 311), (71, 28) */
else:
ENDDECISION;
/* CIF DECISION (511, 368), (98, 50) */
DECISION varbool
/* CIF COMMENT (629, 375), (262, 35) */
COMMENT 'check there is no error';
/* CIF ANSWER (439, 445), (73, 28) */
(true):
/* CIF ANSWER (527, 438), (78, 28) */
(false):
ENDDECISION;
/* CIF DECISION (511, 495), (98, 50) */
DECISION varbool
/* CIF COMMENT (629, 502), (322, 48) */
COMMENT 'check else is missing
and mix of true and varbool is not ok';
/* CIF ANSWER (412, 565), (73, 28) */
(true):
/* CIF ANSWER (495, 565), (98, 28) */
(varbool):
ENDDECISION;
/* CIF DECISION (523, 608), (73, 50) */
DECISION var6 DECISION var6
/* CIF COMMENT (616, 128), (217, 35) */ /* CIF COMMENT (616, 615), (217, 35) */
COMMENT 'check there is no error'; COMMENT 'check there is no error';
/* CIF ANSWER (590, 191), (82, 28) */ /* CIF ANSWER (590, 678), (82, 28) */
(<10.0): (<10.0):
/* CIF ANSWER (440, 191), (92, 28) */ /* CIF ANSWER (440, 678), (92, 28) */
(>=10.0): (>=10.0):
ENDDECISION; ENDDECISION;
/* CIF DECISION (523, 234), (73, 50) */ /* CIF DECISION (523, 721), (73, 50) */
DECISION var6 DECISION var6
/* CIF COMMENT (616, 241), (279, 35) */ /* CIF COMMENT (616, 728), (279, 35) */
COMMENT 'check there is value 10 missing'; COMMENT 'check there is value 10 missing';
/* CIF ANSWER (590, 304), (82, 28) */ /* CIF ANSWER (590, 791), (82, 28) */
(<10.0): (<10.0):
/* CIF ANSWER (440, 304), (92, 28) */ /* CIF ANSWER (440, 791), (92, 28) */
(>10.0): (>10.0):
ENDDECISION; ENDDECISION;
/* CIF DECISION (523, 347), (73, 50) */ /* CIF DECISION (523, 834), (73, 50) */
DECISION var6 DECISION var6
/* CIF COMMENT (616, 354), (314, 35) */ /* CIF COMMENT (616, 841), (314, 35) */
COMMENT 'check there is value 10 overlapping'; COMMENT 'check there is value 10 overlapping';
/* CIF ANSWER (585, 417), (92, 28) */ /* CIF ANSWER (585, 904), (92, 28) */
(<=10.0): (<=10.0):
/* CIF ANSWER (440, 417), (92, 28) */ /* CIF ANSWER (440, 904), (92, 28) */
(>=10.0): (>=10.0):
ENDDECISION; ENDDECISION;
/* CIF DECISION (523, 460), (73, 50) */ /* CIF DECISION (523, 947), (73, 50) */
DECISION var6 DECISION var6
/* CIF COMMENT (616, 467), (314, 35) */ /* CIF COMMENT (616, 954), (314, 35) */
COMMENT 'check missing range ]10.0;10.5['; COMMENT 'check missing range ]10.0;10.5[';
/* CIF ANSWER (585, 530), (92, 28) */ /* CIF ANSWER (585, 1017), (92, 28) */
(<=10.0): (<=10.0):
/* CIF ANSWER (440, 530), (92, 28) */ /* CIF ANSWER (440, 1017), (92, 28) */
(>=10.5): (>=10.5):
ENDDECISION; ENDDECISION;
/* CIF DECISION (523, 573), (73, 50) */ /* CIF DECISION (523, 1060), (73, 50) */
DECISION var6 DECISION var6
/* CIF COMMENT (616, 580), (324, 35) */ /* CIF COMMENT (616, 1067), (324, 35) */
COMMENT 'check there is no error (close range)'; COMMENT 'check there is no error (close range)';
/* CIF ANSWER (496, 643), (116, 28) */ /* CIF ANSWER (496, 1130), (116, 28) */
(-5.0:100.0): (-5.0:100.0):
ENDDECISION; ENDDECISION;
/* CIF DECISION (523, 686), (73, 50) */ /* CIF DECISION (523, 1173), (73, 50) */
DECISION var6 DECISION var6
/* CIF COMMENT (616, 693), (390, 48) */ /* CIF COMMENT (616, 1180), (390, 48) */
COMMENT 'check unreachable branch and missing range'; COMMENT 'check unreachable branch and missing range';
/* CIF ANSWER (585, 756), (92, 28) */ /* CIF ANSWER (585, 1243), (92, 28) */
(>10.0): (>10.0):
/* CIF ANSWER (427, 756), (118, 28) */ /* CIF ANSWER (427, 1243), (118, 28) */
(-10.0:-5.0): (-10.0:-5.0):
ENDDECISION; ENDDECISION;
/* CIF DECISION (523, 799), (73, 50) */ /* CIF DECISION (523, 1286), (73, 50) */
DECISION var6 DECISION var6
/* CIF COMMENT (615, 807), (432, 48) */ /* CIF COMMENT (615, 1294), (432, 48) */
COMMENT 'check missing range 0:0.1 and unrechable 100:150'; COMMENT 'check missing range 0:0.1 and unrechable 100:150';
/* CIF ANSWER (576, 869), (110, 28) */ /* CIF ANSWER (576, 1356), (110, 28) */
(0.1:150.0): (0.1:150.0):
/* CIF ANSWER (427, 869), (118, 28) */ /* CIF ANSWER (427, 1356), (118, 28) */
(-5.0:0.0): (-5.0:0.0):
ENDDECISION; ENDDECISION;
/* CIF NEXTSTATE (525, 912), (70, 35) */ /* CIF NEXTSTATE (525, 1399), (70, 35) */
NEXTSTATE wait; NEXTSTATE wait;
/* CIF STATE (360, 356), (70, 35) */ /* CIF STATE (360, 356), (70, 35) */
STATE wait; STATE wait;
......
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