Files
2026Technology-Competition/tests/test_language_coverage.py
T
lhl d01e1b720f feat(writer): 输出语言一致性保障 + 用户可选输出语言
- 步骤0: 新增中文镜像模板 scripts/make_zh_template.py 与 samples/概要设计书模板_中文.docx(7章锚点原样保留)
- 步骤1: config.WriterConfig.output_language→Settings.writer;GenerationContext.output_language + to_vars.language_instruction(zh/ja/auto);writer_agent【语言约束】改引变量;context_builder/orchestrator/run_trial 透传 --output-language
- 步骤A: 新建 src/genesis/writer/language.py(detect_script/resolve_expected_language/find_language_violations);WriterAgent.generate_chapter 按期望语言强制、违规重试、耗尽硬失败;max_retries 默认 1→2
- 步骤B: _format_impact 影响调查标签按 output_language 本地化(zh 新建/变更/删除/警告)
- 步骤C: eval scorer 第 11 维度 language_consistency(不可验证=满分,不拉低总分);ChapterArtifact.expected_language;QAValidator.validate_doc 透传;QALoop.run 透传 output_language
- 测试: test_zh_template/test_language_plumbing/test_writer_language/test_scorer_language/test_language_coverage,并更新 test_phase5_e2e
- 全量 pytest 424 passed / 99.15%(覆盖率门槛 99% 达标)
2026-08-25 23:30:24 +08:00

103 lines
4.6 KiB
Python

"""步骤 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