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:
@@ -405,9 +405,19 @@ def _add_or_merge(node: BranchNode, root: BranchNode):
|
||||
def _make_if_node(cond_text: str, line_no: int) -> BranchNode:
|
||||
"""Create IF node with proper branch names from condition."""
|
||||
base_cond = cond_text.rstrip('.').strip()
|
||||
# Truncate condition at COBOL statement verbs (one-line IF)
|
||||
_COBOL_VERBS = (
|
||||
'DISPLAY', 'MOVE', 'ADD', 'SUBTRACT', 'MULTIPLY', 'DIVIDE', 'COMPUTE',
|
||||
'STRING', 'UNSTRING', 'SET', 'INSPECT', 'INITIALIZE', 'CONTINUE',
|
||||
'PERFORM', 'CALL', 'EXIT', 'GOBACK', 'STOP', 'THEN', 'ELSE',
|
||||
'READ', 'WRITE', 'DELETE', 'REWRITE', 'ACCEPT', 'OPEN', 'CLOSE',
|
||||
)
|
||||
for verb in _COBOL_VERBS:
|
||||
idx = base_cond.upper().find(f' {verb} ')
|
||||
if idx >= 0:
|
||||
base_cond = base_cond[:idx].strip()
|
||||
break
|
||||
# Parse condition for branch count
|
||||
# Single condition → 2 branches
|
||||
# AND conditions → (N+1) branches
|
||||
has_and = bool(re.search(r'\bAND\b', base_cond, re.IGNORECASE)
|
||||
and not re.search(r'\bAND\b', base_cond.split('NOT')[1], re.IGNORECASE)
|
||||
if 'NOT' in base_cond.upper() and len(base_cond.split('NOT')) > 1
|
||||
@@ -434,15 +444,29 @@ def _make_if_node(cond_text: str, line_no: int) -> BranchNode:
|
||||
def _make_perform_node(rest: str, line_no: int) -> BranchNode:
|
||||
"""Create PERFORM node."""
|
||||
upper = rest.upper()
|
||||
# Truncate at COBOL verbs (one-line PERFORM: UNTIL cond BODY)
|
||||
verb_list = (
|
||||
'DISPLAY', 'MOVE', 'ADD', 'SUBTRACT', 'MULTIPLY', 'DIVIDE', 'COMPUTE',
|
||||
'STRING', 'UNSTRING', 'SET', 'INSPECT', 'INITIALIZE', 'CONTINUE',
|
||||
'PERFORM', 'CALL', 'EXIT', 'GOBACK', 'STOP',
|
||||
'READ', 'WRITE', 'DELETE', 'REWRITE', 'ACCEPT', 'OPEN', 'CLOSE',
|
||||
)
|
||||
cond_text = rest
|
||||
for verb in verb_list:
|
||||
idx = rest.upper().find(f' {verb} ')
|
||||
if idx >= 0:
|
||||
cond_text = rest[:idx].strip()
|
||||
break
|
||||
if upper.startswith('UNTIL'):
|
||||
ctext = cond_text[5:].strip() if cond_text.upper().startswith('UNTIL') else cond_text
|
||||
return BranchNode("PERFORM", branch_names=["ENTER", "SKIP"],
|
||||
condition_text=rest[5:].strip(), source_line=line_no)
|
||||
condition_text=ctext, source_line=line_no)
|
||||
elif upper.startswith('VARYING'):
|
||||
return BranchNode("PERFORM", branch_names=["VARY_ENTER", "VARY_EXIT"],
|
||||
condition_text=rest, source_line=line_no)
|
||||
condition_text=cond_text, source_line=line_no)
|
||||
elif re.match(r'\bTIMES\b', upper):
|
||||
return BranchNode("PERFORM", branch_names=["TIMES_ENTER", "TIMES_EXIT"],
|
||||
condition_text=rest, source_line=line_no)
|
||||
condition_text=cond_text, source_line=line_no)
|
||||
else:
|
||||
# Simple PERFORM paragraph-name — just a call, no branch
|
||||
para_name = rest.split()[0].upper() if rest.split() else "?"
|
||||
|
||||
Reference in New Issue
Block a user