Files
cobol-java-v3/cobol_testgen/data_merger.py

131 lines
4.1 KiB
Python

"""データ統合 — 白盒 + 机能 + 策略データの統合と合併。
generate_all_data() エントリポイント:
① generate_data() → 白盒(MC/DC パスカバレッジ)
② DesignDataGenerator → 机能(式样书から LLM 生成)
③ strategy_supplement() → 策略(HINA 分類に基づく境界条件)
④ 重複除去 + フィールド名正規化
⑤ 統合リスト返却
"""
import logging
from pathlib import Path
from typing import Optional
from cobol_testgen import extract_structure, generate_data
logger = logging.getLogger(__name__)
def _dedup(
main_records: list[dict],
additional_records: list[dict] | None = None,
key_fields: list[str] | None = None,
) -> list[dict]:
"""合并+去重,additional 优先保留。"""
if not additional_records:
return list(main_records)
seen = set()
result = []
def _hash(rec, keys):
if keys:
return tuple(rec.get(k, "") for k in keys)
return tuple(sorted(rec.items()))
for rec in additional_records:
h = _hash(rec, key_fields)
if h not in seen:
seen.add(h)
result.append(rec)
for rec in main_records:
h = _hash(rec, key_fields)
if h not in seen:
seen.add(h)
result.append(rec)
return result
def generate_all_data(
program_id: str,
src_text: str,
st: dict | None = None,
copybook_dirs: list[str | Path] | None = None,
design_doc_dir: str | Path | None = None,
llm_client=None,
config=None,
merge_strategy: str = "merge_to_normal",
) -> list[dict]:
"""白盒 + 机能 + 策略 全量生成と統合。
Args:
program_id: プログラム ID
src_text: COBOL ソーステキスト
st: extract_structure() 結果(省略時は内部で再解析)
copybook_dirs: COPYBOOK 探索パス
design_doc_dir: 式样书配置ディレクトリ
llm_client: LLMClient インスタンス(None で LLM 系スキップ)
config: Config インスタンス
merge_strategy: merge_to_normal / as_separate_scenes / auto
Returns:
list[dict]: 統合済みレコードリスト
"""
cbd = [str(d) for d in (copybook_dirs or [])]
# ① 白盒データ
if st is None:
st = extract_structure(src_text, copybook_dirs=cbd)
whitebox = generate_data(src_text, st, copybook_dirs=cbd)
logger.info(f" White-box records: {len(whitebox)}")
# ② 机能データ(式样书 + LLM)
func_data: list[dict] = []
if design_doc_dir and llm_client:
design_path = Path(design_doc_dir) / f"詳細設計書_{program_id}.md"
if design_path.exists():
from agents.design_data import DesignDataGenerator, _extract_replacing_rules
gen = DesignDataGenerator(llm_client, cbd)
v3_names = list(st.get("field_names", [])) if st else None
replacing = _extract_replacing_rules(src_text)
try:
func_data = gen.generate(
design_md_text=design_path.read_text(encoding="utf-8"),
source_text=src_text,
replacing_rules=replacing,
v3_field_names=v3_names,
)
except Exception as e:
logger.warning(f" DesignDataGenerator failed: {e}")
else:
logger.info(f" Design doc not found: {design_path}")
logger.info(f" Functional records: {len(func_data)}")
# ③ 策略データ
strategy_data: list[dict] = []
try:
from hina.strategy import supplement
strat_raw = supplement([], {})
for s in strat_raw:
if isinstance(s, dict) and "fields" in s:
strategy_data.append(s["fields"])
except Exception as e:
logger.debug(f" Strategy supplement skipped: {e}")
logger.info(f" Strategy records: {len(strategy_data)}")
# ④ 統合
all_records = _dedup(whitebox, func_data)
if strategy_data:
all_records = _dedup(all_records, strategy_data)
logger.info(f" Total merged records: {len(all_records)}")
return all_records