"""Phase5-T11(缩减版):验证 EvalReport.per_chapter 与 failed_chapters 被正确填充。 真实 score() 签名为 score(chapters: list[ChapterArtifact], source: StructuredSource), 故测试按真实签名构造输入(使用 ChapterArtifact)。 """ from __future__ import annotations from genesis.data_models import ( CellValue, ExcelTable, ParsedTemplate, Provenance, SheetType, StructuredSource, ) from genesis.eval.scorer import ChapterArtifact, ChapterScorer, EvalReport def _source() -> StructuredSource: cell = CellValue( value="登録", provenance=Provenance(file_name="f.xlsx", sheet_name="機能一覧", row=3, column="C", column_header="x"), ) table = ExcelTable( name="機能一覧", detected_type=SheetType.FUNCTION, extraction_method="structured", headers=["v"], rows=[{"v": cell}], ) return StructuredSource( tables=[table], template=ParsedTemplate(file_name="t.docx", sections=[], placeholders={}, styles={}), rule_docs=[], image_analyses=[], existing_system=None, comments=[], ) def _artifact(cid: str, text: str) -> ChapterArtifact: return ChapterArtifact( chapter_id=cid, text=text, source_uris=[], template_sections_expected=[cid], ) def test_score_populates_per_chapter_and_failed(): source = _source() good = _artifact("a", "充分且规范的说明内容,满足写入规则要求。") bad = _artifact("b", "x") # 过短/不充分 -> 应判失败 report: EvalReport = ChapterScorer().score([good, bad], source) assert isinstance(report.per_chapter, list) assert len(report.per_chapter) == 2 assert all(isinstance(r, EvalReport) for r in report.per_chapter) assert isinstance(report.failed_chapters, list) assert "b" in report.failed_chapters # 不充分章节被标记 def test_per_chapter_reports_have_dimensions(): source = _source() artifacts = [_artifact("a", "充分且规范的说明内容,满足写入规则要求。"), _artifact("b", "x")] report = ChapterScorer().score(artifacts, source) for r in report.per_chapter: assert len(r.dimensions) > 0 assert 0.0 <= r.total_score <= 1.0 def test_per_chapter_failed_chapters_aligns(): """每个逐章报告自身的 failed_chapters 应与顶层 failed_chapters 一致。""" source = _source() artifacts = [_artifact("a", "充分且规范的说明内容,满足写入规则要求。"), _artifact("b", "x")] report = ChapterScorer().score(artifacts, source) failed_ids = {ch for ch in report.failed_chapters} for ch, r in zip(artifacts, report.per_chapter): if ch.chapter_id in failed_ids: assert ch.chapter_id in r.failed_chapters else: assert r.failed_chapters == [] def test_empty_chapters_backward_compatible(): """空章节输入:向后兼容,per_chapter/failed_chapters 为空列表。""" source = _source() report = ChapterScorer().score([], source) assert report.per_chapter == [] assert report.failed_chapters == [] assert report.total_score == 1.0