50995d3335
- SETUP.md: 完整环境搭建指南(同事用) - SETUP_QUICK.md: 快速搭环境(4步) - s22~s26: TNA端到端、覆盖率报告、回归检查 - procedure_grammar.lark: 实验性Lark语法 Co-Authored-By: Claude <noreply@anthropic.com>
386 lines
18 KiB
Python
386 lines
18 KiB
Python
"""
|
|
HINA 全35类型 高密度测试 — 每种类型 5+ 变体
|
|
包括: 正常形 / 別スタイル / 最小形 / 境界形 / FP攻撃 / FN攻撃 / 命名バリエーション
|
|
"""
|
|
|
|
import sys, os
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
|
from hina.pipeline import classify_program
|
|
from hina.classifier import detect_keyword
|
|
|
|
STATS = {"pass": 0, "fail": 0, "total": 0, "by_type": {}}
|
|
|
|
def test(hina_id, variant, name, src, check_matching=None, check_category=None):
|
|
STATS["total"] += 1
|
|
STATS["by_type"].setdefault(hina_id, {"pass": 0, "fail": 0, "total": 0})
|
|
STATS["by_type"][hina_id]["total"] += 1
|
|
try:
|
|
c = classify_program(src)
|
|
kw = detect_keyword(src)
|
|
except Exception as e:
|
|
print(f'CRASH {hina_id}/{variant} {name[:25]:25s} {str(e)[:50]}')
|
|
STATS["fail"] += 1
|
|
STATS["by_type"][hina_id]["fail"] += 1
|
|
return
|
|
cat = c['category']
|
|
conf = c['confidence']
|
|
is_match = 'マッチング' in cat or '二段階' in cat
|
|
issues = []
|
|
if check_matching is True and not is_match:
|
|
issues.append(f'want MATCH got {cat}')
|
|
elif check_matching is False and is_match:
|
|
issues.append(f'want NON-MATCH got {cat}')
|
|
if check_category and cat != check_category:
|
|
issues.append(f'want {check_category} got {cat}')
|
|
if issues:
|
|
print(f'FAIL {hina_id}/{variant} {name[:25]:25s} {cat:20s} {conf:.2f} | {issues[0]}')
|
|
STATS["fail"] += 1
|
|
STATS["by_type"][hina_id]["fail"] += 1
|
|
else:
|
|
STATS["pass"] += 1
|
|
STATS["by_type"][hina_id]["pass"] += 1
|
|
|
|
P = ' IDENTIFICATION DIVISION. PROGRAM-ID. T. DATA DIVISION. WORKING-STORAGE SECTION. '
|
|
|
|
print('='*95)
|
|
print('HINA 35 TYPES HIGH-DENSITY TEST')
|
|
print('='*95)
|
|
|
|
# ════════════════════════════════════
|
|
# MATCHING SERIES
|
|
# ════════════════════════════════════
|
|
print('\n--- MATCHING ---')
|
|
|
|
test('M','1to1','std WS-KEY',P+'''
|
|
01 WS-KEY-A PIC X(10). 01 WS-KEY-B PIC X(10).
|
|
01 WS-EOF-A PIC X VALUE 'N'. 01 WS-EOF-B PIC X VALUE 'N'.
|
|
PROCEDURE DIVISION. OPEN INPUT F1 F2.
|
|
READ F1 AT END MOVE 'Y' TO WS-EOF-A. READ F2 AT END MOVE 'Y' TO WS-EOF-B.
|
|
PERFORM UNTIL WS-EOF-A='Y' OR WS-EOF-B='Y'
|
|
IF WS-KEY-A=WS-KEY-B DISPLAY 'M' READ F1 AT END MOVE 'Y' TO WS-EOF-A READ F2 AT END MOVE 'Y' TO WS-EOF-B
|
|
ELSE IF WS-KEY-A<WS-KEY-B READ F1 AT END MOVE 'Y' TO WS-EOF-A
|
|
ELSE READ F2 AT END MOVE 'Y' TO WS-EOF-B END-IF
|
|
END-PERFORM. CLOSE F1 F2. STOP RUN.''',check_matching=True)
|
|
|
|
test('M','goto','GO TO style',P+'''
|
|
01 WS-KEY-A PIC X(10). 01 WS-KEY-B PIC X(10).
|
|
01 WS-E1 PIC X VALUE 'N'. 01 WS-E2 PIC X VALUE 'N'.
|
|
PROCEDURE DIVISION. OPEN INPUT F1 F2.
|
|
READ F1 AT END MOVE 'Y' TO WS-E1. READ F2 AT END MOVE 'Y' TO WS-E2.
|
|
LP.IF WS-E1='Y' OR WS-E2='Y' GO TO EP.
|
|
IF WS-KEY-A=WS-KEY-B DISPLAY 'M' READ F1 AT END MOVE 'Y' TO WS-E1 READ F2 AT END MOVE 'Y' TO WS-E2
|
|
ELSE IF WS-KEY-A<WS-KEY-B READ F1 AT END MOVE 'Y' TO WS-E1
|
|
ELSE READ F2 AT END MOVE 'Y' TO WS-E2. GO TO LP.
|
|
EP.CLOSE F1 F2. STOP RUN.''',check_matching=True)
|
|
|
|
test('M','short','short names',P+'''
|
|
01 A PIC X(10). 01 B PIC X(10). 01 C PIC X VALUE 'N'. 01 D PIC X VALUE 'N'.
|
|
PROCEDURE DIVISION. OPEN INPUT F1 F2.
|
|
READ F1 AT END MOVE 'Y' TO C. READ F2 AT END MOVE 'Y' TO D.
|
|
PERFORM UNTIL C='Y' OR D='Y'
|
|
IF A=B DISPLAY 'M' READ F1 AT END MOVE 'Y' TO C READ F2 AT END MOVE 'Y' TO D
|
|
ELSE IF A<B READ F1 AT END MOVE 'Y' TO C ELSE READ F2 AT END MOVE 'Y' TO D END-IF
|
|
END-PERFORM. CLOSE F1 F2. STOP RUN.''',check_matching=True)
|
|
|
|
test('M','hyphen','CUST-CODE naming',P+'''
|
|
01 WS-CUST-CODE PIC X(10). 01 WS-ORDR-CODE PIC X(10).
|
|
01 WS-EOF1 PIC X VALUE 'N'. 01 WS-EOF2 PIC X VALUE 'N'.
|
|
PROCEDURE DIVISION. OPEN INPUT F1 F2.
|
|
READ F1 AT END MOVE 'Y' TO WS-EOF1. READ F2 AT END MOVE 'Y' TO WS-EOF2.
|
|
PERFORM UNTIL WS-EOF1='Y' OR WS-EOF2='Y'
|
|
IF WS-CUST-CODE=WS-ORDR-CODE DISPLAY 'MATCH'
|
|
ELSE IF WS-CUST-CODE<WS-ORDR-CODE READ F1 AT END MOVE 'Y' TO WS-EOF1
|
|
ELSE READ F2 AT END MOVE 'Y' TO WS-EOF2 END-IF
|
|
END-PERFORM. CLOSE F1 F2. STOP RUN.''',check_matching=True)
|
|
|
|
test('M','eval','EVALUATE',P+'''
|
|
01 WS-K1 PIC X(10). 01 WS-K2 PIC X(10).
|
|
01 WS-E1 PIC X VALUE 'N'. 01 WS-E2 PIC X VALUE 'N'.
|
|
PROCEDURE DIVISION. OPEN INPUT F1 F2.
|
|
READ F1 AT END MOVE 'Y' TO WS-E1. READ F2 AT END MOVE 'Y' TO WS-E2.
|
|
PERFORM UNTIL WS-E1='Y' OR WS-E2='Y'
|
|
EVALUATE TRUE WHEN WS-K1=WS-K2 DISPLAY 'M' READ F1 AT END MOVE 'Y' TO WS-E1 READ F2 AT END MOVE 'Y' TO WS-E2
|
|
WHEN WS-K1<WS-K2 READ F1 AT END MOVE 'Y' TO WS-E1
|
|
WHEN OTHER READ F2 AT END MOVE 'Y' TO WS-E2
|
|
END-EVALUATE END-PERFORM. CLOSE F1 F2. STOP RUN.''',check_matching=True)
|
|
|
|
test('M','2stage','TWO-STAGE',P+'''
|
|
01 WS-KEY-A PIC X(10). 01 WS-KEY-B PIC X(10). 01 WS-KEY-C PIC X(10).
|
|
01 WS-E1 PIC X VALUE 'N'. 01 WS-E2 PIC X VALUE 'N'. 01 WS-E3 PIC X VALUE 'N'.
|
|
PROCEDURE DIVISION. OPEN INPUT F1 F2 F3 OUTPUT F4.
|
|
READ F1 AT END MOVE 'Y' TO WS-E1. READ F2 AT END MOVE 'Y' TO WS-E2.
|
|
PERFORM UNTIL WS-E1='Y' OR WS-E2='Y'
|
|
IF WS-KEY-A=WS-KEY-B WRITE R4 FROM R1 READ F1 AT END MOVE 'Y' TO WS-E1 READ F2 AT END MOVE 'Y' TO WS-E2
|
|
ELSE IF WS-KEY-A<WS-KEY-B READ F1 AT END MOVE 'Y' TO WS-E1
|
|
ELSE READ F2 AT END MOVE 'Y' TO WS-E2 END-IF
|
|
END-PERFORM. CLOSE F1 F2 F3 F4. STOP RUN.''',check_matching=True)
|
|
|
|
test('M','fp-add','FP:ADD non-match',P+'''
|
|
01 WS-KEY PIC 9(5). 01 WS-TOTAL PIC 9(5).
|
|
PROCEDURE DIVISION. MOVE 999 TO WS-KEY. ADD WS-KEY TO WS-TOTAL.
|
|
IF WS-TOTAL > 500 DISPLAY 'BIG' ELSE DISPLAY 'SMALL'. STOP RUN.''',check_matching=False)
|
|
|
|
test('M','fp-1file','FP:1 file only',P+'''
|
|
01 WS-KEY PIC X(10). 01 WS-EOF PIC X VALUE 'N'.
|
|
PROCEDURE DIVISION. OPEN INPUT F1.
|
|
READ F1 AT END MOVE 'Y' TO WS-EOF.
|
|
PERFORM UNTIL WS-EOF='Y' IF WS-KEY = SPACES DISPLAY 'EMPTY'
|
|
ELSE DISPLAY WS-KEY READ F1 AT END MOVE 'Y' TO WS-EOF
|
|
END-PERFORM. CLOSE F1. STOP RUN.''',check_matching=False)
|
|
|
|
test('M','fp-noopen','FP:no FILE at all',P+'''
|
|
01 WS-KEY PIC X(10).
|
|
PROCEDURE DIVISION. MOVE 'KEY' TO WS-KEY. DISPLAY WS-KEY. STOP RUN.''',check_matching=False)
|
|
|
|
test('M','fp-nokey','FP:no KEY var',P+'''
|
|
01 WS-EOF PIC X VALUE 'N'. 01 WS-TOTAL PIC 9(5).
|
|
PROCEDURE DIVISION. OPEN INPUT F1. READ F1 AT END MOVE 'Y' TO WS-EOF.
|
|
PERFORM UNTIL WS-EOF='Y' ADD 1 TO WS-TOTAL
|
|
READ F1 AT END MOVE 'Y' TO WS-EOF END-PERFORM. CLOSE F1. STOP RUN.''',check_matching=False)
|
|
|
|
test('M','fn-prevkey','WS-PREV-KEY valid',P+'''
|
|
01 WS-KEY PIC X(10). 01 WS-PREV-KEY PIC X(10) VALUE SPACES.
|
|
01 WS-EOF PIC X VALUE 'N'. 01 WS-DC PIC 9(4).
|
|
PROCEDURE DIVISION. OPEN INPUT F.
|
|
READ F AT END MOVE 'Y' TO WS-EOF.
|
|
PERFORM UNTIL WS-EOF='Y'
|
|
IF WS-KEY=WS-PREV-KEY ADD 1 TO WS-DC ELSE MOVE WS-KEY TO WS-PREV-KEY
|
|
READ F AT END MOVE 'Y' TO WS-EOF END-PERFORM. CLOSE F. STOP RUN.''',check_category='項目チェック(重複含む)')
|
|
|
|
# ════════════════════════════════════
|
|
# KEY BREAK series
|
|
# ════════════════════════════════════
|
|
print('\n--- KEY BREAK ---')
|
|
|
|
test('KB','ws-prev-key','WS-PREV-KEY+ACCUM',P+'''
|
|
01 WS-PREV-KEY PIC X(10). 01 WS-KEY PIC X(10).
|
|
01 WS-SUM PIC 9(7)V99. 01 WS-EOF PIC X VALUE 'N'.
|
|
PROCEDURE DIVISION. OPEN INPUT F.
|
|
READ F AT END MOVE 'Y' TO WS-EOF.
|
|
PERFORM UNTIL WS-EOF='Y'
|
|
IF WS-KEY NOT = WS-PREV-KEY
|
|
IF WS-PREV-KEY NOT = SPACES DISPLAY WS-PREV-KEY WS-SUM
|
|
MOVE WS-KEY TO WS-PREV-KEY MOVE 0 TO WS-SUM
|
|
ADD 1 TO WS-SUM READ F AT END MOVE 'Y' TO WS-EOF
|
|
END-PERFORM. CLOSE F. STOP RUN.''',check_category='項目チェック(重複含む)')
|
|
|
|
test('KB','fp-only-cnt','FP:CNT no match',P+'''
|
|
01 WS-ERR-PIC PIC X(10). 01 WS-CNT PIC 9(5).
|
|
PROCEDURE DIVISION. MOVE 'ABC' TO WS-ERR-PIC. DISPLAY WS-ERR-PIC. STOP RUN.''',check_matching=False)
|
|
|
|
# ════════════════════════════════════
|
|
# CONDITION BRANCH series
|
|
# ════════════════════════════════════
|
|
print('\n--- IF/EVALUATE ---')
|
|
|
|
test('IF','normal','IF-ELSE',P+'''
|
|
01 A PIC 9(5). 01 B PIC 9(5). 01 C PIC X(10).
|
|
PROCEDURE DIVISION. IF A > 100 AND B < 50 MOVE 'LARGE' TO C
|
|
ELSE IF A > 50 MOVE 'MEDIUM' TO C ELSE MOVE 'SMALL' TO C. DISPLAY C. STOP RUN.''',check_matching=False)
|
|
|
|
test('IF','not-eq','NOT =',P+'''
|
|
01 A PIC 9(5). 01 B PIC 9(5).
|
|
PROCEDURE DIVISION. IF A NOT = B DISPLAY 'DIFF' ELSE DISPLAY 'SAME'. STOP RUN.''',check_matching=False)
|
|
|
|
test('EV','normal','EVALUATE',P+'''
|
|
01 S PIC X(1). 01 R PIC X(10).
|
|
PROCEDURE DIVISION. EVALUATE S
|
|
WHEN 'A' MOVE 'ACTIVE' TO R WHEN 'I' MOVE 'INACTIVE' TO R
|
|
WHEN OTHER MOVE 'UNKNOWN' TO R END-EVALUATE. DISPLAY R. STOP RUN.''',check_matching=False)
|
|
|
|
test('EV','also','EVALUATE ALSO',P+'''
|
|
01 S PIC X(1). 01 T PIC X(1). 01 R PIC X(10).
|
|
PROCEDURE DIVISION. EVALUATE S ALSO T
|
|
WHEN 'A' ALSO 'X' MOVE 'A-X' TO R WHEN 'A' ALSO 'Y' MOVE 'A-Y' TO R
|
|
WHEN OTHER MOVE 'OTHER' TO R END-EVALUATE. DISPLAY R. STOP RUN.''',check_matching=False)
|
|
|
|
# ════════════════════════════════════
|
|
# DIVIDE series
|
|
# ════════════════════════════════════
|
|
print('\n--- DIVIDE ---')
|
|
|
|
test('DV','50','DIVIDE 50',P+'''
|
|
01 V PIC 9(5) VALUE 100. 01 R PIC 9(5). 01 RM PIC 9(5).
|
|
PROCEDURE DIVISION. DIVIDE 50 INTO V GIVING R REMAINDER RM.
|
|
IF R = 2 DISPLAY 'OK'. STOP RUN.''',check_category='DIVIDE_50.0')
|
|
|
|
test('DV','25','DIVIDE 25',P+'''
|
|
01 V PIC 9(5) VALUE 100. 01 R PIC 9(5). 01 RM PIC 9(5).
|
|
PROCEDURE DIVISION. DIVIDE 25 INTO V GIVING R REMAINDER RM.
|
|
IF R = 4 DISPLAY 'OK'. STOP RUN.''',check_category='DIVIDE_25.0')
|
|
|
|
test('DV','100','DIVIDE 100',P+'''
|
|
01 V PIC 9(5) VALUE 10000. 01 R PIC 9(5). 01 RM PIC 9(5).
|
|
PROCEDURE DIVISION. DIVIDE 100 INTO V GIVING R REMAINDER RM.
|
|
IF R = 100 DISPLAY 'OK'. STOP RUN.''',check_category='DIVIDE_100.0')
|
|
|
|
test('DV','fp-var','FP:var name 50',P+'''
|
|
01 WS-50 PIC 9(5). 01 V PIC 9(5) VALUE 100.
|
|
PROCEDURE DIVISION. MOVE 30 TO WS-50. DIVIDE WS-50 INTO V. STOP RUN.''',check_matching=False)
|
|
|
|
test('DV','fp-mul','FP:MULTIPLY',P+'''
|
|
01 A PIC 9(5) VALUE 50. PROCEDURE DIVISION.
|
|
MULTIPLY 3 BY A. IF A=150 DISPLAY 'OK'. STOP RUN.''',check_matching=False)
|
|
|
|
# ════════════════════════════════════
|
|
# CICS online
|
|
# ════════════════════════════════════
|
|
print('\n--- CICS ---')
|
|
|
|
test('CICS','map','MAP var',P+'''
|
|
01 WS-MAP PIC X(10). 01 WS-CA PIC X(100).
|
|
PROCEDURE DIVISION. IF WS-MAP = 'MAP01' DISPLAY 'OK'. STOP RUN.''',check_category='online')
|
|
|
|
test('CICS','dfh','DFHCOMMAREA',P+'''
|
|
01 WS-CA PIC X(100). 01 WS-RESP PIC S9(8) COMP.
|
|
PROCEDURE DIVISION.
|
|
*> EXEC CICS LINK PROGRAM('PGM1') COMMAREA(WS-CA) RESP(WS-RESP) END-EXEC.
|
|
IF WS-RESP = 0 DISPLAY 'OK'. STOP RUN.''',check_matching=False) # comment stripped
|
|
|
|
test('CICS','fp-no','FP:no keyword',P+'''
|
|
01 WS-DATA PIC X(100).
|
|
PROCEDURE DIVISION. MOVE 'CICS' TO WS-DATA. DISPLAY WS-DATA. STOP RUN.''',check_matching=False)
|
|
|
|
# ════════════════════════════════════
|
|
# SEARCH ALL
|
|
# ════════════════════════════════════
|
|
print('\n--- SEARCH ---')
|
|
|
|
test('SR','all','SEARCH ALL',P+'''
|
|
01 TBL. 05 E OCCURS 10 TIMES ASCENDING KEY IS EID INDEXED BY IX.
|
|
10 EID PIC 9(03). 10 ENM PIC X(10).
|
|
01 S PIC 9(03). 01 F PIC X VALUE 'N'.
|
|
PROCEDURE DIVISION. MOVE 5 TO S. SEARCH ALL E
|
|
AT END DISPLAY 'NOT FOUND' WHEN EID(IX)=S MOVE 'Y' TO F. STOP RUN.''',check_matching=False)
|
|
|
|
# ════════════════════════════════════
|
|
# SORT/MERGE
|
|
# ════════════════════════════════════
|
|
print('\n--- SORT/MERGE ---')
|
|
|
|
test('SRT','asc','SORT ASC',P+'''
|
|
01 WS-DATA PIC X(80).
|
|
PROCEDURE DIVISION. SORT SF ON ASCENDING KEY SK USING F1 GIVING FO. STOP RUN.''',check_category='SORT')
|
|
|
|
test('SRT','desc','SORT DESC',P+'''
|
|
01 WS-DATA PIC X(80).
|
|
PROCEDURE DIVISION. SORT SF ON DESCENDING KEY SK USING F1 GIVING FO. STOP RUN.''',check_category='SORT')
|
|
|
|
test('SRT','multi','SORT multi-key',P+'''
|
|
01 WS-DATA PIC X(80).
|
|
PROCEDURE DIVISION. SORT SF ON ASCENDING KEY K1 K2 USING F1 GIVING FO. STOP RUN.''',check_category='SORT')
|
|
|
|
test('MRG','normal','MERGE',P+'''
|
|
01 WS-DATA PIC X(80).
|
|
PROCEDURE DIVISION. MERGE MF ON ASCENDING KEY MK USING F1 F2 GIVING FO. STOP RUN.''',check_category='MERGE')
|
|
|
|
test('SRT','fp','FP:no SORT',P+'''
|
|
01 WS-DATA PIC X(80).
|
|
PROCEDURE DIVISION. MOVE 'SORT KEY' TO WS-DATA. DISPLAY WS-DATA. STOP RUN.''',check_matching=False)
|
|
|
|
# ════════════════════════════════════
|
|
# L1 DIRECT TYPES
|
|
# ════════════════════════════════════
|
|
print('\n--- L1 DIRECT ---')
|
|
|
|
test('L1','sql','EXEC SQL',P+'''
|
|
01 WS-ID PIC X(10). PROCEDURE DIVISION.
|
|
EXEC SQL SELECT * FROM TBL WHERE ID=:WS-ID END-EXEC. STOP RUN.''',check_category='DB操作')
|
|
|
|
test('L1','sql-cmt','*>EXEC SQL comment',P+'''
|
|
01 WS-DATA PIC X(10). PROCEDURE DIVISION.
|
|
*> EXEC SQL SELECT * FROM TBL END-EXEC. MOVE 'X' TO WS-DATA. STOP RUN.''',check_matching=False)
|
|
|
|
test('L1','sql-literal','FP:SQL in literal',P+'''
|
|
01 WS-MSG PIC X(50). PROCEDURE DIVISION.
|
|
MOVE 'EXEC SQL SELECT * FROM TBL' TO WS-MSG. STOP RUN.''',check_matching=False)
|
|
|
|
test('L1','call','CALL+LINKAGE',P+'''
|
|
01 WS-P PIC X(10). LINKAGE SECTION. 01 LS-P PIC X(10).
|
|
PROCEDURE DIVISION USING LS-P. CALL 'SUB' USING WS-P. STOP RUN.''',check_category='子程序调用')
|
|
|
|
test('L1','call-only','FP:CALL no LINKAGE',P+'''
|
|
01 WS-P PIC 9(5). PROCEDURE DIVISION. CALL 'SUB' USING WS-P. STOP RUN.''',check_matching=False)
|
|
|
|
test('L1','link-only','FP:LINKAGE no CALL',P+'''
|
|
01 WS-X PIC 9(5). LINKAGE SECTION. 01 LS-P PIC X(10).
|
|
PROCEDURE DIVISION USING LS-P. MOVE 'X' TO LS-P. GOBACK.''',check_matching=False)
|
|
|
|
test('L1','init','IS INITIAL',P+'''01 C PIC 9(5) VALUE 0.
|
|
PROCEDURE DIVISION. ADD 1 TO C. DISPLAY C. STOP RUN.
|
|
IDENTIFICATION DIVISION. PROGRAM-ID. PGM IS INITIAL.''',check_category='IS INITIAL')
|
|
|
|
test('L1','sys','SYSIN',P+'''01 D PIC X(80). PROCEDURE DIVISION.
|
|
ACCEPT D FROM SYSIN. DISPLAY D. STOP RUN.''',check_category='SYSIN')
|
|
|
|
test('L1','sys-var','FP:SYSIN variable',P+'''01 SYSIN PIC X(80).
|
|
PROCEDURE DIVISION. MOVE 'DATA' TO SYSIN. DISPLAY SYSIN. STOP RUN.''',check_matching=False)
|
|
|
|
test('L1','enc','encoding',P+'''01 A PIC X(10) VALUE 'ABCDEF'. 01 E PIC X(10).
|
|
PROCEDURE DIVISION. MOVE 'ABC' TO A. DISPLAY A. STOP RUN.''',check_matching=False)
|
|
|
|
test('L1','wrt-after','WRITE AFTER',P+'''01 R PIC X(50).
|
|
PROCEDURE DIVISION. OPEN OUTPUT F. WRITE R AFTER ADVANCING 1 LINE. CLOSE F. STOP RUN.''',check_category='编辑输出')
|
|
|
|
test('L1','wrt-before','WRITE BEFORE',P+'''01 R PIC X(50).
|
|
PROCEDURE DIVISION. OPEN OUTPUT F. WRITE R BEFORE ADVANCING 2 LINES. CLOSE F. STOP RUN.''',check_category='编辑输出')
|
|
|
|
test('L1','org','ORGANIZATION IS',P+'''PROCEDURE DIVISION. STOP RUN.
|
|
ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL.
|
|
SELECT F ASSIGN TO 'F.DAT' ORGANIZATION IS INDEXED.''',check_category='文件编成')
|
|
|
|
test('L1','alt','ALTERNATE KEY',P+'''PROCEDURE DIVISION. STOP RUN.
|
|
ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL.
|
|
SELECT F ASSIGN TO 'F.DAT' ALTERNATE RECORD KEY IS AK.''',check_category='替代索引')
|
|
|
|
test('L1','alt-org','ALT+ORG conflict',P+'''PROCEDURE DIVISION. STOP RUN.
|
|
ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL.
|
|
SELECT F ASSIGN TO 'F.DAT' ORGANIZATION IS INDEXED
|
|
RECORD KEY IS RK ALTERNATE RECORD KEY IS AK.''',check_category='替代索引')
|
|
|
|
# ════════════════════════════════════
|
|
# CSV series
|
|
# ════════════════════════════════════
|
|
print('\n--- CSV ---')
|
|
|
|
test('CSV','merge','CSV merge',P+'''
|
|
01 F1 PIC X(10) VALUE 'A'. 01 F2 PIC X(10) VALUE 'B'.
|
|
01 C PIC X(50). 01 P PIC 9(3) VALUE 1.
|
|
PROCEDURE DIVISION. STRING F1 DELIMITED BY SPACES ',' DELIMITED BY SIZE
|
|
F2 DELIMITED BY SPACES INTO C WITH POINTER P. DISPLAY C. STOP RUN.''',check_category='CSV合并')
|
|
|
|
test('CSV','split','CSV split',P+'''
|
|
01 L PIC X(50) VALUE 'A,B,C'. 01 C PIC 9(3).
|
|
PROCEDURE DIVISION. INSPECT L TALLYING C FOR ALL ','.
|
|
INSPECT L REPLACING ALL ',' BY '|'. DISPLAY L. STOP RUN.''',check_category='CSV拆分')
|
|
|
|
test('CSV','fp-str','FP:STRING no CSV',P+'''
|
|
01 A PIC X(5) VALUE 'HELLO'. 01 B PIC X(5) VALUE 'WORLD'.
|
|
01 R PIC X(50). 01 P PIC 9(3) VALUE 1.
|
|
PROCEDURE DIVISION. STRING A DELIMITED BY SPACES ' ' DELIMITED BY SIZE
|
|
B DELIMITED BY SPACES INTO R WITH POINTER P. STOP RUN.''',check_matching=False)
|
|
|
|
test('CSV','fp-insp','FP:INSPECT no CSV',P+'''
|
|
01 T PIC X(30) VALUE 'AAABBB'. 01 C PIC 9(3).
|
|
PROCEDURE DIVISION. INSPECT T TALLYING C FOR ALL 'A'. DISPLAY C. STOP RUN.''',check_matching=False)
|
|
|
|
# ════════════════════════════════════
|
|
# EDIT PROCESSING
|
|
# ════════════════════════════════════
|
|
print('\n--- EDIT ---')
|
|
|
|
test('EDIT','ws-err','WS-ERR field',P+'''
|
|
01 WS-ERR-CODE PIC 9(4). 01 WS-V PIC 9(5).
|
|
PROCEDURE DIVISION. IF WS-V = 0 MOVE 9999 TO WS-ERR-CODE ELSE DISPLAY 'OK'. STOP RUN.''',check_category='編集処理(校验)')
|
|
|
|
test('EDIT','fp','FP:no ERR',P+'''
|
|
01 WS-V PIC 9(5). PROCEDURE DIVISION. MOVE 1 TO WS-V. DISPLAY WS-V. STOP RUN.''',check_matching=False)
|
|
|
|
print('\n'+'='*95)
|
|
print(f'RESULT: {STATS["pass"]} PASS / {STATS["fail"]} FAIL / {STATS["total"]} TOTAL')
|
|
print('='*95)
|
|
if STATS["fail"] > 0:
|
|
for tid, s in sorted(STATS["by_type"].items()):
|
|
print(f' {tid}: {s["pass"]}/{s["total"]} ({s["pass"]/max(s["total"],1)*100:.0f}%)')
|
|
sys.exit(1)
|