fix: 覆盖率统计全面修复 + 5漏洞修正
## 修复内容 ### C1: _mark_eval 反向操作符 (coverage.py) - EVALUATE 约束匹配支持 操作符 - WHEN OTHER 的自动检测(全部 WHEN 被否定时) ### C2: _mark_perform 反向操作符 (coverage.py) - PERFORM 同 _mark_if 的反向操作符匹配 - PERFORM UNTIL 条件截断后桥接器通过 branch_names 识别类型 ### H1: parse_single_condition 传递 fields (coverage.py) - collect_decision_points 调用时传 fields 参数 - NOT 前缀条件解析 (NOT WS-X > 50 → WS-X <= 50) ### H4: generate_data 输入约束 (__init__.py) - 文档注明接收原始源码,非预处理后文本 ### M1: not_map break (cond.py) - NOT 操作符映射循环添加 break ## 覆盖测试结果 - IF: 100% (T/F) - NOT IF: 100% (NOT_TRUE/NOT_FALSE) - PERFORM UNTIL: 100% (ENTER/SKIP) - EVALUATE: 100% (4 WHENs) - Nested IF: 100% (4 branches) - S15 回归: 17/17 PASS Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -50,7 +50,7 @@ def collect_decision_points(node, fields, counter=None):
|
||||
counter[0] += 1
|
||||
dp = DecisionPoint(id=counter[0], kind='IF', label=node.condition,
|
||||
branch_names=['T', 'F'])
|
||||
simple = parse_single_condition(node.condition)
|
||||
simple = parse_single_condition(node.condition, fields)
|
||||
if simple and is_field(simple[0], fields):
|
||||
dp.parsed = simple
|
||||
elif simple:
|
||||
@@ -110,7 +110,7 @@ def collect_decision_points(node, fields, counter=None):
|
||||
dp = DecisionPoint(id=counter[0], kind='PERFORM',
|
||||
label=node.condition or '',
|
||||
branch_names=['Enter', 'Skip'])
|
||||
simple = parse_single_condition(node.condition) if node.condition else None
|
||||
simple = parse_single_condition(node.condition, fields) if node.condition else None
|
||||
if simple and is_field(simple[0], fields):
|
||||
dp.parsed = simple
|
||||
elif node.condition:
|
||||
@@ -178,12 +178,17 @@ def _match_leaf(c, leaf):
|
||||
def _mark_if(dp, cons):
|
||||
simple = getattr(dp, 'parsed', None)
|
||||
if simple:
|
||||
field, op, val = simple
|
||||
inv_op = {'=': '<>', '<>': '=', '>': '<=', '<': '>=', '>=': '<', '<=': '>'}.get(op, op)
|
||||
inv_simple = (field, inv_op, val)
|
||||
for c in cons:
|
||||
if _match_constraint(c, simple):
|
||||
if c[3]:
|
||||
dp.active_branches.add('T')
|
||||
else:
|
||||
dp.active_branches.add('F')
|
||||
elif _match_constraint(c, inv_simple):
|
||||
dp.active_branches.add('F')
|
||||
elif dp.cond_tree and dp.cond_leaves:
|
||||
assignment = {}
|
||||
for leaf in dp.cond_leaves:
|
||||
@@ -250,13 +255,27 @@ def _mark_eval(dp, cons, fields=None):
|
||||
if when_fields:
|
||||
dp.active_branches.add('OTHER')
|
||||
return
|
||||
matched_when = False
|
||||
for c in cons:
|
||||
if c[0] == dp.label and c[1] == '=':
|
||||
name = f"WHEN {c[2]}"
|
||||
if name in dp.branch_names:
|
||||
dp.active_branches.add(name)
|
||||
matched_when = True
|
||||
elif c[0] == dp.label and c[1] == '<>':
|
||||
pass # Inverted operator — skip (negation of a prior WHEN)
|
||||
elif c[0] == dp.label and c[1] == 'not_in':
|
||||
dp.active_branches.add('OTHER')
|
||||
matched_when = True
|
||||
# If all subject constraints are '<>' (negations) and no '=' matched,
|
||||
# this path reaches OTHER (EVALUATE ... WHEN OTHER)
|
||||
if not matched_when and 'OTHER' in dp.branch_names:
|
||||
all_negs = all(c[1] == '<>' for c in cons if c[0] == dp.label)
|
||||
if all_negs:
|
||||
dp.active_branches.add('OTHER')
|
||||
elif any(c[1] in ('>=', '<=') for c in cons if c[0] == dp.label):
|
||||
# THRU-range OTHER detection
|
||||
pass
|
||||
thru_lows = {c[2] for c in cons if c[0] == dp.label and c[1] == '>=' and c[3]}
|
||||
thru_highs = {c[2] for c in cons if c[0] == dp.label and c[1] == '<=' and c[3]}
|
||||
if thru_lows or thru_highs:
|
||||
@@ -309,12 +328,17 @@ def _mark_search(dp, cons, fields=None):
|
||||
def _mark_perform(dp, cons):
|
||||
simple = getattr(dp, 'parsed', None)
|
||||
if simple:
|
||||
field, op, val = simple
|
||||
inv_op = {'=': '<>', '<>': '=', '>': '<=', '<': '>=', '>=': '<', '<=': '>'}.get(op, op)
|
||||
inv_simple = (field, inv_op, val)
|
||||
for c in cons:
|
||||
if _match_constraint(c, simple):
|
||||
if c[3]:
|
||||
dp.active_branches.add('Skip')
|
||||
else:
|
||||
dp.active_branches.add('Enter')
|
||||
elif _match_constraint(c, inv_simple):
|
||||
dp.active_branches.add('Enter')
|
||||
elif dp.cond_tree and dp.cond_leaves:
|
||||
assignment = {}
|
||||
for leaf in dp.cond_leaves:
|
||||
|
||||
Reference in New Issue
Block a user