"""字幕时间轴单元测试。""" import pytest from packages.domain.subtitle import ( SubtitleSegment, SubtitleTimeline, SubtitleWord, ) class TestSubtitleWord: def test_duration(self): word = SubtitleWord(text="你", start=1.0, end=1.5) assert word.duration == pytest.approx(0.5) def test_zero_duration(self): word = SubtitleWord(text="", start=1.0, end=1.0) assert word.duration == 0.0 class TestSubtitleSegment: def test_duration(self): seg = SubtitleSegment(text="你好世界", start=0.0, end=2.0) assert seg.duration == pytest.approx(2.0) def test_char_count(self): seg = SubtitleSegment(text="你好世界", start=0.0, end=2.0) assert seg.char_count == 4 class TestSubtitleTimeline: def test_segment_count(self): timeline = SubtitleTimeline( segments=[ SubtitleSegment(text="第一段", start=0, end=1), SubtitleSegment(text="第二段", start=1, end=2), ] ) assert timeline.segment_count == 2 def test_total_chars(self): timeline = SubtitleTimeline( segments=[ SubtitleSegment(text="你好", start=0, end=1), SubtitleSegment(text="世界", start=1, end=2), ] ) assert timeline.total_chars == 4 class TestMergeShortSegments: def test_no_merge_when_long_enough(self): timeline = SubtitleTimeline( segments=[ SubtitleSegment(text="这是第一段测试文字", start=0, end=2), SubtitleSegment(text="这是第二段测试文字", start=2, end=4), ], total_duration=4.0, ) result = timeline.merge_short_segments(min_chars=8) assert result.segment_count == 2 def test_merge_short_segments(self): timeline = SubtitleTimeline( segments=[ SubtitleSegment(text="你好", start=0, end=0.5), SubtitleSegment(text="世界", start=0.5, end=1.0), SubtitleSegment(text="这是一段长文字", start=1.0, end=3.0), ], total_duration=3.0, ) result = timeline.merge_short_segments(min_chars=4) # 前两段合并(共4字),第三段保留 assert result.segment_count == 2 assert result.segments[0].text == "你好世界" assert result.segments[0].start == 0 assert result.segments[0].end == 1.0 def test_merge_remaining_to_last(self): timeline = SubtitleTimeline( segments=[ SubtitleSegment(text="这是第一段测试文字", start=0, end=2), SubtitleSegment(text="你", start=2, end=2.2), SubtitleSegment(text="好", start=2.2, end=2.4), ], total_duration=2.4, ) result = timeline.merge_short_segments(min_chars=8) # 最后两段字数不够,合并到上一段 assert result.segment_count == 1 assert result.segments[0].text == "这是第一段测试文字你好" def test_single_segment_no_change(self): timeline = SubtitleTimeline( segments=[SubtitleSegment(text="你好", start=0, end=1)], total_duration=1.0, ) result = timeline.merge_short_segments(min_chars=8) assert result.segment_count == 1 assert result.segments[0].text == "你好" def test_empty_timeline(self): timeline = SubtitleTimeline(segments=[]) result = timeline.merge_short_segments() assert result.segment_count == 0 class TestSplitLongSegments: def test_no_split_when_short_enough(self): timeline = SubtitleTimeline( segments=[SubtitleSegment(text="你好世界", start=0, end=1)], total_duration=1.0, ) result = timeline.split_long_segments(max_chars=20) assert result.segment_count == 1 def test_split_by_punctuation(self): timeline = SubtitleTimeline( segments=[ SubtitleSegment( text="这是第一段很长的测试文字。这是第二段很长的测试文字!这是第三段很长的测试文字?", start=0, end=6.0, ) ], total_duration=6.0, ) result = timeline.split_long_segments(max_chars=15) # 按标点拆成3段 assert result.segment_count == 3 assert "。" in result.segments[0].text assert "!" in result.segments[1].text assert "?" in result.segments[2].text def test_hard_split_when_no_punctuation(self): timeline = SubtitleTimeline( segments=[ SubtitleSegment( text="一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十", start=0, end=6.0, ) ], total_duration=6.0, ) result = timeline.split_long_segments(max_chars=10) assert result.segment_count == 3 assert len(result.segments[0].text) == 10 def test_time_proportional_split(self): timeline = SubtitleTimeline( segments=[ SubtitleSegment( text="你好世界,这是一段测试文字。用来验证时间比例是否正确。", start=0, end=10.0, ) ], total_duration=10.0, ) result = timeline.split_long_segments(max_chars=10) # 所有片段时间加起来应该等于总时长 total_time = sum(s.duration for s in result.segments) assert total_time == pytest.approx(10.0, abs=0.1) class TestTextSplitByPunctuation: def test_basic_split(self): parts = SubtitleTimeline._split_text_by_punctuation("你好世界!这是测试。", max_chars=10) assert len(parts) == 2 assert parts[0] == "你好世界!" assert parts[1] == "这是测试。" def test_no_punctuation_hard_split(self): parts = SubtitleTimeline._split_text_by_punctuation("一二三四五六七八九十一二三四五六七八九十", max_chars=10) assert len(parts) == 2 assert len(parts[0]) == 10 def test_short_text_no_split(self): parts = SubtitleTimeline._split_text_by_punctuation("你好世界", max_chars=10) assert len(parts) == 1 assert parts[0] == "你好世界"