- Implemented custom form widgets for date, time, and datetime fields with DaisyUI styling. - Created utility functions for formatting dates, times, and numbers according to user preferences. - Developed views for profile settings, API key management, and notifications, including health check endpoints. - Added URL configurations for Themis tests and main application routes. - Established test cases for custom widgets to ensure proper functionality and integration. - Defined project metadata and dependencies in pyproject.toml for package management.
109 lines
4.1 KiB
Python
109 lines
4.1 KiB
Python
"""
|
|
Tests for the content-type-aware chunking service.
|
|
"""
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from django.test import TestCase
|
|
|
|
from library.services.chunker import ChunkResult, ContentTypeChunker
|
|
from library.services.parsers import ParseResult, TextBlock
|
|
|
|
|
|
class ChunkResultTests(TestCase):
|
|
"""Tests for ChunkResult dataclass."""
|
|
|
|
def test_len(self):
|
|
result = ChunkResult(chunks=["a", "b", "c"], chunk_page_map={}, strategy="test")
|
|
self.assertEqual(len(result), 3)
|
|
|
|
def test_empty(self):
|
|
result = ChunkResult(chunks=[], chunk_page_map={}, strategy="test")
|
|
self.assertEqual(len(result), 0)
|
|
|
|
|
|
class ContentTypeChunkerTests(TestCase):
|
|
"""Tests for ContentTypeChunker."""
|
|
|
|
def _make_parse_result(self, text: str, pages: int = 1) -> ParseResult:
|
|
"""Helper to create a ParseResult with text blocks."""
|
|
blocks = []
|
|
if pages == 1:
|
|
blocks = [TextBlock(text=text, page=0)]
|
|
else:
|
|
chunk_size = len(text) // pages
|
|
for i in range(pages):
|
|
start = i * chunk_size
|
|
end = start + chunk_size if i < pages - 1 else len(text)
|
|
blocks.append(TextBlock(text=text[start:end], page=i))
|
|
return ParseResult(text_blocks=blocks, images=[], metadata={}, file_type="txt")
|
|
|
|
@patch("library.services.chunker.ContentTypeChunker._get_splitter")
|
|
def test_chunk_dispatches_strategy(self, mock_splitter):
|
|
"""Chunker uses the strategy from config."""
|
|
mock_instance = MagicMock()
|
|
mock_instance.chunks.return_value = ["chunk1", "chunk2"]
|
|
mock_splitter.return_value = mock_instance
|
|
|
|
chunker = ContentTypeChunker()
|
|
parse_result = self._make_parse_result("Some text to chunk into pieces")
|
|
config = {"strategy": "chapter_aware", "chunk_size": 512, "chunk_overlap": 64}
|
|
|
|
result = chunker.chunk(parse_result, config, library_type="fiction")
|
|
|
|
self.assertIsInstance(result, ChunkResult)
|
|
self.assertEqual(result.strategy, "chapter_aware")
|
|
self.assertEqual(len(result.chunks), 2)
|
|
mock_splitter.assert_called_once_with(512, 64)
|
|
|
|
@patch("library.services.chunker.ContentTypeChunker._get_splitter")
|
|
def test_empty_text_returns_empty(self, mock_splitter):
|
|
"""Empty text produces no chunks."""
|
|
chunker = ContentTypeChunker()
|
|
parse_result = ParseResult(text_blocks=[], images=[], metadata={}, file_type="txt")
|
|
config = {"strategy": "section_aware", "chunk_size": 512, "chunk_overlap": 64}
|
|
|
|
result = chunker.chunk(parse_result, config)
|
|
|
|
self.assertEqual(len(result), 0)
|
|
mock_splitter.assert_not_called()
|
|
|
|
@patch("library.services.chunker.ContentTypeChunker._get_splitter")
|
|
def test_default_config_values(self, mock_splitter):
|
|
"""Missing config keys use defaults."""
|
|
mock_instance = MagicMock()
|
|
mock_instance.chunks.return_value = ["chunk"]
|
|
mock_splitter.return_value = mock_instance
|
|
|
|
chunker = ContentTypeChunker()
|
|
parse_result = self._make_parse_result("Text")
|
|
|
|
result = chunker.chunk(parse_result, {})
|
|
|
|
# Default: strategy=section_aware, chunk_size=512, overlap=64
|
|
self.assertEqual(result.strategy, "section_aware")
|
|
mock_splitter.assert_called_once_with(512, 64)
|
|
|
|
@patch("library.services.chunker.ContentTypeChunker._get_splitter")
|
|
def test_page_mapping(self, mock_splitter):
|
|
"""Chunks are mapped to their source pages."""
|
|
mock_instance = MagicMock()
|
|
mock_instance.chunks.return_value = ["Page 0 text", "Page 1 text"]
|
|
mock_splitter.return_value = mock_instance
|
|
|
|
chunker = ContentTypeChunker()
|
|
parse_result = ParseResult(
|
|
text_blocks=[
|
|
TextBlock(text="Page 0 text content", page=0),
|
|
TextBlock(text="Page 1 text content", page=1),
|
|
],
|
|
images=[],
|
|
metadata={},
|
|
file_type="pdf",
|
|
)
|
|
config = {"strategy": "section_aware", "chunk_size": 512, "chunk_overlap": 64}
|
|
|
|
result = chunker.chunk(parse_result, config)
|
|
|
|
self.assertIn(0, result.chunk_page_map)
|