152 lines
5.1 KiB
Python
152 lines
5.1 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
from yuxi.channels.adapters.slack.chunker import (
|
||
|
|
ChunkMode,
|
||
|
|
TextChunk,
|
||
|
|
convert_table_to_bullets,
|
||
|
|
resolve_text_chunks,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
class TestTextChunk:
|
||
|
|
def test_creation(self):
|
||
|
|
chunk = TextChunk(text="hello", index=0, is_last=True)
|
||
|
|
assert chunk.text == "hello"
|
||
|
|
assert chunk.index == 0
|
||
|
|
assert chunk.is_last is True
|
||
|
|
|
||
|
|
def test_is_last_false(self):
|
||
|
|
chunk = TextChunk(text="part1", index=0, is_last=False)
|
||
|
|
assert chunk.is_last is False
|
||
|
|
|
||
|
|
|
||
|
|
class TestChunkMode:
|
||
|
|
def test_values(self):
|
||
|
|
assert ChunkMode.LENGTH == "length"
|
||
|
|
assert ChunkMode.NEWLINE == "newline"
|
||
|
|
|
||
|
|
|
||
|
|
class TestConvertTableToBullets:
|
||
|
|
def test_basic_table(self):
|
||
|
|
text = "| Name | Age |\n|------|-----|\n| Alice | 30 |"
|
||
|
|
result = convert_table_to_bullets(text)
|
||
|
|
assert "*Name:* Alice | *Age:* 30" in result
|
||
|
|
|
||
|
|
def test_table_with_extra_spaces(self):
|
||
|
|
text = "| Col1 | Col2 |\n|--------|--------|\n| val1 | val2 |"
|
||
|
|
result = convert_table_to_bullets(text)
|
||
|
|
assert "*Col1:* val1" in result
|
||
|
|
assert "*Col2:* val2" in result
|
||
|
|
|
||
|
|
def test_not_a_table_no_pipe(self):
|
||
|
|
text = "Hello\nWorld"
|
||
|
|
assert convert_table_to_bullets(text) == "Hello\nWorld"
|
||
|
|
|
||
|
|
def test_not_a_table_no_separator(self):
|
||
|
|
text = "| A | B |\n| C | D |"
|
||
|
|
assert convert_table_to_bullets(text) == "| A | B |\n| C | D |"
|
||
|
|
|
||
|
|
def test_single_line(self):
|
||
|
|
text = "single line"
|
||
|
|
assert convert_table_to_bullets(text) == "single line"
|
||
|
|
|
||
|
|
def test_empty_text(self):
|
||
|
|
assert convert_table_to_bullets("") == ""
|
||
|
|
|
||
|
|
def test_three_column_table(self):
|
||
|
|
text = "| Name | Age | City |\n|------|-----|------|\n| Bob | 25 | NYC |"
|
||
|
|
result = convert_table_to_bullets(text)
|
||
|
|
assert "*Name:* Bob" in result
|
||
|
|
assert "*Age:* 25" in result
|
||
|
|
assert "*City:* NYC" in result
|
||
|
|
|
||
|
|
def test_table_with_empty_cells(self):
|
||
|
|
text = "| A | B |\n|---|---|\n| x | |"
|
||
|
|
result = convert_table_to_bullets(text)
|
||
|
|
assert "N/A" in result
|
||
|
|
|
||
|
|
|
||
|
|
class TestResolveTextChunks:
|
||
|
|
def test_empty_text(self):
|
||
|
|
assert resolve_text_chunks("", 100) == []
|
||
|
|
|
||
|
|
def test_text_within_limit(self):
|
||
|
|
chunks = resolve_text_chunks("short text", 100)
|
||
|
|
assert len(chunks) == 1
|
||
|
|
assert chunks[0].text == "short text"
|
||
|
|
assert chunks[0].index == 0
|
||
|
|
assert chunks[0].is_last is True
|
||
|
|
|
||
|
|
def test_text_at_exact_limit(self):
|
||
|
|
text = "A" * 10
|
||
|
|
chunks = resolve_text_chunks(text, 10)
|
||
|
|
assert len(chunks) == 1
|
||
|
|
assert chunks[0].text == text
|
||
|
|
|
||
|
|
def test_length_mode_chunks(self):
|
||
|
|
text = "A" * 50
|
||
|
|
chunks = resolve_text_chunks(text, 10, mode=ChunkMode.LENGTH)
|
||
|
|
assert len(chunks) == 5
|
||
|
|
for i, chunk in enumerate(chunks):
|
||
|
|
assert len(chunk.text) <= 10
|
||
|
|
assert chunk.index == i
|
||
|
|
assert chunks[-1].is_last is True
|
||
|
|
|
||
|
|
def test_newline_mode_chunks(self):
|
||
|
|
text = "line1\nline2\nline3\nline4\nline5"
|
||
|
|
chunks = resolve_text_chunks(text, 14, mode=ChunkMode.NEWLINE)
|
||
|
|
assert len(chunks) >= 2
|
||
|
|
for chunk in chunks:
|
||
|
|
assert len(chunk.text) <= 14
|
||
|
|
assert chunks[-1].is_last is True
|
||
|
|
|
||
|
|
def test_newline_mode_single_line(self):
|
||
|
|
text = "a" * 50
|
||
|
|
chunks = resolve_text_chunks(text, 10, mode=ChunkMode.NEWLINE)
|
||
|
|
assert len(chunks) >= 1
|
||
|
|
for chunk in chunks:
|
||
|
|
assert len(chunk.text) <= 10
|
||
|
|
|
||
|
|
def test_length_mode_prefers_newline_split(self):
|
||
|
|
text = "hello world\nfoo bar baz qux"
|
||
|
|
chunks = resolve_text_chunks(text, 15, mode=ChunkMode.LENGTH)
|
||
|
|
assert len(chunks) >= 2
|
||
|
|
assert chunks[0].text == "hello world"
|
||
|
|
|
||
|
|
def test_length_mode_falls_back_to_space_split(self):
|
||
|
|
text = "hello world q" * 10
|
||
|
|
chunks = resolve_text_chunks(text, 10, mode=ChunkMode.LENGTH)
|
||
|
|
for chunk in chunks:
|
||
|
|
assert len(chunk.text) <= 10
|
||
|
|
|
||
|
|
def test_table_conversion_disabled(self):
|
||
|
|
text = "| Name | Age |\n|------|-----|\n| Alice | 30 |"
|
||
|
|
chunks = resolve_text_chunks(text, 200, convert_table=False)
|
||
|
|
assert "| Name" in chunks[0].text
|
||
|
|
assert "*Name:*" not in chunks[0].text
|
||
|
|
|
||
|
|
def test_table_conversion_causes_expansion(self):
|
||
|
|
text = "| Name | Age |\n|------|-----|\n| Alice | 30 |"
|
||
|
|
chunks = resolve_text_chunks(text, 200, convert_table=True)
|
||
|
|
assert "*Name:* Alice" in chunks[0].text
|
||
|
|
|
||
|
|
def test_length_mode_long_text_no_newline(self):
|
||
|
|
text = "a" * 100
|
||
|
|
chunks = resolve_text_chunks(text, 10, mode=ChunkMode.LENGTH)
|
||
|
|
assert len(chunks) == 10
|
||
|
|
for chunk in chunks:
|
||
|
|
assert len(chunk.text) == 10
|
||
|
|
|
||
|
|
def test_single_chunk_is_last(self):
|
||
|
|
chunks = resolve_text_chunks("hello", 100)
|
||
|
|
assert len(chunks) == 1
|
||
|
|
assert chunks[0].is_last is True
|
||
|
|
|
||
|
|
def test_newline_exact_boundary(self):
|
||
|
|
text = "line1\nline2"
|
||
|
|
chunks = resolve_text_chunks(text, 6, mode=ChunkMode.NEWLINE)
|
||
|
|
for chunk in chunks:
|
||
|
|
assert len(chunk.text) <= 6
|
||
|
|
assert chunks[-1].is_last is True
|