Merge pull request #2199 from llbn/fix/telegram-markdownv2-features

Clean PR, well-tested. Adds MarkdownV2 strikethrough, spoiler, and blockquote support to Telegram adapter.
This commit is contained in:
Teknium 2026-03-20 12:45:47 -07:00 committed by GitHub
commit f853e50589
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 125 additions and 4 deletions

View file

@ -320,6 +320,95 @@ class TestItalicNewlineBug:
assert "_italic_" in result
# =========================================================================
# format_message - strikethrough
# =========================================================================
class TestFormatMessageStrikethrough:
def test_strikethrough_converted(self, adapter):
result = adapter.format_message("This is ~~deleted~~ text")
assert "~deleted~" in result
assert "~~" not in result
def test_strikethrough_with_special_chars(self, adapter):
result = adapter.format_message("~~hello.world!~~")
assert "~hello\\.world\\!~" in result
def test_strikethrough_in_code_not_converted(self, adapter):
result = adapter.format_message("`~~not struck~~`")
assert "`~~not struck~~`" in result
def test_strikethrough_with_bold(self, adapter):
result = adapter.format_message("**bold** and ~~struck~~")
assert "*bold*" in result
assert "~struck~" in result
# =========================================================================
# format_message - spoiler
# =========================================================================
class TestFormatMessageSpoiler:
def test_spoiler_converted(self, adapter):
result = adapter.format_message("This is ||hidden|| text")
assert "||hidden||" in result
def test_spoiler_with_special_chars(self, adapter):
result = adapter.format_message("||hello.world!||")
assert "||hello\\.world\\!||" in result
def test_spoiler_in_code_not_converted(self, adapter):
result = adapter.format_message("`||not spoiler||`")
assert "`||not spoiler||`" in result
def test_spoiler_pipes_not_escaped(self, adapter):
"""The || delimiters must not be escaped as \\|\\|."""
result = adapter.format_message("||secret||")
assert "\\|\\|" not in result
assert "||secret||" in result
# =========================================================================
# format_message - blockquote
# =========================================================================
class TestFormatMessageBlockquote:
def test_blockquote_converted(self, adapter):
result = adapter.format_message("> This is a quote")
assert "> This is a quote" in result
# > must NOT be escaped
assert "\\>" not in result
def test_blockquote_with_special_chars(self, adapter):
result = adapter.format_message("> Hello (world)!")
assert "> Hello \\(world\\)\\!" in result
assert "\\>" not in result
def test_blockquote_multiline(self, adapter):
text = "> Line one\n> Line two"
result = adapter.format_message(text)
assert "> Line one" in result
assert "> Line two" in result
assert "\\>" not in result
def test_blockquote_in_code_not_converted(self, adapter):
result = adapter.format_message("```\n> not a quote\n```")
assert "> not a quote" in result
def test_nested_blockquote(self, adapter):
result = adapter.format_message(">> Nested quote")
assert ">> Nested quote" in result
assert "\\>" not in result
def test_gt_in_middle_of_line_still_escaped(self, adapter):
"""Only > at line start is a blockquote; mid-line > should be escaped."""
result = adapter.format_message("5 > 3")
assert "\\>" in result
# =========================================================================
# format_message - mixed/complex
# =========================================================================
@ -418,6 +507,12 @@ class TestStripMdv2:
def test_empty_string(self):
assert _strip_mdv2("") == ""
def test_removes_strikethrough_markers(self):
assert _strip_mdv2("~struck text~") == "struck text"
def test_removes_spoiler_markers(self):
assert _strip_mdv2("||hidden text||") == "hidden text"
@pytest.mark.asyncio
async def test_send_escapes_chunk_indicator_for_markdownv2(adapter):