""" TTS 配音引擎数据类与纯逻辑测试. 覆盖 VoiceoverSegment / VoiceoverResult / TtsEngine 入口判断等纯逻辑. TTS 合成调用依赖外部服务,由集成测试覆盖. """ from __future__ import annotations from pathlib import Path from unittest.mock import MagicMock import pytest from video_processing.tts_engine import TtsEngine, VoiceoverResult, VoiceoverSegment from packages.domain.tts_config import TtsConfig class TestVoiceoverSegment: """配音片段数据类.""" def test_default_values(self): seg = VoiceoverSegment(text="hello") assert seg.text == "hello" assert seg.start_time == 0.0 assert seg.end_time == 0.0 assert seg.audio_path is None assert seg.duration == 0.0 def test_full_values(self): seg = VoiceoverSegment( text="hello world", start_time=1.5, end_time=3.0, audio_path=Path("/tmp/test.wav"), duration=1.5, ) assert seg.text == "hello world" assert seg.start_time == 1.5 assert seg.end_time == 3.0 assert seg.audio_path == Path("/tmp/test.wav") assert seg.duration == 1.5 def test_duration_calculation(self): seg = VoiceoverSegment(text="test", start_time=0.0, end_time=5.5) assert seg.end_time - seg.start_time == 5.5 class TestVoiceoverResult: """配音结果数据类.""" def test_default_failure(self): result = VoiceoverResult() assert result.success is False assert result.segments == [] assert result.total_duration == 0.0 assert result.error_message == "" def test_success_result(self): segs = [ VoiceoverSegment(text="hello", duration=1.0), VoiceoverSegment(text="world", duration=2.0), ] result = VoiceoverResult( success=True, segments=segs, total_duration=3.0, ) assert result.success is True assert len(result.segments) == 2 assert result.total_duration == 3.0 assert result.error_message == "" def test_failure_with_message(self): result = VoiceoverResult(success=False, error_message="TTS服务不可用") assert result.success is False assert result.error_message == "TTS服务不可用" def test_segments_isolated_list(self): """确保每个实例有独立的segments列表.""" r1 = VoiceoverResult() r2 = VoiceoverResult() r1.segments.append(VoiceoverSegment(text="test")) assert len(r2.segments) == 0 class TestTtsEngineInit: """TTS 引擎初始化.""" def test_init_creates_work_dir(self, tmp_path): mock_tts = MagicMock() work_dir = tmp_path / "tts_work" engine = TtsEngine(mock_tts, work_dir) assert work_dir.exists() assert work_dir.is_dir() def test_init_with_existing_dir(self, tmp_path): mock_tts = MagicMock() work_dir = tmp_path / "existing" work_dir.mkdir() engine = TtsEngine(mock_tts, work_dir) assert work_dir.exists() class TestTtsEngineEntryConditions: """TTS 引擎入口判断逻辑(不调用真实 TTS).""" def test_disabled_returns_failure(self, tmp_path): mock_tts = MagicMock() engine = TtsEngine(mock_tts, tmp_path) config = TtsConfig(enabled=False, text="hello") result = engine.generate_full_voiceover(config) assert result.success is False assert "未启用" in result.error_message or "空" in result.error_message mock_tts.synthesize.assert_not_called() def test_empty_text_returns_failure(self, tmp_path): mock_tts = MagicMock() engine = TtsEngine(mock_tts, tmp_path) config = TtsConfig(enabled=True, text="") result = engine.generate_full_voiceover(config) assert result.success is False mock_tts.synthesize.assert_not_called() def test_whitespace_text_returns_failure(self, tmp_path): mock_tts = MagicMock() engine = TtsEngine(mock_tts, tmp_path) config = TtsConfig(enabled=True, text=" ") result = engine.generate_full_voiceover(config) assert result.success is False mock_tts.synthesize.assert_not_called()