feat: Phase 2 complete — 13 Phases of COBOL type classification and test benchmark
P0.6: gcov infrastructure P1: extract_structure output expansion (11 new feature fields) P2: Confusion group rule engine (8 pairs + contradiction + backtrack) P3: 4-factor confidence calculation + quality gate update P4: 33+2 COBOL program type test samples (22 files, 7 categories) P5: parametrized/ test data generation engine P6: japanese_data.py lookup tables P7-10: Type-specific test suites (~159 parametrized tests) P11: Full classification pipeline (classify_program) + orchestrator integration P12: Documentation (module-interfaces, test-plan v3.0, coverage-matrix) Architecture decisions: - classification_pipeline/ merged to hina/pipeline/ - parametrized/ as independent module - japanese_data.py as root-level file - hina/__all__ only exports classify_program() Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
"""JCL Executor 深度测试 — 使用真实 GnuCOBOL"""
|
||||
|
||||
import sys, os, tempfile, subprocess, shutil
|
||||
from pathlib import Path
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
|
||||
import pytest
|
||||
from jcl.executor import JclExecutor
|
||||
from jcl.parser import parse_jcl, Job, JobStep, CondParam, DDEntry
|
||||
|
||||
COBC_OK = subprocess.run(
|
||||
["cobc", "--version"], capture_output=True, timeout=5
|
||||
).returncode == 0
|
||||
|
||||
|
||||
def _cobol(prog: str = "TP") -> str:
|
||||
return f"""
|
||||
IDENTIFICATION DIVISION.
|
||||
PROGRAM-ID. {prog}.
|
||||
PROCEDURE DIVISION.
|
||||
DISPLAY "OK:{prog}" NO ADVANCING.
|
||||
STOP RUN.
|
||||
"""
|
||||
|
||||
|
||||
@pytest.mark.skipif(not COBC_OK, reason="need GnuCOBOL")
|
||||
def test_compile_and_run():
|
||||
tmp = tempfile.mkdtemp()
|
||||
try:
|
||||
root = Path(tmp)
|
||||
cbl = root / "cobol"; cbl.mkdir()
|
||||
(cbl / "P.cbl").write_text(_cobol("P"))
|
||||
jp = tempfile.NamedTemporaryFile(mode="w", suffix=".jcl", delete=False)
|
||||
jp.write("//J JOB\n//S1 EXEC PGM=P"); jp.close()
|
||||
job = parse_jcl(jp.name); os.unlink(jp.name)
|
||||
ex = JclExecutor(str(root), str(cbl), str(root))
|
||||
ex.run(job)
|
||||
assert ex.results["S1"]["status"] == "OK"
|
||||
finally:
|
||||
shutil.rmtree(tmp, ignore_errors=True)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not COBC_OK, reason="need GnuCOBOL")
|
||||
def test_no_dd():
|
||||
tmp = tempfile.mkdtemp()
|
||||
try:
|
||||
root = Path(tmp)
|
||||
cbl = root / "cobol"; cbl.mkdir()
|
||||
(cbl / "P.cbl").write_text(_cobol("P"))
|
||||
job = Job("J"); job.steps.append(JobStep("S1", "P"))
|
||||
ex = JclExecutor(str(root), str(cbl), str(root))
|
||||
ex.run(job)
|
||||
assert ex.results["S1"]["status"] == "OK"
|
||||
finally:
|
||||
shutil.rmtree(tmp, ignore_errors=True)
|
||||
|
||||
|
||||
def test_sort():
|
||||
tmp = tempfile.mkdtemp()
|
||||
try:
|
||||
root = Path(tmp)
|
||||
d = root / "data" / "work"; d.mkdir(parents=True)
|
||||
(d / "in.txt").write_text("c\nb\na\n")
|
||||
job = Job("J"); job.steps.append(JobStep("S1", "SORT"))
|
||||
job.steps[0].dd_entries = [
|
||||
DDEntry(dd_name="SORTIN", dsn="data/work/in.txt"),
|
||||
DDEntry(dd_name="SORTOUT", dsn="data/work/out.txt"),
|
||||
]
|
||||
ex = JclExecutor(str(root), "", "")
|
||||
ex._run_sort(job.steps[0])
|
||||
assert (root / "data" / "work" / "out.txt").read_text().splitlines() == ["a", "b", "c"]
|
||||
finally:
|
||||
shutil.rmtree(tmp, ignore_errors=True)
|
||||
|
||||
|
||||
def test_cond_logic():
|
||||
ex = JclExecutor(".", ".", ".")
|
||||
# no step_name → execute
|
||||
assert ex._check_cond(CondParam(code=4, operator="GT")) is True
|
||||
# COND=(0,EQ) RC=0 → 0==0 True → not True=False → skip
|
||||
ex.step_rcs["PREV"] = 0
|
||||
assert ex._check_cond(CondParam(code=0, operator="EQ", step_name="PREV")) is False
|
||||
# COND=(4,GT) RC=0 → 0>4 False → not False=True → execute
|
||||
assert ex._check_cond(CondParam(code=4, operator="GT", step_name="PREV")) is True
|
||||
|
||||
|
||||
@pytest.mark.skipif(not COBC_OK, reason="need GnuCOBOL")
|
||||
def test_rc_tracking():
|
||||
tmp = tempfile.mkdtemp()
|
||||
try:
|
||||
root = Path(tmp)
|
||||
cbl = root / "cobol"; cbl.mkdir()
|
||||
(cbl / "A.cbl").write_text(_cobol("A"))
|
||||
(cbl / "B.cbl").write_text(_cobol("B"))
|
||||
jp = tempfile.NamedTemporaryFile(mode="w", suffix=".jcl", delete=False)
|
||||
jp.write("//J JOB\n//S1 EXEC PGM=A\n//S2 EXEC PGM=B"); jp.close()
|
||||
job = parse_jcl(jp.name); os.unlink(jp.name)
|
||||
ex = JclExecutor(str(root), str(cbl), str(root))
|
||||
ex.run(job)
|
||||
assert ex.step_rcs["S1"] == 0
|
||||
assert ex.step_rcs["S2"] == 0
|
||||
finally:
|
||||
shutil.rmtree(tmp, ignore_errors=True)
|
||||
Reference in New Issue
Block a user