Files

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()