"""画中画引擎单元测试 - 配置解析+校验等纯逻辑.""" 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