"""像素级扰动滤镜单元测试(Issue #1765)。 覆盖: - generate_pixel_perturbation:生成像素级扰动参数 - 滤镜组合:2-3 种滤镜随机组合 - 参数范围:肉眼不可见但帧级可检测 - FFmpeg 滤镜语法生成 """ from __future__ import annotations import random import pytest from packages.domain.variant_plan_selector import generate_pixel_perturbation class TestGeneratePixelPerturbation: """generate_pixel_perturbation 测试。""" def test_returns_dict(self): """返回 dict。""" result = generate_pixel_perturbation() assert isinstance(result, dict) def test_has_filters_key(self): """包含 filters 键。""" result = generate_pixel_perturbation() assert "filters" in result def test_filters_count_2_or_3(self): """选 2-3 种滤镜。""" for _ in range(50): result = generate_pixel_perturbation() assert len(result["filters"]) in [2, 3] def test_filters_from_valid_options(self): """滤镜来自有效选项。""" valid_options = {"noise", "unsharp", "curves", "color_balance"} for _ in range(50): result = generate_pixel_perturbation() for f in result["filters"]: assert f in valid_options def test_noise_parameters(self): """noise 滤镜有正确参数范围。""" for _ in range(20): result = generate_pixel_perturbation() if "noise" in result["filters"]: strength = result.get("noise_strength", 0) assert 0.01 <= strength <= 0.02 def test_unsharp_parameters(self): """unsharp 滤镜有正确参数范围。""" for _ in range(20): result = generate_pixel_perturbation() if "unsharp" in result["filters"]: amount = result.get("unsharp_amount", 0) assert -0.5 <= amount <= 0.5 def test_curves_parameters(self): """curves 滤镜有正确参数范围。""" for _ in range(20): result = generate_pixel_perturbation() if "curves" in result["filters"]: contrast = result.get("curves_contrast", 1.0) assert 0.95 <= contrast <= 1.05 def test_color_balance_parameters(self): """color_balance 滤镜有正确参数范围。""" valid_colors = [-5, -3, 0, 3, 5] for _ in range(20): result = generate_pixel_perturbation() if "color_balance" in result["filters"]: assert result.get("color_r") in valid_colors assert result.get("color_g") in valid_colors assert result.get("color_b") in valid_colors def test_same_seed_same_result(self): """相同 seed 返回相同结果。""" rng1 = random.Random(42) rng2 = random.Random(42) result1 = generate_pixel_perturbation(rng1) result2 = generate_pixel_perturbation(rng2) assert result1 == result2 def test_different_seeds_may_differ(self): """不同 seed 可能返回不同结果。""" results = set() for seed in range(20): rng = random.Random(seed) result = generate_pixel_perturbation(rng) results.add(tuple(result["filters"])) # 20 个 seed 至少看到 3 种不同组合 assert len(results) >= 3 class TestPixelPerturbationAcceptance: """Issue #1765 验收测试。""" def test_batch_3_variants_have_different_filters(self): """批量 3 个变体有不同的滤镜组合。""" results = [] for seed in [100, 200, 300]: rng = random.Random(seed) result = generate_pixel_perturbation(rng) results.append(tuple(result["filters"])) # 至少 2 种不同组合 unique = len(set(results)) assert unique >= 2, f"Expected >= 2 unique filter combos, got {unique}: {results}" class TestIntSeedSupport: """int seed 入参支持(与 get_rhythm_template(seed) 接口一致)。""" def test_int_seed_returns_dict(self): """int seed 正常返回 dict。""" result = generate_pixel_perturbation(42) assert isinstance(result, dict) assert "filters" in result def test_int_seed_reproducible(self): """相同 int seed 结果一致。""" assert generate_pixel_perturbation(42) == generate_pixel_perturbation(42) def test_int_seed_differs_across_seeds(self): """不同 int seed 大概率不同(遍历确认至少 2 种组合)。""" results = {tuple(generate_pixel_perturbation(s)["filters"]) for s in range(30)} assert len(results) >= 2 def test_int_seed_matches_random_obj(self): """int seed 与等价 random.Random(seed) 结果一致。""" assert generate_pixel_perturbation(7) == generate_pixel_perturbation(random.Random(7)) def test_none_seed_works(self): """None 入参(默认随机)正常返回。""" result = generate_pixel_perturbation(None) assert isinstance(result, dict) assert len(result["filters"]) in [2, 3]