"""Tests for preview title_config feature. 验证预览 API 的 title_config 字段和 Worker 的标题配置解析逻辑。 """ from __future__ import annotations import json import pytest class TestPreviewTitleConfigSchema: """测试 CreatePreviewGenerationTaskRequest 的 title_config 字段.""" def test_title_config_default_empty(self): """title_config 默认为空 dict.""" from app.schemas.generation_task import CreatePreviewGenerationTaskRequest req = CreatePreviewGenerationTaskRequest( template_id="test_template", asset_ids=["asset1"], ) assert req.title_config == {} def test_title_config_with_text(self): """传入标题文本.""" from app.schemas.generation_task import CreatePreviewGenerationTaskRequest req = CreatePreviewGenerationTaskRequest( template_id="test_template", asset_ids=["asset1"], title_config={"text": "测试标题"}, ) assert req.title_config["text"] == "测试标题" def test_title_config_with_full_style(self): """传入完整标题样式配置.""" from app.schemas.generation_task import CreatePreviewGenerationTaskRequest config = { "text": "我的视频标题", "font": "思源黑体", "font_size": 48, "font_color": "#ffffff", "position": "top", "bold": True, "stroke": 2, "shadow": True, } req = CreatePreviewGenerationTaskRequest( template_id="test_template", asset_ids=["asset1"], title_config=config, ) assert req.title_config["text"] == "我的视频标题" assert req.title_config["font_size"] == 48 assert req.title_config["position"] == "top" class TestCommandTitleConfig: """测试 CreateGenerationTaskCommand 的 title_config 字段.""" def test_command_has_title_config(self): """Command 包含 title_config 字段.""" from packages.application.generation_tasks import CreateGenerationTaskCommand cmd = CreateGenerationTaskCommand( title_config={"text": "hello", "font_size": 32}, ) assert cmd.title_config["text"] == "hello" assert cmd.title_config["font_size"] == 32 def test_command_title_config_default_empty(self): """Command 的 title_config 默认为空 dict.""" from packages.application.generation_tasks import CreateGenerationTaskCommand cmd = CreateGenerationTaskCommand() assert cmd.title_config == {} class TestWorkerTitleConfigParsing: """测试 Worker 渲染时的标题配置解析逻辑.""" def test_json_format_parsing(self): """JSON 格式的 custom_title 能正确解析.""" config = {"text": "测试标题", "font_size": 48, "font_color": "#ff0000"} custom_title = json.dumps(config, ensure_ascii=False) ct_stripped = custom_title.strip() parsed = None if ct_stripped.startswith("{"): try: parsed = json.loads(ct_stripped) except (json.JSONDecodeError, ValueError): parsed = None assert parsed is not None assert parsed["text"] == "测试标题" assert parsed["font_size"] == 48 def test_plain_text_fallback(self): """纯文本的 custom_title 不触发 JSON 解析.""" custom_title = "简单的标题文字" ct_stripped = custom_title.strip() parsed = None if ct_stripped.startswith("{"): try: parsed = json.loads(ct_stripped) except (json.JSONDecodeError, ValueError): parsed = None assert parsed is None def test_invalid_json_fallback(self): """无效 JSON 的 custom_title 降级为纯文本.""" custom_title = "{invalid json" ct_stripped = custom_title.strip() parsed = None if ct_stripped.startswith("{"): try: parsed = json.loads(ct_stripped) except (json.JSONDecodeError, ValueError): parsed = None assert parsed is None def test_json_without_text_skipped(self): """JSON 格式但缺少 text 字段时,跳过标题注入.""" config = {"font_size": 48} custom_title = json.dumps(config, ensure_ascii=False) ct_stripped = custom_title.strip() parsed = json.loads(ct_stripped) title_text = (parsed.get("text") or "").strip() assert title_text == "" def test_style_key_mapping(self): """前端字段名正确映射到 ASS 字段名.""" config = { "text": "标题", "font_size": 48, "font_color": "#ffffff", "font_preset": "思源黑体", } style_keys = ["font", "font_size", "font_color", "position", "bold", "stroke", "shadow", "font_preset"] title_cfg = {} for key in style_keys: if key in config and config[key] is not None: mapped_key = { "font_size": "size", "font_color": "color", "font_preset": "font", }.get(key, key) title_cfg[mapped_key] = config[key] assert title_cfg["size"] == 48 assert title_cfg["color"] == "#ffffff" assert title_cfg["font"] == "思源黑体" class TestPreviewRouteTitleConfigPassing: """测试预览路由正确序列化 title_config 到 custom_title.""" def test_title_config_serialization(self): """title_config 序列化为 JSON 字符串.""" title_config = { "text": "我的标题", "font_size": 32, "font_color": "#d4a843", } serialized = json.dumps(title_config, ensure_ascii=False) parsed = json.loads(serialized) assert parsed["text"] == "我的标题" assert parsed["font_size"] == 32 def test_empty_title_config_produces_empty_string(self): """空 title_config 时 custom_title 为空字符串.""" title_config = {} title_text = (title_config.get("text") or "").strip() custom_title_value = "" if title_text: custom_title_value = json.dumps(title_config, ensure_ascii=False) assert custom_title_value == ""