fix: 词表墙的四项审查修复(es 池降级/占位符白名单校验/键 allowlist/提取自检+防呆测试)
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -121,3 +121,96 @@ def test_conversation_triggers_match_seed():
|
||||
("contact_ask", conv.CONTACT_ASK_TRIGGER_RE)):
|
||||
assert module_re.pattern == wall.triggers[name].pattern, name
|
||||
assert module_re.flags == wall.triggers[name].flags, name
|
||||
|
||||
|
||||
# ---- 审查修复契约(I-1/I-2/I-3 + M-4 防呆分支) ----
|
||||
|
||||
def test_missing_es_pool_falls_back_to_en():
|
||||
"""I-1: auto 墙无 es 池,西语消息路由 es 后回落 EN 池,绝不 KeyError。"""
|
||||
from app.engine.services.boundary_filter import deflection_for, pivot_for
|
||||
auto = compile_wall(_load("auto"))
|
||||
assert "es" not in auto.deflections # 前提: auto 确实无 es 池
|
||||
msg = "¿Cuánto cuesta?" # 重音符 → _lang_pool 路由 es → 无池 → 降级 EN
|
||||
assert deflection_for(msg, wall=auto) in auto.deflections["en"]
|
||||
assert (deflection_for(msg, has_contact=True, wall=auto)
|
||||
in auto.deflections_contact["en"])
|
||||
assert pivot_for(msg, wall=auto) == auto.pivots["en"][0]
|
||||
assert pivot_for(msg, has_contact=True, wall=auto) == auto.pivots_contact["en"][0]
|
||||
# 有 es 池的墙(jiancai)不受降级逻辑影响: 仍命中 ES 池
|
||||
jc = compile_wall(_load("jiancai"))
|
||||
assert deflection_for(msg, wall=jc) in jc.deflections["es"]
|
||||
assert pivot_for(msg, wall=jc) == jc.pivots["es"][0]
|
||||
|
||||
|
||||
def test_template_placeholder_whitelist_exported():
|
||||
"""I-2: 白名单 = conversation.py 运行期 .format() 回填键全集(grep 实证)。"""
|
||||
from app.engine.wall_schema import TEMPLATE_PLACEHOLDERS
|
||||
assert TEMPLATE_PLACEHOLDERS == {
|
||||
"shown", "intl", "cc_script",
|
||||
"no_contact_web", "no_contact_app", "no_contact_already",
|
||||
}
|
||||
|
||||
|
||||
def test_template_with_literal_braces_rejected():
|
||||
"""I-2: 话术里的字面花括号(把中文"格式"写成 {格式})编译期拒绝。"""
|
||||
cfg = _load("jiancai")
|
||||
cfg["reminders"]["boundary"]["normal"] = "请用 {格式} 重新描述预算"
|
||||
with pytest.raises(WallConfigError) as ei:
|
||||
compile_wall(cfg)
|
||||
assert "reminders.boundary.normal" in str(ei.value)
|
||||
|
||||
|
||||
def test_template_with_unknown_placeholder_rejected():
|
||||
"""I-2: 白名单外占位符({name})编译期拒绝——原属运行期 KeyError。"""
|
||||
cfg = _load("jiancai")
|
||||
cfg["cc_templates"]["ask"]["en"] = "Hi {name}, could you share your WhatsApp?"
|
||||
with pytest.raises(WallConfigError) as ei:
|
||||
compile_wall(cfg)
|
||||
assert "cc_templates.ask.en" in str(ei.value)
|
||||
|
||||
|
||||
def test_pattern_dict_unknown_key_rejected():
|
||||
"""I-3: 键拼错({"flagss"})曾静默忽略→墙悄悄放宽,必须显性拒绝。"""
|
||||
cfg = _load("jiancai")
|
||||
cfg["price_patterns"] = [{"pattern": r"\$?\s*\d+", "flagss": "i"}]
|
||||
with pytest.raises(WallConfigError) as ei:
|
||||
compile_wall(cfg)
|
||||
assert "flagss" in str(ei.value)
|
||||
assert "pattern" in str(ei.value) # 合法键清单一并给出
|
||||
|
||||
|
||||
def test_reminder_unknown_variant_key_rejected():
|
||||
"""M-4: reminders 类别下未知变体键(拼错)显性拒绝。"""
|
||||
cfg = _load("jiancai")
|
||||
cfg["reminders"]["boundary"]["bogus"] = "话术"
|
||||
with pytest.raises(WallConfigError) as ei:
|
||||
compile_wall(cfg)
|
||||
assert "reminders.boundary.bogus" in str(ei.value)
|
||||
|
||||
|
||||
def test_pool_missing_required_language_rejected():
|
||||
"""M-4: 池缺必填语言(eng/zh 之外的核心双语)编译期拒绝。"""
|
||||
cfg = _load("jiancai")
|
||||
del cfg["deflections"]["zh"]
|
||||
with pytest.raises(WallConfigError) as ei:
|
||||
compile_wall(cfg)
|
||||
assert "deflections" in str(ei.value)
|
||||
assert "zh" in str(ei.value)
|
||||
|
||||
|
||||
def test_pool_non_list_items_rejected():
|
||||
"""M-4: 池语言值非列表(标量串)编译期拒绝。"""
|
||||
cfg = _load("jiancai")
|
||||
cfg["deflections"]["zh"] = "not-a-list"
|
||||
with pytest.raises(WallConfigError) as ei:
|
||||
compile_wall(cfg)
|
||||
assert "deflections.zh" in str(ei.value)
|
||||
|
||||
|
||||
def test_patterns_non_list_and_empty_rejected():
|
||||
"""M-4: patterns 字段非列表/空列表均编译期拒绝。"""
|
||||
for bad in ("nope", []):
|
||||
cfg = _load("jiancai")
|
||||
cfg["price_patterns"] = bad
|
||||
with pytest.raises(WallConfigError):
|
||||
compile_wall(cfg)
|
||||
|
||||
Reference in New Issue
Block a user