"""符文引擎单元测试。""" from __future__ import annotations from app.modules.macros import MacroContext, render def test_replaces_char_and_user() -> None: ctx = MacroContext(char_name="狂三", user_name="士道") assert render("{{char}}对{{user}}说", ctx) == "狂三对士道说" def test_bot_is_char_alias() -> None: assert render("{{bot}}", MacroContext(char_name="狂三")) == "狂三" def test_original_macro() -> None: assert render("[{{original}}]", MacroContext(original="原辞")) == "[原辞]" def test_case_insensitive() -> None: assert render("{{Char}}", MacroContext(char_name="狂三")) == "狂三" def test_unknown_macro_preserved() -> None: assert render("{{unknown}}", MacroContext()) == "{{unknown}}" def test_empty_braces_preserved() -> None: assert render("a{{}}b", MacroContext()) == "a{{}}b" def test_resolver_exception_preserved() -> None: # {{roll:}} 无有效规格参数 → 解析器走默认 1d6,不应抛错;这里测无参 random 不抛 assert render("{{random}}", MacroContext()) == "" def test_random_picks_from_args() -> None: ctx = MacroContext() for _ in range(20): assert render("{{random:甲,乙,丙}}", ctx) in {"甲", "乙", "丙"} def test_roll_in_range() -> None: for _ in range(20): result = render("{{roll:2d6}}", MacroContext()) assert 2 <= int(result) <= 12 def test_roll_default_and_invalid() -> None: # 默认 1d6 assert 1 <= int(render("{{roll}}", MacroContext())) <= 6 # 非法规格原样返回 assert render("{{roll:xyz}}", MacroContext()) == "xyz" def test_getvar() -> None: ctx = MacroContext(variables={"mood": "怅然"}) assert render("{{getvar:mood}}", ctx) == "怅然" assert render("{{getvar:missing}}", ctx) == "" def test_recursive_expansion() -> None: # char 值内含 {{user}},递归展开 ctx = MacroContext(char_name="{{user}}的影子", user_name="士道") assert render("{{char}}", ctx) == "士道的影子" def test_time_macro_without_snapshot_is_empty() -> None: ctx = MacroContext() assert render("{{date}}", ctx) == "" assert render("{{shichen}}", ctx) == "" def test_no_braces_unchanged() -> None: assert render("普通文本无占位符", MacroContext()) == "普通文本无占位符"