c052e857ff
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m1s
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Failing after 2m15s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m34s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m30s
CI/CD Pipeline / Unit Tests (push) Successful in 5m57s
CI/CD Pipeline / Integration Tests (push) Successful in 3m16s
CI/CD Pipeline / Frontend Lint (push) Successful in 40s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 50s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 12m4s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m29s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m25s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 56s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 5m39s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 5m37s
162 lines
5.8 KiB
Python
Executable File
162 lines
5.8 KiB
Python
Executable File
"""BGM配置合并逻辑单元测试。"""
|
|
|
|
import pytest
|
|
|
|
from packages.domain.bgm_utils import merge_bgm_config
|
|
|
|
|
|
class TestMergeBgmConfig:
|
|
"""merge_bgm_config 单元测试。"""
|
|
|
|
def test_template_empty_user_has_config(self):
|
|
"""模板为空,用户有配置 → 返回用户配置副本。"""
|
|
template = {}
|
|
user = {"audio_url": "http://example.com/bgm.mp3", "volume": 0.8}
|
|
|
|
result = merge_bgm_config(template, user)
|
|
|
|
assert result == {"audio_url": "http://example.com/bgm.mp3", "volume": 0.8}
|
|
# 确保返回的是新对象,不是同一引用
|
|
assert result is not user
|
|
|
|
def test_user_empty_template_has_config(self):
|
|
"""用户为空,模板有配置 → 返回模板配置副本。"""
|
|
template = {"audio_url": "http://example.com/default.mp3", "enabled": True}
|
|
user = {}
|
|
|
|
result = merge_bgm_config(template, user)
|
|
|
|
assert result == {"audio_url": "http://example.com/default.mp3", "enabled": True}
|
|
assert result is not template
|
|
|
|
def test_both_empty(self):
|
|
"""都为空 → 返回空dict。"""
|
|
result = merge_bgm_config({}, {})
|
|
assert result == {}
|
|
|
|
def test_user_overrides_single_field(self):
|
|
"""用户覆盖单个普通字段。"""
|
|
template = {"audio_url": "http://template.com/default.mp3", "volume": 0.5}
|
|
user = {"audio_url": "http://user.com/custom.mp3"}
|
|
|
|
result = merge_bgm_config(template, user)
|
|
|
|
assert result["audio_url"] == "http://user.com/custom.mp3"
|
|
assert result["volume"] == 0.5 # 模板值保留
|
|
|
|
def test_user_overrides_multiple_fields(self):
|
|
"""用户覆盖多个字段。"""
|
|
template = {
|
|
"audio_url": "http://template.com/default.mp3",
|
|
"volume": 0.5,
|
|
"fade_in": 1.0,
|
|
"fade_out": 1.0,
|
|
}
|
|
user = {
|
|
"audio_url": "http://user.com/custom.mp3",
|
|
"volume": 0.9,
|
|
}
|
|
|
|
result = merge_bgm_config(template, user)
|
|
|
|
assert result["audio_url"] == "http://user.com/custom.mp3"
|
|
assert result["volume"] == 0.9
|
|
assert result["fade_in"] == 1.0
|
|
assert result["fade_out"] == 1.0
|
|
|
|
def test_enabled_not_in_user_keep_template_true(self):
|
|
"""enabled特殊处理:用户没传,模板enabled=True → 保留True。"""
|
|
template = {"audio_url": "http://template.com/default.mp3", "enabled": True}
|
|
user = {"audio_url": "http://user.com/custom.mp3"}
|
|
|
|
result = merge_bgm_config(template, user)
|
|
|
|
assert result["enabled"] is True
|
|
assert result["audio_url"] == "http://user.com/custom.mp3"
|
|
|
|
def test_enabled_not_in_user_keep_template_false(self):
|
|
"""enabled特殊处理:用户没传,模板enabled=False → 保留False。"""
|
|
template = {"audio_url": "http://template.com/default.mp3", "enabled": False}
|
|
user = {"audio_url": "http://user.com/custom.mp3"}
|
|
|
|
result = merge_bgm_config(template, user)
|
|
|
|
assert result["enabled"] is False
|
|
|
|
def test_enabled_explicit_true_overrides_template_false(self):
|
|
"""enabled特殊处理:用户显式传True,覆盖模板False。"""
|
|
template = {"audio_url": "http://template.com/default.mp3", "enabled": False}
|
|
user = {"enabled": True}
|
|
|
|
result = merge_bgm_config(template, user)
|
|
|
|
assert result["enabled"] is True
|
|
|
|
def test_enabled_explicit_false_overrides_template_true(self):
|
|
"""enabled特殊处理:用户显式传False,覆盖模板True。"""
|
|
template = {"audio_url": "http://template.com/default.mp3", "enabled": True}
|
|
user = {"enabled": False}
|
|
|
|
result = merge_bgm_config(template, user)
|
|
|
|
assert result["enabled"] is False
|
|
|
|
def test_nested_fields_shallow_merge(self):
|
|
"""普通字段(包括嵌套dict)按浅层合并处理。"""
|
|
template = {
|
|
"audio_url": "http://template.com/default.mp3",
|
|
"effects": {"fade_in": 1.0, "fade_out": 1.0},
|
|
}
|
|
user = {
|
|
"effects": {"fade_in": 3.0}, # 整个覆盖,不是深合并
|
|
}
|
|
|
|
result = merge_bgm_config(template, user)
|
|
|
|
# 浅层合并:用户的effects完全替换模板的effects
|
|
assert result["effects"] == {"fade_in": 3.0}
|
|
|
|
def test_user_none_value_fields(self):
|
|
"""用户传None值的字段,会覆盖模板值为None。"""
|
|
template = {"audio_url": "http://template.com/default.mp3", "volume": 0.5}
|
|
user = {"audio_url": None}
|
|
|
|
result = merge_bgm_config(template, user)
|
|
|
|
assert result["audio_url"] is None
|
|
assert result["volume"] == 0.5
|
|
|
|
def test_does_not_mutate_inputs(self):
|
|
"""合并操作不修改原始输入对象。"""
|
|
template = {"audio_url": "http://template.com/default.mp3", "enabled": True, "volume": 0.5}
|
|
user = {"volume": 0.9}
|
|
template_copy = dict(template)
|
|
user_copy = dict(user)
|
|
|
|
merge_bgm_config(template, user)
|
|
|
|
assert template == template_copy
|
|
assert user == user_copy
|
|
|
|
def test_user_adds_new_field(self):
|
|
"""用户新增模板中没有的字段。"""
|
|
template = {"audio_url": "http://template.com/default.mp3"}
|
|
user = {"loop": True, "start_time": 5.0}
|
|
|
|
result = merge_bgm_config(template, user)
|
|
|
|
assert result["audio_url"] == "http://template.com/default.mp3"
|
|
assert result["loop"] is True
|
|
assert result["start_time"] == 5.0
|
|
|
|
def test_asset_id_and_preset_id_fields(self):
|
|
"""asset_id和preset_id字段正常合并。"""
|
|
template = {"preset_id": "preset_default", "volume": 0.5}
|
|
user = {"asset_id": "asset_user_123"}
|
|
|
|
result = merge_bgm_config(template, user)
|
|
|
|
assert result["preset_id"] == "preset_default"
|
|
assert result["asset_id"] == "asset_user_123"
|
|
assert result["volume"] == 0.5
|