Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e06112dfb6 | |||
| 72651cabc4 |
Executable
+299
@@ -0,0 +1,299 @@
|
||||
"""preset_bgm 预设BGM库单测."""
|
||||
|
||||
from dataclasses import FrozenInstanceError
|
||||
|
||||
import pytest
|
||||
from domain.preset_bgm import (
|
||||
BGM_STYLES,
|
||||
PRESET_BGM_LIBRARY,
|
||||
PresetBGM,
|
||||
get_preset_bgm,
|
||||
list_preset_bgm_by_style,
|
||||
search_preset_bgm,
|
||||
)
|
||||
|
||||
# ── PresetBGM dataclass ──────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestPresetBGM:
|
||||
"""PresetBGM dataclass"""
|
||||
|
||||
def test_minimal_creation(self):
|
||||
b = PresetBGM(id="test_001", name="测试音乐", style="upbeat", duration=60.0)
|
||||
assert b.id == "test_001"
|
||||
assert b.name == "测试音乐"
|
||||
assert b.style == "upbeat"
|
||||
assert b.duration == 60.0
|
||||
assert b.artist == ""
|
||||
assert b.description == ""
|
||||
assert b.tags == []
|
||||
assert b.audio_url == ""
|
||||
|
||||
def test_full_creation(self):
|
||||
b = PresetBGM(
|
||||
id="bgm_001",
|
||||
name="阳光清晨",
|
||||
style="upbeat",
|
||||
duration=120.5,
|
||||
artist="音乐人A",
|
||||
description="轻快明亮的吉他",
|
||||
tags=["轻快", "阳光"],
|
||||
audio_url="https://cdn.example.com/bgm.mp3",
|
||||
)
|
||||
assert b.id == "bgm_001"
|
||||
assert b.artist == "音乐人A"
|
||||
assert b.description == "轻快明亮的吉他"
|
||||
assert b.tags == ["轻快", "阳光"]
|
||||
assert b.audio_url == "https://cdn.example.com/bgm.mp3"
|
||||
|
||||
def test_frozen_immutable(self):
|
||||
b = PresetBGM(id="test", name="Test", style="relax", duration=100.0)
|
||||
with pytest.raises(FrozenInstanceError):
|
||||
b.name = "NewName"
|
||||
|
||||
def test_equality(self):
|
||||
b1 = PresetBGM(id="same", name="同名", style="upbeat", duration=60.0)
|
||||
b2 = PresetBGM(id="same", name="同名", style="upbeat", duration=60.0)
|
||||
assert b1 == b2
|
||||
|
||||
def test_inequality(self):
|
||||
b1 = PresetBGM(id="a", name="A", style="upbeat", duration=60.0)
|
||||
b2 = PresetBGM(id="b", name="B", style="relax", duration=90.0)
|
||||
assert b1 != b2
|
||||
|
||||
def test_not_hashable_due_to_list_tags(self):
|
||||
# 包含 list 字段(tags)的 frozen dataclass 不可哈希
|
||||
b = PresetBGM(id="test", name="Test", style="tech", duration=60.0)
|
||||
with pytest.raises(TypeError):
|
||||
hash(b)
|
||||
|
||||
|
||||
# ── PRESET_BGM_LIBRARY 清单 ──────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestPresetBGMLibrary:
|
||||
"""预设BGM库清单"""
|
||||
|
||||
def test_not_empty(self):
|
||||
assert len(PRESET_BGM_LIBRARY) > 0
|
||||
|
||||
def test_all_are_preset_bgm(self):
|
||||
for bgm in PRESET_BGM_LIBRARY:
|
||||
assert isinstance(bgm, PresetBGM)
|
||||
|
||||
def test_unique_ids(self):
|
||||
ids = [b.id for b in PRESET_BGM_LIBRARY]
|
||||
assert len(ids) == len(set(ids))
|
||||
|
||||
def test_all_have_required_fields(self):
|
||||
for bgm in PRESET_BGM_LIBRARY:
|
||||
assert bgm.id != ""
|
||||
assert bgm.name != ""
|
||||
assert bgm.style != ""
|
||||
assert bgm.duration > 0
|
||||
|
||||
def test_upbeat_style_count(self):
|
||||
upbeats = [b for b in PRESET_BGM_LIBRARY if b.style == "upbeat"]
|
||||
assert len(upbeats) >= 3
|
||||
|
||||
def test_relax_style_count(self):
|
||||
relax = [b for b in PRESET_BGM_LIBRARY if b.style == "relax"]
|
||||
assert len(relax) >= 3
|
||||
|
||||
def test_tech_style_count(self):
|
||||
tech = [b for b in PRESET_BGM_LIBRARY if b.style == "tech"]
|
||||
assert len(tech) >= 2
|
||||
|
||||
def test_commerce_style_count(self):
|
||||
commerce = [b for b in PRESET_BGM_LIBRARY if b.style == "commerce"]
|
||||
assert len(commerce) >= 2
|
||||
|
||||
def test_sunny_morning_preset(self):
|
||||
b = next(b for b in PRESET_BGM_LIBRARY if b.id == "bgm_upbeat_001")
|
||||
assert b.name == "阳光清晨"
|
||||
assert b.style == "upbeat"
|
||||
assert b.duration == 120.0
|
||||
assert "吉他" in b.description
|
||||
assert "vlog" in b.tags
|
||||
|
||||
def test_quiet_time_preset(self):
|
||||
b = next(b for b in PRESET_BGM_LIBRARY if b.id == "bgm_relax_001")
|
||||
assert b.name == "静谧时光"
|
||||
assert b.style == "relax"
|
||||
assert b.duration == 180.0
|
||||
|
||||
def test_future_tech_preset(self):
|
||||
b = next(b for b in PRESET_BGM_LIBRARY if b.id == "bgm_tech_001")
|
||||
assert b.name == "未来科技"
|
||||
assert b.style == "tech"
|
||||
|
||||
def test_all_durations_positive(self):
|
||||
for bgm in PRESET_BGM_LIBRARY:
|
||||
assert bgm.duration > 0
|
||||
|
||||
def test_all_tags_are_lists(self):
|
||||
for bgm in PRESET_BGM_LIBRARY:
|
||||
assert isinstance(bgm.tags, list)
|
||||
|
||||
|
||||
# ── BGM_STYLES 风格字典 ─────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestBGMStyles:
|
||||
"""BGM_STYLES 风格分类字典"""
|
||||
|
||||
def test_styles_exist(self):
|
||||
assert "upbeat" in BGM_STYLES
|
||||
assert "relax" in BGM_STYLES
|
||||
assert "tech" in BGM_STYLES
|
||||
assert "commerce" in BGM_STYLES
|
||||
assert "emotional" in BGM_STYLES
|
||||
assert "cinematic" in BGM_STYLES
|
||||
|
||||
def test_style_names_chinese(self):
|
||||
assert BGM_STYLES["upbeat"] == "轻快"
|
||||
assert BGM_STYLES["relax"] == "治愈"
|
||||
assert BGM_STYLES["tech"] == "科技"
|
||||
assert BGM_STYLES["commerce"] == "电商"
|
||||
assert BGM_STYLES["emotional"] == "情感"
|
||||
assert BGM_STYLES["cinematic"] == "电影"
|
||||
|
||||
def test_library_styles_are_defined(self):
|
||||
# 库中的所有风格都应该在 BGM_STYLES 中有定义
|
||||
styles_in_library = {b.style for b in PRESET_BGM_LIBRARY}
|
||||
for style in styles_in_library:
|
||||
assert style in BGM_STYLES, f"style {style} not defined in BGM_STYLES"
|
||||
|
||||
|
||||
# ── get_preset_bgm ──────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestGetPresetBGM:
|
||||
"""get_preset_bgm 函数"""
|
||||
|
||||
def test_get_existing(self):
|
||||
b = get_preset_bgm("bgm_upbeat_001")
|
||||
assert b is not None
|
||||
assert b.id == "bgm_upbeat_001"
|
||||
assert b.name == "阳光清晨"
|
||||
|
||||
def test_get_relax(self):
|
||||
b = get_preset_bgm("bgm_relax_002")
|
||||
assert b is not None
|
||||
assert b.style == "relax"
|
||||
|
||||
def test_get_nonexistent_returns_none(self):
|
||||
b = get_preset_bgm("nonexistent_id")
|
||||
assert b is None
|
||||
|
||||
def test_get_empty_string_returns_none(self):
|
||||
b = get_preset_bgm("")
|
||||
assert b is None
|
||||
|
||||
def test_returns_same_instance(self):
|
||||
b1 = get_preset_bgm("bgm_upbeat_001")
|
||||
b2 = get_preset_bgm("bgm_upbeat_001")
|
||||
assert b1 is b2
|
||||
|
||||
|
||||
# ── list_preset_bgm_by_style ─────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestListPresetBGMByStyle:
|
||||
"""list_preset_bgm_by_style 函数"""
|
||||
|
||||
def test_upbeat_style(self):
|
||||
result = list_preset_bgm_by_style("upbeat")
|
||||
assert len(result) >= 3
|
||||
for b in result:
|
||||
assert b.style == "upbeat"
|
||||
|
||||
def test_relax_style(self):
|
||||
result = list_preset_bgm_by_style("relax")
|
||||
assert len(result) >= 3
|
||||
for b in result:
|
||||
assert b.style == "relax"
|
||||
|
||||
def test_tech_style(self):
|
||||
result = list_preset_bgm_by_style("tech")
|
||||
assert len(result) >= 2
|
||||
|
||||
def test_commerce_style(self):
|
||||
result = list_preset_bgm_by_style("commerce")
|
||||
assert len(result) >= 2
|
||||
|
||||
def test_unknown_style_empty(self):
|
||||
result = list_preset_bgm_by_style("nonexistent_style")
|
||||
assert len(result) == 0
|
||||
|
||||
def test_empty_string_empty(self):
|
||||
result = list_preset_bgm_by_style("")
|
||||
assert len(result) == 0
|
||||
|
||||
def test_returns_new_list(self):
|
||||
# 修改返回值不应影响原始列表
|
||||
result = list_preset_bgm_by_style("upbeat")
|
||||
result.clear()
|
||||
assert len(list_preset_bgm_by_style("upbeat")) >= 3
|
||||
|
||||
|
||||
# ── search_preset_bgm ────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestSearchPresetBGM:
|
||||
"""search_preset_bgm 函数"""
|
||||
|
||||
def test_search_by_name(self):
|
||||
result = search_preset_bgm("阳光")
|
||||
assert len(result) >= 1
|
||||
assert any("阳光" in b.name for b in result)
|
||||
|
||||
def test_search_by_description(self):
|
||||
result = search_preset_bgm("钢琴")
|
||||
assert len(result) >= 1
|
||||
# 应该匹配描述里有钢琴的
|
||||
|
||||
def test_search_by_tag(self):
|
||||
result = search_preset_bgm("vlog")
|
||||
assert len(result) >= 1
|
||||
assert any("vlog" in b.tags for b in result)
|
||||
|
||||
def test_search_tech_keyword(self):
|
||||
result = search_preset_bgm("科技")
|
||||
assert len(result) >= 2
|
||||
|
||||
def test_search_case_insensitive(self):
|
||||
r1 = search_preset_bgm("UPBEAT")
|
||||
r2 = search_preset_bgm("upbeat")
|
||||
assert len(r1) == len(r2)
|
||||
|
||||
def test_search_no_match(self):
|
||||
result = search_preset_bgm("完全不存在的关键词_xyz123")
|
||||
assert len(result) == 0
|
||||
|
||||
def test_search_empty_string(self):
|
||||
# 空字符串应该匹配所有(因为 "" in any string 是 True)
|
||||
result = search_preset_bgm("")
|
||||
assert len(result) == len(PRESET_BGM_LIBRARY)
|
||||
|
||||
def test_search_electronic(self):
|
||||
result = search_preset_bgm("电子")
|
||||
assert len(result) >= 2
|
||||
|
||||
def test_order_preserved(self):
|
||||
# 搜索结果应该保持原列表顺序
|
||||
result = search_preset_bgm("bgm")
|
||||
ids = [b.id for b in result]
|
||||
all_ids = [b.id for b in PRESET_BGM_LIBRARY]
|
||||
# 验证相对顺序
|
||||
pos_in_result = {bgm_id: i for i, bgm_id in enumerate(ids)}
|
||||
prev_pos = -1
|
||||
for bgm_id in all_ids:
|
||||
if bgm_id in pos_in_result:
|
||||
assert pos_in_result[bgm_id] > prev_pos
|
||||
prev_pos = pos_in_result[bgm_id]
|
||||
|
||||
def test_search_partial_tag_match(self):
|
||||
# 关键词是标签的子串也能匹配
|
||||
result = search_preset_bgm("吉他")
|
||||
assert len(result) >= 1
|
||||
Reference in New Issue
Block a user