Files
xiaoxia-saas/tests/unit/domain/test_template_clip_config.py

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