complete restructure
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
"""Tests for the textutil module."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from vibe_bot.textutil import split_message
|
||||
|
||||
|
||||
def test_split_message_empty() -> None:
|
||||
assert split_message("") == []
|
||||
|
||||
|
||||
def test_split_message_short_text_single_chunk() -> None:
|
||||
assert split_message("hello") == ["hello"]
|
||||
|
||||
|
||||
def test_split_message_exact_limit() -> None:
|
||||
text = "a" * 1900
|
||||
chunks = split_message(text)
|
||||
assert chunks == [text]
|
||||
assert len(chunks) == 1
|
||||
|
||||
|
||||
def test_split_message_just_over_limit_no_newline() -> None:
|
||||
text = "a" * 1901
|
||||
chunks = split_message(text)
|
||||
assert "".join(chunks) == text
|
||||
assert all(len(c) <= 1900 for c in chunks)
|
||||
assert chunks == ["a" * 1900, "a"]
|
||||
|
||||
|
||||
def test_split_message_no_newlines_long() -> None:
|
||||
text = "x" * 5000
|
||||
chunks = split_message(text)
|
||||
assert "".join(chunks) == text
|
||||
assert all(len(c) <= 1900 for c in chunks)
|
||||
|
||||
|
||||
def test_split_message_respects_newlines() -> None:
|
||||
# Many short lines spanning several chunks: boundaries fall on newlines.
|
||||
text = "\n".join(f"line {i}" for i in range(1, 501))
|
||||
chunks = split_message(text)
|
||||
assert "".join(chunks) == text
|
||||
assert all(len(c) <= 1900 for c in chunks)
|
||||
assert len(chunks) > 1
|
||||
# Every chunk except the last ends on a newline (split at a line boundary).
|
||||
for chunk in chunks[:-1]:
|
||||
assert chunk.endswith("\n")
|
||||
|
||||
|
||||
def test_split_message_long_line_hard_split() -> None:
|
||||
# A single line longer than the limit must be hard-split.
|
||||
text = "a" * 5000 + "\n" + "short"
|
||||
chunks = split_message(text)
|
||||
assert "".join(chunks) == text
|
||||
assert all(len(c) <= 1900 for c in chunks)
|
||||
|
||||
|
||||
def test_split_message_emoji_round_trip() -> None:
|
||||
# Multi-codepoint emoji at split boundaries must not corrupt on join.
|
||||
text = "hello 🌍 world 👨👩👧👦 end " * 500
|
||||
for limit in (1, 10, 100, 1900):
|
||||
chunks = split_message(text, limit)
|
||||
assert "".join(chunks) == text
|
||||
assert all(len(c) <= limit for c in chunks)
|
||||
|
||||
|
||||
def test_split_message_property_round_trip_corpus() -> None:
|
||||
corpus = [
|
||||
"",
|
||||
"a",
|
||||
"a" * 1900,
|
||||
"a" * 1901,
|
||||
"line1\nline2\nline3",
|
||||
"para one\n\npara two\n\npara three",
|
||||
"no newline " * 1000,
|
||||
"emoji 🎉 " * 1000,
|
||||
"👨👩👧👦" * 2000,
|
||||
"mixed 🌍 text and 日本語 and emoji 🎊 here",
|
||||
# NFD combining marks (e + U+0301, a + U+0308) straddle split points.
|
||||
"cafe\u0301 " * 1000,
|
||||
"a\u0308\u0301 b\u0327\u0301 c\u0308 " * 1000,
|
||||
# Code spans with backticks and spaces.
|
||||
"`inline code` and `x = 1` spans " * 500,
|
||||
"``double backtick`` `single` " * 500,
|
||||
]
|
||||
for text in corpus:
|
||||
for limit in (1, 5, 100, 1900):
|
||||
chunks = split_message(text, limit)
|
||||
assert "".join(chunks) == text, f"round-trip failed for limit={limit}"
|
||||
assert all(len(c) <= limit for c in chunks)
|
||||
|
||||
|
||||
def test_split_message_exact_multiple_of_limit() -> None:
|
||||
"""Input that is an exact multiple of the limit splits into full chunks."""
|
||||
for limit in (1, 5, 100, 1900):
|
||||
text = "z" * (limit * 4)
|
||||
chunks = split_message(text, limit)
|
||||
assert "".join(chunks) == text
|
||||
assert len(chunks) == 4
|
||||
assert all(len(c) == limit for c in chunks)
|
||||
|
||||
|
||||
def test_split_message_limit_must_be_positive() -> None:
|
||||
with pytest.raises(ValueError):
|
||||
split_message("hello", 0)
|
||||
with pytest.raises(ValueError):
|
||||
split_message("hello", -5)
|
||||
Reference in New Issue
Block a user