348 lines
10 KiB
Python
348 lines
10 KiB
Python
"""template_clip_config 单测.
|
|
|
|
domain 层模板片段配置纯逻辑模块,0 外部依赖。
|
|
覆盖:ClipType枚举、TransitionEffect枚举、create工厂/校验、计算属性。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from packages.domain.template_clip_config import (
|
|
ClipType,
|
|
TemplateClipConfig,
|
|
TransitionEffect,
|
|
)
|
|
|
|
|
|
class TestClipType:
|
|
"""ClipType 枚举测试."""
|
|
|
|
def test_six_types(self):
|
|
"""六种片段类型."""
|
|
assert len(ClipType) == 6
|
|
|
|
def test_intro(self):
|
|
assert ClipType.INTRO == "intro"
|
|
|
|
def test_main(self):
|
|
assert ClipType.MAIN == "main"
|
|
|
|
def test_transition(self):
|
|
assert ClipType.TRANSITION == "transition"
|
|
|
|
def test_outro(self):
|
|
assert ClipType.OUTRO == "outro"
|
|
|
|
def test_title(self):
|
|
assert ClipType.TITLE == "title"
|
|
|
|
def test_subtitle(self):
|
|
assert ClipType.SUBTITLE == "subtitle"
|
|
|
|
def test_from_string(self):
|
|
"""可从字符串构造."""
|
|
assert ClipType("main") == ClipType.MAIN
|
|
assert ClipType("intro") == ClipType.INTRO
|
|
|
|
|
|
class TestTransitionEffect:
|
|
"""TransitionEffect 枚举测试."""
|
|
|
|
def test_six_effects(self):
|
|
"""六种转场效果."""
|
|
assert len(TransitionEffect) == 6
|
|
|
|
def test_cut(self):
|
|
assert TransitionEffect.CUT == "cut"
|
|
|
|
def test_fade(self):
|
|
assert TransitionEffect.FADE == "fade"
|
|
|
|
def test_slide_left(self):
|
|
assert TransitionEffect.SLIDE_LEFT == "slide_left"
|
|
|
|
def test_slide_right(self):
|
|
assert TransitionEffect.SLIDE_RIGHT == "slide_right"
|
|
|
|
def test_dissolve(self):
|
|
assert TransitionEffect.DISSOLVE == "dissolve"
|
|
|
|
def test_wipe(self):
|
|
assert TransitionEffect.WIPE == "wipe"
|
|
|
|
def test_from_string(self):
|
|
"""可从字符串构造."""
|
|
assert TransitionEffect("fade") == TransitionEffect.FADE
|
|
assert TransitionEffect("cut") == TransitionEffect.CUT
|
|
|
|
|
|
class TestTemplateClipConfigCreate:
|
|
"""TemplateClipConfig.create 工厂测试."""
|
|
|
|
def test_create_minimal(self):
|
|
"""最简创建."""
|
|
clip = TemplateClipConfig.create(
|
|
template_id="tpl1",
|
|
clip_type=ClipType.MAIN,
|
|
order=0,
|
|
)
|
|
assert clip.template_id == "tpl1"
|
|
assert clip.clip_type == ClipType.MAIN
|
|
assert clip.order == 0
|
|
assert clip.min_duration == 0.0
|
|
assert clip.max_duration == 0.0
|
|
assert clip.text_template == ""
|
|
assert clip.material_requirements == {}
|
|
assert clip.transition_effect == TransitionEffect.CUT
|
|
assert clip.config == {}
|
|
assert isinstance(clip.id, str)
|
|
assert len(clip.id) > 0
|
|
|
|
def test_create_with_string_clip_type(self):
|
|
"""用字符串传 clip_type."""
|
|
clip = TemplateClipConfig.create(
|
|
template_id="t1",
|
|
clip_type="intro",
|
|
order=0,
|
|
)
|
|
assert clip.clip_type == ClipType.INTRO
|
|
|
|
def test_create_with_string_transition(self):
|
|
"""用字符串传 transition_effect."""
|
|
clip = TemplateClipConfig.create(
|
|
template_id="t1",
|
|
clip_type=ClipType.MAIN,
|
|
order=0,
|
|
transition_effect="fade",
|
|
)
|
|
assert clip.transition_effect == TransitionEffect.FADE
|
|
|
|
def test_create_full(self):
|
|
"""带全部字段."""
|
|
clip = TemplateClipConfig.create(
|
|
template_id=" tpl1 ",
|
|
clip_type=ClipType.TITLE,
|
|
order=2,
|
|
min_duration=2.0,
|
|
max_duration=5.0,
|
|
text_template=" 欢迎关注 ",
|
|
material_requirements={"category": "scenic"},
|
|
transition_effect=TransitionEffect.FADE,
|
|
config={"font_size": 24},
|
|
)
|
|
assert clip.template_id == "tpl1" # strip
|
|
assert clip.clip_type == ClipType.TITLE
|
|
assert clip.order == 2
|
|
assert clip.min_duration == 2.0
|
|
assert clip.max_duration == 5.0
|
|
assert clip.text_template == "欢迎关注" # strip
|
|
assert clip.material_requirements == {"category": "scenic"}
|
|
assert clip.transition_effect == TransitionEffect.FADE
|
|
assert clip.config == {"font_size": 24}
|
|
|
|
def test_create_empty_template_id(self):
|
|
"""空 template_id 无效."""
|
|
try:
|
|
TemplateClipConfig.create(template_id="", clip_type=ClipType.MAIN, order=0)
|
|
assert False
|
|
except ValueError as e:
|
|
assert "template_id" in str(e)
|
|
|
|
def test_create_whitespace_template_id(self):
|
|
"""空白 template_id 无效."""
|
|
try:
|
|
TemplateClipConfig.create(template_id=" ", clip_type=ClipType.MAIN, order=0)
|
|
assert False
|
|
except ValueError as e:
|
|
assert "template_id" in str(e)
|
|
|
|
def test_create_negative_min_duration(self):
|
|
"""min_duration 为负无效."""
|
|
try:
|
|
TemplateClipConfig.create(
|
|
template_id="t1",
|
|
clip_type=ClipType.MAIN,
|
|
order=0,
|
|
min_duration=-1.0,
|
|
)
|
|
assert False
|
|
except ValueError as e:
|
|
assert "min_duration" in str(e)
|
|
|
|
def test_create_negative_max_duration(self):
|
|
"""max_duration 为负无效."""
|
|
try:
|
|
TemplateClipConfig.create(
|
|
template_id="t1",
|
|
clip_type=ClipType.MAIN,
|
|
order=0,
|
|
max_duration=-1.0,
|
|
)
|
|
assert False
|
|
except ValueError as e:
|
|
assert "max_duration" in str(e)
|
|
|
|
def test_create_min_greater_than_max(self):
|
|
"""min > max 且 max > 0 时无效."""
|
|
try:
|
|
TemplateClipConfig.create(
|
|
template_id="t1",
|
|
clip_type=ClipType.MAIN,
|
|
order=0,
|
|
min_duration=5.0,
|
|
max_duration=3.0,
|
|
)
|
|
assert False
|
|
except ValueError as e:
|
|
assert "min_duration" in str(e) and "max_duration" in str(e)
|
|
|
|
def test_create_min_equals_max_valid(self):
|
|
"""min == max 合法."""
|
|
clip = TemplateClipConfig.create(
|
|
template_id="t1",
|
|
clip_type=ClipType.MAIN,
|
|
order=0,
|
|
min_duration=3.0,
|
|
max_duration=3.0,
|
|
)
|
|
assert clip.min_duration == 3.0
|
|
assert clip.max_duration == 3.0
|
|
|
|
def test_create_zero_both_valid(self):
|
|
"""都为 0 合法(未设置时长)."""
|
|
clip = TemplateClipConfig.create(
|
|
template_id="t1",
|
|
clip_type=ClipType.MAIN,
|
|
order=0,
|
|
min_duration=0.0,
|
|
max_duration=0.0,
|
|
)
|
|
assert clip.min_duration == 0.0
|
|
assert clip.max_duration == 0.0
|
|
|
|
def test_create_invalid_clip_type_string(self):
|
|
"""无效的 clip_type 字符串抛错."""
|
|
try:
|
|
TemplateClipConfig.create(template_id="t1", clip_type="invalid", order=0)
|
|
assert False
|
|
except ValueError:
|
|
pass # 枚举构造失败会抛 ValueError
|
|
|
|
def test_create_material_req_none_defaults_empty(self):
|
|
"""material_requirements=None 默认为空 dict."""
|
|
clip = TemplateClipConfig.create(
|
|
template_id="t1",
|
|
clip_type=ClipType.MAIN,
|
|
order=0,
|
|
material_requirements=None,
|
|
)
|
|
assert clip.material_requirements == {}
|
|
|
|
def test_create_config_none_defaults_empty(self):
|
|
"""config=None 默认为空 dict."""
|
|
clip = TemplateClipConfig.create(
|
|
template_id="t1",
|
|
clip_type=ClipType.MAIN,
|
|
order=0,
|
|
config=None,
|
|
)
|
|
assert clip.config == {}
|
|
|
|
def test_create_unique_id(self):
|
|
"""不同配置 id 不同."""
|
|
c1 = TemplateClipConfig.create("t", ClipType.MAIN, 0)
|
|
c2 = TemplateClipConfig.create("t", ClipType.MAIN, 0)
|
|
assert c1.id != c2.id
|
|
|
|
def test_create_has_timestamps(self):
|
|
"""有创建和更新时间."""
|
|
clip = TemplateClipConfig.create("t", ClipType.MAIN, 0)
|
|
assert clip.created_at is not None
|
|
assert clip.updated_at is not None
|
|
|
|
|
|
class TestTemplateClipConfigProperties:
|
|
"""计算属性测试."""
|
|
|
|
def test_has_duration_range_false_zero(self):
|
|
"""都为 0 时没有时长范围."""
|
|
clip = TemplateClipConfig.create("t", ClipType.MAIN, 0)
|
|
assert clip.has_duration_range is False
|
|
|
|
def test_has_duration_range_true_min_only(self):
|
|
"""只有 min > 0 也算有范围."""
|
|
clip = TemplateClipConfig.create(
|
|
"t",
|
|
ClipType.MAIN,
|
|
0,
|
|
min_duration=2.0,
|
|
)
|
|
assert clip.has_duration_range is True
|
|
|
|
def test_has_duration_range_true_max_only(self):
|
|
"""只有 max > 0 也算有范围."""
|
|
clip = TemplateClipConfig.create(
|
|
"t",
|
|
ClipType.MAIN,
|
|
0,
|
|
max_duration=5.0,
|
|
)
|
|
assert clip.has_duration_range is True
|
|
|
|
def test_has_duration_range_true_both(self):
|
|
"""两者都 > 0 有范围."""
|
|
clip = TemplateClipConfig.create(
|
|
"t",
|
|
ClipType.MAIN,
|
|
0,
|
|
min_duration=2.0,
|
|
max_duration=5.0,
|
|
)
|
|
assert clip.has_duration_range is True
|
|
|
|
def test_default_duration_zero(self):
|
|
"""都为 0 默认时长 0."""
|
|
clip = TemplateClipConfig.create("t", ClipType.MAIN, 0)
|
|
assert clip.default_duration == 0.0
|
|
|
|
def test_default_duration_middle(self):
|
|
"""两者都有取中间值."""
|
|
clip = TemplateClipConfig.create(
|
|
"t",
|
|
ClipType.MAIN,
|
|
0,
|
|
min_duration=2.0,
|
|
max_duration=6.0,
|
|
)
|
|
assert clip.default_duration == 4.0
|
|
|
|
def test_default_duration_min_only(self):
|
|
"""只有 min 用 min."""
|
|
clip = TemplateClipConfig.create(
|
|
"t",
|
|
ClipType.MAIN,
|
|
0,
|
|
min_duration=3.0,
|
|
)
|
|
assert clip.default_duration == 3.0
|
|
|
|
def test_default_duration_max_only(self):
|
|
"""只有 max 用 max."""
|
|
clip = TemplateClipConfig.create(
|
|
"t",
|
|
ClipType.MAIN,
|
|
0,
|
|
max_duration=5.0,
|
|
)
|
|
assert clip.default_duration == 5.0
|
|
|
|
def test_default_duration_equal_min_max(self):
|
|
"""min == max 时值相等."""
|
|
clip = TemplateClipConfig.create(
|
|
"t",
|
|
ClipType.MAIN,
|
|
0,
|
|
min_duration=3.0,
|
|
max_duration=3.0,
|
|
)
|
|
assert clip.default_duration == 3.0
|