"""EditPlanClip 剪辑计划片段领域实体单测.""" import pytest from packages.domain.edit_plan_clip import EditPlanClip, EditPlanClipStatus class TestEditPlanClipStatus: def test_values(self): assert EditPlanClipStatus.PENDING.value == "pending" assert EditPlanClipStatus.READY.value == "ready" assert EditPlanClipStatus.RENDERED.value == "rendered" assert EditPlanClipStatus.FAILED.value == "failed" class TestEditPlanClipCreate: def test_create_normal(self): clip = EditPlanClip.create( plan_id="plan1", clip_type="video", order=1, start_time=0.0, duration=5.0, ) assert clip.id assert clip.plan_id == "plan1" assert clip.clip_type == "video" assert clip.order == 1 assert clip.status == EditPlanClipStatus.PENDING assert clip.start_time == 0.0 assert clip.duration == 5.0 assert clip.playback_speed == 1.0 assert clip.config == {} def test_create_empty_plan_id_raises(self): with pytest.raises(ValueError, match="plan_id 不能为空"): EditPlanClip.create(plan_id="", clip_type="video", order=1) def test_create_empty_clip_type_raises(self): with pytest.raises(ValueError, match="clip_type 不能为空"): EditPlanClip.create(plan_id="p1", clip_type="", order=1) def test_create_negative_start_time_raises(self): with pytest.raises(ValueError, match="start_time 不能为负数"): EditPlanClip.create(plan_id="p1", clip_type="v", order=1, start_time=-1.0) def test_create_negative_duration_raises(self): with pytest.raises(ValueError, match="duration 不能为负数"): EditPlanClip.create(plan_id="p1", clip_type="v", order=1, duration=-1.0) def test_create_strips_strings(self): clip = EditPlanClip.create( plan_id=" plan1 ", clip_type=" video ", order=1, template_clip_config_id=" cfg1 ", asset_id=" a1 ", text_content=" 你好 ", transition_effect=" fade ", ) assert clip.plan_id == "plan1" assert clip.clip_type == "video" assert clip.template_clip_config_id == "cfg1" assert clip.asset_id == "a1" assert clip.text_content == "你好" assert clip.transition_effect == "fade" def test_create_empty_transition_effect_defaults_to_cut(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1, transition_effect="") assert clip.transition_effect == "cut" def test_create_playback_speed_zero_defaults_to_1(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1, playback_speed=0) assert clip.playback_speed == 1.0 def test_create_playback_speed_negative_defaults_to_1(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1, playback_speed=-1.0) assert clip.playback_speed == 1.0 def test_create_playback_speed_below_min_clamped(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1, playback_speed=0.1) assert clip.playback_speed == 0.25 def test_create_playback_speed_above_max_clamped(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1, playback_speed=5.0) assert clip.playback_speed == 4.0 def test_create_playback_speed_within_range(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1, playback_speed=1.5) assert clip.playback_speed == 1.5 def test_create_transition_duration_negative_clamped(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1, transition_duration=-0.5) assert clip.transition_duration == 0.0 def test_create_none_config_defaults_to_empty(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1, config=None) assert clip.config == {} def test_create_unique_ids(self): c1 = EditPlanClip.create(plan_id="p1", clip_type="v", order=1) c2 = EditPlanClip.create(plan_id="p1", clip_type="v", order=2) assert c1.id != c2.id class TestEditPlanClipStateTransitions: def test_pending_to_ready(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1) clip.mark_ready() assert clip.status == EditPlanClipStatus.READY def test_ready_to_rendered(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1) clip.mark_ready() clip.mark_rendered() assert clip.status == EditPlanClipStatus.RENDERED def test_ready_to_failed(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1) clip.mark_ready() clip.mark_failed() assert clip.status == EditPlanClipStatus.FAILED def test_ready_mark_ready_raises(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1) clip.mark_ready() with pytest.raises(ValueError, match="只有 pending 状态的片段可以标记就绪"): clip.mark_ready() def test_pending_mark_rendered_raises(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1) with pytest.raises(ValueError, match="只有 ready 状态的片段可以标记已渲染"): clip.mark_rendered() def test_pending_mark_failed_raises(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1) with pytest.raises(ValueError, match="只有 ready 状态的片段可以标记失败"): clip.mark_failed() class TestEditPlanClipProperties: def test_end_time(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1, start_time=10.0, duration=5.0) assert clip.end_time == 15.0 def test_end_time_zero_duration(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1, start_time=5.0, duration=0.0) assert clip.end_time == 5.0 def test_has_asset_true(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1, asset_id="a1") assert clip.has_asset is True def test_has_asset_false(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1) assert clip.has_asset is False def test_has_asset_empty_string(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1, asset_id="") assert clip.has_asset is False class TestEditPlanClipAssignAsset: def test_assign_asset(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1) clip.assign_asset("asset1") assert clip.asset_id == "asset1" def test_assign_asset_strips(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1) clip.assign_asset(" asset1 ") assert clip.asset_id == "asset1" def test_assign_asset_empty_raises(self): clip = EditPlanClip.create(plan_id="p1", clip_type="v", order=1) with pytest.raises(ValueError, match="asset_id 不能为空"): clip.assign_asset("")