Files
xiaoxia-saas/tests/unit/test_transition_engine.py
CI Bot 7a72cfd709
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
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 / Validate - Migration (alembic) (push) Successful in 2m9s
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 / Validate - Type Check (mypy) (push) Successful in 2m19s
CI/CD Pipeline / Validate - Code Quality (push) Failing after 3m10s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m7s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 3m7s
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 1m17s
CI/CD Pipeline / Frontend Lint (push) Successful in 3m37s
CI/CD Pipeline / Integration Tests (push) Successful in 2m18s
CI/CD Pipeline / Unit Tests (push) Failing after 4m59s
CI/CD Pipeline / Build Staging API Image (push) Successful in 8m39s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 3m25s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 42s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 27m2s
CI/CD Pipeline / Staging API Integration Tests (push) Failing after 30m15s
style: auto-format with black + isort + prettier
2026-07-25 00:16:10 +00:00

176 lines
5.9 KiB
Python
Executable File

"""转场引擎单元测试 - 配置解析等纯逻辑."""
from __future__ import annotations
import pytest
from video_processing.transition_engine import (
CUT_TRANSITION,
DEFAULT_TRANSITION_DURATION,
MAX_TRANSITION_DURATION,
MIN_TRANSITION_DURATION,
TransitionConfig,
TransitionType,
)
class TestTransitionConstants:
"""常量测试."""
def test_duration_ranges(self):
"""时长范围合理."""
assert MIN_TRANSITION_DURATION == 0.3
assert MAX_TRANSITION_DURATION == 2.0
assert DEFAULT_TRANSITION_DURATION == 0.5
assert MIN_TRANSITION_DURATION < DEFAULT_TRANSITION_DURATION < MAX_TRANSITION_DURATION
def test_cut_transition_value(self):
"""cut转场值."""
assert CUT_TRANSITION == "cut"
class TestTransitionType:
"""TransitionType 枚举测试."""
def test_supports_fade(self):
"""支持fade."""
assert TransitionType.is_supported("fade") is True
def test_supports_cut(self):
"""cut也在TransitionType枚举中."""
assert "cut" in [t.value for t in TransitionType]
def test_unsupported_effect(self):
"""不支持的效果."""
assert TransitionType.is_supported("nonexistent_effect_xyz") is False
def test_is_supported_case_insensitive(self):
"""是否大小写不敏感(看实现)."""
# 直接测试几个已知的
assert TransitionType.is_supported("fade") is True
assert TransitionType.is_supported("dissolve") is True
def test_all_types_have_value(self):
"""所有枚举都有有效值."""
for t in TransitionType:
assert isinstance(t.value, str)
assert len(t.value) > 0
class TestTransitionConfigParse:
"""TransitionConfig.parse 解析测试."""
def test_no_args_default(self):
"""无参数默认配置."""
config = TransitionConfig.parse()
assert config.effect == CUT_TRANSITION
assert config.duration == DEFAULT_TRANSITION_DURATION
def test_none_effect_default(self):
"""None effect默认为cut."""
config = TransitionConfig.parse(effect=None)
assert config.effect == CUT_TRANSITION
def test_empty_effect_default(self):
"""空字符串effect默认为cut."""
config = TransitionConfig.parse(effect="")
assert config.effect == CUT_TRANSITION
def test_whitespace_effect_default(self):
"""空白effect默认为cut."""
config = TransitionConfig.parse(effect=" ")
assert config.effect == CUT_TRANSITION
def test_fade_effect(self):
"""fade效果."""
config = TransitionConfig.parse(effect="fade")
assert config.effect == "fade"
def test_unsupported_effect_falls_back_to_cut(self):
"""不支持的效果降级到cut."""
config = TransitionConfig.parse(effect="super_cool_effect")
assert config.effect == CUT_TRANSITION
def test_cut_effect(self):
"""显式cut效果."""
config = TransitionConfig.parse(effect="cut")
assert config.effect == CUT_TRANSITION
def test_custom_duration(self):
"""自定义时长."""
config = TransitionConfig.parse(duration=1.0)
assert config.duration == 1.0
def test_duration_below_min_clamped(self):
"""时长低于最小值钳制."""
config = TransitionConfig.parse(duration=0.1)
assert config.duration == MIN_TRANSITION_DURATION
def test_duration_above_max_clamped(self):
"""时长高于最大值钳制."""
config = TransitionConfig.parse(duration=5.0)
assert config.duration == MAX_TRANSITION_DURATION
def test_duration_at_min(self):
"""时长边界最小值."""
config = TransitionConfig.parse(duration=MIN_TRANSITION_DURATION)
assert config.duration == MIN_TRANSITION_DURATION
def test_duration_at_max(self):
"""时长边界最大值."""
config = TransitionConfig.parse(duration=MAX_TRANSITION_DURATION)
assert config.duration == MAX_TRANSITION_DURATION
def test_invalid_duration_falls_back(self):
"""无效时长回退到默认."""
config = TransitionConfig.parse(duration="not_a_number")
assert config.duration == DEFAULT_TRANSITION_DURATION
def test_none_duration_default(self):
"""None时长用默认值."""
config = TransitionConfig.parse(duration=None)
assert config.duration == DEFAULT_TRANSITION_DURATION
def test_effect_and_duration(self):
"""同时指定效果和时长."""
config = TransitionConfig.parse(effect="fade", duration=1.0)
assert config.effect == "fade"
assert config.duration == 1.0
class TestIsCut:
"""is_cut 属性测试."""
def test_cut_is_cut(self):
"""cut是硬切."""
config = TransitionConfig(effect=CUT_TRANSITION, duration=0.5)
assert config.is_cut is True
def test_fade_not_cut(self):
"""fade不是硬切."""
config = TransitionConfig(effect="fade", duration=0.5)
assert config.is_cut is False
class TestFfmpegTransition:
"""ffmpeg_transition 属性测试."""
def test_cut_returns_empty(self):
"""cut返回空字符串."""
config = TransitionConfig(effect=CUT_TRANSITION, duration=0.5)
assert config.ffmpeg_transition == ""
def test_fade_returns_fade(self):
"""fade返回fade."""
config = TransitionConfig(effect="fade", duration=0.5)
result = config.ffmpeg_transition
assert isinstance(result, str)
assert len(result) > 0
def test_valid_effect_has_ffmpeg_name(self):
"""所有非cut的支持效果都有对应的ffmpeg名称."""
for t in TransitionType:
if t.value == CUT_TRANSITION:
continue # cut返回空是正常的
config = TransitionConfig(effect=t.value, duration=0.5)
assert config.ffmpeg_transition != ""