b98acefe0f
CI/CD Pipeline / Check if frontend-only change (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (push) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / PR Build API Image (push) Has been cancelled
CI/CD Pipeline / PR Build Web Image (push) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
fix(ci): 修复daily-check/acr-cleanup docker兼容性 + 清理ruff历史遗留 + 修复Unit Tests死循环和ffmpeg兼容性问题 (#981)
204 lines
6.6 KiB
Python
Executable File
204 lines
6.6 KiB
Python
Executable File
"""Preset BGM 预设背景音乐单元测试。"""
|
|
|
|
from dataclasses import FrozenInstanceError
|
|
|
|
import pytest
|
|
|
|
from packages.domain.preset_bgm import (
|
|
BGM_STYLES,
|
|
PRESET_BGM_LIBRARY,
|
|
PresetBGM,
|
|
get_preset_bgm,
|
|
list_preset_bgm_by_style,
|
|
search_preset_bgm,
|
|
)
|
|
|
|
|
|
class TestPresetBGMDataclass:
|
|
def test_creation_required_fields(self):
|
|
bgm = PresetBGM(id="test_001", name="Test BGM", style="upbeat", duration=120.0)
|
|
assert bgm.id == "test_001"
|
|
assert bgm.name == "Test BGM"
|
|
assert bgm.style == "upbeat"
|
|
assert bgm.duration == 120.0
|
|
assert bgm.artist == ""
|
|
assert bgm.description == ""
|
|
assert bgm.tags == []
|
|
assert bgm.audio_url == ""
|
|
|
|
def test_creation_all_fields(self):
|
|
bgm = PresetBGM(
|
|
id="test_002",
|
|
name="Full BGM",
|
|
style="relax",
|
|
duration=180.5,
|
|
artist="Artist Name",
|
|
description="A test description",
|
|
tags=["tag1", "tag2"],
|
|
audio_url="https://cdn/test.mp3",
|
|
)
|
|
assert bgm.artist == "Artist Name"
|
|
assert bgm.description == "A test description"
|
|
assert bgm.tags == ["tag1", "tag2"]
|
|
assert bgm.audio_url == "https://cdn/test.mp3"
|
|
|
|
def test_frozen_immutable(self):
|
|
bgm = PresetBGM(id="t1", name="T", style="upbeat", duration=60.0)
|
|
with pytest.raises(FrozenInstanceError):
|
|
bgm.name = "new name"
|
|
|
|
def test_equality(self):
|
|
bgm1 = PresetBGM(id="same", name="N", style="upbeat", duration=60.0)
|
|
bgm2 = PresetBGM(id="same", name="N", style="upbeat", duration=60.0)
|
|
assert bgm1 == bgm2
|
|
|
|
def test_inequality(self):
|
|
bgm1 = PresetBGM(id="a", name="A", style="upbeat", duration=60.0)
|
|
bgm2 = PresetBGM(id="b", name="B", style="upbeat", duration=60.0)
|
|
assert bgm1 != bgm2
|
|
|
|
def test_frozen_with_list_field_not_hashable(self):
|
|
# 包含 list 字段的 frozen dataclass 仍然不可哈希(list 不可哈希)
|
|
bgm = PresetBGM(id="h1", name="H", style="upbeat", duration=60.0, tags=["a"])
|
|
with pytest.raises(TypeError, match="unhashable"):
|
|
hash(bgm)
|
|
|
|
|
|
class TestPresetBGMLibrary:
|
|
def test_library_not_empty(self):
|
|
assert len(PRESET_BGM_LIBRARY) > 0
|
|
|
|
def test_library_has_entries(self):
|
|
assert len(PRESET_BGM_LIBRARY) >= 10
|
|
|
|
def test_all_have_unique_ids(self):
|
|
ids = [bgm.id for bgm in PRESET_BGM_LIBRARY]
|
|
assert len(ids) == len(set(ids))
|
|
|
|
def test_all_have_valid_styles(self):
|
|
for bgm in PRESET_BGM_LIBRARY:
|
|
assert bgm.style in BGM_STYLES
|
|
|
|
def test_all_have_positive_duration(self):
|
|
for bgm in PRESET_BGM_LIBRARY:
|
|
assert bgm.duration > 0
|
|
|
|
def test_all_have_non_empty_name(self):
|
|
for bgm in PRESET_BGM_LIBRARY:
|
|
assert bgm.name.strip() != ""
|
|
|
|
|
|
class TestBGMStyles:
|
|
def test_styles_dict_keys(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_styles_have_chinese_names(self):
|
|
for _, value in BGM_STYLES.items():
|
|
assert isinstance(value, str)
|
|
assert len(value) > 0
|
|
|
|
|
|
class TestGetPresetBGM:
|
|
def test_get_existing(self):
|
|
bgm = get_preset_bgm("bgm_upbeat_001")
|
|
assert bgm is not None
|
|
assert bgm.id == "bgm_upbeat_001"
|
|
assert bgm.name == "阳光清晨"
|
|
assert bgm.style == "upbeat"
|
|
|
|
def test_get_nonexistent(self):
|
|
assert get_preset_bgm("nonexistent_id") is None
|
|
|
|
def test_get_empty_string(self):
|
|
assert get_preset_bgm("") is None
|
|
|
|
def test_get_returns_same_object(self):
|
|
bgm1 = get_preset_bgm("bgm_relax_001")
|
|
bgm2 = get_preset_bgm("bgm_relax_001")
|
|
assert bgm1 is bgm2 # 同一实例(引用同一列表中的对象)
|
|
|
|
|
|
class TestListPresetBGMByStyle:
|
|
def test_list_upbeat(self):
|
|
results = list_preset_bgm_by_style("upbeat")
|
|
assert len(results) >= 3
|
|
for bgm in results:
|
|
assert bgm.style == "upbeat"
|
|
|
|
def test_list_relax(self):
|
|
results = list_preset_bgm_by_style("relax")
|
|
assert len(results) >= 3
|
|
for bgm in results:
|
|
assert bgm.style == "relax"
|
|
|
|
def test_list_tech(self):
|
|
results = list_preset_bgm_by_style("tech")
|
|
assert len(results) >= 2
|
|
for bgm in results:
|
|
assert bgm.style == "tech"
|
|
|
|
def test_list_commerce(self):
|
|
results = list_preset_bgm_by_style("commerce")
|
|
assert len(results) >= 2
|
|
for bgm in results:
|
|
assert bgm.style == "commerce"
|
|
|
|
def test_list_empty_style(self):
|
|
results = list_preset_bgm_by_style("nonexistent_style")
|
|
assert results == []
|
|
|
|
def test_list_preserves_order(self):
|
|
results = list_preset_bgm_by_style("upbeat")
|
|
ids = [b.id for b in results]
|
|
# 应该按照在列表中的出现顺序排列
|
|
assert ids == sorted(ids, key=lambda x: PRESET_BGM_LIBRARY.index(get_preset_bgm(x)))
|
|
|
|
|
|
class TestSearchPresetBGM:
|
|
def test_search_by_name(self):
|
|
results = search_preset_bgm("阳光")
|
|
assert len(results) >= 1
|
|
assert any("阳光" in b.name for b in results)
|
|
|
|
def test_search_by_description(self):
|
|
results = search_preset_bgm("钢琴")
|
|
assert len(results) >= 1
|
|
# 钢琴出现在名称或描述或标签中
|
|
found = False
|
|
for b in results:
|
|
if "钢琴" in b.description or "钢琴" in b.name or "钢琴" in b.tags:
|
|
found = True
|
|
break
|
|
assert found
|
|
|
|
def test_search_by_tag(self):
|
|
results = search_preset_bgm("科技")
|
|
assert len(results) >= 1
|
|
found_tech = any(b.style == "tech" for b in results)
|
|
assert found_tech
|
|
|
|
def test_search_case_insensitive(self):
|
|
results1 = search_preset_bgm("Tech")
|
|
results2 = search_preset_bgm("tech")
|
|
assert len(results1) == len(results2)
|
|
|
|
def test_search_no_match(self):
|
|
results = search_preset_bgm("zzzzzzzzzzz_nonexistent_keyword")
|
|
assert results == []
|
|
|
|
def test_search_empty_keyword(self):
|
|
# 空字符串应该匹配所有(因为空字符串 in 任何字符串都是 True)
|
|
results = search_preset_bgm("")
|
|
assert len(results) == len(PRESET_BGM_LIBRARY)
|
|
|
|
def test_search_no_duplicates(self):
|
|
# 确保同一个 BGM 不会出现多次
|
|
results = search_preset_bgm("电子")
|
|
ids = [b.id for b in results]
|
|
assert len(ids) == len(set(ids))
|