"""preset_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, ) class TestPresetBGM: """PresetBGM 数据类测试.""" def test_create_required_fields(self): bgm = PresetBGM(id="test_001", name="测试音乐", style="upbeat", duration=120.0) assert bgm.id == "test_001" assert bgm.name == "测试音乐" assert bgm.style == "upbeat" assert bgm.duration == 120.0 # 默认值 assert bgm.artist == "" assert bgm.description == "" assert bgm.tags == [] assert bgm.audio_url == "" def test_create_all_fields(self): bgm = PresetBGM( id="test_002", name="完整版", style="relax", duration=180.5, artist="测试艺术家", description="测试描述", tags=["标签1", "标签2"], audio_url="https://example.com/test.mp3", ) assert bgm.artist == "测试艺术家" assert bgm.description == "测试描述" assert bgm.tags == ["标签1", "标签2"] assert bgm.audio_url == "https://example.com/test.mp3" def test_frozen_immutable(self): """frozen=True,实例不可变.""" bgm = PresetBGM(id="test", name="测试", style="upbeat", duration=60.0) with pytest.raises(FrozenInstanceError): bgm.name = "修改" # type: ignore[misc] def test_tags_default_new_list(self): """每次创建都有独立的 tags 列表.""" b1 = PresetBGM(id="1", name="a", style="upbeat", duration=60.0) b2 = PresetBGM(id="2", name="b", style="upbeat", duration=60.0) assert b1.tags is not b2.tags assert b1.tags == [] assert b2.tags == [] class TestPresetBGMLibrary: """PRESET_BGM_LIBRARY 预设库测试.""" def test_not_empty(self): assert len(PRESET_BGM_LIBRARY) > 0 def test_all_unique_ids(self): ids = [b.id for b in PRESET_BGM_LIBRARY] assert len(ids) == len(set(ids)), "BGM ID 不能重复" def test_all_are_preset_bgm_instances(self): for bgm in PRESET_BGM_LIBRARY: assert isinstance(bgm, PresetBGM) def test_all_have_positive_duration(self): for bgm in PRESET_BGM_LIBRARY: assert bgm.duration > 0, f"{bgm.id} duration 必须为正" def test_styles_are_known(self): for bgm in PRESET_BGM_LIBRARY: assert bgm.style in BGM_STYLES, f"{bgm.id} style {bgm.style} 不在 BGM_STYLES 中" def test_style_distribution(self): """每种风格至少有 1 个 BGM.""" styles_found = {b.style for b in PRESET_BGM_LIBRARY} for style in ["upbeat", "relax", "tech", "commerce"]: assert style in styles_found class TestBGMStyles: """BGM_STYLES 风格字典测试.""" def test_has_expected_styles(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_values_are_chinese_labels(self): assert BGM_STYLES["upbeat"] == "轻快" assert BGM_STYLES["relax"] == "治愈" class TestGetPresetBGM: """get_preset_bgm 函数测试.""" def test_existing_id(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_nonexistent_id(self): assert get_preset_bgm("nonexistent") is None def test_empty_string(self): assert get_preset_bgm("") is None def test_returns_preset_bgm_instance(self): bgm = get_preset_bgm("bgm_relax_001") assert isinstance(bgm, PresetBGM) class TestListPresetBGMByStyle: """list_preset_bgm_by_style 函数测试.""" def test_upbeat_style(self): result = list_preset_bgm_by_style("upbeat") assert len(result) >= 3 for bgm in result: assert bgm.style == "upbeat" def test_relax_style(self): result = list_preset_bgm_by_style("relax") assert len(result) >= 3 for bgm in result: assert bgm.style == "relax" def test_tech_style(self): result = list_preset_bgm_by_style("tech") assert len(result) >= 2 def test_unknown_style_returns_empty(self): result = list_preset_bgm_by_style("nonexistent_style") assert result == [] def test_empty_style_returns_empty(self): result = list_preset_bgm_by_style("") assert result == [] class TestSearchPresetBGM: """search_preset_bgm 函数测试.""" def test_search_by_name(self): result = search_preset_bgm("阳光") assert len(result) >= 1 assert any(b.name == "阳光清晨" for b in result) def test_search_by_tag(self): result = search_preset_bgm("钢琴") assert len(result) >= 1 for bgm in result: assert any("钢琴" in tag for tag in bgm.tags) or "钢琴" in bgm.name or "钢琴" in bgm.description def test_search_by_description(self): result = search_preset_bgm("vlog") assert len(result) >= 1 def test_search_case_insensitive(self): r1 = search_preset_bgm("BGM") r2 = search_preset_bgm("bgm") assert len(r1) == len(r2) def test_search_no_match(self): result = search_preset_bgm("xyz_nonexistent_keyword_12345") assert result == [] def test_search_empty_keyword_returns_all(self): """空关键词应该匹配所有(keyword in string 恒成立).""" result = search_preset_bgm("") assert len(result) == len(PRESET_BGM_LIBRARY) def test_search_partial_match(self): result = search_preset_bgm("科技") assert len(result) >= 1