Compare commits

...

1 Commits

Author SHA1 Message Date
AI Bot 5072a43274 test(wave127): template_version+数据类单测 +30
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 7s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m7s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 1m32s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m7s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 1m30s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m54s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 26s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 1m23s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m25s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 38s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m1s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 0s
CI/CD Pipeline / Integration Tests (pull_request) Failing after 0s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 1s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 17m41s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 32s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
覆盖EditTemplateVersion/Template/Recipe/TitleLibrary/VoiceLibrary
2026-07-27 18:24:09 +08:00
@@ -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 == ["温柔", "女声"]