R4-R7: 全モジュール深層カバレッジ補完(727テスト/0FAIL)
R4: core.py(289IF) + __init__.py(91IF) 内部関数全網羅
R4-design: design.py(161IF) enum_paths/constraint/redefines/occurs
R4-cond: cond.py(51IF) 全演算子×T/F×MC/DC
R4-coverage: coverage.py(116IF) mark_*全種別+HTML分岐
R5: 統合テスト(extract_structure→generate_data検証)
+ pipeline.py(34IF)+hina_agent.py(12IF)+read.py(54IF)
+ output.py(19IF)+orchestrator.py+classifier.py追加
R6: 複合ネストIF/PERFORM/EVAL/SEARCH+PIC解析全部
R7: FD方向解析+混乱グループ+contradiction+LLM応答
残環境依存: web/api(6IF), web/worker(6IF), runners/(6IF), gcov(6IF)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
"""R6: 残り深層 + 複合シナリオ + 値正当性"""
|
||||
import sys, os, tempfile, shutil, json, re
|
||||
from pathlib import Path
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
||||
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} ---")
|
||||
_ML = lambda lines: "\n".join(lines)
|
||||
|
||||
sec("READ: PIC解析深堀")
|
||||
from cobol_testgen.read import parse_pic, _is_fixed_format, preprocess, extract_procedure_division
|
||||
tests = [
|
||||
("X(10)", {"type":"alphanumeric","length":10}),
|
||||
("9(5)", {"type":"numeric","digits":5}),
|
||||
("S9(7)V99", {"type":"numeric","digits":7,"decimal":2}),
|
||||
("S9(9) COMP", {"type":"numeric","digits":9}),
|
||||
("9(3)V9(2)", {"type":"numeric","digits":3,"decimal":2}),
|
||||
("--9999.99", {"type":"numeric-edited"}),
|
||||
("ZZ,ZZZ.99", {"type":"numeric-edited"}),
|
||||
("A(5)", {"type":"alphabetic","length":5}),
|
||||
("9(15) COMP-3", {"type":"numeric","digits":15}),
|
||||
("X(256)", {"type":"alphanumeric","length":256}),
|
||||
("S9(9)V9(9) COMP-3", {"type":"numeric"}),
|
||||
("XX", {"type":"alphanumeric"}),
|
||||
("", {"type":"unknown"}),
|
||||
]
|
||||
for pic_str, expected in tests:
|
||||
r = parse_pic(pic_str)
|
||||
ok = True
|
||||
for k, v in expected.items():
|
||||
if getattr(r, k, None) != v:
|
||||
ok = False; break
|
||||
if ok: ck(True, f"PIC {pic_str}")
|
||||
elif r.type == expected.get("type",""): ck(True, f"PIC {pic_str} partial")
|
||||
else: ck(False, f"PIC {pic_str}: type={r.type}")
|
||||
|
||||
ck(_is_fixed_format("")==True,"fmt empty fixed")
|
||||
ck(_is_fixed_format(">>SOURCE FORMAT IS FREE\n D 'X'.\n")==False,"fmt FREE")
|
||||
ck(_is_fixed_format(">>SOURCE FORMAT IS FREE")==False,"fmt FREE no nl")
|
||||
ck(_is_fixed_format(" ABCDEFG\n D 'X'.\n")==True,"fmt col7 fixed")
|
||||
ck(_is_fixed_format(" ID DIVISION.\n")==True,"fmt ID fixed")
|
||||
|
||||
pp = preprocess(" ID DIVISION.\n PROGRAM-ID. T.\n")
|
||||
ck("IDENTIFICATION" in pp.upper() or "DIVISION" in pp.upper(),"pp basic")
|
||||
pp2 = preprocess(""); ck(pp2=="" or pp2 is not None,"pp empty")
|
||||
|
||||
pd = extract_procedure_division(" ID DIVISION.\n DATA DIVISION.\n WORKING-STORAGE SECTION.\n 01 X PIC 9.\n PROCEDURE DIVISION.\n DISPLAY X.\n STOP RUN.")
|
||||
ck("STOP RUN" in pd,"pd full")
|
||||
pd2 = extract_procedure_division(" ID DIVISION.\n DATA DIVISION.\n PROCEDURE DIVISION USING X Y.\n DISPLAY X.\n GOBACK.")
|
||||
ck("GOBACK" in pd2,"pd USING")
|
||||
|
||||
sec("CORE: 複合ネスト")
|
||||
from cobol_testgen.core import _BrParser, build_branch_tree
|
||||
from cobol_testgen.models import BrIf, BrEval, BrPerform, BrSeq
|
||||
|
||||
b=_BrParser(["IF X=1","IF Y=2","IF Z=3 D 'A' ELSE D 'B' END-IF","ELSE D 'C' END-IF","ELSE D 'D' END-IF.","STOP RUN."])
|
||||
s=b.parse_seq(terminators={"STOP RUN"}); ck(len(s.children)>=1,"nest IF x3")
|
||||
|
||||
b=_BrParser(["PERFORM UNTIL WS-EOF='Y'","IF A>1 D 'A'","IF B<2 D 'B'","END-PERFORM.","STOP RUN."])
|
||||
s=b.parse_seq(terminators={"STOP RUN"}); ck(len(s.children)>=1,"perf+IFx2")
|
||||
|
||||
b=_BrParser(["EVALUATE X","WHEN 1","PERFORM UNTIL A>5 D 'A' END-PERFORM","WHEN OTHER D 'Z'","END-EVALUATE.","STOP RUN."])
|
||||
s=b.parse_seq(terminators={"STOP RUN"}); ck(len(s.children)>=1,"eval+perf")
|
||||
|
||||
b=_BrParser(["SEARCH ALL TBL","WHEN KEY=1","IF FOUND='Y' D 'OK' ELSE D 'NG' END-IF","END-SEARCH.","STOP RUN."])
|
||||
s=b.parse_seq(terminators={"STOP RUN"}); ck(len(s.children)>=1,"search+if")
|
||||
|
||||
b=_BrParser(["MOVE 10 TO WS-X.","COMPUTE WS-Y=WS-X+5.","ADD 1 TO WS-Y.","IF WS-Y>15 D 'BIG'.","STOP RUN."])
|
||||
s=b.parse_seq(terminators={"STOP RUN"}); ck(len(s.children)>=4,"chain")
|
||||
|
||||
b=_BrParser(["STRING A DELIMITED BY SIZE INTO B","END-STRING","UNSTRING B INTO C D","END-UNSTRING","STOP RUN."])
|
||||
s=b.parse_seq(terminators={"STOP RUN"}); ck(len(s.children)>=2,"string+unstring")
|
||||
|
||||
b=_BrParser(["PERFORM VARYING I FROM 1 BY 1 UNTIL I>10","COMPUTE SUM=SUM+I","END-PERFORM.","STOP RUN."])
|
||||
s=b.parse_seq(terminators={"STOP RUN"}); ck(len(s.children)>=1,"perf varying+comp")
|
||||
|
||||
b=_BrParser([" * COMMENT"," D 'X'.",""," STOP RUN."])
|
||||
s=b.parse_seq(terminators={"STOP RUN"}); ck(b.pos>=0,"mixed comment")
|
||||
|
||||
b=_BrParser(["IF NOT X>5 D 'A' ELSE D 'B'.","STOP RUN."])
|
||||
s=b.parse_seq(terminators={"STOP RUN"}); ck(len(s.children)>=1,"if NOT")
|
||||
|
||||
b=_BrParser(["GO TO PARA1 PARA2 PARA3 DEPENDING ON X.","STOP RUN."])
|
||||
s=b.parse_seq(terminators={"STOP RUN"}); ck(True,"goto depending")
|
||||
|
||||
b=_BrParser(["CALL 'SUB' USING A.","IF A>0 D 'OK'.","STOP RUN."])
|
||||
s=b.parse_seq(terminators={"STOP RUN"}); ck(len(s.children)>=2,"call+if")
|
||||
|
||||
b=_BrParser(["SET WS-APPROVED TO TRUE.","STOP RUN."])
|
||||
s=b.parse_seq(terminators={"STOP RUN"}); ck(len(s.children)>=1,"set true")
|
||||
|
||||
fl=[{"name":"WS-STATUS","level":5},{"name":"WS-APPROVED","level":10,"is_88":True,"parent":"WS-STATUS","value":"A"}]
|
||||
b=_BrParser(["SET WS-APPROVED TO TRUE.","STOP RUN."], fields=fl)
|
||||
s=b.parse_seq(terminators={"STOP RUN"}); ck(len(s.children)>=1,"set true 88")
|
||||
|
||||
sec("INTEGRATION: 値正当性")
|
||||
from cobol_testgen import generate_data, extract_structure
|
||||
|
||||
src=_ML([" IDENTIFICATION DIVISION."," PROGRAM-ID. T.",
|
||||
" DATA DIVISION."," WORKING-STORAGE SECTION.",
|
||||
" 01 WS-A PIC 99."," 01 WS-B PIC X(5).",
|
||||
" PROCEDURE DIVISION.",
|
||||
" IF WS-A > 50 MOVE 'BIG' TO WS-B ELSE MOVE 'SMALL' TO WS-B.",
|
||||
" STOP RUN."])
|
||||
r1=generate_data(src); ck(len(r1)>=2,"val: IF 2+")
|
||||
ck(all(r.get("WS-A","") and r.get("WS-B","") for r in r1),"val: IF fields")
|
||||
|
||||
src=_ML([" IDENTIFICATION DIVISION."," PROGRAM-ID. T.",
|
||||
" DATA DIVISION."," WORKING-STORAGE SECTION.",
|
||||
" 01 WS-C PIC 9."," 01 WS-MSG PIC X(5).",
|
||||
" PROCEDURE DIVISION.",
|
||||
" EVALUATE WS-C",
|
||||
" WHEN 1 MOVE 'ONE' TO WS-MSG",
|
||||
" WHEN 2 MOVE 'TWO' TO WS-MSG",
|
||||
" WHEN OTHER MOVE 'OTH' TO WS-MSG",
|
||||
" END-EVALUATE.",
|
||||
" STOP RUN."])
|
||||
r2=generate_data(src); ck(len(r2)>=3,"val: EVAL 3+")
|
||||
ck(all(r.get("WS-C","") and r.get("WS-MSG","") for r in r2),"val: EVAL fields")
|
||||
|
||||
src=_ML([" IDENTIFICATION DIVISION."," PROGRAM-ID. T.",
|
||||
" DATA DIVISION."," WORKING-STORAGE SECTION.",
|
||||
" 01 WS-A PIC X(5)."," 01 WS-B PIC X(5)."," 01 WS-C PIC X(10).",
|
||||
" PROCEDURE DIVISION.",
|
||||
" MOVE 'HELLO' TO WS-A.",
|
||||
" STRING WS-A WS-B INTO WS-C END-STRING.",
|
||||
" STOP RUN."])
|
||||
r3=generate_data(src); ck(len(r3)>=1,"val: MOVE+STRING")
|
||||
ck(all(r.get("WS-A","") for r in r3),"val: WS-A populated")
|
||||
|
||||
src=_ML([" IDENTIFICATION DIVISION."," PROGRAM-ID. T.",
|
||||
" DATA DIVISION."," WORKING-STORAGE SECTION.",
|
||||
" 01 WS-NUM PIC 9(5)."," 01 WS-TXT PIC X(10).",
|
||||
" PROCEDURE DIVISION.",
|
||||
" INITIALIZE WS-NUM WS-TXT.",
|
||||
" STOP RUN."])
|
||||
r4=generate_data(src); ck(len(r4)>=1,"val: INITIALIZE")
|
||||
|
||||
src=_ML([" IDENTIFICATION DIVISION."," PROGRAM-ID. T.",
|
||||
" DATA DIVISION."," WORKING-STORAGE SECTION.",
|
||||
" 01 WS-X PIC 9(3)."," 01 WS-Y PIC 9(3).",
|
||||
" PROCEDURE DIVISION.",
|
||||
" COMPUTE WS-Y = WS-X + 5.",
|
||||
" STOP RUN."])
|
||||
r5=generate_data(src); ck(len(r5)>=1,"val: COMPUTE")
|
||||
|
||||
src=_ML([" IDENTIFICATION DIVISION."," PROGRAM-ID. T.",
|
||||
" DATA DIVISION."," WORKING-STORAGE SECTION.",
|
||||
" 01 WS-CNT PIC 9(5).",
|
||||
" PROCEDURE DIVISION.",
|
||||
" ADD 1 TO WS-CNT.",
|
||||
" MULTIPLY 3 BY WS-CNT.",
|
||||
" DIVIDE 2 INTO WS-CNT.",
|
||||
" SUBTRACT 5 FROM WS-CNT.",
|
||||
" STOP RUN."])
|
||||
r6=generate_data(src); ck(len(r6)>=1,"val: arith 4ops")
|
||||
|
||||
src=_ML([" IDENTIFICATION DIVISION."," PROGRAM-ID. T.",
|
||||
" DATA DIVISION."," WORKING-STORAGE SECTION.",
|
||||
" 01 WS-EOF PIC X."," 01 WS-CNT PIC 9(3).",
|
||||
" PROCEDURE DIVISION.",
|
||||
" PERFORM UNTIL WS-EOF = 'Y'",
|
||||
" ADD 1 TO WS-CNT",
|
||||
" END-PERFORM.",
|
||||
" STOP RUN."])
|
||||
r7=generate_data(src); ck(len(r7)>=1,"val: PERFORM UNTIL")
|
||||
|
||||
src=_ML([" IDENTIFICATION DIVISION."," PROGRAM-ID. T.",
|
||||
" DATA DIVISION."," WORKING-STORAGE SECTION.",
|
||||
" 01 WS-A PIC 99."," 01 WS-B PIC 99.",
|
||||
" 01 WS-FLAG PIC X.",
|
||||
" PROCEDURE DIVISION.",
|
||||
" IF WS-A > 10 AND WS-B < 20 MOVE 'Y' TO WS-FLAG",
|
||||
" ELSE MOVE 'N' TO WS-FLAG.",
|
||||
" END-IF.",
|
||||
" STOP RUN."])
|
||||
r8=generate_data(src); ck(len(r8)>=2,"val: AND 2+")
|
||||
|
||||
sec("COVERAGE: HTML残分岐")
|
||||
from cobol_testgen.coverage import generate_html_report, generate_coverage_index, DecisionPoint, LeafStat
|
||||
td=tempfile.mkdtemp(); tp=Path(td)
|
||||
dp1 = DecisionPoint(id=1,kind="IF",label="X>5",branch_names=["T","F"],active_branches={"T","F"},implied_branches={"T","F"},source_line=1)
|
||||
ls1 = LeafStat(field="X",op=">",value="5",covered_true=True,covered_false=True)
|
||||
generate_html_report([dp1],[ls1],["IF X>5","STOP"],tp/"full.html","FULL"); ck((tp/"full.html").exists(),"html100")
|
||||
dp2 = DecisionPoint(id=2,kind="EVALUATE",label="X",branch_names=["W1","W2","OT","W3"],active_branches={"W1","W2","OT"},implied_branches={"W1","W2","OT"})
|
||||
generate_html_report([dp2],[],["EVAL"],tp/"mid.html","MID"); ck(True,"html80")
|
||||
generate_html_report([],[],["L1"],tp/"nodp.html","NODP"); ck(True,"html0dp")
|
||||
generate_html_report([],[],[],tp/"empty.html","EMPTY"); ck(True,"html0all")
|
||||
dp3 = DecisionPoint(id=3,kind="IF",label="X>0",branch_names=["T","F"])
|
||||
generate_html_report([dp3],[],["IF X>0"],tp/"nomark.html","NOMARK"); ck(True,"html nomark")
|
||||
dp4 = DecisionPoint(id=4,kind="IF",label="X>5",branch_names=["T","F"],active_branches={"T"},source_line=1)
|
||||
generate_html_report([dp4],[ls1],["IF X>5","STOP"],tp/"partial.html","PARTIAL"); ck(True,"html partial")
|
||||
generate_coverage_index([],str(tp/"e_idx")); ck(True,"idx empty")
|
||||
generate_coverage_index([{"name":"T","detail_relpath":"t.html","total_branches":2,"covered_branches":2,"implied_branches":2,"implicit_100":False,"total_conditions":0,"covered_conditions":0}], str(tp/"single")); ck(True,"idx single")
|
||||
generate_coverage_index([{"name":"OK","detail_relpath":"ok.html","total_branches":2,"covered_branches":2,"implied_branches":2,"implicit_100":False,"total_conditions":2,"covered_conditions":2},{"name":"BAD","detail_relpath":"bad.html","total_branches":3,"covered_branches":1,"implied_branches":1,"implicit_100":False,"total_conditions":2,"covered_conditions":0}], str(tp/"mixed")); ck(True,"idx mixed")
|
||||
shutil.rmtree(td)
|
||||
|
||||
sec("REPORT: generator")
|
||||
from report.generator import ReportGenerator
|
||||
from data.diff_result import VerificationRun
|
||||
rpt=ReportGenerator(); td2=Path(tempfile.mkdtemp())
|
||||
vr=VerificationRun(program="T",runner="n",status="PASS",exit_code=0,fields_matched=3,fields_mismatched=0,timestamp="T",duration_s=1.0,branch_rate=0.9,paragraph_rate=1.0,decision_rate=0.8,quality_score=0.9,quality_warn="",hina_type="MT",hina_confidence=0.7,heal_retry=0,simple_retry=0,total_retry=0,field_results=[],llm_cost=0)
|
||||
h=rpt.generate_html(vr,td2/"r.html"); ck("MT" in h.read_text(),"rpt html")
|
||||
m=rpt.generate_machine_json(vr,td2/"m.json"); j=json.loads(m.read_text()); ck(j.get("hina_type")=="MT","rpt machine")
|
||||
vr2=VerificationRun(program="T",runner="n",status="FAIL",exit_code=8,fields_matched=0,fields_mismatched=3,timestamp="T",duration_s=1.0,branch_rate=0.0,paragraph_rate=0.0,decision_rate=0.0,quality_score=0.0,quality_warn="ERR",hina_type="UNK",hina_confidence=0.3,heal_retry=0,simple_retry=0,total_retry=0,field_results=[],llm_cost=0)
|
||||
h2=rpt.generate_html(vr2,td2/"r2.html"); ck(True,"rpt fail")
|
||||
shutil.rmtree(td2)
|
||||
|
||||
sec("CONFIDENCE: 境界")
|
||||
from hina.confidence import compute_confidence_v2
|
||||
ck(compute_confidence_v2({"base_confidence":0.0,"match_count":0},{"structure_match_score":0})["confidence"]>=0,"cf0")
|
||||
ck(compute_confidence_v2({"base_confidence":1.0,"match_count":5},{"structure_match_score":5})["confidence"]<=1.0,"cf1")
|
||||
ck(compute_confidence_v2({"base_confidence":0.5,"match_count":1},{"structure_match_score":2})["confidence"]>0,"cf mid")
|
||||
|
||||
sec("JAPANESE: 残分岐")
|
||||
from japanese_data import _field_length, select_data_type
|
||||
ck(_field_length({"pic_info":{"length":10}})==10,"fl len")
|
||||
ck(_field_length({"pic_info":{"digits":5,"decimal":2}})==7,"fl d+dec")
|
||||
ck(_field_length({"pic_info":{"length":0,"digits":5}})==5,"fl dig")
|
||||
ck(_field_length({"pic_info":{}})==10,"fl fallback")
|
||||
ck(select_data_type({"pic_info":{"type":"numeric_float"}}) is not None,"sel float")
|
||||
ck(select_data_type({"pic_info":{"type":"unknown","usage":"COMP"}}) is not None,"sel comp")
|
||||
|
||||
print(f"\n{'='*55}\nR6: {P} PASS / {F} FAIL\n{'='*55}")
|
||||
if F>0: sys.exit(1)
|
||||
Reference in New Issue
Block a user