"""chroma_key_config 领域模型单测.""" from __future__ import annotations import pytest from packages.domain.chroma_key_config import ( CHROMA_KEY_PRESETS, ChromaKeyConfig, apply_chroma_key_if_needed, build_chromakey_filter, build_colorkey_filter, get_preset_names, normalize_color, ) # ── ChromaKeyConfig.from_dict 测试 ──────────────────────────────────────── class TestChromaKeyConfigFromDict: def test_none_returns_disabled(self): cfg = ChromaKeyConfig.from_dict(None) assert cfg.enabled is False def test_empty_dict_returns_disabled(self): cfg = ChromaKeyConfig.from_dict({}) assert cfg.enabled is False def test_disabled_returns_disabled(self): cfg = ChromaKeyConfig.from_dict({"enabled": False}) assert cfg.enabled is False def test_enabled_default_params(self): cfg = ChromaKeyConfig.from_dict({"enabled": True}) assert cfg.enabled is True assert cfg.key_color == "#00FF00" assert cfg.similarity == 0.3 assert cfg.blend == 0.1 assert cfg.spill_suppress == 0.0 def test_custom_params(self): cfg = ChromaKeyConfig.from_dict( { "enabled": True, "key_color": "#0000FF", "similarity": 0.5, "blend": 0.2, "spill_suppress": 0.4, } ) assert cfg.key_color == "#0000FF" assert cfg.similarity == 0.5 assert cfg.blend == 0.2 assert cfg.spill_suppress == 0.4 def test_similarity_clamped_low(self): cfg = ChromaKeyConfig.from_dict({"enabled": True, "similarity": 0.001}) assert cfg.similarity == 0.01 def test_similarity_clamped_high(self): cfg = ChromaKeyConfig.from_dict({"enabled": True, "similarity": 2.0}) assert cfg.similarity == 1.0 def test_blend_clamped_low(self): cfg = ChromaKeyConfig.from_dict({"enabled": True, "blend": -0.5}) assert cfg.blend == 0.0 def test_blend_clamped_high(self): cfg = ChromaKeyConfig.from_dict({"enabled": True, "blend": 1.5}) assert cfg.blend == 1.0 def test_spill_suppress_clamped(self): cfg = ChromaKeyConfig.from_dict({"enabled": True, "spill_suppress": 2.0}) assert cfg.spill_suppress == 1.0 def test_invalid_similarity_type_uses_default(self): cfg = ChromaKeyConfig.from_dict({"enabled": True, "similarity": "high"}) assert cfg.similarity == 0.3 def test_key_color_stripped(self): cfg = ChromaKeyConfig.from_dict({"enabled": True, "key_color": " #00FF00 "}) assert cfg.key_color == "#00FF00" # ── from_preset 测试 ────────────────────────────────────────────────────── class TestFromPreset: def test_green_screen_preset(self): cfg = ChromaKeyConfig.from_preset("green_screen") assert cfg is not None assert cfg.enabled is True assert cfg.key_color == "#00FF00" assert cfg.similarity == 0.3 def test_blue_screen_preset(self): cfg = ChromaKeyConfig.from_preset("blue_screen") assert cfg is not None assert cfg.key_color == "#0000FF" def test_invalid_preset_returns_none(self): assert ChromaKeyConfig.from_preset("nonexistent") is None def test_all_presets_valid(self): for name in CHROMA_KEY_PRESETS: cfg = ChromaKeyConfig.from_preset(name) assert cfg is not None assert cfg.enabled is True # ── has_effect / validate 测试 ──────────────────────────────────────────── class TestHasEffectAndValidate: def test_disabled_no_effect(self): cfg = ChromaKeyConfig(enabled=False) assert cfg.has_effect() is False def test_enabled_has_effect(self): cfg = ChromaKeyConfig(enabled=True, similarity=0.3) assert cfg.has_effect() is True def test_zero_similarity_no_effect(self): cfg = ChromaKeyConfig(enabled=True, similarity=0.0) # similarity 被钳制后为 0.01,所以应该有效果 # 等等,from_dict 才会钳制,直接构造不会 assert cfg.has_effect() is False def test_validate_disabled_valid(self): cfg = ChromaKeyConfig(enabled=False) ok, msg = cfg.validate() assert ok is True assert msg == "" def test_validate_enabled_valid(self): cfg = ChromaKeyConfig(enabled=True, key_color="#00FF00") ok, msg = cfg.validate() assert ok is True def test_validate_empty_color_invalid(self): cfg = ChromaKeyConfig(enabled=True, key_color="") ok, msg = cfg.validate() assert ok is False assert "key_color" in msg def test_validate_similarity_out_of_range(self): cfg = ChromaKeyConfig(enabled=True, similarity=2.0) ok, msg = cfg.validate() assert ok is False assert "similarity" in msg # ── normalize_color 测试 ────────────────────────────────────────────────── class TestNormalizeColor: def test_hex_with_hash(self): assert normalize_color("#00FF00") == "0x00FF00" def test_hex_lowercase(self): assert normalize_color("#00ff00") == "0x00FF00" def test_hex_without_hash(self): assert normalize_color("00FF00") == "0x00FF00" def test_hex_with_alpha(self): assert normalize_color("#00FF00FF") == "0x00FF00" def test_already_0x_format(self): assert normalize_color("0x00FF00") == "0X00FF00" def test_0x_lowercase(self): assert normalize_color("0x00ff00") == "0X00FF00" def test_color_name_passthrough(self): assert normalize_color("green") == "green" assert normalize_color("blue") == "blue" def test_whitespace_stripped(self): assert normalize_color(" #FF0000 ") == "0xFF0000" # ── build_colorkey_filter 测试 ──────────────────────────────────────────── class TestBuildColorkeyFilter: def test_disabled_returns_copy(self): cfg = ChromaKeyConfig(enabled=False) result = build_colorkey_filter(cfg, "[in]", "[out]") assert "copy" in result assert "[in]" in result assert "[out]" in result def test_basic_colorkey(self): cfg = ChromaKeyConfig(enabled=True, key_color="#00FF00", similarity=0.3, blend=0.1) result = build_colorkey_filter(cfg, "[v]", "[ck]") assert "colorkey=" in result assert "color=0x00FF00" in result assert "similarity=0.3" in result assert "blend=0.1" in result assert "[v]" in result assert "[ck]" in result def test_with_spill_suppress(self): cfg = ChromaKeyConfig(enabled=True, key_color="#00FF00", spill_suppress=0.5) result = build_colorkey_filter(cfg, "[in]", "[out]") assert "colorchannelmixer=" in result assert "rr=" in result assert "gg=" in result assert "bb=" in result def test_no_spill_suppress_no_colorchannelmixer(self): cfg = ChromaKeyConfig(enabled=True, spill_suppress=0.0) result = build_colorkey_filter(cfg, "[in]", "[out]") assert "colorchannelmixer" not in result # ── build_chromakey_filter 测试 ─────────────────────────────────────────── class TestBuildChromakeyFilter: def test_disabled_returns_copy(self): cfg = ChromaKeyConfig(enabled=False) result = build_chromakey_filter(cfg, "[in]", "[out]") assert "copy" in result def test_basic_chromakey(self): cfg = ChromaKeyConfig(enabled=True, key_color="#00FF00", similarity=0.3, blend=0.1) result = build_chromakey_filter(cfg, "[v]", "[ck]") assert "chromakey=" in result assert "color=0x00FF00" in result assert "similarity=0.3" in result assert "blend=0.1" in result def test_contains_input_and_output_labels(self): cfg = ChromaKeyConfig(enabled=True) result = build_chromakey_filter(cfg, "[in_v]", "[out_v]") assert "[in_v]" in result assert "[out_v]" in result # ── apply_chroma_key_if_needed 测试 ─────────────────────────────────────── class TestApplyChromaKeyIfNeeded: def test_none_config_returns_none(self): assert apply_chroma_key_if_needed(None, "[in]", "[out]") is None def test_no_chroma_key_returns_none(self): assert apply_chroma_key_if_needed({}, "[in]", "[out]") is None def test_disabled_chroma_key_returns_none(self): config = {"chroma_key": {"enabled": False}} assert apply_chroma_key_if_needed(config, "[in]", "[out]") is None def test_enabled_chroma_key_returns_filter(self): config = {"chroma_key": {"enabled": True, "key_color": "#00FF00"}} result = apply_chroma_key_if_needed(config, "[in]", "[out]") assert result is not None assert "colorkey" in result def test_invalid_config_handles_exception(self): # 传入无效配置触发异常,应该返回 None 而不是抛出 config = {"chroma_key": "invalid_string"} result = apply_chroma_key_if_needed(config, "[in]", "[out]") assert result is None # ── 预设工具函数测试 ─────────────────────────────────────────────────────── class TestPresetUtils: def test_get_preset_names_returns_sorted_list(self): names = get_preset_names() assert isinstance(names, list) assert len(names) == len(CHROMA_KEY_PRESETS) assert names == sorted(names) def test_all_preset_names_in_presets_dict(self): for name in get_preset_names(): assert name in CHROMA_KEY_PRESETS