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

178 lines
5.6 KiB
Python
Executable File

"""统一渲染服务纯逻辑测试 — _resolve_layer_role + 图层配置 + 数据结构."""
from __future__ import annotations
from pathlib import Path
import pytest
from video_processing.unified_render_service import (
_LAYER_Z_INDEX,
_PIP_SCALE,
RenderLayer,
ResolvedClip,
_resolve_layer_role,
)
class TestResolveLayerRole:
"""_resolve_layer_role 图层角色映射测试."""
def test_intro_is_main(self):
"""intro片段 → main层."""
assert _resolve_layer_role("intro", {}) == "main"
def test_outro_is_main(self):
"""outro片段 → main层."""
assert _resolve_layer_role("outro", {}) == "main"
def test_overlay_is_overlay(self):
"""overlay片段 → overlay层."""
assert _resolve_layer_role("overlay", {}) == "overlay"
def test_corner_voice(self):
"""corner_voice片段 → corner_voice层."""
assert _resolve_layer_role("corner_voice", {}) == "corner_voice"
def test_background(self):
"""background片段 → background层."""
assert _resolve_layer_role("background", {}) == "background"
def test_b_roll(self):
"""b_roll片段 → broll层."""
assert _resolve_layer_role("b_roll", {}) == "broll"
def test_main_default(self):
"""main type默认 → main层."""
assert _resolve_layer_role("main", {}) == "main"
def test_main_with_broll_role(self):
"""main type + role=b_roll → broll层."""
assert _resolve_layer_role("main", {"role": "b_roll"}) == "broll"
def test_main_with_audio_role(self):
"""main type + role=audio → audio层."""
assert _resolve_layer_role("main", {"role": "audio"}) == "audio"
def test_unknown_type_falls_back_to_main(self):
"""未知类型 → main层."""
assert _resolve_layer_role("random_type", {}) == "main"
def test_intro_ignores_role(self):
"""intro/outro忽略role配置."""
assert _resolve_layer_role("intro", {"role": "b_roll"}) == "main"
assert _resolve_layer_role("outro", {"role": "overlay"}) == "main"
def test_empty_config(self):
"""空config不影响结果."""
assert _resolve_layer_role("main", {}) == "main"
def test_none_role(self):
"""role=None时走默认."""
assert _resolve_layer_role("main", {"role": None}) == "main"
class TestLayerZIndex:
"""_LAYER_Z_INDEX 图层层级配置测试."""
def test_background_lowest(self):
"""background在最底层."""
assert _LAYER_Z_INDEX["background"] == -1
def test_main_and_broll_same_level(self):
"""main和broll在同一层(z=0)."""
assert _LAYER_Z_INDEX["main"] == 0
assert _LAYER_Z_INDEX["broll"] == 0
def test_overlay_and_corner_voice_above(self):
"""overlay和corner_voice在z=1."""
assert _LAYER_Z_INDEX["overlay"] == 1
assert _LAYER_Z_INDEX["corner_voice"] == 1
def test_audio_highest(self):
"""audio在z=2(最高,因为音频不涉及z顺序但参与混音)."""
assert _LAYER_Z_INDEX["audio"] == 2
def test_pip_scale_is_positive(self):
"""PiP缩放比例为正数."""
assert _PIP_SCALE > 0
assert _PIP_SCALE < 1.0
class TestResolvedClip:
"""ResolvedClip 数据结构测试."""
def test_default_values(self):
"""默认值正确."""
clip = ResolvedClip(
clip_id="c1",
asset_id="a1",
local_path=Path("/tmp/test.mp4"),
clip_type="main",
order=0,
)
assert clip.start_time == 0.0
assert clip.duration == 0.0
assert clip.transition_effect == "cut"
assert clip.transition_duration == 0.0
assert clip.playback_speed == 1.0
assert clip.config == {}
assert clip.actual_duration == 0.0
assert clip.trim_config is None
def test_custom_values(self):
"""自定义值正确."""
clip = ResolvedClip(
clip_id="c2",
asset_id="a2",
local_path=Path("/tmp/video.mp4"),
clip_type="overlay",
order=1,
start_time=5.0,
duration=10.0,
transition_effect="fade",
transition_duration=0.5,
playback_speed=1.5,
)
assert clip.clip_id == "c2"
assert clip.asset_id == "a2"
assert clip.clip_type == "overlay"
assert clip.order == 1
assert clip.start_time == 5.0
assert clip.duration == 10.0
assert clip.transition_effect == "fade"
assert clip.transition_duration == 0.5
assert clip.playback_speed == 1.5
class TestRenderLayer:
"""RenderLayer 数据结构测试."""
def test_default_values(self):
"""默认值正确."""
layer = RenderLayer(role="main")
assert layer.clips == []
assert layer.z_index == 0
assert layer.opacity == 1.0
assert layer.position is None
def test_with_clips(self):
"""带片段的图层."""
clip = ResolvedClip(
clip_id="c1",
asset_id="a1",
local_path=Path("/tmp/t.mp4"),
clip_type="main",
order=0,
)
layer = RenderLayer(role="overlay", clips=[clip], z_index=1)
assert len(layer.clips) == 1
assert layer.z_index == 1
assert layer.role == "overlay"
def test_background_layer(self):
"""background图层配置."""
layer = RenderLayer(role="background", z_index=-1, opacity=1.0)
assert layer.role == "background"
assert layer.z_index == -1
assert layer.opacity == 1.0