"""Tests for REPL helper functions: peek, lines, search, chunk."""
from __future__ import annotations
import pytest
from aleph.repl.helpers import peek, lines, search, chunk
class TestPeek:
"""Tests for peek() character slicing."""
def test_peek_full(self) -> None:
assert peek("hello world", 0, None) == "hello world"
def test_peek_default(self) -> None:
assert peek("hello world") == "hello world"
def test_peek_slice_start(self) -> None:
assert peek("hello world", 0, 5) == "hello"
def test_peek_slice_middle(self) -> None:
assert peek("hello world", 6, 11) == "world"
def test_peek_offset_only(self) -> None:
assert peek("hello world", 6) == "world"
def test_peek_negative_index(self) -> None:
assert peek("hello world", -5) == "world"
def test_peek_empty(self) -> None:
assert peek("", 0, 10) == ""
def test_peek_dict(self) -> None:
result = peek({"key": "value"})
assert "key" in result
assert "value" in result
def test_peek_list(self) -> None:
result = peek([1, 2, 3])
assert "1" in result
assert "2" in result
def test_peek_none(self) -> None:
assert peek(None) == ""
def test_peek_bytes(self) -> None:
result = peek(b"hello")
assert "hello" in result
class TestLines:
"""Tests for lines() line slicing."""
def test_lines_full(self) -> None:
text = "line1\nline2\nline3"
assert lines(text) == text
def test_lines_slice_first_two(self) -> None:
text = "line1\nline2\nline3"
assert lines(text, 0, 2) == "line1\nline2"
def test_lines_slice_last_two(self) -> None:
text = "line1\nline2\nline3"
assert lines(text, 1, 3) == "line2\nline3"
def test_lines_single(self) -> None:
text = "line1\nline2\nline3"
assert lines(text, 1, 2) == "line2"
def test_lines_offset_only(self) -> None:
text = "line1\nline2\nline3"
assert lines(text, 2) == "line3"
def test_lines_negative_index(self) -> None:
text = "line1\nline2\nline3"
assert lines(text, -1) == "line3"
def test_lines_empty(self) -> None:
assert lines("") == ""
def test_lines_no_newlines(self) -> None:
assert lines("single line") == "single line"
class TestSearch:
"""Tests for search() regex functionality."""
def test_search_basic(self) -> None:
text = "foo bar\nbaz foo\nqux"
results = search(text, "foo")
assert len(results) == 2
assert results[0]["line_num"] == 0
assert results[1]["line_num"] == 1
def test_search_returns_match_line(self) -> None:
text = "alpha\nbeta\ngamma"
results = search(text, "beta")
assert len(results) == 1
assert results[0]["match"] == "beta"
def test_search_context_lines(self) -> None:
text = "line0\nline1\nmatch\nline3\nline4"
results = search(text, "match", context_lines=1)
assert len(results) == 1
assert "line1" in results[0]["context"]
assert "match" in results[0]["context"]
assert "line3" in results[0]["context"]
def test_search_max_results(self) -> None:
text = "\n".join([f"foo{i}" for i in range(100)])
results = search(text, "foo", max_results=5)
assert len(results) == 5
def test_search_no_match(self) -> None:
text = "alpha\nbeta\ngamma"
results = search(text, "delta")
assert len(results) == 0
def test_search_regex(self) -> None:
text = "apple123\nbanana456\ncherry789"
results = search(text, r"\d+")
assert len(results) == 3
def test_search_case_insensitive(self) -> None:
import re
text = "Hello\nWORLD\nhello"
results = search(text, "hello", flags=re.IGNORECASE)
assert len(results) == 2
def test_search_context_at_start(self) -> None:
text = "match\nline1\nline2"
results = search(text, "match", context_lines=2)
assert len(results) == 1
# Context shouldn't go negative
assert results[0]["context"].startswith("match")
def test_search_context_at_end(self) -> None:
text = "line0\nline1\nmatch"
results = search(text, "match", context_lines=2)
assert len(results) == 1
assert results[0]["context"].endswith("match")
class TestChunk:
"""Tests for chunk() text splitting."""
def test_chunk_basic(self) -> None:
text = "0123456789"
chunks = chunk(text, 3)
assert chunks == ["012", "345", "678", "9"]
def test_chunk_exact_fit(self) -> None:
text = "012345"
chunks = chunk(text, 3)
assert chunks == ["012", "345"]
def test_chunk_overlap(self) -> None:
text = "0123456789"
chunks = chunk(text, 5, overlap=2)
assert chunks[0] == "01234"
assert chunks[1] == "34567"
assert chunks[2] == "6789"
def test_chunk_large_chunk_size(self) -> None:
text = "short"
chunks = chunk(text, 100)
assert chunks == ["short"]
def test_chunk_single_char(self) -> None:
text = "abc"
chunks = chunk(text, 1)
assert chunks == ["a", "b", "c"]
def test_chunk_invalid_size_zero(self) -> None:
with pytest.raises(ValueError, match="chunk_size must be > 0"):
chunk("test", 0)
def test_chunk_invalid_size_negative(self) -> None:
with pytest.raises(ValueError, match="chunk_size must be > 0"):
chunk("test", -1)
def test_chunk_invalid_overlap_negative(self) -> None:
with pytest.raises(ValueError, match="overlap must be >= 0"):
chunk("test", 5, overlap=-1)
def test_chunk_invalid_overlap_too_large(self) -> None:
with pytest.raises(ValueError, match="overlap must be < chunk_size"):
chunk("test", 5, overlap=5)
def test_chunk_empty_string(self) -> None:
chunks = chunk("", 10)
assert chunks == []
def test_chunk_with_dict(self) -> None:
chunks = chunk({"key": "value"}, 5)
assert len(chunks) > 0
# Should be JSON-ified
assert any("{" in c for c in chunks)