f26d4d8f7f
- Multi-source content aggregation (Bilibili/YouTube/Zhihu) - Smart inbox management with AI quality scoring - Long video chunking analysis (30min+ auto-segmentation) - Topic-based organization - Git auto-sync to Obsidian - Template system with Jinja2 and fallback rendering - CLI commands: subscribe, inbox, process, skip, status, search - Comprehensive test suite with unit and integration tests - Documentation: README.md and SKILL.md Checkpoint 7-8 completed by Agent E
150 lines
5.0 KiB
Python
150 lines
5.0 KiB
Python
"""
|
|
Unit tests for content chunking module.
|
|
"""
|
|
import unittest
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
sys.path.insert(0, str(Path(__file__).parent.parent / 'src'))
|
|
|
|
from content_chunker import ContentChunker, Chunk
|
|
|
|
|
|
class TestContentChunker(unittest.TestCase):
|
|
"""Test ContentChunker class."""
|
|
|
|
def setUp(self):
|
|
"""Set up test fixtures."""
|
|
self.chunker = ContentChunker(chunk_duration_seconds=900)
|
|
|
|
def test_chunker_initialization(self):
|
|
"""Test chunker initialization."""
|
|
self.assertEqual(self.chunker.chunk_duration, 900)
|
|
self.assertEqual(self.chunker.max_chunk_duration, 1800)
|
|
|
|
def test_parse_srt(self):
|
|
"""Test SRT parsing."""
|
|
srt_content = """1
|
|
00:00:01,000 --> 00:00:05,000
|
|
First subtitle
|
|
|
|
2
|
|
00:00:06,000 --> 00:00:10,000
|
|
Second subtitle
|
|
|
|
3
|
|
00:00:11,000 --> 00:00:15,000
|
|
Third subtitle"""
|
|
|
|
subtitles = self.chunker._parse_srt(srt_content)
|
|
|
|
self.assertEqual(len(subtitles), 3)
|
|
self.assertEqual(subtitles[0], (1.0, 5.0, "First subtitle"))
|
|
self.assertEqual(subtitles[1], (6.0, 10.0, "Second subtitle"))
|
|
self.assertEqual(subtitles[2], (11.0, 15.0, "Third subtitle"))
|
|
|
|
def test_time_to_seconds(self):
|
|
"""Test time conversion."""
|
|
self.assertEqual(self.chunker._time_to_seconds("00:00:30,000"), 30.0)
|
|
self.assertEqual(self.chunker._time_to_seconds("00:01:30,000"), 90.0)
|
|
self.assertEqual(self.chunker._time_to_seconds("01:00:00,000"), 3600.0)
|
|
self.assertEqual(self.chunker._time_to_seconds("01:30:45,500"), 5445.5)
|
|
|
|
def test_chunk_by_duration_short_content(self):
|
|
"""Test chunking short content (single chunk)."""
|
|
srt_content = """1
|
|
00:00:00,000 --> 00:00:10,000
|
|
This is the first line
|
|
|
|
2
|
|
00:00:10,000 --> 00:00:20,000
|
|
This is the second line"""
|
|
|
|
chunks = self.chunker.chunk_by_duration(srt_content, target_duration=900)
|
|
|
|
self.assertEqual(len(chunks), 1)
|
|
self.assertEqual(chunks[0].index, 0)
|
|
self.assertEqual(chunks[0].start_time, 0.0)
|
|
self.assertEqual(chunks[0].end_time, 20.0)
|
|
|
|
def test_chunk_by_duration_long_content(self):
|
|
"""Test chunking long content (multiple chunks)."""
|
|
# Create SRT content that spans 25 minutes
|
|
srt_lines = []
|
|
for i in range(25):
|
|
start = i * 60
|
|
end = (i + 1) * 60
|
|
srt_lines.append(f"{i+1}")
|
|
srt_lines.append(f"00:{i:02d}:00,000 --> 00:{i+1:02d}:00,000")
|
|
srt_lines.append(f"Minute {i+1} content")
|
|
srt_lines.append("")
|
|
|
|
srt_content = "\n".join(srt_lines)
|
|
|
|
# Use 10-minute chunks
|
|
chunks = self.chunker.chunk_by_duration(srt_content, target_duration=600)
|
|
|
|
self.assertGreater(len(chunks), 1)
|
|
# First chunk should start at 0
|
|
self.assertEqual(chunks[0].start_time, 0.0)
|
|
|
|
def test_chunk_time_range(self):
|
|
"""Test chunk time range formatting."""
|
|
chunk = Chunk(index=0, start_time=125.0, end_time=245.0, text="Test")
|
|
|
|
self.assertEqual(chunk.time_range, "02:05-04:05")
|
|
self.assertEqual(chunk.duration, 120.0)
|
|
|
|
def test_chunk_time_range_with_hours(self):
|
|
"""Test chunk time range with hours."""
|
|
chunk = Chunk(index=0, start_time=3665.0, end_time=7265.0, text="Test")
|
|
|
|
self.assertEqual(chunk.time_range, "01:01:05-02:01:05")
|
|
|
|
def test_get_chunking_strategy_short(self):
|
|
"""Test chunking strategy for short content."""
|
|
strategy = self.chunker.get_chunking_strategy(300) # 5 minutes
|
|
|
|
self.assertEqual(strategy['strategy'], 'direct')
|
|
self.assertEqual(strategy['chunk_count'], 1)
|
|
|
|
def test_get_chunking_strategy_medium(self):
|
|
"""Test chunking strategy for medium content."""
|
|
strategy = self.chunker.get_chunking_strategy(1200) # 20 minutes
|
|
|
|
self.assertEqual(strategy['strategy'], 'truncate')
|
|
self.assertEqual(strategy['chunk_count'], 1)
|
|
|
|
def test_get_chunking_strategy_long(self):
|
|
"""Test chunking strategy for long content."""
|
|
strategy = self.chunker.get_chunking_strategy(2400) # 40 minutes
|
|
|
|
self.assertEqual(strategy['strategy'], 'two_part')
|
|
self.assertEqual(strategy['chunk_count'], 2)
|
|
|
|
def test_get_chunking_strategy_very_long(self):
|
|
"""Test chunking strategy for very long content."""
|
|
strategy = self.chunker.get_chunking_strategy(7200) # 2 hours
|
|
|
|
self.assertEqual(strategy['strategy'], 'multi_part')
|
|
self.assertGreater(strategy['chunk_count'], 2)
|
|
|
|
|
|
class TestChunk(unittest.TestCase):
|
|
"""Test Chunk dataclass."""
|
|
|
|
def test_chunk_properties(self):
|
|
chunk = Chunk(
|
|
index=1,
|
|
start_time=100.0,
|
|
end_time=250.0,
|
|
text="Test content"
|
|
)
|
|
|
|
self.assertEqual(chunk.index, 1)
|
|
self.assertEqual(chunk.duration, 150.0)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|