diff --git a/tests/unit/test_template_and_data_modules.py b/tests/unit/test_template_and_data_modules.py new file mode 100644 index 000000000..7882e98ad --- /dev/null +++ b/tests/unit/test_template_and_data_modules.py @@ -0,0 +1,273 @@ +"""EditTemplateVersion + 数据类 domain 模块单测.""" + +from __future__ import annotations + +import pytest + +from packages.domain.recipe import Recipe, RecipeItem +from packages.domain.template import Template, TemplateCategory, TemplateSegment +from packages.domain.template_version import EditTemplateVersion +from packages.domain.title_library import TitleLibraryItem +from packages.domain.voice_library import VoiceLibraryItem + + +# ── EditTemplateVersion ──────────────────────────────────────────────────── + + +class TestEditTemplateVersion: + def test_create_basic(self): + v = EditTemplateVersion.create(template_id="t1", version=1) + assert v.id + assert v.template_id == "t1" + assert v.version == 1 + assert v.name == "" + assert v.editing_mode == "one_take" + assert v.config == {} + assert v.clip_configs == [] + assert v.change_note == "" + assert v.published_by == "" + + def test_create_with_name(self): + v = EditTemplateVersion.create(template_id="t1", version=1, name="v1.0 初版") + assert v.name == "v1.0 初版" + + def test_create_with_editing_mode(self): + v = EditTemplateVersion.create(template_id="t1", version=1, editing_mode="pip") + assert v.editing_mode == "pip" + + def test_create_with_config(self): + config = {"bgm": {"volume": 0.5}} + v = EditTemplateVersion.create(template_id="t1", version=1, config=config) + assert v.config == config + + def test_create_config_none_defaults_empty(self): + v = EditTemplateVersion.create(template_id="t1", version=1, config=None) + assert v.config == {} + + def test_create_with_clip_configs(self): + clips = [{"type": "intro"}, {"type": "main"}] + v = EditTemplateVersion.create(template_id="t1", version=1, clip_configs=clips) + assert v.clip_configs == clips + + def test_create_clip_configs_none_defaults_empty(self): + v = EditTemplateVersion.create(template_id="t1", version=1, clip_configs=None) + assert v.clip_configs == [] + + def test_create_with_change_note(self): + v = EditTemplateVersion.create( + template_id="t1", version=2, + change_note="修复时长计算问题", + ) + assert v.change_note == "修复时长计算问题" + + def test_create_with_published_by(self): + v = EditTemplateVersion.create(template_id="t1", version=1, published_by="user1") + assert v.published_by == "user1" + + def test_created_at_auto_set(self): + v = EditTemplateVersion.create(template_id="t1", version=1) + assert v.created_at is not None + + def test_unique_ids(self): + v1 = EditTemplateVersion.create(template_id="t1", version=1) + v2 = EditTemplateVersion.create(template_id="t1", version=2) + assert v1.id != v2.id + + def test_version_integer(self): + v = EditTemplateVersion.create(template_id="t1", version=5) + assert v.version == 5 + + +# ── Template / TemplateSegment / TemplateCategory ───────────────────────── + + +class TestTemplate: + def test_template_defaults(self): + t = Template(id="t1", user_id="u1", name="我的模板", mode="pip") + assert t.id == "t1" + assert t.user_id == "u1" + assert t.name == "我的模板" + assert t.mode == "pip" + assert t.category == "" + assert t.tags == [] + assert t.title_config == {} + assert t.subtitle_config == {} + assert t.bgm_config == {} + assert t.estimated_duration == 0.0 + assert t.segments == [] + assert t.is_active is True + assert t.created_at is not None + assert t.updated_at is not None + + def test_template_with_segments(self): + seg = TemplateSegment( + id="s1", template_id="t1", segment_order=0, + duration_min=2.0, duration_max=5.0, + ) + t = Template(id="t1", user_id="u1", name="T1", mode="pip", segments=[seg]) + assert len(t.segments) == 1 + assert t.segments[0].id == "s1" + + def test_template_with_tags(self): + t = Template(id="t1", user_id="u1", name="T1", mode="pip", tags=["旅行", "美食"]) + assert t.tags == ["旅行", "美食"] + + def test_template_segment_defaults(self): + seg = TemplateSegment( + id="s1", template_id="t1", segment_order=0, + duration_min=1.0, duration_max=3.0, + ) + assert seg.material_type is None + assert seg.created_at is not None + + def test_template_segment_with_material_type(self): + seg = TemplateSegment( + id="s1", template_id="t1", segment_order=0, + duration_min=1.0, duration_max=3.0, + material_type="人物", + ) + assert seg.material_type == "人物" + + def test_template_category(self): + cat = TemplateCategory(id="c1", user_id="u1", name="旅行vlog") + assert cat.id == "c1" + assert cat.user_id == "u1" + assert cat.name == "旅行vlog" + assert cat.created_at is not None + + +# ── Recipe ───────────────────────────────────────────────────────────────── + + +class TestRecipe: + def test_recipe_defaults(self): + r = Recipe(id="r1", user_id="u1", name="一键旅行") + assert r.id == "r1" + assert r.user_id == "u1" + assert r.name == "一键旅行" + assert r.description == "" + assert r.template_id == "" + assert r.generation_params == {} + assert r.items == [] + assert r.is_active is True + assert r.metadata_ == {} + assert r.created_at is not None + assert r.updated_at is not None + + def test_recipe_with_items(self): + item = RecipeItem( + id="i1", recipe_id="r1", + item_type="asset", item_id="asset_1", position=0, + ) + r = Recipe(id="r1", user_id="u1", name="R1", items=[item]) + assert len(r.items) == 1 + assert r.items[0].item_type == "asset" + + def test_recipe_item_defaults(self): + item = RecipeItem(id="i1", recipe_id="r1", item_type="title", item_id="t1") + assert item.position == 0 + assert item.metadata_ == {} + + def test_recipe_item_with_metadata(self): + item = RecipeItem( + id="i1", recipe_id="r1", item_type="voice", item_id="v1", + position=2, metadata_={"speed": 1.2}, + ) + assert item.position == 2 + assert item.metadata_ == {"speed": 1.2} + + +# ── TitleLibraryItem ─────────────────────────────────────────────────────── + + +class TestTitleLibraryItem: + def test_defaults(self): + item = TitleLibraryItem( + id="t1", user_id="u1", name="标题1", text="欢迎收看", + ) + assert item.id == "t1" + assert item.user_id == "u1" + assert item.name == "标题1" + assert item.text == "欢迎收看" + assert item.category == "default" + assert item.description == "" + assert item.tags == [] + assert item.usage_count == 0 + assert item.is_active is True + assert item.metadata_ == {} + assert item.created_at is not None + assert item.updated_at is not None + + def test_with_category(self): + item = TitleLibraryItem( + id="t1", user_id="u1", name="t1", text="txt", + category="opening", + ) + assert item.category == "opening" + + def test_with_tags(self): + item = TitleLibraryItem( + id="t1", user_id="u1", name="t1", text="txt", + tags=["搞笑", "热门"], + ) + assert item.tags == ["搞笑", "热门"] + + def test_with_usage_count(self): + item = TitleLibraryItem( + id="t1", user_id="u1", name="t1", text="txt", + usage_count=42, + ) + assert item.usage_count == 42 + + +# ── VoiceLibraryItem ─────────────────────────────────────────────────────── + + +class TestVoiceLibraryItem: + def test_defaults(self): + item = VoiceLibraryItem( + id="v1", user_id="u1", name="温柔女声", + ) + assert item.id == "v1" + assert item.user_id == "u1" + assert item.name == "温柔女声" + assert item.text == "" + assert item.voice_provider == "" + assert item.voice_id == "" + assert item.voice_name == "" + assert item.audio_url == "" + assert item.duration == 0 + assert item.file_size == 0 + assert item.status == "completed" + assert item.project_id is None + assert item.tags == [] + assert item.metadata_ == {} + assert item.created_at is not None + assert item.updated_at is not None + + def test_with_voice_info(self): + item = VoiceLibraryItem( + id="v1", user_id="u1", name="v1", + voice_provider="cosyvoice", voice_id="voice_001", voice_name="小溪", + audio_url="https://example.com/audio.mp3", + duration=15.5, file_size=320000, + ) + assert item.voice_provider == "cosyvoice" + assert item.voice_id == "voice_001" + assert item.voice_name == "小溪" + assert item.duration == 15.5 + assert item.file_size == 320000 + + def test_with_project_id(self): + item = VoiceLibraryItem( + id="v1", user_id="u1", name="v1", + project_id="proj_123", + ) + assert item.project_id == "proj_123" + + def test_with_tags(self): + item = VoiceLibraryItem( + id="v1", user_id="u1", name="v1", + tags=["温柔", "女声"], + ) + assert item.tags == ["温柔", "女声"]