Files
cobol-java-v3/SETUP.md
T

17 KiB
Raw Blame History

COBOL Test Data Generator — 环境搭建与运行指南

1. 系统概述

COBOL 测试数据生成器(cobol-java-v3)是一个 Python 工具链,用于解析 COBOL 程序、提取控制流结构、生成覆盖所有分支的测试数据,并输出为固定的 flat file 格式供 GnuCOBOL 编译运行。

系统支持两条平行的测试管道:非 DB 管道flat file I-O 程序 → cobc 编译运行 → 二进制比对)和 DB 管道EXEC SQL 程序 → gixpp ESQL 预处理 → cobc + libgixsql 编译运行 → SQLite 表比对),自动根据源码中是否包含 EXEC SQL 路由到对应管道。

核心能力

能力 说明
解析 COBOL DATA DIVISION Lark 语法 (Earley parser) → 字段定义
解析 COBOL PROCEDURE DIVISION 行级状态机 → 决策点树 + EXEC SQL 抽取
分支覆盖数据生成 每决策点生成 True/False 路径 → 记录
Flat file + SQLite DB 双输出 非 DB 程序→二进制 flat fileDB 程序→flat file + SQLite 表行
GnuCOBOL 编译运行 (非 DB) 测试数据 → cobc 编译 → 运行 → 二进制比对
gixsql 编译运行 (DB) gixpp ESQL 预处理 → cobc -l gixsql 编译 → SQLite 运行 → 表比对
覆盖率报告 (gcov) --gcov 模式下编译带 -g --coverage,合并后生成 HTML 报告

2. 必要条件

2.1 硬件要求

项目 最低 推荐
CPU 2 cores 4+ cores
内存 4 GB 8 GB
磁盘 500 MB 2 GB
OS Windows 10/11 64-bit Windows 11

2.2 软件要求

软件 版本 用途
Python 3.12+ 运行测试数据生成器
GnuCOBOL (cobc) 3.2.0 (GC32-BDB-SP1) 编译 COBOL 程序 & 运行时验证(DB 管道需要含 SQLite 支持的版本)
gixsql 已 vendored (gixsql/) ESQL 预处理器 (gixpp.exe) + 运行时 DLL (libgixsql.dll)DB 管道必备
Git 任意 拉取代码

2.3 Python 依赖

lark>=1.1.0          # Lark Earley parser (DATA DIVISION 解析)
pathlib>=1.0.1       # 路径处理
pyyaml>=6.0          # YAML 配置加载(DB 管道:per-program schema

安装命令:

pip install lark pathlib pyyaml

2.4 GnuCOBOL 安装

GnuCOBOL 3.2.0 (OpenCOBOL) 需要单独安装。

下载:

  • GnuCOBOL 3.2 Windows 二进制包
  • 推荐: GC32-BDB-SP1 版本(含 DB2/SQLite 支持)

安装后确认:

cobc --version
# 输出示例: cobc (GnuCOBOL) 3.2.0

环境变量

# cobc 需要在 PATH 中
# 典型路径: C:\GnuCOBOL\bin
# 或自定义安装路径

# COB_LIBRARY_PATH — 运行时 DLL 搜索路径
# 非 DB 管道:子程序 DLL 目录(如 cobol-tna-system\bin
# DB 管道:必须包含 gixsql\lib\libgixsql.dll, libgcc_s_dw2-1.dll 等)
#   如: set COB_LIBRARY_PATH=D:\cobol-java\cobol-java-v3\gixsql\lib

# GIXSQL_DB_PATH — DB 管道 SQLite 数据库路径(默认 C:\Temp\gix\
#   如: set GIXSQL_DB_PATH=C:\Temp\gix

3. 环境搭建步骤

3.1 安装 Python 3.12+

# 下载: https://www.python.org/downloads/
# 安装时勾选 "Add Python to PATH"
python --version
# Python 3.12.x

