diff --git a/cobol_testgen/runner.py b/cobol_testgen/runner.py index edb1d49..01b8d1a 100644 --- a/cobol_testgen/runner.py +++ b/cobol_testgen/runner.py @@ -995,6 +995,117 @@ def run_all(program_name: str, outdir: str, temp_dir: str, return results, merged_gcov +# ── 外部(黑盒)数据组执行 ── + + +def run_external_groups(program_name: str, outdir: str, temp_dir: str, + fields_dict: list[dict], fd_fields: dict, + select_info: dict, open_dir: dict, + roles: dict, field_to_fd: dict, + groups: list, source_dir: str, + data_fields: list[dict] | None = None, + multi_write_fds: set | None = None, + java_src_dir: str | None = None + ) -> tuple[list, list[dict]]: + """跑外部(黑盒)数据组:编译一次 → 逐组写输入/执行/Java 比对。 + + groups: list[BlackBoxGroup](具备 label/records/term_types 属性)。 + Returns: (results, java_reports) + """ + from .output import output_input_files + + fd_field_dicts = _build_fd_field_dicts(fd_fields, fields_dict) + log_dir = os.path.join(outdir, 'logs') + work_dir = Path(temp_dir).resolve() + work_dir.mkdir(parents=True, exist_ok=True) + + sub_dir = _resolve_sub_dir(source_dir) + cpy_dir = _resolve_cpy_dir(source_dir) + sub_o = compile_sub_modules(sub_dir, str(work_dir), cpy_dir, log_dir=log_dir) + exe_path = compile_program(program_name, source_dir, str(work_dir), sub_o, + cpy_dir, log_dir=log_dir) + + java_cfg = None + if str(os.environ.get('COBOL_JAVA_RUN', '1')).lower() not in ('0', 'off', 'false'): + _jsrc = (java_src_dir + or os.environ.get('COBOL_JAVA_SRC_DIR') + or str(Path(source_dir).parent / 'JavaSrc')) + java_cfg = _discover_java(_jsrc, program_name) + if java_cfg: + logger.info(f" 发现 Java 对应程序: {java_cfg['main_class']}") + else: + logger.info(f" 未发现 Java 对应程序({_jsrc}),跳过 Java 运行/比对") + + results = [] + java_reports = [] + for grp in groups: + label = grp.label + records = grp.records or [] + term_types = grp.term_types or ['normal'] * len(records) + if not records: + logger.warning(f" 黑盒组 {label}: 无记录,跳过") + continue + + base = Path(outdir) / 'black_box' / label + src_in_dir = base / 'cobol' / 'input' + dst_out_dir = base / 'cobol' / 'output' + if src_in_dir.exists(): + shutil.rmtree(str(src_in_dir), ignore_errors=True) + + output_input_files( + records, src_in_dir, f'{program_name}_{label}', roles, + fd_fields, field_to_fd, open_dir, + term_types=term_types, + data_fields=data_fields or fields_dict, + select_info=select_info, + drop_secondary_tail=False, + ) + + if src_in_dir.is_dir(): + for src in sorted(src_in_dir.iterdir()): + if src.is_file() and src.suffix.lower() != '.json': + shutil.copy2(str(src), str(work_dir / src.name)) + + _clean_gcda(str(work_dir)) + group = GroupInfo( + name=f'{program_name}_black_box_{label}', + records=records, + expected_outputs=[{}] * len(records), + fd_field_dicts=fd_field_dicts, + open_dir=open_dir, + select_info=select_info, + multi_write_fds=multi_write_fds or set(), + ) + r = run_group(group, exe_path, str(work_dir), log_dir=log_dir) + results.append(r) + logger.info(f" 组 '{group.name}': returncode={r.returncode}, " + f"{'✓' if r.passed else '✗'}") + + dst_out_dir.mkdir(parents=True, exist_ok=True) + for fd_name in fd_field_dicts: + if (open_dir or {}).get(fd_name, '') not in ('OUTPUT', 'I-O'): + continue + sel = select_info.get(fd_name, {}) + assign = sel.get('assign', fd_name) if isinstance(sel, dict) else fd_name + src = os.path.join(str(work_dir), assign) + if os.path.exists(src): + shutil.copy2(src, str(dst_out_dir / assign)) + + if java_cfg: + jrep = _run_java_scene( + program_name, label, + base / 'java' / 'output', + str(work_dir), + src_in_dir, dst_out_dir, + fd_field_dicts, open_dir, select_info, + java_cfg, log_dir=log_dir, label=label, + ) + jrep['section'] = 'black_box' + java_reports.append(jrep) + + return results, java_reports + + # ── run_and_compare(被 --run 调用,SOURCE 兼容)──