"""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)