Files
cobol-java-v3/tests/cobol_testgen/test_skill_key_suffix.py

149 lines
5.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""JIN02SKL 型"明细键─主表键"后缀配对测试。
复现根因:跨文件键协调 _find_key_pairs 只做同名精确匹配 / WORK- 变体 /
EMP 族回退。当明细键 base='SKILL-CODE' 与主表键 base='MST-SKILL-CODE'
(多 'MST-' 限定词)时匹配不到,导致 SEARCH ALL 永未命中、
TBL-EMP-COUNT 恒 0#7/#8> ZEROTRUE 分支不可达。
修复:增加"后缀匹配"层级——一方 base 是另一方真后缀且 key 类别一致
(同为 -CODE/-ID/-NO/DATE/EMP-ID)时配对。通用实现、无程序名硬编码。
"""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
import pytest
from cobol_testgen.__init__ import (
_coordinate_multi_file_keys,
_find_key_pairs_inner,
)
def _group(name):
return {'name': name, 'level': 1, 'pic': None,
'pic_info': {'type': 'group', 'digits': 0, 'decimal': 0, 'length': 200, 'signed': False},
'section': 'FILE', 'is_filler': False, 'redefines': None, 'usage': 'DISPLAY',
'occurs': 0, 'occurs_depending': None, 'value': None, 'values': None}
def _field(name, level, pic, ftype, length):
return {'name': name, 'level': level, 'pic': pic,
'pic_info': {'type': ftype, 'digits': 0, 'decimal': 0, 'length': length, 'signed': False},
'section': 'FILE', 'is_filler': False, 'redefines': None, 'usage': 'DISPLAY',
'occurs': 0, 'occurs_depending': None, 'value': None, 'values': None}
def _skill_fields():
# 字段顺序与源文件一致:01 记录紧跟其子字段(COPY REPLACING R01/R02
return [
_group('R01INNREC'),
_field('R01SKILL-CODE', 3, 'X(004)', 'alphanumeric', 4),
_field('R01EMP-ID', 3, 'X(008)', 'alphanumeric', 8),
_field('R01EMP-NAME', 3, 'X(040)', 'alphanumeric', 40),
_field('R01EVAL-DATE', 3, 'X(008)', 'alphanumeric', 8),
_field('R01SCORE', 3, '9(003)', 'numeric', 3),
_group('R02INNREC'),
_field('R02MST-SKILL-CODE', 3, 'X(004)', 'alphanumeric', 4),
_field('R02MST-LEVEL', 3, '9(002)', 'numeric', 2),
_field('R02MST-SCORE-FROM', 3, '9(003)', 'numeric', 3),
_field('R02MST-SCORE-TO', 3, '9(003)', 'numeric', 3),
_field('R02MST-LEVEL-NAME', 3, 'X(020)', 'alphanumeric', 20),
]
def _skill_records(n=6):
recs = []
for i in range(n):
recs.append({
'R01SKILL-CODE': f'A{i + 1:03d}',
'R01EMP-ID': f'B{i + 1:07d}',
'R01EMP-NAME': 'N' * 40,
'R01EVAL-DATE': f'D{i + 1:08d}',
'R01SCORE': f'{100 + i:03d}',
'R02MST-SKILL-CODE': f'F{i + 1:03d}',
'R02MST-LEVEL': f'{20 + i:02d}',
'R02MST-SCORE-FROM': f'{300 + i:03d}',
'R02MST-SCORE-TO': f'{400 + i:03d}',
'R02MST-LEVEL-NAME': 'G' * 20,
})
return recs
FILE_SEC = {
'R01INNFIL': ['R01INNREC'],
'R02INNFIL': ['R02INNREC'],
'W01OUTFIL': ['W01OUTREC'],
'W02OUTFIL': ['W02OUTREC'],
}
OPEN_DIR = {
'R01INNFIL': 'INPUT',
'R02INNFIL': 'INPUT',
'W01OUTFIL': 'OUTPUT',
'W02OUTFIL': 'OUTPUT',
}
def test_find_key_pairs_suffix_skill_code():
"""明细键 SKILL-CODE 应与主表键 MST-SKILL-CODE 后缀配对。"""
fields = _skill_fields()
pairs = _find_key_pairs_inner('R01', 'R02', fields)
assert ('R01SKILL-CODE', 'R02MST-SKILL-CODE') in pairs, f'SKILL-CODE↔MST-SKILL-CODE 应配对, 实际 {pairs}'
def test_find_key_pairs_suffix_no_cross_class():
"""类别不一致的后缀不应误配:DATE 类键不与 CODE 类键配对。"""
fields = _skill_fields()
pairs = _find_key_pairs_inner('R01', 'R02', fields)
date_keys = [fa for fa, _ in pairs if 'DATE' in fa.upper()]
code_keys = [fb for _, fb in pairs if '-CODE' in fb.upper()]
# R01EVAL-DATE 不应与 R02MST-SKILL-CODE 配对
assert not any('R01EVAL-DATE' == fa and fb == 'R02MST-SKILL-CODE' for fa, fb in pairs), f'DATE 不应与 CODE 后缀配对, 实际 {pairs}'
def test_coordinate_multi_file_keys_skill_match():
"""协调后应使部分记录 R01SKILL-CODE == R02MST-SKILL-CODE,运行时 SEARCH 可达。"""
fields = _skill_fields()
records = _skill_records(6)
_coordinate_multi_file_keys(
records, [], fields, {}, FILE_SEC,
term_types=['normal'] * len(records), open_dir=OPEN_DIR,
)
matched = [r for r in records
if str(r['R01SKILL-CODE']).strip() == str(r['R02MST-SKILL-CODE']).strip()]
assert matched, '至少一条记录明细键应与主表键一致'
def test_coordinate_exact_match_still_pairs():
"""既有同名精确匹配(EMP-ID↔EMP-ID)不受后缀层级影响。"""
fields = [
_group('R01INNREC'),
_field('R01EMP-ID', 3, 'X(008)', 'alphanumeric', 8),
_group('R02INNREC'),
_field('R02EMP-ID', 3, 'X(008)', 'alphanumeric', 8),
]
pairs = _find_key_pairs_inner('R01', 'R02', fields)
assert ('R01EMP-ID', 'R02EMP-ID') in pairs, f'同名 EMP-ID 应仍精确配对, 实际 {pairs}'
def test_coordinate_last_record_matches_table_key():
"""末条 normal 记录明细键应对齐表内键(首条 R02 键)。
社员工键中断集约(JIN09RPT 型):最终社员工组在 EOF 後の终了处理で出力される
`IF WRK-EMP-EVAL-CNT > ZERO PERFORM 3000OUTPUSOR`)。協調が先頭のみ整列だと
最終组に照合データがなく最终组输出分支不可達。末条记录も表内键に揃えることで
該分支が到達可能になる。
"""
fields = _skill_fields()
records = _skill_records(12)
_coordinate_multi_file_keys(
records, [], fields, {}, FILE_SEC,
term_types=['normal'] * len(records), open_dir=OPEN_DIR,
)
table_key = str(records[0]['R02MST-SKILL-CODE']).strip()
last = records[-1]
assert str(last['R01SKILL-CODE']).strip() == table_key, \
f'末条记录明细键应对齐表内键 {table_key}, 实际 {last["R01SKILL-CODE"]!r}'