test(wave172): color_grade_config色彩调色 +72测 #1111

Merged
xiaoxia merged 1 commits from test/wave172-color-grade-config into develop 2026-07-28 16:18:21 +08:00
+474
View File
@@ -0,0 +1,474 @@
"""ColorGradeConfig 色彩调色配置单测.
纯逻辑模块,覆盖:数据类、resolve_params参数解析、has_effect效果判断、
from_dict字典解析、validate校验、预设查询函数、clamp_param钳制。
"""
from __future__ import annotations
from packages.domain.color_grade_config import (
ALL_PARAM_KEYS,
DEFAULT_PARAMS,
PARAM_RANGES,
PRESET_DISPLAY_NAMES,
PRESET_PARAMS,
VALID_PRESETS,
ColorGradeConfig,
clamp_param,
get_preset_names,
get_preset_params,
)
class TestColorGradeConfigDefaults:
def test_default_disabled(self):
config = ColorGradeConfig()
assert config.enabled is False
assert config.preset == ""
assert config.brightness is None
assert config.contrast is None
assert config.saturation is None
assert config.temperature is None
assert config.hue is None
def test_default_resolve_returns_defaults(self):
config = ColorGradeConfig()
params = config.resolve_params()
for key in ALL_PARAM_KEYS:
assert params[key] == DEFAULT_PARAMS[key]
def test_default_has_no_effect(self):
config = ColorGradeConfig()
assert config.has_effect() is False
def test_default_validate_passes(self):
config = ColorGradeConfig()
ok, msg = config.validate()
assert ok is True
assert msg == ""
class TestResolveParams:
def test_disabled_still_resolves(self):
"""禁用状态下仍能解析参数."""
config = ColorGradeConfig(enabled=False, brightness=50.0)
params = config.resolve_params()
assert params["brightness"] == 50.0
def test_preset_fresh(self):
config = ColorGradeConfig(enabled=True, preset="fresh")
params = config.resolve_params()
assert params["brightness"] == 8
assert params["contrast"] == 10
assert params["saturation"] == 120
assert params["temperature"] == -8
assert params["hue"] == 5
def test_preset_black_white(self):
config = ColorGradeConfig(enabled=True, preset="black_white")
params = config.resolve_params()
assert params["saturation"] == 0
assert params["contrast"] == 15
def test_preset_warm(self):
config = ColorGradeConfig(enabled=True, preset="warm")
params = config.resolve_params()
assert params["temperature"] == 30
def test_preset_cool(self):
config = ColorGradeConfig(enabled=True, preset="cool")
params = config.resolve_params()
assert params["temperature"] == -25
def test_invalid_preset_uses_defaults(self):
config = ColorGradeConfig(enabled=True, preset="nonexistent")
params = config.resolve_params()
for key in ALL_PARAM_KEYS:
assert params[key] == DEFAULT_PARAMS[key]
def test_custom_override_preset(self):
config = ColorGradeConfig(
enabled=True,
preset="fresh",
brightness=50.0,
)
params = config.resolve_params()
# custom覆盖了预设
assert params["brightness"] == 50.0
# 其他参数仍用预设值
assert params["contrast"] == 10
assert params["saturation"] == 120
def test_multiple_custom_overrides(self):
config = ColorGradeConfig(
enabled=True,
preset="vintage",
brightness=20.0,
saturation=150.0,
hue=10.0,
)
params = config.resolve_params()
assert params["brightness"] == 20.0
assert params["saturation"] == 150.0
assert params["hue"] == 10.0
# 未覆盖的保留预设值
assert params["contrast"] == 5
assert params["temperature"] == 25
def test_custom_without_preset(self):
config = ColorGradeConfig(
enabled=True,
preset="",
brightness=30.0,
contrast=-20.0,
)
params = config.resolve_params()
assert params["brightness"] == 30.0
assert params["contrast"] == -20.0
# 未设置的用默认值
assert params["saturation"] == 100.0
assert params["temperature"] == 0.0
assert params["hue"] == 0.0
def test_clamping_brightness_above_max(self):
config = ColorGradeConfig(enabled=True, brightness=200.0)
params = config.resolve_params()
assert params["brightness"] == 100.0
def test_clamping_brightness_below_min(self):
config = ColorGradeConfig(enabled=True, brightness=-200.0)
params = config.resolve_params()
assert params["brightness"] == -100.0
def test_clamping_saturation_below_zero(self):
config = ColorGradeConfig(enabled=True, saturation=-10.0)
params = config.resolve_params()
assert params["saturation"] == 0.0
def test_clamping_saturation_above_max(self):
config = ColorGradeConfig(enabled=True, saturation=300.0)
params = config.resolve_params()
assert params["saturation"] == 200.0
def test_clamping_hue_above_max(self):
config = ColorGradeConfig(enabled=True, hue=200.0)
params = config.resolve_params()
assert params["hue"] == 180.0
def test_clamping_hue_below_min(self):
config = ColorGradeConfig(enabled=True, hue=-200.0)
params = config.resolve_params()
assert params["hue"] == -180.0
def test_clamping_preset_plus_custom(self):
"""预设值+自定义值超出范围时仍会钳制."""
config = ColorGradeConfig(
enabled=True,
preset="fresh",
saturation=250.0, # 超出200上限
)
params = config.resolve_params()
assert params["saturation"] == 200.0
def test_returns_new_dict_each_time(self):
config = ColorGradeConfig(enabled=True, brightness=10.0)
p1 = config.resolve_params()
p2 = config.resolve_params()
assert p1 is not p2
p1["brightness"] = 999
assert p2["brightness"] == 10.0
class TestHasEffect:
def test_default_no_effect(self):
config = ColorGradeConfig()
assert config.has_effect() is False
def test_enabled_but_all_defaults(self):
config = ColorGradeConfig(
enabled=True,
brightness=0.0,
contrast=0.0,
saturation=100.0,
temperature=0.0,
hue=0.0,
)
assert config.has_effect() is False
def test_brightness_change_has_effect(self):
config = ColorGradeConfig(enabled=True, brightness=1.0)
assert config.has_effect() is True
def test_contrast_change_has_effect(self):
config = ColorGradeConfig(enabled=True, contrast=1.0)
assert config.has_effect() is True
def test_saturation_change_has_effect(self):
config = ColorGradeConfig(enabled=True, saturation=99.0)
assert config.has_effect() is True
def test_temperature_change_has_effect(self):
config = ColorGradeConfig(enabled=True, temperature=1.0)
assert config.has_effect() is True
def test_hue_change_has_effect(self):
config = ColorGradeConfig(enabled=True, hue=1.0)
assert config.has_effect() is True
def test_all_presets_have_effect(self):
for preset in VALID_PRESETS:
config = ColorGradeConfig(enabled=True, preset=preset)
assert config.has_effect() is True, f"preset {preset} should have effect"
def test_very_small_change_no_effect(self):
"""小于0.001的浮点误差视为无效果."""
config = ColorGradeConfig(enabled=True, brightness=0.0001)
assert config.has_effect() is False
class TestFromDict:
def test_none_returns_disabled(self):
config = ColorGradeConfig.from_dict(None)
assert config.enabled is False
def test_empty_dict_returns_disabled(self):
config = ColorGradeConfig.from_dict({})
assert config.enabled is False
def test_enabled_false_returns_disabled(self):
config = ColorGradeConfig.from_dict({"enabled": False})
assert config.enabled is False
def test_basic_enabled(self):
config = ColorGradeConfig.from_dict({"enabled": True})
assert config.enabled is True
assert config.preset == ""
assert config.brightness is None
def test_with_preset(self):
config = ColorGradeConfig.from_dict({"enabled": True, "preset": "warm"})
assert config.enabled is True
assert config.preset == "warm"
def test_invalid_preset_ignored(self):
config = ColorGradeConfig.from_dict({"enabled": True, "preset": "invalid"})
assert config.enabled is True
assert config.preset == ""
def test_with_custom_params(self):
config = ColorGradeConfig.from_dict(
{
"enabled": True,
"brightness": 50,
"contrast": -10.5,
"saturation": 150.0,
"temperature": 20,
"hue": -15.5,
}
)
assert config.brightness == 50.0
assert config.contrast == -10.5
assert config.saturation == 150.0
assert config.temperature == 20.0
assert config.hue == -15.5
def test_invalid_float_values_return_none(self):
config = ColorGradeConfig.from_dict(
{
"enabled": True,
"brightness": "not_a_number",
"contrast": None,
}
)
assert config.brightness is None
assert config.contrast is None
def test_int_values_work(self):
config = ColorGradeConfig.from_dict({"enabled": True, "brightness": 10})
assert config.brightness == 10.0
def test_string_float_values_work(self):
config = ColorGradeConfig.from_dict({"enabled": True, "brightness": "15.5"})
assert config.brightness == 15.5
def test_partial_custom_params(self):
config = ColorGradeConfig.from_dict(
{
"enabled": True,
"preset": "cinema",
"brightness": 5.0,
}
)
assert config.preset == "cinema"
assert config.brightness == 5.0
assert config.contrast is None
class TestValidate:
def test_disabled_valid(self):
config = ColorGradeConfig(enabled=False)
ok, msg = config.validate()
assert ok is True
assert msg == ""
def test_valid_config(self):
config = ColorGradeConfig(
enabled=True,
preset="fresh",
brightness=50.0,
)
ok, msg = config.validate()
assert ok is True
def test_invalid_preset(self):
config = ColorGradeConfig(enabled=True, preset="invalid")
ok, msg = config.validate()
assert ok is False
assert "预设" in msg
def test_brightness_above_max_invalid(self):
config = ColorGradeConfig(enabled=True, brightness=150.0)
ok, msg = config.validate()
assert ok is False
assert "brightness" in msg
def test_brightness_below_min_invalid(self):
config = ColorGradeConfig(enabled=True, brightness=-150.0)
ok, msg = config.validate()
assert ok is False
assert "brightness" in msg
def test_saturation_below_zero_invalid(self):
config = ColorGradeConfig(enabled=True, saturation=-10.0)
ok, msg = config.validate()
assert ok is False
assert "saturation" in msg
def test_saturation_above_max_invalid(self):
config = ColorGradeConfig(enabled=True, saturation=250.0)
ok, msg = config.validate()
assert ok is False
assert "saturation" in msg
def test_hue_above_max_invalid(self):
config = ColorGradeConfig(enabled=True, hue=200.0)
ok, msg = config.validate()
assert ok is False
assert "hue" in msg
def test_hue_below_min_invalid(self):
config = ColorGradeConfig(enabled=True, hue=-200.0)
ok, msg = config.validate()
assert ok is False
assert "hue" in msg
def test_boundary_values_valid(self):
config = ColorGradeConfig(
enabled=True,
brightness=-100.0,
contrast=100.0,
saturation=0.0,
temperature=-100.0,
hue=-180.0,
)
ok, _ = config.validate()
assert ok is True
def test_none_values_valid(self):
"""None值不参与校验(视为未设置)."""
config = ColorGradeConfig(enabled=True)
ok, _ = config.validate()
assert ok is True
class TestGetPresetNames:
def test_returns_sorted_list(self):
names = get_preset_names()
assert isinstance(names, list)
preset_keys = [n[0] for n in names]
assert preset_keys == sorted(preset_keys)
def test_count_matches_valid_presets(self):
names = get_preset_names()
assert len(names) == len(VALID_PRESETS)
def test_each_entry_has_name_and_display(self):
names = get_preset_names()
for name, display in names:
assert name in VALID_PRESETS
assert display == PRESET_DISPLAY_NAMES[name]
assert len(display) > 0
class TestGetPresetParams:
def test_existing_preset(self):
params = get_preset_params("fresh")
assert params is not None
assert params["brightness"] == 8
def test_nonexistent_preset(self):
params = get_preset_params("nonexistent")
assert params is None
def test_all_presets_have_all_params(self):
for preset in VALID_PRESETS:
params = get_preset_params(preset)
assert params is not None
for key in ALL_PARAM_KEYS:
assert key in params
def test_returns_dict_with_correct_values(self):
"""返回的字典包含所有预期参数."""
params = get_preset_params("warm")
assert params["brightness"] == 5
assert params["temperature"] == 30
assert len(params) == 5
class TestClampParam:
def test_brightness_within_range(self):
assert clamp_param("brightness", 50.0) == 50.0
def test_brightness_above_max(self):
assert clamp_param("brightness", 200.0) == 100.0
def test_brightness_below_min(self):
assert clamp_param("brightness", -200.0) == -100.0
def test_saturation_within_range(self):
assert clamp_param("saturation", 100.0) == 100.0
def test_saturation_at_boundary(self):
assert clamp_param("saturation", 0.0) == 0.0
assert clamp_param("saturation", 200.0) == 200.0
def test_hue_within_range(self):
assert clamp_param("hue", 90.0) == 90.0
def test_hue_above_max(self):
assert clamp_param("hue", 200.0) == 180.0
def test_unknown_param_passthrough(self):
assert clamp_param("unknown", 999.0) == 999.0
class TestConstants:
def test_all_presets_have_params(self):
for preset in VALID_PRESETS:
assert preset in PRESET_PARAMS
def test_all_presets_have_display_names(self):
for preset in VALID_PRESETS:
assert preset in PRESET_DISPLAY_NAMES
def test_param_ranges_has_all_keys(self):
for key in ALL_PARAM_KEYS:
assert key in PARAM_RANGES
def test_default_params_has_all_keys(self):
for key in ALL_PARAM_KEYS:
assert key in DEFAULT_PARAMS
def test_param_ranges_min_less_than_max(self):
for key, (min_val, max_val) in PARAM_RANGES.items():
assert min_val < max_val, f"{key}: min ({min_val}) should be < max ({max_val})"