"""剪辑计划领域模型单元测试.""" from __future__ import annotations from datetime import datetime, timezone import pytest from packages.domain.edit_plan import EditPlan, EditPlanStatus class TestEditPlanStatus: """EditPlanStatus 枚举测试.""" def test_status_values(self): assert EditPlanStatus.DRAFT.value == "draft" assert EditPlanStatus.EDITING.value == "editing" assert EditPlanStatus.RENDERING.value == "rendering" assert EditPlanStatus.COMPLETED.value == "completed" assert EditPlanStatus.FAILED.value == "failed" def test_status_is_str(self): assert isinstance(EditPlanStatus.DRAFT, str) assert EditPlanStatus.DRAFT == "draft" class TestEditPlanCreate: """创建剪辑计划测试.""" def test_create_basic(self): plan = EditPlan.create(template_id="tpl_001", name="测试计划") assert plan.id assert len(plan.id) == 32 # uuid4 hex assert plan.template_id == "tpl_001" assert plan.name == "测试计划" assert plan.status == EditPlanStatus.DRAFT assert plan.total_duration == 0.0 assert plan.config == {} assert plan.source_edit_plan_id == "" assert plan.project_id == "" assert plan.created_by_user_id == "" def test_create_with_all_fields(self): plan = EditPlan.create( template_id="tpl_001", name="完整测试计划", config={"key": "value"}, total_duration=60.5, source_edit_plan_id="src_001", project_id="proj_001", created_by_user_id="user_001", ) assert plan.name == "完整测试计划" assert plan.total_duration == 60.5 assert plan.config == {"key": "value"} assert plan.source_edit_plan_id == "src_001" assert plan.project_id == "proj_001" assert plan.created_by_user_id == "user_001" def test_create_empty_name_raises(self): with pytest.raises(ValueError, match="名称不能为空"): EditPlan.create(template_id="tpl_001", name="") def test_create_whitespace_name_raises(self): with pytest.raises(ValueError, match="名称不能为空"): EditPlan.create(template_id="tpl_001", name=" ") def test_create_empty_template_id_raises(self): with pytest.raises(ValueError, match="template_id 不能为空"): EditPlan.create(template_id="", name="测试") def test_create_whitespace_template_id_raises(self): with pytest.raises(ValueError, match="template_id 不能为空"): EditPlan.create(template_id=" ", name="测试") def test_create_name_stripped(self): plan = EditPlan.create(template_id="tpl_001", name=" 我的计划 ") assert plan.name == "我的计划" def test_create_template_id_stripped(self): plan = EditPlan.create(template_id=" tpl_001 ", name="测试") assert plan.template_id == "tpl_001" def test_create_timestamps_set(self): before = datetime.now(timezone.utc) plan = EditPlan.create(template_id="tpl_001", name="测试") after = datetime.now(timezone.utc) assert before <= plan.created_at <= after assert before <= plan.updated_at <= after def test_create_config_none_defaults_to_empty(self): plan = EditPlan.create(template_id="tpl_001", name="测试", config=None) assert plan.config == {} class TestEditPlanStateMachine: """状态机流转测试.""" def _make_plan(self, status: EditPlanStatus) -> EditPlan: return EditPlan( id="test_id", template_id="tpl_001", name="测试计划", status=status, ) def test_draft_to_editing(self): plan = self._make_plan(EditPlanStatus.DRAFT) plan.start_editing() assert plan.status == EditPlanStatus.EDITING assert plan.updated_at > plan.created_at def test_editing_to_rendering(self): plan = self._make_plan(EditPlanStatus.EDITING) plan.start_rendering() assert plan.status == EditPlanStatus.RENDERING def test_rendering_to_completed(self): plan = self._make_plan(EditPlanStatus.RENDERING) plan.mark_completed() assert plan.status == EditPlanStatus.COMPLETED def test_rendering_to_failed(self): plan = self._make_plan(EditPlanStatus.RENDERING) plan.mark_failed() assert plan.status == EditPlanStatus.FAILED def test_completed_to_editing_resume(self): plan = self._make_plan(EditPlanStatus.COMPLETED) plan.resume_editing() assert plan.status == EditPlanStatus.EDITING def test_failed_to_editing_resume(self): plan = self._make_plan(EditPlanStatus.FAILED) plan.resume_editing() assert plan.status == EditPlanStatus.EDITING def test_failed_to_draft_reset(self): plan = self._make_plan(EditPlanStatus.FAILED) plan.reset_to_draft() assert plan.status == EditPlanStatus.DRAFT def test_invalid_start_editing_from_editing(self): plan = self._make_plan(EditPlanStatus.EDITING) with pytest.raises(ValueError, match="只有 draft 状态"): plan.start_editing() def test_invalid_start_editing_from_rendering(self): plan = self._make_plan(EditPlanStatus.RENDERING) with pytest.raises(ValueError): plan.start_editing() def test_invalid_start_rendering_from_draft(self): plan = self._make_plan(EditPlanStatus.DRAFT) with pytest.raises(ValueError, match="只有 editing 状态"): plan.start_rendering() def test_invalid_start_rendering_from_completed(self): plan = self._make_plan(EditPlanStatus.COMPLETED) with pytest.raises(ValueError): plan.start_rendering() def test_invalid_mark_completed_from_draft(self): plan = self._make_plan(EditPlanStatus.DRAFT) with pytest.raises(ValueError, match="只有 rendering 状态"): plan.mark_completed() def test_invalid_mark_failed_from_editing(self): plan = self._make_plan(EditPlanStatus.EDITING) with pytest.raises(ValueError): plan.mark_failed() def test_invalid_resume_editing_from_draft(self): plan = self._make_plan(EditPlanStatus.DRAFT) with pytest.raises(ValueError, match="只有 completed/failed 状态"): plan.resume_editing() def test_invalid_resume_editing_from_rendering(self): plan = self._make_plan(EditPlanStatus.RENDERING) with pytest.raises(ValueError): plan.resume_editing() def test_invalid_reset_to_draft_from_draft(self): plan = self._make_plan(EditPlanStatus.DRAFT) with pytest.raises(ValueError, match="只有 failed 状态"): plan.reset_to_draft() def test_invalid_reset_to_draft_from_completed(self): plan = self._make_plan(EditPlanStatus.COMPLETED) with pytest.raises(ValueError): plan.reset_to_draft() def test_state_transition_updates_updated_at(self): plan = self._make_plan(EditPlanStatus.DRAFT) old_updated = plan.updated_at plan.start_editing() assert plan.updated_at >= old_updated class TestEditPlanDataclass: """数据类属性测试.""" def test_slots_prevents_dynamic_attributes(self): plan = EditPlan(id="1", template_id="t1", name="test") with pytest.raises(AttributeError): plan.new_field = "value" def test_full_flow_draft_editing_rendering_completed(self): """完整流程:草稿 → 编辑 → 渲染 → 完成.""" plan = EditPlan.create(template_id="tpl_001", name="完整流程") assert plan.status == EditPlanStatus.DRAFT plan.start_editing() assert plan.status == EditPlanStatus.EDITING plan.start_rendering() assert plan.status == EditPlanStatus.RENDERING plan.mark_completed() assert plan.status == EditPlanStatus.COMPLETED def test_full_flow_draft_editing_rendering_failed_reset(self): """完整流程:草稿 → 编辑 → 渲染 → 失败 → 重置 → 编辑 → 渲染 → 完成.""" plan = EditPlan.create(template_id="tpl_001", name="失败重试流程") plan.start_editing() plan.start_rendering() plan.mark_failed() assert plan.status == EditPlanStatus.FAILED plan.reset_to_draft() assert plan.status == EditPlanStatus.DRAFT plan.start_editing() plan.start_rendering() plan.mark_completed() assert plan.status == EditPlanStatus.COMPLETED