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
176 lines
5.9 KiB
Python
Executable File
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 != ""
|