chore: import deployable mai-bot source tree
This commit is contained in:
220
pytests/prompt_test/test_prompt_i18n.py
Normal file
220
pytests/prompt_test/test_prompt_i18n.py
Normal file
@@ -0,0 +1,220 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from src.common.i18n import set_locale
|
||||
from src.common.prompt_i18n import clear_prompt_cache, load_prompt, list_prompt_templates
|
||||
from src.prompt.prompt_manager import PromptManager
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def clear_prompt_i18n_cache() -> None:
|
||||
set_locale("zh-CN")
|
||||
clear_prompt_cache()
|
||||
yield
|
||||
clear_prompt_cache()
|
||||
set_locale("zh-CN")
|
||||
|
||||
|
||||
def write_prompt(prompt_dir: Path, locale: str | None, name: str, content: str) -> None:
|
||||
base_dir = prompt_dir if locale is None else prompt_dir / locale
|
||||
base_dir.mkdir(parents=True, exist_ok=True)
|
||||
(base_dir / f"{name}.prompt").write_text(content, encoding="utf-8")
|
||||
|
||||
|
||||
def test_load_prompt_prefers_requested_locale(tmp_path: Path) -> None:
|
||||
prompts_root = tmp_path / "prompts"
|
||||
write_prompt(prompts_root, "zh-CN", "replyer", "你好,{user_name}")
|
||||
write_prompt(prompts_root, "en-US", "replyer", "Hello, {user_name}")
|
||||
|
||||
rendered = load_prompt("replyer", locale="en-US", prompts_root=prompts_root, user_name="Mai")
|
||||
|
||||
assert rendered == "Hello, Mai"
|
||||
|
||||
|
||||
def test_load_prompt_falls_back_to_default_locale(tmp_path: Path) -> None:
|
||||
prompts_root = tmp_path / "prompts"
|
||||
write_prompt(prompts_root, "zh-CN", "replyer", "你好,{user_name}")
|
||||
|
||||
rendered = load_prompt("replyer", locale="en-US", prompts_root=prompts_root, user_name="Mai")
|
||||
|
||||
assert rendered == "你好,Mai"
|
||||
|
||||
|
||||
def test_load_prompt_does_not_fall_back_to_legacy_root(tmp_path: Path) -> None:
|
||||
prompts_root = tmp_path / "prompts"
|
||||
write_prompt(prompts_root, None, "replyer", "Legacy {user_name}")
|
||||
|
||||
with pytest.raises(FileNotFoundError):
|
||||
load_prompt("replyer", locale="en-US", prompts_root=prompts_root, user_name="Mai")
|
||||
|
||||
|
||||
def test_load_prompt_with_category_falls_back_to_default_locale_root(tmp_path: Path) -> None:
|
||||
prompts_root = tmp_path / "prompts"
|
||||
write_prompt(prompts_root, "zh-CN", "replyer", "你好,{user_name}")
|
||||
|
||||
rendered = load_prompt("replyer", locale="en-US", category="chat", prompts_root=prompts_root, user_name="Mai")
|
||||
|
||||
assert rendered == "你好,Mai"
|
||||
|
||||
|
||||
def test_load_prompt_prefers_custom_prompt_override(tmp_path: Path) -> None:
|
||||
prompts_root = tmp_path / "prompts"
|
||||
custom_prompts_root = tmp_path / "data" / "custom_prompts"
|
||||
write_prompt(prompts_root, "zh-CN", "replyer", "Base {user_name}")
|
||||
write_prompt(custom_prompts_root, "zh-CN", "replyer", "Custom {user_name}")
|
||||
|
||||
rendered = load_prompt(
|
||||
"replyer",
|
||||
locale="zh-CN",
|
||||
prompts_root=prompts_root,
|
||||
custom_prompts_root=custom_prompts_root,
|
||||
user_name="Mai",
|
||||
)
|
||||
|
||||
assert rendered == "Custom Mai"
|
||||
|
||||
|
||||
def test_load_prompt_prefers_custom_prompt_requested_locale(tmp_path: Path) -> None:
|
||||
prompts_root = tmp_path / "prompts"
|
||||
custom_prompts_root = tmp_path / "data" / "custom_prompts"
|
||||
write_prompt(prompts_root, "zh-CN", "replyer", "Base zh {user_name}")
|
||||
write_prompt(prompts_root, "en-US", "replyer", "Base en {user_name}")
|
||||
write_prompt(custom_prompts_root, "zh-CN", "replyer", "Custom zh {user_name}")
|
||||
write_prompt(custom_prompts_root, "en-US", "replyer", "Custom en {user_name}")
|
||||
|
||||
rendered = load_prompt(
|
||||
"replyer",
|
||||
locale="en-US",
|
||||
prompts_root=prompts_root,
|
||||
custom_prompts_root=custom_prompts_root,
|
||||
user_name="Mai",
|
||||
)
|
||||
|
||||
assert rendered == "Custom en Mai"
|
||||
|
||||
|
||||
def test_load_prompt_uses_requested_locale_source_before_default_custom(tmp_path: Path) -> None:
|
||||
prompts_root = tmp_path / "prompts"
|
||||
custom_prompts_root = tmp_path / "data" / "custom_prompts"
|
||||
write_prompt(prompts_root, "zh-CN", "replyer", "Base zh {user_name}")
|
||||
write_prompt(prompts_root, "en-US", "replyer", "Base en {user_name}")
|
||||
write_prompt(custom_prompts_root, "zh-CN", "replyer", "Custom zh {user_name}")
|
||||
|
||||
rendered = load_prompt(
|
||||
"replyer",
|
||||
locale="en-US",
|
||||
prompts_root=prompts_root,
|
||||
custom_prompts_root=custom_prompts_root,
|
||||
user_name="Mai",
|
||||
)
|
||||
|
||||
assert rendered == "Base en Mai"
|
||||
|
||||
|
||||
def test_load_prompt_strict_mode_raises_on_missing_placeholder(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
prompts_root = tmp_path / "prompts"
|
||||
write_prompt(prompts_root, "zh-CN", "replyer", "你好,{user_name},现在是 {current_time}")
|
||||
monkeypatch.setenv("MAIBOT_PROMPT_I18N_STRICT", "1")
|
||||
|
||||
with pytest.raises(KeyError) as exc_info:
|
||||
load_prompt("replyer", locale="zh-CN", prompts_root=prompts_root, user_name="Mai")
|
||||
|
||||
assert "current_time" in str(exc_info.value)
|
||||
|
||||
|
||||
def test_load_prompt_rejects_path_traversal(tmp_path: Path) -> None:
|
||||
prompts_root = tmp_path / "prompts"
|
||||
write_prompt(prompts_root, "zh-CN", "replyer", "你好")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
load_prompt("../replyer", locale="zh-CN", prompts_root=prompts_root)
|
||||
|
||||
|
||||
def test_list_prompt_templates_prefers_locale_specific_files(tmp_path: Path) -> None:
|
||||
prompts_root = tmp_path / "prompts"
|
||||
write_prompt(prompts_root, "zh-CN", "replyer", "中文")
|
||||
write_prompt(prompts_root, "en-US", "replyer", "English")
|
||||
set_locale("en-US")
|
||||
|
||||
prompt_templates = list_prompt_templates(prompts_root=prompts_root)
|
||||
|
||||
assert prompt_templates["replyer"].path.read_text(encoding="utf-8") == "English"
|
||||
|
||||
|
||||
def test_list_prompt_templates_loads_directory_metadata(tmp_path: Path) -> None:
|
||||
prompts_root = tmp_path / "prompts"
|
||||
write_prompt(prompts_root, "zh-CN", "replyer", "中文")
|
||||
metadata_path = prompts_root / "zh-CN" / ".meta.toml"
|
||||
metadata_path.write_text(
|
||||
"""
|
||||
[replyer]
|
||||
display_name = "回复器"
|
||||
advanced = true
|
||||
description = "用于生成回复的主模板"
|
||||
""".strip(),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
prompt_templates = list_prompt_templates(prompts_root=prompts_root)
|
||||
metadata = prompt_templates["replyer"].metadata
|
||||
|
||||
assert metadata.display_name == "回复器"
|
||||
assert metadata.advanced is True
|
||||
assert metadata.description == "用于生成回复的主模板"
|
||||
|
||||
|
||||
def test_list_prompt_templates_loads_prompt_specific_metadata(tmp_path: Path) -> None:
|
||||
prompts_root = tmp_path / "prompts"
|
||||
write_prompt(prompts_root, "zh-CN", "replyer", "中文")
|
||||
metadata_path = prompts_root / "zh-CN" / "replyer.meta.json"
|
||||
metadata_path.write_text(
|
||||
'{"display_name": "Replyer", "advanced": false, "description": "Prompt specific metadata"}',
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
prompt_templates = list_prompt_templates(prompts_root=prompts_root)
|
||||
metadata = prompt_templates["replyer"].metadata
|
||||
|
||||
assert metadata.display_name == "Replyer"
|
||||
assert metadata.advanced is False
|
||||
assert metadata.description == "Prompt specific metadata"
|
||||
|
||||
|
||||
def test_list_prompt_templates_reports_duplicate_name_with_custom_root(tmp_path: Path) -> None:
|
||||
prompts_root = tmp_path / "prompts"
|
||||
first_dir = prompts_root / "zh-CN" / "chat"
|
||||
second_dir = prompts_root / "zh-CN" / "system"
|
||||
first_dir.mkdir(parents=True, exist_ok=True)
|
||||
second_dir.mkdir(parents=True, exist_ok=True)
|
||||
(first_dir / "replyer.prompt").write_text("chat", encoding="utf-8")
|
||||
(second_dir / "replyer.prompt").write_text("system", encoding="utf-8")
|
||||
|
||||
with pytest.raises(ValueError) as exc_info:
|
||||
list_prompt_templates(prompts_root=prompts_root)
|
||||
|
||||
assert "zh-CN/chat/replyer.prompt" in str(exc_info.value)
|
||||
assert "zh-CN/system/replyer.prompt" in str(exc_info.value)
|
||||
|
||||
|
||||
def test_prompt_manager_load_prompts_prefers_locale_dir(
|
||||
tmp_path: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
prompts_root = tmp_path / "prompts"
|
||||
custom_prompts_root = tmp_path / "data" / "custom_prompts"
|
||||
custom_prompts_root.mkdir(parents=True, exist_ok=True)
|
||||
write_prompt(prompts_root, "zh-CN", "replyer", "中文模板")
|
||||
write_prompt(prompts_root, "en-US", "replyer", "English template")
|
||||
set_locale("en-US")
|
||||
|
||||
monkeypatch.setattr("src.prompt.prompt_manager.PROMPTS_DIR", prompts_root, raising=False)
|
||||
monkeypatch.setattr("src.prompt.prompt_manager.CUSTOM_PROMPTS_DIR", custom_prompts_root, raising=False)
|
||||
monkeypatch.setattr("src.prompt.prompt_manager.SUFFIX_PROMPT", ".prompt", raising=False)
|
||||
|
||||
manager = PromptManager()
|
||||
manager.load_prompts()
|
||||
|
||||
assert manager.get_prompt("replyer").template == "English template"
|
||||
Reference in New Issue
Block a user