merge local cobol_testgen improvements into v3 shared modules
- cond.py: SQLCODE/SQLSTATE handling, alphanumeric >/< boundary fix - output.py: termination tracking, db_input support, _is_field_assigned filter - coverage.py: mark_from_gcov, THRU support, KeyError protection - gcov.py: new file (dependency for coverage.py) - grammar.lark: multi-segment PIC support - read.py: SQL INCLUDE resolution, DECLARE TABLE parsing, * comment fix - core.py: SQL parsing, blocked_names, keyword list - design.py: multi-sentinel, THRU ranges, PERFORM VARYING last iteration - __init__.py: local main() + v3 API functions, guarded imports All 6 ZAN programs verified passing through v3 pipeline
This commit is contained in:
+68
-25
@@ -23,27 +23,68 @@ def _scenario_text(path_cons):
|
||||
return ', '.join(parts)
|
||||
|
||||
|
||||
def _write_json(entries, outpath):
|
||||
if not entries:
|
||||
return
|
||||
outpath.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(outpath, 'w', encoding='utf-8') as f:
|
||||
json.dump(entries, f, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
def _is_field_assigned(fname, assigned_set, fields, fd_fields_lookup):
|
||||
if not assigned_set:
|
||||
return False
|
||||
if fname in assigned_set:
|
||||
return True
|
||||
level_map = {}
|
||||
name_order = []
|
||||
for f in fields:
|
||||
fn = f['name']
|
||||
lv = f.get('level', 77)
|
||||
level_map[fn] = lv
|
||||
name_order.append((lv, fn))
|
||||
flv = level_map.get(fname, 77)
|
||||
ancestor = None
|
||||
for lv, fn in name_order:
|
||||
if fn == fname:
|
||||
break
|
||||
if lv < flv:
|
||||
ancestor = fn
|
||||
if ancestor and ancestor in assigned_set:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def output_json(records, outpath, roles=None, fd_fields=None, field_to_fd=None,
|
||||
open_dir=None, path_cons_list=None):
|
||||
open_dir=None, term_types=None, db_input=None, data_fields=None):
|
||||
outpath.parent.mkdir(parents=True, exist_ok=True)
|
||||
if not roles:
|
||||
out = []
|
||||
for i, rec in enumerate(records):
|
||||
entry = dict(rec)
|
||||
entry['termination'] = (term_types or ['normal'] * len(records))[i]
|
||||
out.append(entry)
|
||||
obj = {'program': outpath.stem, 'records': out}
|
||||
if db_input:
|
||||
obj['db_input'] = db_input
|
||||
with open(outpath, 'w', encoding='utf-8') as f:
|
||||
json.dump(records, f, ensure_ascii=False, indent=2)
|
||||
json.dump(obj, f, ensure_ascii=False, indent=2)
|
||||
return
|
||||
|
||||
# FD direction lookup
|
||||
term_types = term_types or ['normal'] * len(records)
|
||||
|
||||
out = []
|
||||
for i, rec in enumerate(records):
|
||||
inp = {}
|
||||
out_exp = {}
|
||||
ws = {}
|
||||
|
||||
# Group by FD
|
||||
if fd_fields and field_to_fd:
|
||||
for fd_name, fds_set in fd_fields.items():
|
||||
direction = (open_dir or {}).get(fd_name, '')
|
||||
inp_block = {}
|
||||
out_block = {}
|
||||
assigned_set = rec.get('_assigned_fields', set())
|
||||
for fname in fds_set:
|
||||
if fname not in rec:
|
||||
continue
|
||||
@@ -52,13 +93,13 @@ def output_json(records, outpath, roles=None, fd_fields=None, field_to_fd=None,
|
||||
if direction in ('INPUT', 'I-O') and r in ('input', 'inout'):
|
||||
inp_block[fname] = val
|
||||
if direction in ('OUTPUT', 'I-O') and r in ('output', 'inout'):
|
||||
out_block[fname] = val
|
||||
if _is_field_assigned(fname, assigned_set, data_fields or [], fd_fields):
|
||||
out_block[fname] = val
|
||||
if inp_block:
|
||||
inp[fd_name] = inp_block
|
||||
if out_block:
|
||||
out_exp[fd_name] = out_block
|
||||
|
||||
# Working-storage: not belonging to any FD
|
||||
for name, val in rec.items():
|
||||
if not field_to_fd or name not in field_to_fd:
|
||||
ws[name] = val
|
||||
@@ -66,25 +107,21 @@ def output_json(records, outpath, roles=None, fd_fields=None, field_to_fd=None,
|
||||
entry = {
|
||||
'input': inp,
|
||||
'expected_output': out_exp,
|
||||
'working_storage': ws,
|
||||
'working_storage': {k: v for k, v in ws.items() if k != '_assigned_fields'},
|
||||
'termination': term_types[i] if i < len(term_types) else 'normal',
|
||||
}
|
||||
|
||||
if path_cons_list and i < len(path_cons_list):
|
||||
text = _scenario_text(path_cons_list[i])
|
||||
if text:
|
||||
entry['scenario'] = text
|
||||
|
||||
out.append(entry)
|
||||
|
||||
with open(outpath, 'w', encoding='utf-8') as f:
|
||||
json.dump(out, f, ensure_ascii=False, indent=2)
|
||||
obj = {'program': outpath.stem, 'records': out}
|
||||
if db_input:
|
||||
obj['db_input'] = db_input
|
||||
_write_json(obj, outpath)
|
||||
|
||||
|
||||
def output_input_files(records, outdir, stem, roles, fd_fields, field_to_fd, open_dir):
|
||||
"""按 FD 名拆分出力入力 JSON 文件。
|
||||
每个 INPUT / I-O 方向 FD 生成一个文件:{stem}_{fd_name}.json
|
||||
内容为路径数 × 记录,每条只含该 FD 的入力字段值。
|
||||
"""
|
||||
def output_input_files(records, outdir, stem, roles, fd_fields, field_to_fd, open_dir,
|
||||
term_types=None):
|
||||
term_types = term_types or ['normal'] * len(records)
|
||||
input_fds = {}
|
||||
for fd_name, fds_set in fd_fields.items():
|
||||
direction = (open_dir or {}).get(fd_name, '')
|
||||
@@ -101,9 +138,11 @@ def output_input_files(records, outdir, stem, roles, fd_fields, field_to_fd, ope
|
||||
outdir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for fd_name, fds_set in input_fds.items():
|
||||
fd_records = []
|
||||
normals = []
|
||||
abends = []
|
||||
direction = (open_dir or {}).get(fd_name, '')
|
||||
for rec in records:
|
||||
for i, rec in enumerate(records):
|
||||
term = term_types[i] if i < len(term_types) else 'normal'
|
||||
fd_rec = {}
|
||||
for fname in fds_set:
|
||||
r = roles.get(fname, 'unused')
|
||||
@@ -111,8 +150,12 @@ def output_input_files(records, outdir, stem, roles, fd_fields, field_to_fd, ope
|
||||
if fname in rec:
|
||||
fd_rec[fname] = rec[fname]
|
||||
if fd_rec:
|
||||
fd_records.append(fd_rec)
|
||||
if term == 'abend':
|
||||
abends.append(fd_rec)
|
||||
else:
|
||||
normals.append(fd_rec)
|
||||
|
||||
outpath = outdir / f'{stem}_{fd_name}.json'
|
||||
with open(outpath, 'w', encoding='utf-8') as f:
|
||||
json.dump(fd_records, f, ensure_ascii=False, indent=2)
|
||||
if normals:
|
||||
_write_json(normals, outdir / f'{stem}_{fd_name}.json')
|
||||
if abends:
|
||||
_write_json(abends, outdir / f'{stem}_abend_{fd_name}.json')
|
||||
|
||||
Reference in New Issue
Block a user