Files
xiaoxia-saas/tests/unit/test_pip_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

272 lines
8.5 KiB
Python
Executable File

"""画中画引擎单元测试 - 配置解析+校验等纯逻辑."""
from __future__ import annotations
import pytest
from video_processing.pip_engine import PiPConfig, PiPLayerConfig
class TestPiPLayerConfigDefaults:
"""PiPLayerConfig 默认配置测试."""
def test_default_values(self):
"""默认值正确."""
layer = PiPLayerConfig()
assert layer.source == ""
assert layer.source_type == "asset_id"
assert layer.position == "bottom_right"
assert layer.margin == 20
assert layer.width == "25%"
assert layer.height == ""
assert layer.opacity == 1.0
assert layer.corner_radius == 0
assert layer.border_width == 0
assert layer.border_color == "white"
assert layer.start_time == 0.0
assert layer.duration == 0.0
assert layer.animation_in == ""
assert layer.animation_out == ""
assert layer.animation_duration == 0.5
assert layer.z_index == 1
class TestPiPLayerConfigValidate:
"""PiPLayerConfig.validate 校验测试."""
def test_valid_config(self):
"""合法配置."""
layer = PiPLayerConfig(source="asset_123")
ok, msg = layer.validate()
assert ok is True
assert msg == ""
def test_empty_source_invalid(self):
"""空source非法."""
layer = PiPLayerConfig(source="")
ok, msg = layer.validate()
assert ok is False
assert "source" in msg
def test_invalid_position(self):
"""无效position."""
layer = PiPLayerConfig(source="asset_123", position="invalid_pos")
ok, msg = layer.validate()
assert ok is False
assert "position" in msg
def test_custom_position_valid(self):
"""custom位置合法."""
layer = PiPLayerConfig(
source="asset_123",
position="custom",
x=100,
y=100,
)
ok, _ = layer.validate()
assert ok is True
def test_opacity_too_high(self):
"""透明度超过1."""
layer = PiPLayerConfig(source="a", opacity=1.5)
ok, msg = layer.validate()
assert ok is False
assert "opacity" in msg
def test_opacity_negative(self):
"""透明度为负."""
layer = PiPLayerConfig(source="a", opacity=-0.1)
ok, msg = layer.validate()
assert ok is False
assert "opacity" in msg
def test_opacity_boundary_zero(self):
"""透明度边界值0."""
layer = PiPLayerConfig(source="a", opacity=0.0)
ok, _ = layer.validate()
assert ok is True
def test_opacity_boundary_one(self):
"""透明度边界值1."""
layer = PiPLayerConfig(source="a", opacity=1.0)
ok, _ = layer.validate()
assert ok is True
def test_negative_corner_radius(self):
"""负圆角."""
layer = PiPLayerConfig(source="a", corner_radius=-5)
ok, msg = layer.validate()
assert ok is False
assert "corner_radius" in msg
def test_negative_start_time(self):
"""负开始时间."""
layer = PiPLayerConfig(source="a", start_time=-1.0)
ok, msg = layer.validate()
assert ok is False
assert "start_time" in msg
def test_negative_duration(self):
"""负时长."""
layer = PiPLayerConfig(source="a", duration=-2.0)
ok, msg = layer.validate()
assert ok is False
assert "duration" in msg
def test_zero_duration_valid(self):
"""零时长(全程显示)合法."""
layer = PiPLayerConfig(source="a", duration=0.0)
ok, _ = layer.validate()
assert ok is True
def test_invalid_animation_in(self):
"""无效入场动画."""
layer = PiPLayerConfig(source="a", animation_in="invalid_anim")
ok, msg = layer.validate()
assert ok is False
assert "入场动画" in msg
def test_invalid_animation_out(self):
"""无效出场动画."""
layer = PiPLayerConfig(source="a", animation_out="invalid_anim")
ok, msg = layer.validate()
assert ok is False
assert "出场动画" in msg
def test_negative_animation_duration(self):
"""负动画时长."""
layer = PiPLayerConfig(source="a", animation_duration=-0.5)
ok, msg = layer.validate()
assert ok is False
assert "animation_duration" in msg
class TestPiPConfigDefaults:
"""PiPConfig 默认配置测试."""
def test_default_values(self):
"""默认值正确."""
config = PiPConfig()
assert config.enabled is False
assert config.layers == []
class TestPiPConfigFromDict:
"""PiPConfig.from_dict 解析测试."""
def test_none_returns_disabled(self):
"""None 返回禁用配置."""
config = PiPConfig.from_dict(None)
assert config.enabled is False
assert config.layers == []
def test_empty_dict_returns_disabled(self):
"""空 dict 返回禁用."""
config = PiPConfig.from_dict({})
assert config.enabled is False
def test_disabled_returns_disabled(self):
"""enabled=False 返回禁用."""
config = PiPConfig.from_dict({"enabled": False})
assert config.enabled is False
def test_enabled_no_layers(self):
"""启用但无图层,disabled."""
config = PiPConfig.from_dict({"enabled": True, "layers": []})
assert config.enabled is False
assert config.layers == []
def test_single_layer(self):
"""单个图层."""
config = PiPConfig.from_dict(
{
"enabled": True,
"layers": [
{"source": "asset_001", "position": "top_left"},
],
}
)
assert config.enabled is True
assert len(config.layers) == 1
assert config.layers[0].source == "asset_001"
assert config.layers[0].position == "top_left"
def test_multiple_layers_sorted_by_z_index(self):
"""多个图层按z_index排序."""
config = PiPConfig.from_dict(
{
"enabled": True,
"layers": [
{"source": "a", "z_index": 3},
{"source": "b", "z_index": 1},
{"source": "c", "z_index": 2},
],
}
)
assert len(config.layers) == 3
assert config.layers[0].z_index == 1
assert config.layers[1].z_index == 2
assert config.layers[2].z_index == 3
def test_invalid_layer_skipped(self):
"""无效图层跳过."""
config = PiPConfig.from_dict(
{
"enabled": True,
"layers": [
{"source": "valid_asset"},
{"source": ""}, # 无效,空source
],
}
)
assert len(config.layers) == 1
assert config.layers[0].source == "valid_asset"
def test_all_invalid_layers_disabled(self):
"""全部无效则disabled."""
config = PiPConfig.from_dict(
{
"enabled": True,
"layers": [
{"source": ""},
{"source": ""},
],
}
)
assert config.enabled is False
assert config.layers == []
def test_layer_full_config(self):
"""完整图层配置."""
config = PiPConfig.from_dict(
{
"enabled": True,
"layers": [
{
"source": "https://example.com/video.mp4",
"source_type": "url",
"position": "bottom_right",
"width": "30%",
"opacity": 0.8,
"corner_radius": 10,
"border_width": 2,
"border_color": "red",
"start_time": 5.0,
"duration": 10.0,
"z_index": 5,
},
],
}
)
assert len(config.layers) == 1
layer = config.layers[0]
assert layer.source == "https://example.com/video.mp4"
assert layer.source_type == "url"
assert layer.width == "30%"
assert layer.opacity == 0.8
assert layer.corner_radius == 10
assert layer.border_width == 2
assert layer.border_color == "red"
assert layer.start_time == 5.0
assert layer.duration == 10.0
assert layer.z_index == 5