bb98620a8a
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 4s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 19s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 1m36s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 20s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m26s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m36s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
- generate_pixel_perturbation():随机选 2-3 种滤镜组合 - noise: 轻微噪声 (0.01~0.02) - unsharp: 锐化/柔化 (-0.5~+0.5) - curves: 对比度微调 (0.95~1.05) - color_balance: RGB 通道偏移 - _apply_pixel_perturbation():渲染时追加到 FFmpeg filter chain - edit_plan_service:批量变体生成时为每个变体生成不同像素扰动 - 参数幅度确保肉眼不可见(SSIM > 0.95),帧级差异 > 3% - 11 个新测试覆盖滤镜组合/参数范围/验收
113 lines
3.9 KiB
Python
113 lines
3.9 KiB
Python
"""像素级扰动滤镜单元测试(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}"
|