fix: 清除硬编码API Key与机器特定路径,改用环境变量+混合式路径解析

This commit is contained in:
hangshuo652
2026-08-25 21:53:18 +08:00
parent b3895a905e
commit 8e81f960af
32 changed files with 200 additions and 76 deletions
+26
View File
@@ -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-createagent 模式联调用)─────────────────
# JCL_ROOT=D:\jcl-cobol-data-create
+6
View File
@@ -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 - 文档 ### 2026-08-24 03:00:00 - 文档
- **范式步骤:** V3总体设计文档更新 - **范式步骤:** V3总体设计文档更新
- **修改摘要:** 更新00-overview.md,添加黑盒模块设计(2B章节)、PGMパターン、多KEY测试、黑盒数据流、双管道架构图 - **修改摘要:** 更新00-overview.md,添加黑盒模块设计(2B章节)、PGMパターン、多KEY测试、黑盒数据流、双管道架构图
+2 -1
View File
@@ -1,3 +1,4 @@
__pycache__/ __pycache__/
*.pyc *.pyc
output/ output/
config.json
+1 -1
View File
@@ -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()` が識別子でマッチする。 - **同一COPYBOOKの複数REPLACING**: `ZAN01REC``R01`/`R02` 両方で使われる場合、`_extract_copy_replacing()` はリスト `[(copy_name, prefix), ...]` を返し、`_parse_copybooks()` が識別子でマッチする。
- **PGMタイプ = サブ はスキップ**: `generate()` 関数で `meta.pgm_type == 'サブ'` の場合 `ValueError` - **PGMタイプ = サブ はスキップ**: `generate()` 関数で `meta.pgm_type == 'サブ'` の場合 `ValueError`
- **入力タイプ判定**: `使用ファイル一覧``I/O` 列に `'I'` を含む行の `媒体` 列を見る。`PS`=ファイル、`DB`=DB、両方=混合。 - **入力タイプ判定**: `使用ファイル一覧``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テスト ## 多keyテスト
-10
View File
@@ -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
}
}
@@ -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. > **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, def generate(design_md: str, source_cbl: str, file_db_md: str,
cpy_dir: str, db_md: str, output_dir: str = "output", cpy_dir: str, db_md: str, output_dir: str = "output",
api_key: str = "sk-6156cccdc9c14d949cf5bfc5afc67a03", api_key: str = "<API_KEY>",
api_model: str = "deepseek-v4-flash", api_model: str = "deepseek-v4-flash",
rules_dir: str = "rules") -> dict: rules_dir: str = "rules") -> dict:
"""生成测试数据的主入口函数。 """生成测试数据的主入口函数。
@@ -2151,7 +2151,7 @@ def main():
help='DB 定義書 .md のパス') help='DB 定義書 .md のパス')
parser.add_argument('--output', default='output', parser.add_argument('--output', default='output',
help='出力ディレクトリ (デフォルト: output)') help='出力ディレクトリ (デフォルト: output)')
parser.add_argument('--api-key', default='sk-6156cccdc9c14d949cf5bfc5afc67a03', parser.add_argument('--api-key', default='<API_KEY>',
help='DeepSeek API Key') help='DeepSeek API Key')
parser.add_argument('--model', default='deepseek-v4-flash', parser.add_argument('--model', default='deepseek-v4-flash',
help='API モデル名') help='API モデル名')
@@ -1,4 +1,4 @@
# COBOL 测试数据生成 Agent 设计文档 # COBOL 测试数据生成 Agent 设计文档
## 背景 ## 背景
@@ -203,7 +203,7 @@ PGMパターン 值到规则文件名的映射:
**API 配置** **API 配置**
- 地址:https://api.deepseek.com/chat/completions - 地址:https://api.deepseek.com/chat/completions
- 模型:`deepseek-v4-flash` - 模型:`deepseek-v4-flash`
- API Key`sk-6156cccdc9c14d949cf5bfc5afc67a03` - API Key`<API_KEY>`
- timeout120 秒 - timeout120 秒
**请求结构** **请求结构**
+6 -5
View File
@@ -2,24 +2,25 @@
"""Append the remaining sections to the design document.""" """Append the remaining sections to the design document."""
from pathlib import Path 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 = OUT.read_text(encoding="utf-8")
content = content.replace("PLACEHOLDER", "") content = content.replace("PLACEHOLDER", "")
# Read part2 content # 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") content += part2.read_text(encoding="utf-8")
# Read part3 content # 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") content += part3.read_text(encoding="utf-8")
# Read part4 content # 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") content += part4.read_text(encoding="utf-8")
# Read part5 content # 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") content += part5.read_text(encoding="utf-8")
OUT.write_text(content, encoding="utf-8") OUT.write_text(content, encoding="utf-8")
+8 -3
View File
@@ -11,9 +11,14 @@ logger = logging.getLogger(__name__)
HEALING_FIXES = { HEALING_FIXES = {
"compile_error": { "compile_error": {
"detect": lambda log: "not found" in (log or "").lower(), "detect": lambda log: "not found" in (log or "").lower(),
"fix": lambda: _try_set_env( # GnuCOBOL 库路径自愈:仅当环境变量 COB_GNUCOBOL_LIB 已设置时生效
"COB_LIBRARY_PATH", # (见 .env.example)。不再内置任何机器特定回退路径。
"D:\\360安全浏览器下载\\GC32-BDB-SP1-rename-7z-to-exe\\lib\\gnucobol", "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": { "s0c7": {
+8 -3
View File
@@ -33,6 +33,11 @@ from runners.gixsql_runner import GixsqlCobolRunner, GixsqlTableData
logger = logging.getLogger(__name__) 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: def _calc_birth_date(age: int, as_of: str = '20260802') -> str:
"""年龄 → 出生日期 YYYYMMDD(通用)。as_of 为运行时运用日。""" """年龄 → 出生日期 YYYYMMDD(通用)。as_of 为运行时运用日。"""
@@ -103,8 +108,8 @@ class GixsqlOrchestrator:
compile_flags=config.gixsql_compile_flags, compile_flags=config.gixsql_compile_flags,
) )
# Derive DB path: C:\Temp\gix\<program_id>.db (matches COBOL CONNECT TO, short enough for col 72) # Derive DB path: <GIXSQL_DB_DIR>\<program_id>.db (matches COBOL CONNECT TO, short enough for col 72)
self.db_path = Path("C:/Temp/gix") / f"{self.program_id}.db" self.db_path = GIXSQL_DB_DIR / f"{self.program_id}.db"
# Pipeline state # Pipeline state
self.src_path: Optional[Path] = None self.src_path: Optional[Path] = None
@@ -263,7 +268,7 @@ class GixsqlOrchestrator:
# シナリオに応じた DB パス # シナリオに応じた DB パス
if scenario: 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 self._current_db_path = db_path
else: else:
db_path = self.db_path db_path = self.db_path
+19 -5
View File
@@ -33,11 +33,20 @@ from pathlib import Path
# ============================================================================ # ============================================================================
PROJECT_ROOT = Path(__file__).resolve().parent.parent 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 = [ 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"), Path(r"D:\jcl-cobol-data-create"),
] ]
COBOL_PROJECT = Path(r"C:\Users\marye\Desktop\2026技术大赛\cobol-tna-system")
PROGRAM = "ZAN04MAT" PROGRAM = "ZAN04MAT"
TEST_INPUTS = { TEST_INPUTS = {
@@ -48,8 +57,9 @@ TEST_INPUTS = {
"db-md": COBOL_PROJECT / "詳細設計書" / "DB定義書.md", "db-md": COBOL_PROJECT / "詳細設計書" / "DB定義書.md",
} }
DEFAULT_API_KEY = "sk-6156cccdc9c14d949cf5bfc5afc67a03" # API key/model come from env or black-box-data-create/config.json (never hardcoded)
DEFAULT_API_MODEL = "deepseek-v4-flash" 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" ORCHESTRATOR_JCL = PROJECT_ROOT / "orchestrator_jcl.py"
@@ -414,10 +424,14 @@ def run_full_pipeline():
"--cpy", str(TEST_INPUTS["cpy"]), "--cpy", str(TEST_INPUTS["cpy"]),
"--db-md", str(TEST_INPUTS["db-md"]), "--db-md", str(TEST_INPUTS["db-md"]),
"--output", str(output_dir), "--output", str(output_dir),
"--api-key", DEFAULT_API_KEY,
"--api-model", DEFAULT_API_MODEL, "--api-model", DEFAULT_API_MODEL,
"--verbose", "--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)...") step("Executing pipeline (this may take several minutes)...")
info(f"Command: {' '.join(cmd)}") info(f"Command: {' '.join(cmd)}")
+47
View File
@@ -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-gitHINA 分类验证用旧仓库)
COBOL_GIT_ROOT = _resolve("COBOL_GIT_ROOT", _CONTEST_ROOT / "jcl-cobol-git")
# 散置样本源码
SAMPLE_SRC_DIR = _resolve("SAMPLE_SRC_DIR", _CONTEST_ROOT)
+1 -1
View File
@@ -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 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} ---") 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 cobol_testgen import extract_structure, generate_data
from hina.pipeline.pipeline import classify_program from hina.pipeline.pipeline import classify_program
from hina.classifier import detect_keyword from hina.classifier import detect_keyword
+1 -1
View File
@@ -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 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}") 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") COPYBOOKS = os.path.join(ROOT, "common", "copybooks")
COBC = "cobc" COBC = "cobc"
+1 -1
View 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 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} ---") 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") COPYBOOKS = os.path.join(ROOT, "common", "copybooks")
from cobol_testgen import extract_structure, generate_data from cobol_testgen import extract_structure, generate_data
+2 -2
View File
@@ -1,6 +1,6 @@
"""S18: ALL benchmark programs — full E2E: parse → generate → flatfile → compile → run → verify """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 <project-root> && python test-data/s18_all_benchmark_e2e.py
""" """
import sys, os, subprocess, re, json import sys, os, subprocess, re, json
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) 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 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}") 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") COPYBOOKS = os.path.join(ROOT, "common", "copybooks")
COBC = "cobc" COBC = "cobc"
+1 -1
View File
@@ -2,7 +2,7 @@
import sys, os, re, time import sys, os, re, time
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) 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") COPYBOOKS = os.path.join(ROOT, "common", "copybooks")
from cobol_testgen import extract_structure, generate_data from cobol_testgen import extract_structure, generate_data
from cobol_testgen.read import preprocess, resolve_copybooks from cobol_testgen.read import preprocess, resolve_copybooks
+1 -1
View File
@@ -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 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}") 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") COPYBOOKS = os.path.join(ROOT, "common", "copybooks")
COBC = "cobc" COBC = "cobc"
+1 -1
View File
@@ -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 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}") 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") COPYBOOKS = os.path.join(ROOT, "common", "copybooks")
from cobol_testgen import extract_structure, generate_data from cobol_testgen import extract_structure, generate_data
+1 -1
View 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 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}") 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") COPYBOOKS = os.path.join(ROOT, "cpy")
BINDIR = os.path.join(ROOT, "bin") BINDIR = os.path.join(ROOT, "bin")
COBC = "cobc" COBC = "cobc"
+2 -2
View File
@@ -2,9 +2,9 @@
import sys, os, re, subprocess, time import sys, os, re, subprocess, time
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) 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") 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") COPYBOOKS_TNA = os.path.join(ROOT_TNA, "cpy")
from cobol_testgen import extract_structure, generate_data from cobol_testgen import extract_structure, generate_data
+2 -2
View File
@@ -2,9 +2,9 @@
import sys, os, re, time import sys, os, re, time
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) 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") 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") COPYBOOKS_TNA = os.path.join(ROOT_TNA, "cpy")
from cobol_testgen import extract_structure, generate_data from cobol_testgen import extract_structure, generate_data
+2 -4
View File
@@ -2,10 +2,8 @@
import sys, os, re, time, json import sys, os, re, time, json
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) 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") from _paths import TNA_ROOT as ROOT_TNA, COPYBOOKS_TNA
ROOT_TNA = "D:/cobol-java/cobol-tna-system/"
COPYBOOKS_TNA = os.path.join(ROOT_TNA, "cpy")
from cobol_testgen import extract_structure, generate_data from cobol_testgen import extract_structure, generate_data
from cobol_testgen.read import preprocess, resolve_copybooks, \ from cobol_testgen.read import preprocess, resolve_copybooks, \
+2 -2
View File
@@ -2,9 +2,9 @@
import sys, os, re import sys, os, re
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) 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") 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 from cobol_testgen import extract_structure, generate_data
total_br = 0; total_cov = 0; errors = []; below = [] total_br = 0; total_cov = 0; errors = []; below = []
+2 -2
View File
@@ -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 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}") def sec(n): print(f"\n{'='*60}\n{n}\n{'='*60}")
DESKTOP = os.path.join(os.environ['USERPROFILE'], "Desktop") from _paths import TNA_ROOT, require
ROOT = os.path.join(DESKTOP, "2026技术大赛", "cobol-tna-system") + "/" ROOT = str(require(TNA_ROOT, "TNA 测试数据", "COBOL_TNA_ROOT")) + "/"
COPYBOOKS = [os.path.join(ROOT, "cpy"), os.path.join(ROOT, "src")] COPYBOOKS = [os.path.join(ROOT, "cpy"), os.path.join(ROOT, "src")]
from config import Config from config import Config
+4 -2
View File
@@ -47,7 +47,8 @@ from cobol_testgen.read import resolve_copybooks, preprocess, extract_procedure_
from cobol_testgen.core import build_branch_tree from cobol_testgen.core import build_branch_tree
try: 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") src = src_path.read_text(encoding="utf-8")
sdir = str(src_path.parent) sdir = str(src_path.parent)
@@ -89,7 +90,8 @@ section("2. HINA分類: 実プログラム判定精度")
from hina.classifier import compute_confidence from hina.classifier import compute_confidence
# jcl-cobol-git の4プログラム # 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(): if cobol_git.exists():
for f in ['CRDVAL', 'CRDCALC', 'CRDRPT', 'GENDATA']: for f in ['CRDVAL', 'CRDCALC', 'CRDRPT', 'GENDATA']:
try: try:
+13 -2
View File
@@ -7,6 +7,8 @@
""" """
import sys, os import sys, os
from pathlib import Path
import pytest
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
from cobol_testgen.read import ( 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.core import build_branch_tree
from cobol_testgen.coverage import collect_decision_points from cobol_testgen.coverage import collect_decision_points
_SRC = r'C:\Users\marye\Desktop\2026技术大赛\cobol-tna-system\src' # TNA 测试数据目录: 环境变量优先 → 大赛兄弟目录兜底(见 .env.example
_CPY = r'C:\Users\marye\Desktop\2026技术大赛\cobol-tna-system\cpy' _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): def _load(pid):
+14 -4
View File
@@ -1,7 +1,8 @@
"""E2E Tests for COBOL->Java Verification Platform """E2E Tests for COBOL->Java Verification Platform
Run: cd D:/cobol-java/v3-gstack-code-gen && python -m pytest tests/e2e/ -v Run: cd <project-root> && python -m pytest tests/e2e/ -v
Requires: web server on http://127.0.0.1:8000, WSL available 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 import json, os, sys, time, uuid, shutil
from datetime import datetime from datetime import datetime
@@ -50,10 +51,19 @@ def create_task(copybook: str, cobol: str, java_dir: str, mapping: str, runner="
return tid return tid
def _wsl_path(p: Path) -> str:
"""Convert a Windows path to its WSL /mnt/<drive> 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): def run_worker_for_task(tid: str):
api_key = os.environ.get("DEEPSEEK_API_KEY", "")
script = ( script = (
"cd /mnt/d/cobol-java/v3-gstack-code-gen && " f"cd {_wsl_path(PROJECT)} && "
"export LLM_API_KEY=sk-ca4961087c7f4aefa8ed0fc6f3d02329 && " f"export LLM_API_KEY='{api_key}' && "
"export LLM_API_BASE=https://api.deepseek.com/v1 && " "export LLM_API_BASE=https://api.deepseek.com/v1 && "
"export LLM_MODEL=deepseek-chat && " "export LLM_MODEL=deepseek-chat && "
f"python3 -c \"exec(open('write_result.py').read().replace('ec17bf32','{tid}'))\"" f"python3 -c \"exec(open('write_result.py').read().replace('ec17bf32','{tid}'))\""
+5 -1
View File
@@ -1,8 +1,12 @@
"""Prepare test data for Playwright E2E tests.""" """Prepare test data for Playwright E2E tests."""
import os
from pathlib import Path from pathlib import Path
FIXTURES = Path(__file__).parent / "fixtures" 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(): def prepare():
+4 -4
View File
@@ -40,10 +40,10 @@ def test_normalize_injects_mapping_after_endsql(tmp_path):
assert "SQLCODE = -2067" in out assert "SQLCODE = -2067" in out
def test_normalize_mapping_before_if_sqlcode(): def test_normalize_mapping_before_if_sqlcode(tmp_path):
"""映射代码注入在 IF SQLCODE = -803 判断之前""" """映射代码注入在 IF SQLCODE = -803 判断之前"""
r = _make_runner() 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.parent.mkdir(parents=True, exist_ok=True)
pp.write_text(_pp_text_with_if(), encoding="utf-8") pp.write_text(_pp_text_with_if(), encoding="utf-8")
r._patch_sqlcode_normalize(pp) r._patch_sqlcode_normalize(pp)
@@ -56,10 +56,10 @@ def test_normalize_mapping_before_if_sqlcode():
assert mapping_idx < if_idx 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 成功路径""" """归一化不影响 SQLCODE=0 成功路径"""
r = _make_runner() 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") pp.write_text(_pp_text_with_if(), encoding="utf-8")
r._patch_sqlcode_normalize(pp) r._patch_sqlcode_normalize(pp)
out = pp.read_text(encoding="utf-8") out = pp.read_text(encoding="utf-8")
+6 -5
View File
@@ -8,6 +8,7 @@ from pathlib import Path
from playwright.sync_api import Page, expect, sync_playwright from playwright.sync_api import Page, expect, sync_playwright
BASE_URL = "http://127.0.0.1:8000" 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" FIXTURES = Path(__file__).parent / "fixtures"
TESTS_DIR = Path(__file__).parent 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") @pytest.mark.skipif(not _cobol_available(), reason="WSL not available")
def test_cobol_system_pipeline_exists(page: Page): def test_cobol_system_pipeline_exists(page: Page):
"""TC-E2E-02 prep: Verify COBOL system data files exist.""" """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/member.dat").exists(), "member.dat missing"
assert (data_dir / "input/rate.dat").exists(), "rate.dat missing" assert (data_dir / "input/rate.dat").exists(), "rate.dat missing"
assert (data_dir / "output/summary_report.dat").exists(), "summary_report 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") @pytest.mark.skipif(not _cobol_available(), reason="WSL not available")
def test_cobol_output_consistent(page: Page): def test_cobol_output_consistent(page: Page):
"""TC-E2E-02: CRDVAL output matches known golden data.""" """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 # Verify error report has 7+ error types
errors = (output / "error_report.dat").read_text() 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") @pytest.mark.skipif(not _cobol_available(), reason="WSL not available")
def test_java_output_equals_cobol(page: Page): def test_java_output_equals_cobol(page: Page):
"""TC-E2E-02: Java CRDVAL output matches COBOL.""" """TC-E2E-02: Java CRDVAL output matches COBOL."""
cobol_dir = Path(r"D:\cobol-java\jcl-cobol-git\data\output") cobol_dir = COBOL_GIT / "data" / "output"
java_dir = Path(r"D:\cobol-java\jcl-cobol-git\data\output") java_dir = COBOL_GIT / "data" / "output"
cobol_report = cobol_dir / "error_report.dat" cobol_report = cobol_dir / "error_report.dat"
assert cobol_report.exists(), "COBOL error report missing" 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") @pytest.mark.skipif(not _cobol_available(), reason="WSL not available")
def test_file_format_consistency(page: Page): def test_file_format_consistency(page: Page):
"""TC-E2E-03: COBOL LINE SEQUENTIAL → JSON → Java roundtrip works.""" """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 # Check JSON conversion output exists
json_file = cobol_dir / "data/work/validated_tx.json" json_file = cobol_dir / "data/work/validated_tx.json"
+7 -4
View File
@@ -1,12 +1,12 @@
""" """
Golden tests 对接真实 COBOL 信用卡月结系统 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 验证目标: 28 transactions 20 valid + 8 rejected 6 cards ¥48,250.20 total
""" """
import sys, os import sys, os
sys.path.insert(0, r"D:\cobol-java\v3-gstack-code-gen")
from pathlib import Path from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from data.field_tree import Field, FieldTree from data.field_tree import Field, FieldTree
from comparator.cobol_binary_reader import CobolBinaryReader from comparator.cobol_binary_reader import CobolBinaryReader
from comparator.normalizer import Normalizer from comparator.normalizer import Normalizer
@@ -14,7 +14,10 @@ from comparator.field_compare import compare_field
from comparator.aligner import align_records from comparator.aligner import align_records
from preprocessor import CopybookPreprocessor 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 结构验证 ── # ── Test 1: TXCPY COPYBOOK 结构验证 ──