214 lines
7.3 KiB
Python
214 lines
7.3 KiB
Python
"""Unit tests for Phase 8 EditTemplate and EditPlan domain entities + repositories."""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "apps" / "api"))
|
|
|
|
import logging
|
|
|
|
from sqlalchemy import create_engine
|
|
from sqlalchemy.orm import sessionmaker
|
|
|
|
from packages.adapters.sqlalchemy_impl.edit_plan_repository import (
|
|
SQLAlchemyEditPlanRepository,
|
|
)
|
|
from packages.adapters.sqlalchemy_impl.edit_template_repository import (
|
|
SQLAlchemyEditTemplateRepository,
|
|
)
|
|
from packages.adapters.sqlalchemy_impl.models import Base
|
|
from packages.domain.edit_plan import EditPlan, EditPlanStatus
|
|
from packages.domain.edit_template import EditTemplate, EditTemplateStatus
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
# ── EditTemplate 领域实体测试 ──────────────────────────────────────────
|
|
|
|
|
|
class TestEditTemplate:
|
|
def test_create_success(self):
|
|
t = EditTemplate.create("vlog模板", description="日常vlog", template_type="vlog")
|
|
assert t.name == "vlog模板"
|
|
assert t.description == "日常vlog"
|
|
assert t.template_type == "vlog"
|
|
assert t.status == EditTemplateStatus.ACTIVE
|
|
assert t.config == {}
|
|
assert t.sort_weight == 0
|
|
assert t.id # 自动生成
|
|
|
|
def test_create_strips_whitespace(self):
|
|
t = EditTemplate.create(" 模板 ")
|
|
assert t.name == "模板"
|
|
|
|
def test_create_empty_name_raises(self):
|
|
try:
|
|
EditTemplate.create(" ")
|
|
raise AssertionError("应该抛出 ValueError")
|
|
except ValueError as e:
|
|
assert "模板名称不能为空" in str(e)
|
|
|
|
def test_activate_deactivate(self):
|
|
t = EditTemplate.create("test")
|
|
assert t.is_active is True
|
|
t.deactivate()
|
|
assert t.is_active is False
|
|
assert t.status == EditTemplateStatus.INACTIVE
|
|
t.activate()
|
|
assert t.is_active is True
|
|
assert t.status == EditTemplateStatus.ACTIVE
|
|
|
|
|
|
# ── EditPlan 领域实体测试 ──────────────────────────────────────────────
|
|
|
|
|
|
class TestEditPlan:
|
|
def test_create_success(self):
|
|
p = EditPlan.create("tpl-1", "我的计划", config={"bgm": "happy"})
|
|
assert p.template_id == "tpl-1"
|
|
assert p.name == "我的计划"
|
|
assert p.status == EditPlanStatus.DRAFT
|
|
assert p.config == {"bgm": "happy"}
|
|
assert p.total_duration == 0.0
|
|
|
|
def test_create_empty_name_raises(self):
|
|
try:
|
|
EditPlan.create("tpl-1", " ")
|
|
raise AssertionError("应该抛出 ValueError")
|
|
except ValueError as e:
|
|
assert "计划名称不能为空" in str(e)
|
|
|
|
def test_create_empty_template_id_raises(self):
|
|
try:
|
|
EditPlan.create(" ", "test")
|
|
raise AssertionError("应该抛出 ValueError")
|
|
except ValueError as e:
|
|
assert "template_id 不能为空" in str(e)
|
|
|
|
def test_status_transitions_happy_path(self):
|
|
p = EditPlan.create("tpl-1", "test")
|
|
assert p.status == EditPlanStatus.DRAFT
|
|
|
|
p.start_editing()
|
|
assert p.status == EditPlanStatus.EDITING
|
|
|
|
p.start_rendering()
|
|
assert p.status == EditPlanStatus.RENDERING
|
|
|
|
p.mark_completed()
|
|
assert p.status == EditPlanStatus.COMPLETED
|
|
|
|
def test_status_transitions_failure_path(self):
|
|
p = EditPlan.create("tpl-1", "test")
|
|
p.start_editing()
|
|
p.start_rendering()
|
|
p.mark_failed()
|
|
assert p.status == EditPlanStatus.FAILED
|
|
|
|
p.reset_to_draft()
|
|
assert p.status == EditPlanStatus.DRAFT
|
|
|
|
def test_invalid_transition_raises(self):
|
|
p = EditPlan.create("tpl-1", "test")
|
|
try:
|
|
p.start_rendering() # draft → rendering 不合法
|
|
raise AssertionError("应该抛出 ValueError")
|
|
except ValueError as e:
|
|
logger.warning(f"Operation failed in tests/unit/test_phase8_edit_models.py: {e}", exc_info=True)
|
|
|
|
def test_mark_completed_from_non_rendering_raises(self):
|
|
p = EditPlan.create("tpl-1", "test")
|
|
try:
|
|
p.mark_completed() # draft → completed 不合法
|
|
raise AssertionError("应该抛出 ValueError")
|
|
except ValueError as e:
|
|
logger.warning(f"Operation failed in tests/unit/test_phase8_edit_models.py: {e}", exc_info=True)
|
|
|
|
def test_reset_from_non_failed_raises(self):
|
|
p = EditPlan.create("tpl-1", "test")
|
|
try:
|
|
p.reset_to_draft() # draft → draft 不合法
|
|
raise AssertionError("应该抛出 ValueError")
|
|
except ValueError as e:
|
|
logger.warning(f"Operation failed in tests/unit/test_phase8_edit_models.py: {e}", exc_info=True)
|
|
|
|
|
|
# ── Repository 集成测试(内存 SQLite) ─────────────────────────────────
|
|
|
|
|
|
class TestRepositories:
|
|
def _make_session(self):
|
|
engine = create_engine("sqlite:///:memory:")
|
|
Base.metadata.create_all(engine)
|
|
SessionLocal = sessionmaker(bind=engine)
|
|
return SessionLocal()
|
|
|
|
def test_edit_template_repository_crud(self):
|
|
session = self._make_session()
|
|
try:
|
|
repo = SQLAlchemyEditTemplateRepository(session)
|
|
|
|
t = EditTemplate.create("模板A", description="测试模板")
|
|
repo.create(t)
|
|
|
|
fetched = repo.get(t.id)
|
|
assert fetched is not None
|
|
assert fetched.name == "模板A"
|
|
assert fetched.description == "测试模板"
|
|
|
|
# list
|
|
active = repo.list_active()
|
|
assert len(active) == 1
|
|
assert active[0].id == t.id
|
|
|
|
# update
|
|
fetched.deactivate()
|
|
repo.update(fetched)
|
|
assert repo.get(t.id).status == EditTemplateStatus.INACTIVE
|
|
assert len(repo.list_active()) == 0
|
|
|
|
# count
|
|
assert repo.count() == 1
|
|
|
|
# delete
|
|
assert repo.delete(t.id) is True
|
|
assert repo.get(t.id) is None
|
|
assert repo.count() == 0
|
|
finally:
|
|
session.close()
|
|
|
|
def test_edit_plan_repository_crud(self):
|
|
session = self._make_session()
|
|
try:
|
|
repo = SQLAlchemyEditPlanRepository(session)
|
|
|
|
p = EditPlan.create("tpl-1", "计划A", config={"key": "val"})
|
|
repo.create(p)
|
|
|
|
fetched = repo.get(p.id)
|
|
assert fetched is not None
|
|
assert fetched.name == "计划A"
|
|
assert fetched.config == {"key": "val"}
|
|
assert fetched.status == EditPlanStatus.DRAFT
|
|
|
|
# list_by_template
|
|
plans = repo.list_by_template("tpl-1")
|
|
assert len(plans) == 1
|
|
|
|
# update status
|
|
fetched.start_editing()
|
|
repo.update(fetched)
|
|
editing = repo.list_by_template("tpl-1", status=EditPlanStatus.EDITING)
|
|
assert len(editing) == 1
|
|
|
|
# count
|
|
assert repo.count() == 1
|
|
assert repo.count(status=EditPlanStatus.EDITING) == 1
|
|
assert repo.count(status=EditPlanStatus.DRAFT) == 0
|
|
|
|
# delete
|
|
assert repo.delete(p.id) is True
|
|
assert repo.get(p.id) is None
|
|
finally:
|
|
session.close()
|