Files
xiaoxia-saas/tests/unit/test_reverse_engine.py
CI Bot 18bd0de3fa
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 1m42s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m44s
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 / Build Staging Web Image (push) Successful in 1m42s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 1m26s
CI/CD Pipeline / Validate - Code Quality (push) Failing after 3m13s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m22s
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Successful in 4m29s
CI/CD Pipeline / Integration Tests (push) Successful in 2m16s
CI/CD Pipeline / Unit Tests (push) Failing after 5m46s
CI/CD Pipeline / Build Staging API Image (push) Successful in 11m28s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 3m18s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 30s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 2m13s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 5m58s
style: auto-format with black + isort + prettier
2026-07-24 14:07:12 +00:00

194 lines
7.2 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""ReverseEngine 单测 — 倒放引擎配置解析 + 滤镜构建."""
from __future__ import annotations
import pytest
from video_processing.reverse_engine import ReverseConfig, ReverseEngine
# ── ReverseConfig.from_dict ────────────────────────────────────────────────
class TestReverseConfigFromDict:
"""ReverseConfig.from_dict 配置解析."""
def test_none_returns_disabled(self):
config = ReverseConfig.from_dict(None)
assert config.enabled is False
assert config.reverse_video is True
assert config.reverse_audio is True
def test_empty_dict_returns_disabled(self):
config = ReverseConfig.from_dict({})
assert config.enabled is False
def test_enabled_false(self):
config = ReverseConfig.from_dict({"enabled": False})
assert config.enabled is False
def test_enabled_true_defaults(self):
"""只传 enabled=Truevideo/audio 默认都开."""
config = ReverseConfig.from_dict({"enabled": True})
assert config.enabled is True
assert config.reverse_video is True
assert config.reverse_audio is True
def test_disable_video_only(self):
config = ReverseConfig.from_dict(
{
"enabled": True,
"reverse_video": False,
"reverse_audio": True,
}
)
assert config.enabled is True
assert config.reverse_video is False
assert config.reverse_audio is True
def test_disable_audio_only(self):
config = ReverseConfig.from_dict(
{
"enabled": True,
"reverse_video": True,
"reverse_audio": False,
}
)
assert config.enabled is True
assert config.reverse_video is True
assert config.reverse_audio is False
def test_both_disabled(self):
config = ReverseConfig.from_dict(
{
"enabled": True,
"reverse_video": False,
"reverse_audio": False,
}
)
assert config.enabled is True
assert config.reverse_video is False
assert config.reverse_audio is False
def test_invalid_type_falls_back_default(self):
"""传入非字典类型(如列表),捕获 TypeError,返回默认配置."""
config = ReverseConfig.from_dict([1, 2, 3]) # type: ignore[arg-type]
assert config.enabled is False
def test_attribute_error_falls_back(self):
"""没有 .get() 方法的对象,捕获 AttributeError,返回默认配置."""
config = ReverseConfig.from_dict(123) # type: ignore[arg-type]
assert config.enabled is False
def test_truthy_values(self):
"""非布尔真值也能被 bool() 转换."""
config = ReverseConfig.from_dict(
{
"enabled": 1,
"reverse_video": 1,
"reverse_audio": "yes",
}
)
assert config.enabled is True
assert config.reverse_video is True
assert config.reverse_audio is True
def test_falsy_values(self):
"""非布尔假值也能被 bool() 转换."""
config = ReverseConfig.from_dict(
{
"enabled": True,
"reverse_video": 0,
"reverse_audio": "",
}
)
assert config.enabled is True
assert config.reverse_video is False
assert config.reverse_audio is False
# ── ReverseEngine.build_video_filter ───────────────────────────────────────
class TestBuildVideoFilter:
"""ReverseEngine.build_video_filter 视频倒放滤镜构建."""
def test_disabled_returns_empty(self):
config = ReverseConfig(enabled=False)
result = ReverseEngine.build_video_filter(config)
assert result == ""
def test_enabled_but_video_off_returns_empty(self):
config = ReverseConfig(enabled=True, reverse_video=False, reverse_audio=True)
result = ReverseEngine.build_video_filter(config)
assert result == ""
def test_enabled_normal_duration(self):
config = ReverseConfig(enabled=True)
result = ReverseEngine.build_video_filter(config, duration=10.0)
assert result == "reverse"
def test_zero_duration(self):
config = ReverseConfig(enabled=True)
result = ReverseEngine.build_video_filter(config, duration=0.0)
assert result == "reverse"
def test_exactly_max_safe_duration(self):
"""刚好等于上限,允许."""
config = ReverseConfig(enabled=True)
result = ReverseEngine.build_video_filter(config, duration=ReverseEngine.MAX_SAFE_DURATION)
assert result == "reverse"
def test_exceeds_max_safe_duration_skips(self):
"""超过上限,跳过倒放,返回空字符串."""
config = ReverseConfig(enabled=True)
result = ReverseEngine.build_video_filter(config, duration=ReverseEngine.MAX_SAFE_DURATION + 1)
assert result == ""
def test_negative_duration(self):
"""负时长应该不会触发上限,但仍会正常返回 reverse."""
config = ReverseConfig(enabled=True)
result = ReverseEngine.build_video_filter(config, duration=-5.0)
assert result == "reverse"
# ── ReverseEngine.build_audio_filter ───────────────────────────────────────
class TestBuildAudioFilter:
"""ReverseEngine.build_audio_filter 音频倒放滤镜构建."""
def test_disabled_returns_empty(self):
config = ReverseConfig(enabled=False)
result = ReverseEngine.build_audio_filter(config)
assert result == ""
def test_enabled_but_audio_off_returns_empty(self):
config = ReverseConfig(enabled=True, reverse_video=True, reverse_audio=False)
result = ReverseEngine.build_audio_filter(config)
assert result == ""
def test_enabled_normal_duration(self):
config = ReverseConfig(enabled=True)
result = ReverseEngine.build_audio_filter(config, duration=10.0)
assert result == "areverse"
def test_zero_duration(self):
config = ReverseConfig(enabled=True)
result = ReverseEngine.build_audio_filter(config, duration=0.0)
assert result == "areverse"
def test_exactly_max_safe_duration(self):
config = ReverseConfig(enabled=True)
result = ReverseEngine.build_audio_filter(config, duration=ReverseEngine.MAX_SAFE_DURATION)
assert result == "areverse"
def test_exceeds_max_safe_duration_skips(self):
config = ReverseConfig(enabled=True)
result = ReverseEngine.build_audio_filter(config, duration=ReverseEngine.MAX_SAFE_DURATION + 1)
assert result == ""
def test_both_video_and_audio_disabled(self):
"""两个都关,两个滤镜都为空."""
config = ReverseConfig(enabled=True, reverse_video=False, reverse_audio=False)
assert ReverseEngine.build_video_filter(config, 10) == ""
assert ReverseEngine.build_audio_filter(config, 10) == ""