pip install lark pathlib pyyaml

3.2 安装 GnuCOBOL 3.2

  1. 下载 GC32-BDB-SP1 包
  2. 解压到 D:\360安全浏览器下载\GC32-BDB-SP1-rename-7z-to-exe\
  3. bin\ 子目录添加到系统 PATH
  4. 验证:
cobc --version
# cobc (GnuCOBOL) 3.2.0

3.3 克隆代码

cd D:\
git clone https://gittea.dev/hangshuo652/cobol-java-v3.git
# 或从已有仓库拉取
cd D:\cobol-java\cobol-java-v3
git pull

3.4 验证安装

cd D:\cobol-java\cobol-java-v3
python -c "from cobol_testgen import extract_structure; print('OK')"
# 输出: OK

4. 目录结构

cobol-java-v3/
├── cobol_testgen/             # 核心代码
│   ├── __init__.py            # 公开 API (extract_structure, generate_data) + DB 自动路由
│   ├── read.py                # 预处理器 + DATA DIVISION 解析 + EXEC SQL INCLUDE 解决
│   ├── core.py                # 旧 PROCEDURE DIVISION 解析器 + EXEC SQL 抽取
│   ├── cond.py                # 条件解析器
│   ├── coverage.py            # 覆盖率统计 (+ gcov HTML 报告)
│   ├── design_mcdc.py         # 线性路径枚举 (O(N) 替代 O(2^N))
│   ├── pipeline_bridge.py     # 新旧解析器桥接层
│   ├── procedure_parser.py    # 新 PROCEDURE DIVISION 解析器
│   ├── flatfile.py            # Flat file 写入器
│   ├── design.py              # 值生成 + 约束应用
│   ├── to_sql.py              # SQL 约束解析 + DB 行生成 (DB 管道)
│   ├── models.py              # 数据模型 (BrSeq, BrIf, BrEval...)
│   ├── grammar.lark           # DATA DIVISION Lark 语法
│   └── procedure_grammar.lark # PROCEDURE DIVISION Lark 语法 (实验性)
├── orchestrator_db.py         # DB 6 步管道编排 (GixsqlOrchestrator)
├── runners/                   # 编译运行引擎
│   ├── cobol_runner.py        # 标准 GnuCOBOL runner(非 DB
│   ├── gixsql_runner.py       # gixpp + cobc runnerDB
│   ├── native_java_runner.py  # 原生 Java runner
│   ├── spark_java_runner.py   # Spark Java runner
│   ├── data_writer.py         # 测试数据写入器
│   └── runner.py              # 基类
├── config/
│   ├── program_schema.py      # DB 程序 schema 加载器
│   └── programs/              # per-program YAML 配置(6 个 DB 程序)
│       ├── KIN02UPD.yaml
│       ├── KIN03EXP.yaml
│       ├── KIN06CLD.yaml
│       ├── KIN08DBU.yaml
│       ├── KIN09CSV.yaml
│       └── ZAN06UPD.yaml
├── gixsql/                    # 已 vendored ESQL 工具链
│   ├── bin/gixpp.exe          # ESQL 预处理器
│   └── lib/*.dll              # 运行时 (libgixsql, libgixsql-sqlite, libgcc 等)
├── test-data/                 # 测试套件
│   ├── s15_coverage_verification.py   # 基础覆盖率验证 (8种控制结构)
│   ├── s19_final_bridge_test.py       # 桥接器验证
│   ├── s21_cond_fix_verify.py         # 条件解析验证
│   ├── s25_per_program_report.py      # 每程序详细报告
│   ├── s26_regression_check.py        # 回归检查
│   └── s30_db_e2e.py                 # DB 端到端测试 (ZAN06UPD)
├── diagnose_db2.py            # DB 全流程诊断脚本
├── diagnose_kind8dbrun.py     # DB 单步诊断 (仅编译运行)
├── SETUP.md                  # 本文件
└── docs/                      # 设计文档
└── runtime/                   # 运行产物(测试数据、输入文件、覆盖率报告,已 gitignore)

5. 运行测试

5.1 快速验证(10 秒)

cd D:\cobol-java\cobol-java-v3
python test-data/s15_coverage_verification.py

期望输出:

S15: 17 PASS / 0 FAIL

5.2 完整 43 程序覆盖率报告(2-3 分钟)

python test-data/s25_per_program_report.py

期望输出末尾:

100%: 43 programs
TOTAL 3178 3178 100%

5.3 回归快速检查(2 分钟)

python test-data/s26_regression_check.py

期望输出:

Total: 3178/3178 = 100.00%
ALL 43/43 AT 100% — NO REGRESSIONS

5.4 指定 COPYBOOK 目录

如果 COBOL 程序依赖 COPYBOOK,需要在调用 generate_data 时指定 copybook_dirs

from cobol_testgen import extract_structure, generate_data

src = open("program.cbl", encoding="utf-8").read()
st = extract_structure(src)
recs = generate_data(src, st, copybook_dirs=["path/to/copybooks"])

5.5 DB 端到端测试(5 分钟)

DB 管道需要使用 cobol-tna-system 同级项目中的 DB 程序(含 EXEC SQL 的 COBOL 源码):

# 1. 确认同级目录存在 cobol-tna-system
dir ..\cobol-tna-system

# 2. 设置环境变量
set COB_LIBRARY_PATH=<proj_dir>\gixsql\lib
mkdir C:\Temp\gix 2>nul
set GIXSQL_DB_PATH=C:\Temp\gix

# 3. 运行 DB 端到端测试 (ZAN06UPD - 6 步管线: 编译→生成数据→运行→提取→Java→比对)
python test-data\s30_db_e2e.py

期望输出末尾:

COVERAGE: DB pipeline E2E PASSED

5.6 DB 单程序运行

# 自动路由: 源码含 EXEC SQL → DB 管道,否则走非 DB 管道
python -m cobol_testgen ..\cobol-tna-system\src\ZAN06UPD.cbl

# 带 gcov 覆盖率收集 (编译带 -g --coverage,生成 HTML 报告)
python -m cobol_testgen --gcov ..\cobol-tna-system\src\KIN08DBU.cbl runtime\

DB 管道会自动加载 config/programs/<PROGRAM_ID>.yaml 中的表定义、子程序列表、运行场景(normal/collision/abnormal),多场景运行的 gcov 覆盖率会被合并输出。


6. 关键 API

6.1 extract_structure(cobol_source)

输入: COBOL 程序源码文本
返回: dict — 包含总分支数、决策点列表、分支树对象等

st = extract_structure(src)
branches = st["total_branches"]    # 总分支数
dps = st["decision_points"]        # 决策点列表
tree = st["branch_tree_obj"]       # 分支树对象

6.2 generate_data(cobol_source, structure, copybook_dirs=None)

输入:

  • cobol_source: COBOL 程序原始源码(未预处理)
  • structure: extract_structure 返回的 dict
  • copybook_dirs: COPYBOOK 搜索路径列表(可选)

返回: list[dict] — 每条记录包含所有字段的值

recs = generate_data(src, st)
# 或带 COPYBOOK 目录
recs = generate_data(src, st, copybook_dirs=["./cpy", "../common/copybooks"])

6.3 覆盖率数据

generate_data 执行后,structure 对象包含 coverage 键:

cov = st["coverage"]
total = cov["total"]        # 总分支数
covered = cov["covered"]    # 覆盖分支数
pct = cov["pct"]            # 覆盖率百分比
dps = cov["decision_points"]  # 各决策点明细

7. DB 管道概述

系统包含两条平行管道,根据 COBOL 源码是否包含 EXEC SQL 自动路由:

方面 非 DB 管道 DB 管道
入口 main.pyorchestrator.py Python CLI 自动检测 EXEC SQLorchestrator_db.py: GixsqlOrchestrator
编译器 cobc -E + 标准编译 gixpp.exe (ESQL 预处理) + cobc -l gixsql
运行时 平面二进制文件 (I-O) SQLite DB (EXEC SQL) + 平面文件 (顺序 I-O)
数据生成 分支覆盖记录集 分支覆盖记录集 + SQLite 表行 (按 WHERE 约束生成)
程序配置 config/programs/<ID>.yaml (表定义、子程序、场景)
验证 二进制平面文件比对 SQLite 表行比对 + Java 中间 JSON (W01.json)
覆盖率 静态分支覆盖 动态 gcov 覆盖率 (跨场景合并)
Java 集成 Native Java / Spark Java Java 读取中间 JSON

7.1 DB 管道 6 步流程

步骤 方法 说明
1 step1_setup_environment gixpp ESQL 预处理 → cobc 编译(链接 libgixsql),避免中文路径问题
2 step2_generate_inputs 解析 COBOL → 分支覆盖数据 + SQLite 表行(含正/异常场景)
3 step3_run_cobol 运行编译后 .exeGIXSQL_DB_PATH 环境变量),收集 gcov
4 step4_extract_intermediate 读取 SQLite 表 → 中间 JSONW01.json,供 Java 消费)
5 step5_run_java 执行 Java JAR,以中间 JSON 为输入
6 step6_verify Java 输出 vs COBOL 预期值比对

7.2 前置条件

  • cobol-tna-system 同级项目: DB 程序源码需位于 ../cobol-tna-system/src/(或通过 config/programs/*.yaml 配置路径)
  • config/programs/<PROGRAM_ID>.yaml: 每个 DB 程序必须有对应的 YAML schema,定义:
    • db_tables: 表名、列类型、主键
    • subprograms: 子程序列表(编译时链接)
    • runs: 运行场景(normal / collision / abnormal),每种场景可配置不同的 sysin 和预期输出
  • C:\Temp\gix\: SQLite 数据库存放目录(由 GIXSQL_DB_PATH 指定)
  • COB_LIBRARY_PATH: 必须包含 gixsql/lib/(运行时载入 libgixsql.dll

8. 运行条件明细(同事配置检查清单)

必须满足

  • Python 3.12+ 已安装,在 PATH 中
  • pip install lark 执行成功
  • GnuCOBOL (cobc) 3.2.0 已安装,在 PATH 中
  • cobc --version 输出正常
  • 无防火墙阻止 gittea.dev 的 git 访问
  • D:\ 盘有至少 500MB 空闲

如果使用 GnuCOBOL 编译运行

  • cobc 命令可用(which cobcwhere cobc
  • 子程序 DLL 路径在 COB_LIBRARY_PATH 环境中
  • EXEC SQL 需要 SQLite3 支持(GC32-BDB-SP1 版本含)

DB 管道额外检查

  • gixsql/bin/gixpp.exe 存在(vendored ESQL 预处理器)
  • COB_LIBRARY_PATH 包含 <proj>/gixsql/lib/(运行时 DLL
  • GIXSQL_DB_PATH 已设置(如 C:\Temp\gix),目录存在
  • config/programs/<ID>.yaml 存在(per-program schema
  • ../cobol-tna-system/ 同级目录存在(DB 程序源码)
  • pip install pyyaml 执行成功

常见问题

问题 原因 解决
ModuleNotFoundError: No module named 'lark' 缺少 Lark pip install lark
cobc: command not found GnuCOBOL 不在 PATH 添加 bin\ 到 PATH
Errno 13 Permission denied 文件权限 以管理员运行或修改文件权限
gbk codec can't decode byte 编码问题 设置 PYTHONIOENCODING=utf-8
name 'pp_str' is not defined 报告脚本 Bug 已修复,git pull 最新代码
EXEC SQL ... not supported 需要 DB2/SQLite 用 GC32-BDB-SP1 版本 GnuCOBOL
gixpp: command not found gixsql/bin 不在 PATH $env:PATH += ";<proj>\\gixsql\\bin"
Cannot load libgixsql.dll COB_LIBRARY_PATH 未设置 $env:COB_LIBRARY_PATH = "<proj>\\gixsql\\lib"
GIXSQL_DB_PATH not set SQLite 路径未指定 mkdir C:\Temp\gix -Force; $env:GIXSQL_DB_PATH = "C:\Temp\gix"
config/programs/<ID>.yaml not found DB 程序缺少 schema 补充对应 YAML 配置文件

9. 测试基准程序说明

系统包含两套测试基准程序:

电信计费系统 (37 程序)

路径: D:\cobol-java\cobol-test-programs/
COPYBOOK: common/copybooks/
类型: Matching / KeyBreak / Division / CSV / Sort 等

勤怠管理系统 (22 程序)

路径: D:\cobol-java\cobol-tna-system/
COPYBOOK: cpy/
子程序: sub/*.cbl → bin/*.dll
类型: 日企勤怠管理 (打工统计)
DB 程序 (EXEC SQL): KIN02UPD, KIN03EXP, KIN06CLD, KIN08DBU, KIN09CSV, ZAN06UPD — 共 6 个
非 DB 程序: KIN01INP, KIN04CHK, KIN05MAT, KIN07DAI, ZAN01CHKZAN05CAL, KYU01CVTKYU09MRG — 共 16 个

10. 快速启动脚本

Windows (batch)

@echo off
cd /d D:\cobol-java\cobol-java-v3
echo === COBOL Test Data Generator ===
echo [1/3] Checking dependencies...
python -c "import lark" 2>nul || pip install lark
echo [2/3] Running regression test...
python test-data\s15_coverage_verification.py
if %errorlevel% neq 0 echo FAILED && exit /b 1
echo [3/3] Running full coverage report...
set PYTHONIOENCODING=utf-8
python test-data\s25_per_program_report.py
echo === DONE ===

Linux/macOS

#!/bin/bash
cd /path/to/cobol-java-v3
echo "=== COBOL Test Data Generator ==="
echo "[1/3] Checking dependencies..."
python3 -c "import lark" 2>/dev/null || pip3 install lark
echo "[2/3] Running regression test..."
python3 test-data/s15_coverage_verification.py
if [ $? -ne 0 ]; then echo "FAILED"; exit 1; fi
echo "[3/3] Running full coverage report..."
PYTHONIOENCODING=utf-8 python3 test-data/s25_per_program_report.py
echo "=== DONE ==="

11. 版本信息

版本 日期 说明
v3.0 2026-06-25 当前版本。43/43 程序 100% 分支覆盖
v2.0 2026-06-20 新 PROCEDURE DIVISION 解析器 + 线性路径枚举
v1.0 2026-06-14 初始版本,BrParser regex 解析器

附录:覆盖率数据验证方法

系统使用三层验证确保覆盖率数据真实:

  1. S15 测试: 8 个手动构建的 COBOL 片段,每个决策点的手工分支数与系统检测数逐一对比
  2. 所有约束通过 _match_constraint 精确匹配:约束侧和解析侧的字段名都会去掉下标后再比较
  3. 无条件 fallback 已全部移除:没有 "任何路径到达就标记全部" 的逻辑
# coverage.py 中 _mark_if 的真实覆盖逻辑(无 fallback):
def _mark_if(dp, cons):
    # 只有约束侧字段名 == 解析侧字段名时标记覆盖
    # 加了防御性下标剥离
    if _match_constraint(c, simple):
        dp.active_branches.add('T' if c[3] else 'F')
    elif _match_constraint(c, inv_simple):
        dp.active_branches.add('F')
    # 没有任何 else + unconditional add