# SPDX-License-Identifier: AGPL-3.0-only # Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 """Chunking unit tests (no DB, no model).""" from core.rag.chunking import chunk_pages from core.rag.parsers import Page, parse_text WORDS = lambda t: len(t.split()) # noqa: E731 def _page(text: str, page_number = None) -> Page: return Page(text = text, page_number = page_number, char_count = len(text)) def test_chunk_token_bounds_and_overlap(): text = " ".join(f"w{i}" for i in range(300)) chunks = chunk_pages([_page(text)], max_tokens = 128, overlap = 24, count = WORDS) assert len(chunks) >= 3 assert all(c.token_count <= 128 for c in chunks) a, b = chunks[0].text.split(), chunks[1].text.split() shared = next((n for n in range(60, 0, -1) if a[-n:] == b[:n]), 0) assert shared == 24 # exactly overlap tokens carried def test_chunk_never_exceeds_max_with_overlap_carry(): """Overlap carry is trimmed so no chunk exceeds max_tokens (else the embedder overflows).""" s1 = " ".join("a" for _ in range(10)) s2 = " ".join("b" for _ in range(95)) # near max chunks = chunk_pages([_page(f"{s1}. {s2}")], max_tokens = 100, overlap = 24, count = WORDS) assert all(c.token_count <= 100 for c in chunks), [c.token_count for c in chunks] def test_chunk_indices_are_sequential(): chunks = chunk_pages([_page("alpha. " * 200)], max_tokens = 32, overlap = 0, count = WORDS) assert [c.chunk_index for c in chunks] == list(range(len(chunks))) def test_chunk_tracks_source_page_index(): pages = [_page("alpha bravo " * 80, 1), _page("charlie delta " * 80, 2)] chunks = chunk_pages(pages, max_tokens = 32, overlap = 0, count = WORDS) page0 = [c for c in chunks if c.source_page_index == 0] page1 = [c for c in chunks if c.source_page_index == 1] assert page0 and page1 assert all(c.page_number == 1 for c in page0) assert all(c.page_number == 2 for c in page1) def test_chunk_char_offsets_locate_text_in_page(): # Each chunk's char span must slice back to text containing it. page_text = "alpha bravo charlie delta echo foxtrot golf hotel " * 30 pages = [_page(page_text, 1)] chunks = chunk_pages(pages, max_tokens = 16, overlap = 0, count = WORDS) assert len(chunks) > 1 for c in chunks: assert 0 <= c.page_char_start < c.page_char_end <= len(page_text) sliced = page_text[c.page_char_start : c.page_char_end] assert c.text in sliced or sliced.strip() == c.text def test_empty_page_yields_no_chunks(): chunks = chunk_pages([_page(" \n ")], max_tokens = 32, overlap = 0, count = WORDS) assert chunks == [] def test_parse_text_single_page(): pages = parse_text("hello world") assert len(pages) == 1 assert pages[0].char_count == len("hello world")