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