Files
cobol-java-v3/tests/cobol_testgen/test_read_into_layout.py
T

139 lines
6.3 KiB
Python

"""RI-01~05: opaque FD + READ INTO — WS 子字段值序列化回 FD 记录字节 + 跨记录 key 差异保证"""
import sys, os, json, tempfile
from pathlib import Path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
from cobol_testgen import _serialize_read_into_records
from cobol_testgen.core import build_branch_tree
def _mk_fields():
return [
{'name': 'R01INNREC', 'level': 1, 'pic': 'X(080)',
'pic_info': {'type': 'alphanumeric', 'digits': 0, 'decimal': 0, 'length': 80, 'signed': False},
'is_filler': False, 'redefines': None, 'is_88': False},
{'name': 'WRK-ABSENCE-REC', 'level': 1, 'pic': '',
'pic_info': {'type': 'unknown', 'digits': 0, 'decimal': 0, 'length': 0, 'signed': False},
'is_filler': False, 'redefines': None, 'is_88': False},
{'name': 'WRK-EMP-ID', 'level': 5, 'pic': 'X(008)',
'pic_info': {'type': 'alphanumeric', 'digits': 0, 'decimal': 0, 'length': 8, 'signed': False},
'is_filler': False, 'redefines': None, 'is_88': False},
{'name': 'WRK-YEAR-MONTH', 'level': 5, 'pic': 'X(006)',
'pic_info': {'type': 'alphanumeric', 'digits': 0, 'decimal': 0, 'length': 6, 'signed': False},
'is_filler': False, 'redefines': None, 'is_88': False},
{'name': 'WRK-ABSENT-HOURS', 'level': 5, 'pic': '9(004)V9(001)',
'pic_info': {'type': 'numeric', 'digits': 4, 'decimal': 1, 'length': 0, 'signed': False},
'is_filler': False, 'redefines': None, 'is_88': False},
{'name': 'FILLER', 'level': 5, 'pic': 'X(062)',
'pic_info': {'type': 'alphanumeric', 'digits': 0, 'decimal': 0, 'length': 62, 'signed': False},
'is_filler': True, 'redefines': None, 'is_88': False},
{'name': 'WRK-PREV-EMP-ID', 'level': 1, 'pic': 'X(008)',
'pic_info': {'type': 'alphanumeric', 'digits': 0, 'decimal': 0, 'length': 8, 'signed': False},
'is_filler': False, 'redefines': None, 'is_88': False},
]
def _mk_records():
return [
{'R01INNREC': 'A' + '0' * 79,
'WRK-EMP-ID': 'G0000001', 'WRK-YEAR-MONTH': 'H00001', 'WRK-ABSENT-HOURS': '01501'},
{'R01INNREC': 'A' + '0' * 79,
'WRK-EMP-ID': 'G0000007', 'WRK-YEAR-MONTH': 'H00007', 'WRK-ABSENT-HOURS': '01507'},
{'R01INNREC': 'A' + '0' * 79,
'WRK-EMP-ID': 'G0000007', 'WRK-YEAR-MONTH': 'H00008', 'WRK-ABSENT-HOURS': '01508'},
]
def test_serialize_into_fd_bytes():
"""RI-01: INTO 组子字段值按 PIC 布局 pack 回 R01INNREC 字节"""
records = _mk_records()
file_sec = {'R01INNFIL': ['R01INNREC']}
assignments = {'WRK-ABSENCE-REC': [{'type': 'read_into', 'file': 'R01INNFIL', 'source_vars': []}]}
_serialize_read_into_records(records, assignments, _mk_fields(), file_sec)
r0 = records[0]['R01INNREC']
assert r0[0:8] == 'G0000001', r0[0:8]
assert r0[8:14] == 'H00001', r0[8:14]
assert r0[14:19] == '01501', r0[14:19]
assert len(r0) == 80
assert r0[19:].strip(' ') == '', r0[19:]
def test_key_variation_both_pairs():
"""RI-02: 相邻记录 key 既有相同又有差异(同 key 累加 + 新 key flush 两路径均可达)"""
records = _mk_records()
file_sec = {'R01INNFIL': ['R01INNREC']}
assignments = {'WRK-ABSENCE-REC': [{'type': 'read_into', 'file': 'R01INNFIL', 'source_vars': []}]}
_serialize_read_into_records(records, assignments, _mk_fields(), file_sec)
keys = [r['R01INNREC'][0:8] for r in records]
has_same = any(keys[i] == keys[i + 1] for i in range(len(keys) - 1))
has_diff = any(keys[i] != keys[i + 1] for i in range(len(keys) - 1))
assert has_same, f"no same-key pair: {keys}"
assert has_diff, f"no diff-key pair: {keys}"
def test_all_same_key_gets_break():
"""RI-03: 全记录同 key 时自动注入差异,保证新 key 分支可达"""
records = [
{'R01INNREC': 'A' + '0' * 79,
'WRK-EMP-ID': 'G0000001', 'WRK-YEAR-MONTH': 'H00001', 'WRK-ABSENT-HOURS': '01501'},
{'R01INNREC': 'A' + '0' * 79,
'WRK-EMP-ID': 'G0000001', 'WRK-YEAR-MONTH': 'H00002', 'WRK-ABSENT-HOURS': '01502'},
{'R01INNREC': 'A' + '0' * 79,
'WRK-EMP-ID': 'G0000001', 'WRK-YEAR-MONTH': 'H00003', 'WRK-ABSENT-HOURS': '01503'},
]
file_sec = {'R01INNFIL': ['R01INNREC']}
assignments = {'WRK-ABSENCE-REC': [{'type': 'read_into', 'file': 'R01INNFIL', 'source_vars': []}]}
_serialize_read_into_records(records, assignments, _mk_fields(), file_sec)
keys = [r['R01INNREC'][0:8] for r in records]
has_diff = any(keys[i] != keys[i + 1] for i in range(len(keys) - 1))
assert has_diff, f"no diff-key pair: {keys}"
def test_noop_without_read_into():
"""RI-04: 无 READ INTO 或 FD 有子字段时不改动记录"""
records = _mk_records()
file_sec = {'R01INNFIL': ['R01INNREC']}
before = [dict(r) for r in records]
_serialize_read_into_records(records, {}, _mk_fields(), file_sec)
assert records == before
fields_with_children = [
{'name': 'R01INNREC', 'level': 1, 'pic': 'X(080)',
'pic_info': {'type': 'alphanumeric', 'digits': 0, 'decimal': 0, 'length': 80, 'signed': False},
'is_filler': False, 'redefines': None, 'is_88': False},
{'name': 'R01EMP-ID', 'level': 5, 'pic': 'X(008)',
'pic_info': {'type': 'alphanumeric', 'digits': 0, 'decimal': 0, 'length': 8, 'signed': False},
'is_filler': False, 'redefines': None, 'is_88': False},
]
records2 = _mk_records()
before2 = [dict(r) for r in records2]
assignments = {'WRK-ABSENCE-REC': [{'type': 'read_into', 'file': 'R01INNFIL', 'source_vars': []}]}
_serialize_read_into_records(records2, assignments, fields_with_children, file_sec)
assert records2 == before2
def test_multiline_read_into_parsed():
"""RI-05: READ <FD> / INTO <GRP> 分行书写仍能解析为 read_into 赋值"""
proc = """PROCEDURE DIVISION.
MAIN.
PERFORM UNTIL WRK-EOF = 'Y'
READ R01INNFIL
INTO WRK-ABSENCE-REC
AT END
MOVE 'Y' TO WRK-EOF
END-READ
IF WRK-EOF = 'Y'
EXIT PERFORM
END-IF
END-PERFORM.
GOBACK.
"""
tree, asgn = build_branch_tree(proc, [])
read_keys = [k for k in asgn if any(
isinstance(a, dict) and a.get('type') == 'read_into' for a in asgn[k])]
assert read_keys == ['WRK-ABSENCE-REC'], read_keys
assert asgn['WRK-ABSENCE-REC'][0]['file'] == 'R01INNFIL'