From 8e81f960af754d7eedba61a8917fdbc393a93a35 Mon Sep 17 00:00:00 2001 From: hangshuo652 Date: Tue, 25 Aug 2026 21:53:18 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=B8=85=E9=99=A4=E7=A1=AC=E7=BC=96?= =?UTF-8?q?=E7=A0=81API=20Key=E4=B8=8E=E6=9C=BA=E5=99=A8=E7=89=B9=E5=AE=9A?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=EF=BC=8C=E6=94=B9=E7=94=A8=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E5=8F=98=E9=87=8F+=E6=B7=B7=E5=90=88=E5=BC=8F=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 26 ++++++++++ _AI_USAGE_LOG.md | 6 +++ black-box-data-create/.gitignore | 3 +- black-box-data-create/AGENTS.md | 2 +- black-box-data-create/config.json | 10 ---- .../plans/2026-07-12-testdata-agent-plan.md | 6 +-- .../specs/2026-07-12-testdata-agent-design.md | 4 +- docs/detailed-design/append_doc.py | 11 +++-- hina/retry.py | 11 +++-- orchestrator_db.py | 11 +++-- scripts/test_agent_mode.py | 24 ++++++++-- test-data/_paths.py | 47 +++++++++++++++++++ test-data/s14_benchmark_suite.py | 2 +- test-data/s16_benchmark_e2e.py | 2 +- test-data/s17_gcov_comparison.py | 2 +- test-data/s18_all_benchmark_e2e.py | 4 +- test-data/s19_final_bridge_test.py | 2 +- test-data/s20_runtime_verification.py | 2 +- test-data/s20v2_runtime_gcov.py | 2 +- test-data/s22_tna_e2e.py | 2 +- test-data/s23_coverage_report.py | 4 +- test-data/s24_final_report.py | 4 +- test-data/s25_per_program_report.py | 6 +-- test-data/s26_regression_check.py | 4 +- test-data/s30_db_e2e.py | 4 +- test-data/test_deep_validation.py | 6 ++- tests/cobol_testgen/test_merge_pipeline.py | 15 +++++- tests/e2e/test_pipeline.py | 18 +++++-- tests/prepare_test_data.py | 6 ++- tests/runners/test_sqlcode_normalize.py | 8 ++-- tests/test_biz_e2e.py | 11 +++-- tests/test_golden.py | 11 +++-- 32 files changed, 200 insertions(+), 76 deletions(-) create mode 100644 .env.example delete mode 100644 black-box-data-create/config.json create mode 100644 test-data/_paths.py diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..23256db --- /dev/null +++ b/.env.example @@ -0,0 +1,26 @@ +# COBOL → Java/Spark 迁移验证平台 v3 — 环境变量模板 +# 复制本文件并按需设置: copy .env.example .env (或用 setx 持久化) + +# ── DeepSeek API ───────────────────────────────────────────── +# 黑盒数据生成 / LLM 路径生成所需。也可写入 +# black-box-data-create/config.json(该文件已被 gitignore,不会入库) +DEEPSEEK_API_KEY= +# DEEPSEEK_MODEL=deepseek-v4-flash +# DEEPSEEK_BASE_URL=https://api.deepseek.com/chat/completions +# DEEPSEEK_TIMEOUT=120 +# DEEPSEEK_MAX_RETRIES=3 +# DEEPSEEK_MAX_TOKENS=32768 + +# ── 外部测试数据目录(test-data/ 回归脚本、诊断脚本)────────── +# 未设置时自动推导为 %USERPROFILE%\Desktop\2026技术大赛\ 下同名目录 +# COBOL_TNA_ROOT=D:\cobol-tna-system +# COBOL_BENCH_ROOT=D:\cobol-test-programs + +# ── GnuCOBOL / gixsql 运行时 ──────────────────────────────── +# 编译失败自愈回退用的库路径(hina/retry.py) +# COB_GNUCOBOL_LIB=D:\GnuCOBOL\lib\gnucobol +# DB 管道 SQLite 存放目录(须为短 ASCII 路径,COBOL CONNECT TO 受72列限制) +# GIXSQL_DB_DIR=C:/Temp/gix + +# ── jcl-cobol-data-create(agent 模式联调用)───────────────── +# JCL_ROOT=D:\jcl-cobol-data-create diff --git a/_AI_USAGE_LOG.md b/_AI_USAGE_LOG.md index d71a86a..43b6e54 100644 --- a/_AI_USAGE_LOG.md +++ b/_AI_USAGE_LOG.md @@ -4,6 +4,12 @@ --- +### 2026-08-24 04:00:00 - 修复 +- **范式步骤:** 硬编码清除(P0+P1) +- **修改摘要:** 清除2个硬编码API Key及文档明文(config.json取消跟踪改gitignore管理);orchestrator_db.py DB路径抽GIXSQL_DB_DIR常量;hina/retry.py移除浏览器下载路径回退;新增test-data/_paths.py集中路径解析(环境变量→目录推导兜底);13个test-data脚本、tests下5文件、3个diagnose脚本全部去机器特定路径;创建.env.example。回归:260通过/6既有失败,零新增失败 +- **涉及文件:** `scripts/test_agent_mode.py`, `tests/e2e/test_pipeline.py`, `black-box-data-create/config.json`, `black-box-data-create/.gitignore`, `black-box-data-create/AGENTS.md`, `black-box-data-create/docs/superpowers/*`, `.env.example`, `orchestrator_db.py`, `hina/retry.py`, `diagnose_*.py`(本地), `test-data/_paths.py`, `test-data/s*.py`(13个), `tests/test_golden.py`, `tests/test_biz_e2e.py`, `tests/prepare_test_data.py`, `tests/cobol_testgen/test_merge_pipeline.py`, `tests/runners/test_sqlcode_normalize.py`, `docs/detailed-design/append_doc.py` +- **使用模型:** deepseek + ### 2026-08-24 03:00:00 - 文档 - **范式步骤:** V3总体设计文档更新 - **修改摘要:** 更新00-overview.md,添加黑盒模块设计(2B章节)、PGMパターン、多KEY测试、黑盒数据流、双管道架构图 diff --git a/black-box-data-create/.gitignore b/black-box-data-create/.gitignore index 5a7222a..f3c7569 100644 --- a/black-box-data-create/.gitignore +++ b/black-box-data-create/.gitignore @@ -1,3 +1,4 @@ __pycache__/ *.pyc -output/ \ No newline at end of file +output/ +config.json \ No newline at end of file diff --git a/black-box-data-create/AGENTS.md b/black-box-data-create/AGENTS.md index e0b2463..6a0aa89 100644 --- a/black-box-data-create/AGENTS.md +++ b/black-box-data-create/AGENTS.md @@ -52,7 +52,7 @@ python main.py --design "D:\cobol-tna-system\詳細設計書\詳細設計書_XXX - **同一COPYBOOKの複数REPLACING**: `ZAN01REC` が `R01`/`R02` 両方で使われる場合、`_extract_copy_replacing()` はリスト `[(copy_name, prefix), ...]` を返し、`_parse_copybooks()` が識別子でマッチする。 - **PGMタイプ = サブ はスキップ**: `generate()` 関数で `meta.pgm_type == 'サブ'` の場合 `ValueError`。 - **入力タイプ判定**: `使用ファイル一覧` の `I/O` 列に `'I'` を含む行の `媒体` 列を見る。`PS`=ファイル、`DB`=DB、両方=混合。 -- **APIキー**: コード内にハードコード (`sk-6156cccdc9c14d949cf5bfc5afc67a03`)。モデルは `deepseek-v4-flash`。 +- **APIキー**: コードにハードコードしない。`config.json` または環境変数 `DEEPSEEK_API_KEY` から読み込む(`agent/config.py` 参照)。モデルは `DEEPSEEK_MODEL`(既定: `deepseek-v4-flash`)。 ## 多keyテスト diff --git a/black-box-data-create/config.json b/black-box-data-create/config.json deleted file mode 100644 index 71ac6c2..0000000 --- a/black-box-data-create/config.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "api": { - "api_key": "sk-6156cccdc9c14d949cf5bfc5afc67a03", - "model": "deepseek-v4-flash", - "base_url": "https://api.deepseek.com/chat/completions", - "timeout": 120, - "max_retries": 3, - "max_tokens": 32768 - } -} diff --git a/black-box-data-create/docs/superpowers/plans/2026-07-12-testdata-agent-plan.md b/black-box-data-create/docs/superpowers/plans/2026-07-12-testdata-agent-plan.md index cad7e2a..574864c 100644 --- a/black-box-data-create/docs/superpowers/plans/2026-07-12-testdata-agent-plan.md +++ b/black-box-data-create/docs/superpowers/plans/2026-07-12-testdata-agent-plan.md @@ -1,4 +1,4 @@ -# 测试数据生成 Agent 实现计划 +# 测试数据生成 Agent 实现计划 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. @@ -2042,7 +2042,7 @@ from agent.models import ProgramMeta, FileInfo, CopyField, KeyInfo, TableColumn, def generate(design_md: str, source_cbl: str, file_db_md: str, cpy_dir: str, db_md: str, output_dir: str = "output", - api_key: str = "sk-6156cccdc9c14d949cf5bfc5afc67a03", + api_key: str = "", api_model: str = "deepseek-v4-flash", rules_dir: str = "rules") -> dict: """生成测试数据的主入口函数。 @@ -2151,7 +2151,7 @@ def main(): help='DB 定義書 .md のパス') parser.add_argument('--output', default='output', help='出力ディレクトリ (デフォルト: output)') - parser.add_argument('--api-key', default='sk-6156cccdc9c14d949cf5bfc5afc67a03', + parser.add_argument('--api-key', default='', help='DeepSeek API Key') parser.add_argument('--model', default='deepseek-v4-flash', help='API モデル名') diff --git a/black-box-data-create/docs/superpowers/specs/2026-07-12-testdata-agent-design.md b/black-box-data-create/docs/superpowers/specs/2026-07-12-testdata-agent-design.md index 7870694..3e46b82 100644 --- a/black-box-data-create/docs/superpowers/specs/2026-07-12-testdata-agent-design.md +++ b/black-box-data-create/docs/superpowers/specs/2026-07-12-testdata-agent-design.md @@ -1,4 +1,4 @@ -# COBOL 测试数据生成 Agent 设计文档 +# COBOL 测试数据生成 Agent 设计文档 ## 背景 @@ -203,7 +203,7 @@ PGMパターン 值到规则文件名的映射: **API 配置**: - 地址:https://api.deepseek.com/chat/completions - 模型:`deepseek-v4-flash` -- API Key:`sk-6156cccdc9c14d949cf5bfc5afc67a03` +- API Key:`` - timeout:120 秒 **请求结构**: diff --git a/docs/detailed-design/append_doc.py b/docs/detailed-design/append_doc.py index 7305c75..a68b8b1 100644 --- a/docs/detailed-design/append_doc.py +++ b/docs/detailed-design/append_doc.py @@ -2,24 +2,25 @@ """Append the remaining sections to the design document.""" from pathlib import Path -OUT = Path(r"C:\Users\marye\Desktop\2026技术大赛\cobol-java-v3\docs\detailed-design\01-cobol-testgen-core.md") +_HERE = Path(__file__).resolve().parent +OUT = _HERE / "01-cobol-testgen-core.md" content = OUT.read_text(encoding="utf-8") content = content.replace("PLACEHOLDER", "") # Read part2 content -part2 = Path(r"C:\Users\marye\Desktop\2026技术大赛\cobol-java-v3\docs\detailed-design\part2.md") +part2 = _HERE / "part2.md" content += part2.read_text(encoding="utf-8") # Read part3 content -part3 = Path(r"C:\Users\marye\Desktop\2026技术大赛\cobol-java-v3\docs\detailed-design\part3.md") +part3 = _HERE / "part3.md" content += part3.read_text(encoding="utf-8") # Read part4 content -part4 = Path(r"C:\Users\marye\Desktop\2026技术大赛\cobol-java-v3\docs\detailed-design\part4.md") +part4 = _HERE / "part4.md" content += part4.read_text(encoding="utf-8") # Read part5 content -part5 = Path(r"C:\Users\marye\Desktop\2026技术大赛\cobol-java-v3\docs\detailed-design\part5.md") +part5 = _HERE / "part5.md" content += part5.read_text(encoding="utf-8") OUT.write_text(content, encoding="utf-8") diff --git a/hina/retry.py b/hina/retry.py index a8a7fd6..c4a5339 100644 --- a/hina/retry.py +++ b/hina/retry.py @@ -11,9 +11,14 @@ logger = logging.getLogger(__name__) HEALING_FIXES = { "compile_error": { "detect": lambda log: "not found" in (log or "").lower(), - "fix": lambda: _try_set_env( - "COB_LIBRARY_PATH", - "D:\\360安全浏览器下载\\GC32-BDB-SP1-rename-7z-to-exe\\lib\\gnucobol", + # GnuCOBOL 库路径自愈:仅当环境变量 COB_GNUCOBOL_LIB 已设置时生效 + # (见 .env.example)。不再内置任何机器特定回退路径。 + "fix": lambda: ( + _try_set_env("COB_LIBRARY_PATH", os.environ["COB_GNUCOBOL_LIB"]) + if os.environ.get("COB_GNUCOBOL_LIB") + else logger.warning( + "[Retry] COB_GNUCOBOL_LIB 未设置,无法自动修复库路径" + ) ), }, "s0c7": { diff --git a/orchestrator_db.py b/orchestrator_db.py index ff0f9a1..df8f12b 100644 --- a/orchestrator_db.py +++ b/orchestrator_db.py @@ -33,6 +33,11 @@ from runners.gixsql_runner import GixsqlCobolRunner, GixsqlTableData logger = logging.getLogger(__name__) +# DB 管道 SQLite 存放目录。默认保持短 ASCII 路径: +# COBOL CONNECT TO 字符串受固定格式第 72 列限制,且 gixpp 无法处理中文路径。 +# 可用环境变量 GIXSQL_DB_DIR 覆盖(见 .env.example)。 +GIXSQL_DB_DIR = Path(os.environ.get("GIXSQL_DB_DIR", "C:/Temp/gix")) + def _calc_birth_date(age: int, as_of: str = '20260802') -> str: """年龄 → 出生日期 YYYYMMDD(通用)。as_of 为运行时运用日。""" @@ -103,8 +108,8 @@ class GixsqlOrchestrator: compile_flags=config.gixsql_compile_flags, ) - # Derive DB path: C:\Temp\gix\.db (matches COBOL CONNECT TO, short enough for col 72) - self.db_path = Path("C:/Temp/gix") / f"{self.program_id}.db" + # Derive DB path: \.db (matches COBOL CONNECT TO, short enough for col 72) + self.db_path = GIXSQL_DB_DIR / f"{self.program_id}.db" # Pipeline state self.src_path: Optional[Path] = None @@ -263,7 +268,7 @@ class GixsqlOrchestrator: # シナリオに応じた DB パス if scenario: - db_path = Path("C:/Temp/gix") / f"{self.program_id}_{scenario.id}.db" + db_path = GIXSQL_DB_DIR / f"{self.program_id}_{scenario.id}.db" self._current_db_path = db_path else: db_path = self.db_path diff --git a/scripts/test_agent_mode.py b/scripts/test_agent_mode.py index 686b891..b073313 100644 --- a/scripts/test_agent_mode.py +++ b/scripts/test_agent_mode.py @@ -33,11 +33,20 @@ from pathlib import Path # ============================================================================ PROJECT_ROOT = Path(__file__).resolve().parent.parent +_DESKTOP = Path(os.environ.get("USERPROFILE", "")) / "Desktop" +_CONTEST_ROOT = _DESKTOP / "2026技术大赛" + +# COBOL test data project: env var -> contest sibling dir fallback +COBOL_PROJECT = Path( + os.environ["COBOL_TNA_ROOT"] +) if "COBOL_TNA_ROOT" in os.environ else _CONTEST_ROOT / "cobol-tna-system" + +# jcl-cobol-data-create candidates: env var first, then common locations JCL_ROOT_CANDIDATES = [ - Path(r"C:\Users\marye\Desktop\2026技术大赛\jcl-cobol-data-create"), + *( [Path(os.environ["JCL_ROOT"])] if "JCL_ROOT" in os.environ else [] ), + _CONTEST_ROOT / "jcl-cobol-data-create", Path(r"D:\jcl-cobol-data-create"), ] -COBOL_PROJECT = Path(r"C:\Users\marye\Desktop\2026技术大赛\cobol-tna-system") PROGRAM = "ZAN04MAT" TEST_INPUTS = { @@ -48,8 +57,9 @@ TEST_INPUTS = { "db-md": COBOL_PROJECT / "詳細設計書" / "DB定義書.md", } -DEFAULT_API_KEY = "sk-6156cccdc9c14d949cf5bfc5afc67a03" -DEFAULT_API_MODEL = "deepseek-v4-flash" +# API key/model come from env or black-box-data-create/config.json (never hardcoded) +DEFAULT_API_KEY = os.environ.get("DEEPSEEK_API_KEY", "") +DEFAULT_API_MODEL = os.environ.get("DEEPSEEK_MODEL", "deepseek-v4-flash") ORCHESTRATOR_JCL = PROJECT_ROOT / "orchestrator_jcl.py" @@ -414,10 +424,14 @@ def run_full_pipeline(): "--cpy", str(TEST_INPUTS["cpy"]), "--db-md", str(TEST_INPUTS["db-md"]), "--output", str(output_dir), - "--api-key", DEFAULT_API_KEY, "--api-model", DEFAULT_API_MODEL, "--verbose", ] + if DEFAULT_API_KEY: + # Only pass explicitly when provided; otherwise main.py falls back + # to black-box-data-create/config.json or DEEPSEEK_API_KEY env. + idx = cmd.index("--api-model") + cmd[idx:idx] = ["--api-key", DEFAULT_API_KEY] step("Executing pipeline (this may take several minutes)...") info(f"Command: {' '.join(cmd)}") diff --git a/test-data/_paths.py b/test-data/_paths.py new file mode 100644 index 0000000..7255cbb --- /dev/null +++ b/test-data/_paths.py @@ -0,0 +1,47 @@ +# ============================================================================ +# _paths.py — test-data 回归脚本统一路径解析(混合式) +# +# 优先级: 环境变量 → %USERPROFILE%\Desktop\2026技术大赛\ 兜底推导 +# 缺失时在使用方通过 require() 得到清晰的设置指引。 +# 环境变量说明见项目根 .env.example。 +# ============================================================================ +import os +import sys +from pathlib import Path + +V3_ROOT = Path(__file__).resolve().parent.parent +_DESKTOP = Path(os.environ.get("USERPROFILE", "")) / "Desktop" +_CONTEST_ROOT = _DESKTOP / "2026技术大赛" + + +def _resolve(env_name: str, fallback: Path) -> Path: + if env_name in os.environ: + return Path(os.environ[env_name]) + return fallback + + +def require(path, label: str, env_name: str) -> Path: + """存在性检查,失败时给出环境变量设置指引。""" + p = Path(path) + if not p.exists(): + sys.exit( + f"[错误] {label} 目录不存在: {p}\n" + f"请设置环境变量 {env_name} 指向实际目录" + f"(例: setx {env_name} \"D:\\...\"),或参见 .env.example" + ) + return p + + +# 基准程序集(cobol-test-programs)— 本机当前布局中不存在,需 COBOL_BENCH_ROOT +BENCH_ROOT = _resolve("COBOL_BENCH_ROOT", _CONTEST_ROOT / "cobol-test-programs") +COPYBOOKS_BENCH = BENCH_ROOT / "common" / "copybooks" + +# TNA 电信测试系统 — 当前布局位于大赛目录下 +TNA_ROOT = _resolve("COBOL_TNA_ROOT", _CONTEST_ROOT / "cobol-tna-system") +COPYBOOKS_TNA = TNA_ROOT / "cpy" + +# jcl-cobol-git(HINA 分类验证用旧仓库) +COBOL_GIT_ROOT = _resolve("COBOL_GIT_ROOT", _CONTEST_ROOT / "jcl-cobol-git") + +# 散置样本源码 +SAMPLE_SRC_DIR = _resolve("SAMPLE_SRC_DIR", _CONTEST_ROOT) diff --git a/test-data/s14_benchmark_suite.py b/test-data/s14_benchmark_suite.py index d869baa..4649a81 100644 --- a/test-data/s14_benchmark_suite.py +++ b/test-data/s14_benchmark_suite.py @@ -5,7 +5,7 @@ P=0;F=0;BUGS=[] def ck(v,m=""): global P,F; (P:=P+1) if v else (F:=F+1,BUGS.append(m)) def sec(n): print(f"\n--- {n} ---") -ROOT = "D:/cobol-java/cobol-test-programs/" +from _paths import BENCH_ROOT as ROOT from cobol_testgen import extract_structure, generate_data from hina.pipeline.pipeline import classify_program from hina.classifier import detect_keyword diff --git a/test-data/s16_benchmark_e2e.py b/test-data/s16_benchmark_e2e.py index f35f754..a464af6 100644 --- a/test-data/s16_benchmark_e2e.py +++ b/test-data/s16_benchmark_e2e.py @@ -5,7 +5,7 @@ P=0;F=0 def ck(v,m=""): global P,F; (P:=P+1) if v else (F:=F+1, print(f" FAIL {m}")) def sec(n): print(f"\n{'='*60}\n{n}\n{'='*60}") -ROOT = "D:/cobol-java/cobol-test-programs/" +from _paths import BENCH_ROOT as ROOT COPYBOOKS = os.path.join(ROOT, "common", "copybooks") COBC = "cobc" diff --git a/test-data/s17_gcov_comparison.py b/test-data/s17_gcov_comparison.py index 6239176..427b300 100644 --- a/test-data/s17_gcov_comparison.py +++ b/test-data/s17_gcov_comparison.py @@ -8,7 +8,7 @@ P=0;F=0 def ck(v,m=""): global P,F; (P:=P+1) if v else (F:=F+1, print(f" FAIL {m}")) def sec(n): print(f"\n--- {n} ---") -ROOT = "D:/cobol-java/cobol-test-programs/" +from _paths import BENCH_ROOT as ROOT COPYBOOKS = os.path.join(ROOT, "common", "copybooks") from cobol_testgen import extract_structure, generate_data diff --git a/test-data/s18_all_benchmark_e2e.py b/test-data/s18_all_benchmark_e2e.py index 8b59d78..75b0444 100644 --- a/test-data/s18_all_benchmark_e2e.py +++ b/test-data/s18_all_benchmark_e2e.py @@ -1,6 +1,6 @@ """S18: ALL benchmark programs — full E2E: parse → generate → flatfile → compile → run → verify -Run: cd D:/cobol-java/cobol-java-v3 && python test-data/s18_all_benchmark_e2e.py +Run: cd && python test-data/s18_all_benchmark_e2e.py """ import sys, os, subprocess, re, json sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) @@ -8,7 +8,7 @@ P=0;F=0 def ck(v,m=""): global P,F; (P:=P+1) if v else (F:=F+1, print(f" FAIL {m}")) def sec(n): print(f"\n{'='*60}\n{n}\n{'='*60}") -ROOT = "D:/cobol-java/cobol-test-programs/" +from _paths import BENCH_ROOT as ROOT COPYBOOKS = os.path.join(ROOT, "common", "copybooks") COBC = "cobc" diff --git a/test-data/s19_final_bridge_test.py b/test-data/s19_final_bridge_test.py index f9d032f..344d4cc 100644 --- a/test-data/s19_final_bridge_test.py +++ b/test-data/s19_final_bridge_test.py @@ -2,7 +2,7 @@ import sys, os, re, time sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) -ROOT = "D:/cobol-java/cobol-test-programs/" +from _paths import BENCH_ROOT as ROOT COPYBOOKS = os.path.join(ROOT, "common", "copybooks") from cobol_testgen import extract_structure, generate_data from cobol_testgen.read import preprocess, resolve_copybooks diff --git a/test-data/s20_runtime_verification.py b/test-data/s20_runtime_verification.py index bd29189..17663a4 100644 --- a/test-data/s20_runtime_verification.py +++ b/test-data/s20_runtime_verification.py @@ -17,7 +17,7 @@ P=0;F=0 def ck(v,m=""): global P,F; (P:=P+1) if v else (F:=F+1, print(f" FAIL {m}")) def sec(n): print(f"\n{'='*60}\n{n}\n{'='*60}") -ROOT = "D:/cobol-java/cobol-test-programs/" +from _paths import BENCH_ROOT as ROOT COPYBOOKS = os.path.join(ROOT, "common", "copybooks") COBC = "cobc" diff --git a/test-data/s20v2_runtime_gcov.py b/test-data/s20v2_runtime_gcov.py index 3d26bc5..106e66c 100644 --- a/test-data/s20v2_runtime_gcov.py +++ b/test-data/s20v2_runtime_gcov.py @@ -16,7 +16,7 @@ P=0;F=0 def ck(v,m=""): global P,F; (P:=P+1) if v else (F:=F+1, print(f" FAIL {m}")) def sec(n): print(f"\n{'='*60}\n{n}\n{'='*60}") -ROOT = "D:/cobol-java/cobol-test-programs/" +from _paths import BENCH_ROOT as ROOT COPYBOOKS = os.path.join(ROOT, "common", "copybooks") from cobol_testgen import extract_structure, generate_data diff --git a/test-data/s22_tna_e2e.py b/test-data/s22_tna_e2e.py index 9358992..5d38b81 100644 --- a/test-data/s22_tna_e2e.py +++ b/test-data/s22_tna_e2e.py @@ -8,7 +8,7 @@ P=0;F=0 def ck(v,m=""): global P,F; (P:=P+1) if v else (F:=F+1, print(f" FAIL {m}")) def sec(n): print(f"\n{'='*60}\n{n}\n{'='*60}") -ROOT = "D:/cobol-java/cobol-tna-system/" +from _paths import TNA_ROOT as ROOT COPYBOOKS = os.path.join(ROOT, "cpy") BINDIR = os.path.join(ROOT, "bin") COBC = "cobc" diff --git a/test-data/s23_coverage_report.py b/test-data/s23_coverage_report.py index 713872c..2e3c4f6 100644 --- a/test-data/s23_coverage_report.py +++ b/test-data/s23_coverage_report.py @@ -2,9 +2,9 @@ import sys, os, re, subprocess, time sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) -ROOT_BENCH = "D:/cobol-java/cobol-test-programs/" +from _paths import BENCH_ROOT as ROOT_BENCH, COPYBOOKS_BENCH COPYBOOKS_BENCH = os.path.join(ROOT_BENCH, "common", "copybooks") -ROOT_TNA = "D:/cobol-java/cobol-tna-system/" +from _paths import TNA_ROOT as ROOT_TNA COPYBOOKS_TNA = os.path.join(ROOT_TNA, "cpy") from cobol_testgen import extract_structure, generate_data diff --git a/test-data/s24_final_report.py b/test-data/s24_final_report.py index 967f52b..1bebbd5 100644 --- a/test-data/s24_final_report.py +++ b/test-data/s24_final_report.py @@ -2,9 +2,9 @@ import sys, os, re, time sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) -ROOT_BENCH = "D:/cobol-java/cobol-test-programs/" +from _paths import BENCH_ROOT as ROOT_BENCH, COPYBOOKS_BENCH COPYBOOKS_BENCH = os.path.join(ROOT_BENCH, "common", "copybooks") -ROOT_TNA = "D:/cobol-java/cobol-tna-system/" +from _paths import TNA_ROOT as ROOT_TNA COPYBOOKS_TNA = os.path.join(ROOT_TNA, "cpy") from cobol_testgen import extract_structure, generate_data diff --git a/test-data/s25_per_program_report.py b/test-data/s25_per_program_report.py index 5c030ae..7a7cae4 100644 --- a/test-data/s25_per_program_report.py +++ b/test-data/s25_per_program_report.py @@ -2,10 +2,8 @@ import sys, os, re, time, json sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) -ROOT_BENCH = "D:/cobol-java/cobol-test-programs/" -COPYBOOKS_BENCH = os.path.join(ROOT_BENCH, "common", "copybooks") -ROOT_TNA = "D:/cobol-java/cobol-tna-system/" -COPYBOOKS_TNA = os.path.join(ROOT_TNA, "cpy") +from _paths import BENCH_ROOT as ROOT_BENCH, COPYBOOKS_BENCH +from _paths import TNA_ROOT as ROOT_TNA, COPYBOOKS_TNA from cobol_testgen import extract_structure, generate_data from cobol_testgen.read import preprocess, resolve_copybooks, \ diff --git a/test-data/s26_regression_check.py b/test-data/s26_regression_check.py index 915c70e..3d5373d 100644 --- a/test-data/s26_regression_check.py +++ b/test-data/s26_regression_check.py @@ -2,9 +2,9 @@ import sys, os, re sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) -ROOT = "D:/cobol-java/cobol-test-programs/" +from _paths import BENCH_ROOT as ROOT COPYBOOKS = os.path.join(ROOT, "common/copybooks") -TNA = "D:/cobol-java/cobol-tna-system/" +from _paths import TNA_ROOT as TNA from cobol_testgen import extract_structure, generate_data total_br = 0; total_cov = 0; errors = []; below = [] diff --git a/test-data/s30_db_e2e.py b/test-data/s30_db_e2e.py index 46b1103..7ac92a1 100644 --- a/test-data/s30_db_e2e.py +++ b/test-data/s30_db_e2e.py @@ -5,8 +5,8 @@ P=0;F=0 def ck(v,m=""): global P,F; (P:=P+1) if v else (F:=F+1, print(f" FAIL {m}")) def sec(n): print(f"\n{'='*60}\n{n}\n{'='*60}") -DESKTOP = os.path.join(os.environ['USERPROFILE'], "Desktop") -ROOT = os.path.join(DESKTOP, "2026技术大赛", "cobol-tna-system") + "/" +from _paths import TNA_ROOT, require +ROOT = str(require(TNA_ROOT, "TNA 测试数据", "COBOL_TNA_ROOT")) + "/" COPYBOOKS = [os.path.join(ROOT, "cpy"), os.path.join(ROOT, "src")] from config import Config diff --git a/test-data/test_deep_validation.py b/test-data/test_deep_validation.py index c3b5882..70e41f5 100644 --- a/test-data/test_deep_validation.py +++ b/test-data/test_deep_validation.py @@ -47,7 +47,8 @@ from cobol_testgen.read import resolve_copybooks, preprocess, extract_procedure_ from cobol_testgen.core import build_branch_tree try: - src_path = Path("D:/cobol-java/sample_ソース_SAN01MAT.cbl") + from _paths import SAMPLE_SRC_DIR + src_path = SAMPLE_SRC_DIR / "sample_ソース_SAN01MAT.cbl" src = src_path.read_text(encoding="utf-8") sdir = str(src_path.parent) @@ -89,7 +90,8 @@ section("2. HINA分類: 実プログラム判定精度") from hina.classifier import compute_confidence # jcl-cobol-git の4プログラム -cobol_git = Path("D:/cobol-java/jcl-cobol-git/cobol") +from _paths import COBOL_GIT_ROOT +cobol_git = COBOL_GIT_ROOT / "cobol" if cobol_git.exists(): for f in ['CRDVAL', 'CRDCALC', 'CRDRPT', 'GENDATA']: try: diff --git a/tests/cobol_testgen/test_merge_pipeline.py b/tests/cobol_testgen/test_merge_pipeline.py index b5a3378..1432ce2 100644 --- a/tests/cobol_testgen/test_merge_pipeline.py +++ b/tests/cobol_testgen/test_merge_pipeline.py @@ -7,6 +7,8 @@ """ import sys, os +from pathlib import Path +import pytest sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) from cobol_testgen.read import ( @@ -17,8 +19,17 @@ from cobol_testgen.read import ( from cobol_testgen.core import build_branch_tree from cobol_testgen.coverage import collect_decision_points -_SRC = r'C:\Users\marye\Desktop\2026技术大赛\cobol-tna-system\src' -_CPY = r'C:\Users\marye\Desktop\2026技术大赛\cobol-tna-system\cpy' +# TNA 测试数据目录: 环境变量优先 → 大赛兄弟目录兜底(见 .env.example) +_TNA = Path(os.environ.get( + "COBOL_TNA_ROOT", + Path(__file__).resolve().parent.parent.parent.parent / "cobol-tna-system", +)) +_SRC = str(_TNA / "src") +_CPY = str(_TNA / "cpy") + +pytestmark = pytest.mark.skipif( + not _TNA.exists(), reason=f"TNA test data not found: {_TNA} (set COBOL_TNA_ROOT)" +) def _load(pid): diff --git a/tests/e2e/test_pipeline.py b/tests/e2e/test_pipeline.py index 28e7f0e..9f9464d 100644 --- a/tests/e2e/test_pipeline.py +++ b/tests/e2e/test_pipeline.py @@ -1,7 +1,8 @@ """E2E Tests for COBOL->Java Verification Platform -Run: cd D:/cobol-java/v3-gstack-code-gen && python -m pytest tests/e2e/ -v -Requires: web server on http://127.0.0.1:8000, WSL available +Run: cd && python -m pytest tests/e2e/ -v +Requires: web server on http://127.0.0.1:8000, WSL available, + DEEPSEEK_API_KEY set in the environment. """ import json, os, sys, time, uuid, shutil from datetime import datetime @@ -50,10 +51,19 @@ def create_task(copybook: str, cobol: str, java_dir: str, mapping: str, runner=" return tid +def _wsl_path(p: Path) -> str: + """Convert a Windows path to its WSL /mnt/ equivalent.""" + s = str(p).replace("\\", "/") + if len(s) > 1 and s[1] == ":": + return f"/mnt/{s[0].lower()}{s[2:]}" + return s + + def run_worker_for_task(tid: str): + api_key = os.environ.get("DEEPSEEK_API_KEY", "") script = ( - "cd /mnt/d/cobol-java/v3-gstack-code-gen && " - "export LLM_API_KEY=sk-ca4961087c7f4aefa8ed0fc6f3d02329 && " + f"cd {_wsl_path(PROJECT)} && " + f"export LLM_API_KEY='{api_key}' && " "export LLM_API_BASE=https://api.deepseek.com/v1 && " "export LLM_MODEL=deepseek-chat && " f"python3 -c \"exec(open('write_result.py').read().replace('ec17bf32','{tid}'))\"" diff --git a/tests/prepare_test_data.py b/tests/prepare_test_data.py index 59929d0..d68da05 100644 --- a/tests/prepare_test_data.py +++ b/tests/prepare_test_data.py @@ -1,8 +1,12 @@ """Prepare test data for Playwright E2E tests.""" +import os from pathlib import Path FIXTURES = Path(__file__).parent / "fixtures" -COBOL_GIT = Path(r"D:\cobol-java\jcl-cobol-git") +COBOL_GIT = Path( + os.environ.get("COBOL_GIT_ROOT", + Path(__file__).resolve().parent.parent.parent / "jcl-cobol-git") +) def prepare(): diff --git a/tests/runners/test_sqlcode_normalize.py b/tests/runners/test_sqlcode_normalize.py index 91b3293..896ef39 100644 --- a/tests/runners/test_sqlcode_normalize.py +++ b/tests/runners/test_sqlcode_normalize.py @@ -40,10 +40,10 @@ def test_normalize_injects_mapping_after_endsql(tmp_path): assert "SQLCODE = -2067" in out -def test_normalize_mapping_before_if_sqlcode(): +def test_normalize_mapping_before_if_sqlcode(tmp_path): """映射代码注入在 IF SQLCODE = -803 判断之前""" r = _make_runner() - pp = Path(r'C:\Users\marye\AppData\Local\Temp\opencode\t3_pp.cbl') + pp = tmp_path / "t3_pp.cbl" pp.parent.mkdir(parents=True, exist_ok=True) pp.write_text(_pp_text_with_if(), encoding="utf-8") r._patch_sqlcode_normalize(pp) @@ -56,10 +56,10 @@ def test_normalize_mapping_before_if_sqlcode(): assert mapping_idx < if_idx -def test_normalize_does_not_change_ok_path(): +def test_normalize_does_not_change_ok_path(tmp_path): """归一化不影响 SQLCODE=0 成功路径""" r = _make_runner() - pp = Path(r'C:\Users\marye\AppData\Local\Temp\opencode\t3b_pp.cbl') + pp = tmp_path / "t3b_pp.cbl" pp.write_text(_pp_text_with_if(), encoding="utf-8") r._patch_sqlcode_normalize(pp) out = pp.read_text(encoding="utf-8") diff --git a/tests/test_biz_e2e.py b/tests/test_biz_e2e.py index 9b281f7..b673c80 100644 --- a/tests/test_biz_e2e.py +++ b/tests/test_biz_e2e.py @@ -8,6 +8,7 @@ from pathlib import Path from playwright.sync_api import Page, expect, sync_playwright BASE_URL = "http://127.0.0.1:8000" +COBOL_GIT = Path(os.environ.get("COBOL_GIT_ROOT", Path(__file__).resolve().parent.parent.parent / "jcl-cobol-git")) FIXTURES = Path(__file__).parent / "fixtures" TESTS_DIR = Path(__file__).parent @@ -172,7 +173,7 @@ def test_file_size_limit(page: Page): @pytest.mark.skipif(not _cobol_available(), reason="WSL not available") def test_cobol_system_pipeline_exists(page: Page): """TC-E2E-02 prep: Verify COBOL system data files exist.""" - data_dir = Path(r"D:\cobol-java\jcl-cobol-git\data") + data_dir = COBOL_GIT / "data" assert (data_dir / "input/member.dat").exists(), "member.dat missing" assert (data_dir / "input/rate.dat").exists(), "rate.dat missing" assert (data_dir / "output/summary_report.dat").exists(), "summary_report missing" @@ -181,7 +182,7 @@ def test_cobol_system_pipeline_exists(page: Page): @pytest.mark.skipif(not _cobol_available(), reason="WSL not available") def test_cobol_output_consistent(page: Page): """TC-E2E-02: CRDVAL output matches known golden data.""" - output = Path(r"D:\cobol-java\jcl-cobol-git\data\output") + output = COBOL_GIT / "data" / "output" # Verify error report has 7+ error types errors = (output / "error_report.dat").read_text() @@ -200,8 +201,8 @@ def test_cobol_output_consistent(page: Page): @pytest.mark.skipif(not _cobol_available(), reason="WSL not available") def test_java_output_equals_cobol(page: Page): """TC-E2E-02: Java CRDVAL output matches COBOL.""" - cobol_dir = Path(r"D:\cobol-java\jcl-cobol-git\data\output") - java_dir = Path(r"D:\cobol-java\jcl-cobol-git\data\output") + cobol_dir = COBOL_GIT / "data" / "output" + java_dir = COBOL_GIT / "data" / "output" cobol_report = cobol_dir / "error_report.dat" assert cobol_report.exists(), "COBOL error report missing" @@ -218,7 +219,7 @@ def test_java_output_equals_cobol(page: Page): @pytest.mark.skipif(not _cobol_available(), reason="WSL not available") def test_file_format_consistency(page: Page): """TC-E2E-03: COBOL LINE SEQUENTIAL → JSON → Java roundtrip works.""" - cobol_dir = Path(r"D:\cobol-java\jcl-cobol-git") + cobol_dir = COBOL_GIT # Check JSON conversion output exists json_file = cobol_dir / "data/work/validated_tx.json" diff --git a/tests/test_golden.py b/tests/test_golden.py index 82383a6..0700d77 100644 --- a/tests/test_golden.py +++ b/tests/test_golden.py @@ -1,12 +1,12 @@ """ Golden tests — 对接真实 COBOL 信用卡月结系统 -数据源: D:\cobol-java\jcl-cobol-git\ +数据源: COBOL_GIT_ROOT 环境变量指定的 jcl-cobol-git 目录 验证目标: 28 transactions → 20 valid + 8 rejected → 6 cards → ¥48,250.20 total """ import sys, os -sys.path.insert(0, r"D:\cobol-java\v3-gstack-code-gen") - from pathlib import Path +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) + from data.field_tree import Field, FieldTree from comparator.cobol_binary_reader import CobolBinaryReader from comparator.normalizer import Normalizer @@ -14,7 +14,10 @@ from comparator.field_compare import compare_field from comparator.aligner import align_records from preprocessor import CopybookPreprocessor -GOLDEN = Path(r"D:\cobol-java\jcl-cobol-git") +GOLDEN = Path( + os.environ.get("COBOL_GIT_ROOT", + Path(__file__).resolve().parent.parent.parent / "jcl-cobol-git") +) # ── Test 1: TXCPY COPYBOOK 结构验证 ──