242 lines
9.3 KiB
Python
242 lines
9.3 KiB
Python
"""Offline tests for build_prompt() and parse_terminology().
|
|
|
|
These don't require torch, transformers, or a running ComfyUI — they're
|
|
pure-Python checks of string formatting and parsing rules. Safe to run on
|
|
any CI runner.
|
|
"""
|
|
import pytest
|
|
|
|
from nodes.runtime import build_prompt, parse_terminology
|
|
from nodes._types import (
|
|
SUPPORTED_LANGS_EN,
|
|
SUPPORTED_LANGS_ZH,
|
|
EN_TO_ZH,
|
|
ZH_TO_EN,
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Language tables
|
|
# ---------------------------------------------------------------------------
|
|
class TestLanguageTables:
|
|
def test_en_zh_lists_same_length(self):
|
|
assert len(SUPPORTED_LANGS_EN) == len(SUPPORTED_LANGS_ZH)
|
|
|
|
def test_en_zh_lists_have_38_entries(self):
|
|
# Per the Hy-MT2 model card table.
|
|
assert len(SUPPORTED_LANGS_EN) == 38
|
|
|
|
def test_en_to_zh_is_round_trip(self):
|
|
for en, zh in EN_TO_ZH.items():
|
|
assert ZH_TO_EN[zh] == en
|
|
|
|
def test_unique_names(self):
|
|
assert len(set(SUPPORTED_LANGS_EN)) == len(SUPPORTED_LANGS_EN)
|
|
assert len(set(SUPPORTED_LANGS_ZH)) == len(SUPPORTED_LANGS_ZH)
|
|
|
|
@pytest.mark.parametrize("lang", ["English", "Chinese", "Cantonese",
|
|
"Japanese", "Traditional Chinese"])
|
|
def test_well_known_langs_present(self, lang):
|
|
assert lang in SUPPORTED_LANGS_EN
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# parse_terminology()
|
|
# ---------------------------------------------------------------------------
|
|
class TestParseTerminology:
|
|
def test_empty_input(self):
|
|
assert parse_terminology("") == []
|
|
assert parse_terminology(None) == []
|
|
|
|
def test_arrow_separator(self):
|
|
assert parse_terminology("API => 接口") == [("API", "接口")]
|
|
assert parse_terminology("API -> 接口") == [("API", "接口")]
|
|
|
|
def test_pipe_separator(self):
|
|
assert parse_terminology("API | 接口") == [("API", "接口")]
|
|
|
|
def test_tab_separator(self):
|
|
assert parse_terminology("API\t接口") == [("API", "接口")]
|
|
|
|
def test_multiline(self):
|
|
pairs = parse_terminology(
|
|
"API => 接口\n"
|
|
"endpoint -> 端点\n"
|
|
"webhook | webhook\n"
|
|
"token\ttoken"
|
|
)
|
|
assert pairs == [
|
|
("API", "接口"),
|
|
("endpoint", "端点"),
|
|
("webhook", "webhook"),
|
|
("token", "token"),
|
|
]
|
|
|
|
def test_comment_lines_skipped(self):
|
|
pairs = parse_terminology(
|
|
"# this is a comment\n"
|
|
"API => 接口\n"
|
|
"# another\n"
|
|
"endpoint => 端点"
|
|
)
|
|
assert pairs == [("API", "接口"), ("endpoint", "端点")]
|
|
|
|
def test_blank_lines_skipped(self):
|
|
pairs = parse_terminology(
|
|
"API => 接口\n"
|
|
"\n"
|
|
" \n"
|
|
"endpoint => 端点"
|
|
)
|
|
assert pairs == [("API", "接口"), ("endpoint", "端点")]
|
|
|
|
def test_whitespace_stripped(self):
|
|
pairs = parse_terminology(" API => 接口 ")
|
|
assert pairs == [("API", "接口")]
|
|
|
|
def test_separator_precedence(self):
|
|
# `=>` should win over `->` if both appear (it's checked first)
|
|
pairs = parse_terminology("a => b -> c")
|
|
assert pairs == [("a", "b -> c")]
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# build_prompt() — default template
|
|
# ---------------------------------------------------------------------------
|
|
class TestDefaultTemplate:
|
|
def test_en_default(self):
|
|
prompt = build_prompt("hello world", "Chinese", prompt_lang="en")
|
|
assert "Translate the following text into Chinese" in prompt
|
|
assert "hello world" in prompt
|
|
assert "only output the translated result" in prompt
|
|
|
|
def test_zh_default(self):
|
|
prompt = build_prompt("hello world", "中文", prompt_lang="zh")
|
|
assert "将以下文本翻译为 中文" in prompt
|
|
assert "hello world" in prompt
|
|
assert "只需要输出翻译后的结果" in prompt
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# build_prompt() — terminology template
|
|
# ---------------------------------------------------------------------------
|
|
class TestTerminologyTemplate:
|
|
def test_en_terminology_present(self):
|
|
prompt = build_prompt(
|
|
"the API endpoint", "Chinese", prompt_lang="en",
|
|
terminology=[("API", "API"), ("endpoint", "端点")],
|
|
)
|
|
assert "Reference the following translations" in prompt
|
|
assert "API translates to API" in prompt
|
|
assert "endpoint translates to 端点" in prompt
|
|
assert "Translate the following text into Chinese" in prompt
|
|
assert "the API endpoint" in prompt
|
|
|
|
def test_zh_terminology_present(self):
|
|
prompt = build_prompt(
|
|
"the API endpoint", "中文", prompt_lang="zh",
|
|
terminology=[("API", "API"), ("endpoint", "端点")],
|
|
)
|
|
assert "参考下面的翻译" in prompt
|
|
assert "API 翻译成 API" in prompt
|
|
assert "endpoint 翻译成 端点" in prompt
|
|
|
|
def test_empty_terminology_falls_back_to_default(self):
|
|
# An empty terminology list shouldn't trigger the terminology header.
|
|
prompt = build_prompt("hello", "Chinese", prompt_lang="en",
|
|
terminology=[])
|
|
assert "Reference the following translations" not in prompt
|
|
assert "Translate the following text into Chinese" in prompt
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# build_prompt() — style template
|
|
# ---------------------------------------------------------------------------
|
|
class TestStyleTemplate:
|
|
def test_en_style(self):
|
|
prompt = build_prompt("hello", "Japanese", prompt_lang="en",
|
|
target_style="casual colloquial")
|
|
assert "Please translate the following text into Japanese" in prompt
|
|
assert "casual colloquial" in prompt
|
|
assert "hello" in prompt
|
|
|
|
def test_zh_style(self):
|
|
prompt = build_prompt("hello", "日语", prompt_lang="zh",
|
|
target_style="正式书面语")
|
|
assert "请将以下文本翻译为 日语" in prompt
|
|
assert "正式书面语" in prompt
|
|
assert "翻译的风格要严格符合" in prompt
|
|
|
|
def test_whitespace_only_style_falls_back(self):
|
|
prompt = build_prompt("hello", "Chinese", prompt_lang="en",
|
|
target_style=" ")
|
|
# We strip and treat empty as no style override.
|
|
assert "casual" not in prompt
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# build_prompt() — background template
|
|
# ---------------------------------------------------------------------------
|
|
class TestBackgroundTemplate:
|
|
def test_en_background(self):
|
|
prompt = build_prompt(
|
|
"本判决系终审判决。", "English", prompt_lang="en",
|
|
background_text="legal court document",
|
|
)
|
|
assert "[Background Information]" in prompt
|
|
assert "legal court document" in prompt
|
|
assert "translate the following text into English" in prompt
|
|
assert "[Source Text]" in prompt
|
|
assert "本判决系终审判决。" in prompt
|
|
|
|
def test_zh_background(self):
|
|
prompt = build_prompt(
|
|
"本判决系终审判决。", "英语", prompt_lang="zh",
|
|
background_text="法院判决书",
|
|
)
|
|
assert "【背景信息】" in prompt
|
|
assert "法院判决书" in prompt
|
|
assert "请结合背景信息将以下文本翻译为 英语" in prompt
|
|
assert "【待翻译文本】" in prompt
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Precedence: background > style > terminology > default
|
|
# ---------------------------------------------------------------------------
|
|
class TestPrecedence:
|
|
def test_background_beats_style(self):
|
|
prompt = build_prompt(
|
|
"hello", "Japanese", prompt_lang="en",
|
|
target_style="formal",
|
|
background_text="business email context",
|
|
)
|
|
assert "[Background Information]" in prompt
|
|
assert "business email context" in prompt
|
|
# style words should NOT appear when background wins
|
|
assert "translation style" not in prompt.lower()
|
|
|
|
def test_background_beats_terminology(self):
|
|
prompt = build_prompt(
|
|
"hello", "Japanese", prompt_lang="en",
|
|
terminology=[("X", "Y")],
|
|
background_text="some context",
|
|
)
|
|
assert "[Background Information]" in prompt
|
|
assert "X translates to Y" not in prompt
|
|
|
|
def test_style_beats_terminology(self):
|
|
prompt = build_prompt(
|
|
"hello", "Japanese", prompt_lang="en",
|
|
terminology=[("X", "Y")],
|
|
target_style="formal",
|
|
)
|
|
assert "formal" in prompt
|
|
assert "X translates to Y" not in prompt
|
|
|
|
def test_all_three_optional_unset_uses_default(self):
|
|
prompt = build_prompt("hello", "Chinese", prompt_lang="en")
|
|
assert "Translate the following text into Chinese" in prompt
|
|
assert "[Background Information]" not in prompt
|
|
assert "Reference the following translations" not in prompt
|
|
assert "translation style" not in prompt.lower()
|