Files
vibe-bot/vibe_bot/tests/test_textutil.py
T
2026-08-19 13:16:43 -04:00

110 lines
3.5 KiB
Python

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