c575a4b835
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m21s
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Failing after 1m55s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m52s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m27s
CI/CD Pipeline / Unit Tests (push) Failing after 6m39s
CI/CD Pipeline / Integration Tests (push) Successful in 2m41s
CI/CD Pipeline / Frontend Lint (push) Successful in 44s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 2m0s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 15m23s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m49s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 5m11s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (push) Failing after 5s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m11s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 5m28s
132 lines
4.2 KiB
Python
132 lines
4.2 KiB
Python
"""
|
||
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()
|