"""片头片尾引擎单元测试 - 配置解析等纯逻辑.""" from __future__ import annotations import pytest from video_processing.intro_outro_engine import IntroOutroConfig class TestIntroOutroConfigDefaults: """默认配置测试.""" def test_default_values(self): """默认值正确.""" config = IntroOutroConfig() assert config.enabled is False assert config.intro_type == "none" assert config.outro_type == "none" assert config.intro_duration == 3.0 assert config.outro_duration == 3.0 assert config.transition_effect == "fade" assert config.transition_duration == 0.5 class TestIntroOutroConfigFromDict: """from_dict 配置解析测试.""" def test_none_returns_default(self): """None 返回默认配置.""" config = IntroOutroConfig.from_dict(None) assert config.enabled is False def test_empty_dict_returns_default(self): """空 dict 返回默认.""" config = IntroOutroConfig.from_dict({}) assert config.enabled is False def test_disabled_returns_default(self): """enabled=False 返回默认.""" config = IntroOutroConfig.from_dict({"enabled": False}) assert config.enabled is False def test_enabled_defaults(self): """启用时默认值正确.""" config = IntroOutroConfig.from_dict({"enabled": True}) assert config.enabled is True assert config.intro_type == "none" assert config.outro_type == "none" def test_text_intro(self): """文字片头配置.""" config = IntroOutroConfig.from_dict({ "enabled": True, "intro": { "type": "text", "title": "我的片头", "subtitle": "欢迎收看", }, }) assert config.intro_type == "text" assert config.intro_title == "我的片头" assert config.intro_subtitle == "欢迎收看" def test_video_intro(self): """视频片头配置.""" config = IntroOutroConfig.from_dict({ "enabled": True, "intro": { "type": "video", "video_path": "/videos/intro.mp4", "duration": 5.0, }, }) assert config.intro_type == "video" assert config.intro_video_path == "/videos/intro.mp4" assert config.intro_duration == 5.0 def test_video_intro_video_alias(self): """video 字段作为 video_path 别名.""" config = IntroOutroConfig.from_dict({ "enabled": True, "intro": { "type": "video", "video": "/videos/intro.mp4", }, }) assert config.intro_video_path == "/videos/intro.mp4" def test_text_outro(self): """文字片尾配置.""" config = IntroOutroConfig.from_dict({ "enabled": True, "outro": { "type": "text", "title": "感谢观看", "subtitle": "点赞关注", }, }) assert config.outro_type == "text" assert config.outro_title == "感谢观看" assert config.outro_subtitle == "点赞关注" def test_outro_default_title(self): """片尾默认标题.""" config = IntroOutroConfig.from_dict({ "enabled": True, "outro": {"type": "text"}, }) assert config.outro_title == "感谢观看" assert config.outro_subtitle == "点赞关注不迷路" def test_text_intro_styling(self): """文字片头样式配置.""" config = IntroOutroConfig.from_dict({ "enabled": True, "intro": { "type": "text", "title": "测试", "background": "#FF0000", "title_color": "yellow", "title_size": 64, "subtitle_color": "white", "subtitle_size": 32, }, }) assert config.intro_background == "#FF0000" assert config.intro_title_color == "yellow" assert config.intro_title_size == 64 assert config.intro_subtitle_color == "white" assert config.intro_subtitle_size == 32 def test_transition_config(self): """转场配置.""" config = IntroOutroConfig.from_dict({ "enabled": True, "transition": "dissolve", "transition_duration": 1.0, }) assert config.transition_effect == "dissolve" assert config.transition_duration == 1.0 def test_empty_intro_dict(self): """空 intro dict.""" config = IntroOutroConfig.from_dict({ "enabled": True, "intro": {}, }) assert config.intro_type == "none" def test_none_intro(self): """None intro 值.""" config = IntroOutroConfig.from_dict({ "enabled": True, "intro": None, }) assert config.intro_type == "none" class TestHasIntroOutro: """has_intro / has_outro 属性测试.""" def test_no_intro_when_disabled(self): """禁用时无片头.""" config = IntroOutroConfig() assert config.has_intro is False assert config.has_outro is False def test_video_intro_has_intro(self): """视频片头有has_intro.""" config = IntroOutroConfig( enabled=True, intro_type="video", intro_video_path="/a.mp4", ) assert config.has_intro is True def test_text_intro_has_intro(self): """文字片头有has_intro.""" config = IntroOutroConfig( enabled=True, intro_type="text", intro_title="test", ) assert config.has_intro is True def test_none_intro_no_intro(self): """none类型无片头.""" config = IntroOutroConfig(enabled=True, intro_type="none") assert config.has_intro is False def test_video_outro_has_outro(self): """视频片尾有has_outro.""" config = IntroOutroConfig( enabled=True, outro_type="video", outro_video_path="/a.mp4", ) assert config.has_outro is True def test_text_outro_has_outro(self): """文字片尾有has_outro.""" config = IntroOutroConfig( enabled=True, outro_type="text", outro_title="test", ) assert config.has_outro is True def test_follow_outro_has_outro(self): """follow类型片尾有has_outro.""" config = IntroOutroConfig( enabled=True, outro_type="follow", outro_title="test", ) assert config.has_outro is True class TestValidate: """validate 配置校验测试.""" def test_disabled_valid(self): """禁用配置合法.""" config = IntroOutroConfig() ok, msg = config.validate() assert ok is True assert msg == "" def test_video_intro_missing_path(self): """视频片头缺少路径.""" config = IntroOutroConfig( enabled=True, intro_type="video", intro_video_path="", ) ok, msg = config.validate() assert ok is False assert "video_path" in msg def test_text_intro_missing_title(self): """文字片头缺少标题.""" config = IntroOutroConfig( enabled=True, intro_type="text", intro_title="", ) ok, msg = config.validate() assert ok is False assert "title" in msg def test_video_outro_missing_path(self): """视频片尾缺少路径.""" config = IntroOutroConfig( enabled=True, outro_type="video", outro_video_path="", ) ok, msg = config.validate() assert ok is False assert "video_path" in msg def test_text_outro_missing_title(self): """文字片尾缺少标题.""" config = IntroOutroConfig( enabled=True, outro_type="text", outro_title="", ) ok, msg = config.validate() assert ok is False assert "title" in msg def test_zero_intro_duration_invalid(self): """片头时长为0无效.""" config = IntroOutroConfig( enabled=True, intro_type="text", intro_title="test", intro_duration=0, ) ok, msg = config.validate() assert ok is False assert "时长" in msg def test_negative_outro_duration_invalid(self): """片尾时长为负无效.""" config = IntroOutroConfig( enabled=True, outro_type="text", outro_title="test", outro_duration=-1.0, ) ok, msg = config.validate() assert ok is False assert "时长" in msg def test_valid_text_both(self): """文字片头片尾都合法.""" config = IntroOutroConfig( enabled=True, intro_type="text", intro_title="片头", intro_duration=3.0, outro_type="text", outro_title="片尾", outro_duration=3.0, ) ok, msg = config.validate() assert ok is True