"""步骤 A/C 边界覆盖测试(恢复覆盖率至 ≥99%)。""" from __future__ import annotations from pathlib import Path from types import SimpleNamespace from genesis.writer.language import find_language_violations from genesis.writer.models import ChapterContent, ContentBlock, GenerationContext, ChapterSpec from genesis.writer.writer_agent import WriterAgent from genesis.writer.writer_state import WriterState from genesis.writer.exceptions import WriterGenerationError from genesis.qa.qa_loop import QALoop from genesis.data_models import StructuredSource from genesis.parsers.word_template_parser import WordTemplateParser class _Reg: @staticmethod def get_or_create(name, template): return SimpleNamespace(name=name, version="1", template=template) def test_find_violations_unexpected_language_code_returns_empty(): blocks = [ContentBlock(block_id="0", type="paragraph", text="中文正文内容充分长度足够")] # 非 zh/ja 的期望语言 → 不强制,返回空 assert find_language_violations(blocks, "xx") == [] def test_writer_agent_zh_expected_rejects_japanese(): class JpEngine: def chat_structured(self, *, session_id, prompt, variables, schema, retry_count=2): return SimpleNamespace( data={"title": variables["title"], "blocks": [{"type": "paragraph", "text": "本機能は注文処理を行う画面であり、詳細は以下の通り。"}]}, status="ok", ) agent = WriterAgent(session_id="s", engine=JpEngine(), prompt_registry=_Reg(), state=WriterState(["db_design"]), max_retries=1) ctx = GenerationContext(chapter_id="db_design", title="DB 設計", template_marker=ChapterSpec(chapter_id="db_design", title="DB 設計"), structured_source=None, write_rules=[], design_rules=[], template_styles=set(), output_language="zh") try: agent.generate_chapter(ctx) assert False, "应抛 WriterGenerationError" except WriterGenerationError: pass def test_qa_loop_passes_with_explicit_zh_on_chinese_fake(tmp_path): """显式 zh + 中文 Fake → 语言维度通过(验证透传链路)。""" template = Path("samples/phase5-slice/template.docx") if not template.exists(): import pytest pytest.skip("样本模板缺失") parsed = WordTemplateParser().parse(str(template)) ss = StructuredSource(template=parsed, tables=[], rule_docs=[], image_analyses=[], existing_system=None, comments=[]) out = tmp_path / "o.docx" class ZhEngine: def chat_structured(self, *, session_id, prompt, variables, schema, retry_count=2): return SimpleNamespace( data={"title": variables["title"], "blocks": [{"type": "paragraph", "text": "由 FakeLLM 生成的充分说明内容,满足写入规则要求。"}]}, status="ok", ) loop = QALoop(max_rounds=1) report = loop.run(ss, str(out), samples_dir="nonexistent_dir_xyz", engine=ZhEngine(), template_path=str(template), output_language="zh") assert report.passed is True def test_qa_loop_fails_with_explicit_ja_on_chinese_fake(tmp_path): """显式 ja + 中文 Fake → 语言维度判失败。""" template = Path("samples/phase5-slice/template.docx") if not template.exists(): import pytest pytest.skip("样本模板缺失") parsed = WordTemplateParser().parse(str(template)) ss = StructuredSource(template=parsed, tables=[], rule_docs=[], image_analyses=[], existing_system=None, comments=[]) out = tmp_path / "o.docx" class ZhEngine: def chat_structured(self, *, session_id, prompt, variables, schema, retry_count=2): return SimpleNamespace( data={"title": variables["title"], "blocks": [{"type": "paragraph", "text": "由 FakeLLM 生成的充分说明内容,满足写入规则要求。"}]}, status="ok", ) loop = QALoop(max_rounds=1) # 显式 ja + 中文 Fake:writer 生成阶段即因语言不一致硬失败(设计语义) try: loop.run(ss, str(out), samples_dir="nonexistent_dir_xyz", engine=ZhEngine(), template_path=str(template), output_language="ja") assert False, "应抛出 WriterGenerationError" except WriterGenerationError: pass