139 lines
4.3 KiB
Python
139 lines
4.3 KiB
Python
"""黑盒(black-box-data-create)测试数据接入:JSON → cobol_testgen 内部 record。
|
|
|
|
黑盒 JSON 结构(每组一个文件):
|
|
{ "program": "ZAN04MAT",
|
|
"records": [ { "input": { "<FD>": { "<字段>": "<值>" } } } ] }
|
|
|
|
FD 键与字段名由 LLM 生成,存在多种写法(FD名 / DD名 / 识别子,字段带或不带 '-'),
|
|
因此这里做归一化容错匹配。
|
|
"""
|
|
|
|
import json
|
|
import logging
|
|
from dataclasses import dataclass, field
|
|
from pathlib import Path
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@dataclass
|
|
class BlackBoxGroup:
|
|
label: str
|
|
records: list[dict]
|
|
term_types: list[str] = field(default_factory=list)
|
|
source_path: str = ''
|
|
|
|
|
|
def norm_name(name) -> str:
|
|
"""字段/FD 名归一化:大写 + 去除 '-' '_' 分隔符。"""
|
|
return str(name).upper().replace('-', '').replace('_', '')
|
|
|
|
|
|
def _fd_aliases(fd_name: str, select_info: dict) -> set:
|
|
aliases = {norm_name(fd_name)}
|
|
sel = select_info.get(fd_name, {})
|
|
if isinstance(sel, dict):
|
|
assign = sel.get('assign')
|
|
if assign:
|
|
aliases.add(norm_name(assign))
|
|
return aliases
|
|
|
|
|
|
def _resolve_fd(bb_key, fd_aliases: dict):
|
|
"""bb_key → 内部 fd_name;先精确别名,再前缀容错(R01 → R01INNFIL)。"""
|
|
nk = norm_name(bb_key)
|
|
for fd_name, aliases in fd_aliases.items():
|
|
if nk in aliases:
|
|
return fd_name
|
|
for fd_name, aliases in fd_aliases.items():
|
|
for a in aliases:
|
|
if a and (nk.startswith(a) or a.startswith(nk)):
|
|
return fd_name
|
|
return None
|
|
|
|
|
|
def _field_alias_map(data_fields: list[dict]) -> dict:
|
|
m = {}
|
|
for f in data_fields or []:
|
|
if f.get('is_88'):
|
|
continue
|
|
m.setdefault(norm_name(f['name']), f['name'])
|
|
return m
|
|
|
|
|
|
def _iter_group_files(path: Path) -> list[Path]:
|
|
p = Path(path)
|
|
if p.is_file() and p.suffix.lower() == '.json':
|
|
return [p]
|
|
if not p.is_dir():
|
|
return []
|
|
files = sorted(p.glob('*_g*.json'))
|
|
if files:
|
|
return files
|
|
bb = p / 'black_box'
|
|
if bb.is_dir():
|
|
return sorted(bb.rglob('*_g*.json'))
|
|
return []
|
|
|
|
|
|
def _group_label(json_path: Path) -> str:
|
|
for token in json_path.stem.split('_'):
|
|
if token.lower().startswith('g') and token[1:].isdigit():
|
|
return token
|
|
return json_path.stem
|
|
|
|
|
|
def _map_record(raw, fd_aliases, field_map, jf: Path) -> dict:
|
|
inp = raw.get('input')
|
|
if not isinstance(inp, dict):
|
|
return {}
|
|
rec = {}
|
|
for bb_fd, fields in inp.items():
|
|
fd_name = _resolve_fd(bb_fd, fd_aliases)
|
|
if fd_name is None:
|
|
logger.debug(f"黑盒 FD 未匹配: {bb_fd} ({jf.name})")
|
|
continue
|
|
if not isinstance(fields, dict):
|
|
continue
|
|
for bb_field, val in fields.items():
|
|
internal = field_map.get(norm_name(bb_field))
|
|
if internal is None:
|
|
logger.debug(f"黑盒字段未匹配: {bb_field} ({jf.name})")
|
|
continue
|
|
rec[internal] = '' if val is None else str(val)
|
|
return rec
|
|
|
|
|
|
def load_black_box_groups(path, fd_fields: dict, select_info: dict,
|
|
data_fields: list[dict]) -> list[BlackBoxGroup]:
|
|
"""读取黑盒 JSON,返回分组列表。
|
|
|
|
path 可以是:程序目录(自动找 black_box/)、black_box 目录、或单个 JSON 文件。
|
|
"""
|
|
fd_aliases = {fd: _fd_aliases(fd, select_info) for fd in fd_fields}
|
|
field_map = _field_alias_map(data_fields)
|
|
groups = []
|
|
for jf in _iter_group_files(Path(path)):
|
|
try:
|
|
obj = json.loads(jf.read_text(encoding='utf-8'))
|
|
except Exception as e: # noqa: BLE001
|
|
logger.warning(f"黑盒 JSON 解析失败 {jf}: {e}")
|
|
continue
|
|
label = _group_label(jf)
|
|
records = []
|
|
for raw in obj.get('records', []) or []:
|
|
rec = _map_record(raw, fd_aliases, field_map, jf)
|
|
if rec:
|
|
records.append(rec)
|
|
if not records:
|
|
logger.warning(f"黑盒组 {label} 无有效记录,跳过 ({jf.name})")
|
|
continue
|
|
groups.append(BlackBoxGroup(
|
|
label=label,
|
|
records=records,
|
|
term_types=['normal'] * len(records),
|
|
source_path=str(jf),
|
|
))
|
|
logger.info(f" 黑盒组 {label}: {len(records)} 条记录 ({jf.name})")
|
|
return groups
|