"""로직 조각 후처리(summarize/chunks.py) — 줄 앵커 검증·보정, 파서 사실 채움, 버림 규칙.""" from __future__ import annotations from summarize.chunks import numbered_code, parser_hints, resolve_chunks from summarize.schemas import LogicChunk CODE = """REPORT ztest. FORM select_data. CLEAR gt_t001. SELECT bukrs waers FROM t001 INTO TABLE gt_t001 WHERE bukrs IN s_bukrs. SORT gt_t001 BY bukrs. CALL FUNCTION 'BAPI_CURRENCY_CONV_TO_EXTERNAL' EXPORTING amount = lv_amt. ENDFORM.""".split("\n") UNIT = (2, 10) def _chunk(**kw) -> LogicChunk: base = {"line_start": 4, "line_end": 7, "first_line": "SELECT bukrs waers FROM t001", "kind": "sql_select", "purpose_ko": "회사코드별 통화 조회", "confidence": 0.8} base.update(kw) return LogicChunk(**base) def test_exact_anchor_and_parser_facts(): chunks, dropped = resolve_chunks([_chunk()], CODE, *UNIT, "ZTEST", known_symbols={"GT_T001"}) assert dropped == [] c = chunks[0] assert (c.line_start, c.line_end, c.seq) == (4, 7, 1) assert c.tables_read == ["T001"] # LLM 이 아니라 파서가 채운 값 assert c.code.startswith(" SELECT bukrs") assert len(c.code_hash) == 64 def test_anchor_shift_corrects_line_numbers(): """LLM 이 줄 번호를 2줄 어긋나게 줘도 first_line 으로 보정된다.""" chunks, dropped = resolve_chunks([_chunk(line_start=6, line_end=9)], CODE, *UNIT, "ZTEST", set()) assert dropped == [] assert (chunks[0].line_start, chunks[0].line_end) == (4, 7) def test_unfindable_anchor_is_dropped(): chunks, dropped = resolve_chunks( [_chunk(first_line="SELECT * FROM nowhere_table_xyz")], CODE, *UNIT, "ZTEST", set()) assert chunks == [] and len(dropped) == 1 def test_out_of_unit_range_dropped_and_end_clamped(): chunks, dropped = resolve_chunks( [_chunk(line_start=1, line_end=3, first_line="REPORT ztest."), # unit 밖 → 버림 _chunk(line_start=8, line_end=40, first_line="CALL FUNCTION 'BAPI_CURRENCY_CONV_TO_EXTERNAL'", kind="fm_call", purpose_ko="환율 변환 BAPI 호출")], # 끝은 unit 끝으로 클램프 CODE, *UNIT, "ZTEST", set()) assert len(dropped) == 1 and dropped[0].startswith("L1-L3") assert (chunks[0].line_start, chunks[0].line_end) == (8, 10) assert "BAPI_CURRENCY_CONV_TO_EXTERNAL" in chunks[0].calls def test_unknown_kind_falls_back_and_duplicates_dropped(): chunks, dropped = resolve_chunks([_chunk(kind="weird"), _chunk()], CODE, *UNIT, "ZTEST", set()) assert len(chunks) == 1 and chunks[0].kind == "other" assert any("중복" in d for d in dropped) def test_numbered_code_and_hints(): txt = numbered_code(CODE, 2, 4) assert txt.splitlines()[0].startswith(" 2| FORM select_data.") hints = parser_hints(CODE, *UNIT) assert any(h.startswith("L4 SELECT") for h in hints) assert any("CALL FUNCTION" in h for h in hints)