Files
ledgrab/server/tests/test_postprocessing_looks.py
alexei.dolgolyov e18d56c838 feat(processing): built-in 'look' presets (Cinematic/Vivid/Cozy/Soft/Cool)
Seed five curated, read-only post-processing templates so a non-expert gets
instant good-looking output before discovering the filter pipeline. Each is an
opinionated chain of existing filters (auto-crop/saturation/contrast/colour-
temperature/temporal-blur) tuned for a use case (films, games, evening ambience,
low-flicker, crisp cool-white).

Mirrors the built-in-gradient pattern: adds is_builtin to PostprocessingTemplate,
seeds missing looks on store init (idempotent, additive — no migration), and
makes built-ins read-only (update/delete raise -> 400; clone to customise).
Surfaced via the existing template picker + is_builtin in the response/type.

7 unit tests (seeding, idempotency, read-only protection, round-trip); full
suite green (1926 passed). (A runtime intensity slider is a follow-up — it needs
a filter-chain parameterisation layer.)
2026-06-04 23:43:11 +03:00

82 lines
2.7 KiB
Python

"""Tests for built-in curated 'look' postprocessing templates."""
import pytest
from ledgrab.core.filters.registry import FilterRegistry
from ledgrab.storage.postprocessing_template import PostprocessingTemplate
from ledgrab.storage.postprocessing_template_store import (
_BUILTIN_LOOKS,
PostprocessingTemplateStore,
)
def test_builtins_are_seeded(tmp_db):
store = PostprocessingTemplateStore(tmp_db)
for key in _BUILTIN_LOOKS:
tpl = store.get_template(f"pp_builtin_{key}")
assert tpl.is_builtin is True
assert tpl.filters # non-empty chain
def test_builtin_filters_use_registered_ids(tmp_db):
store = PostprocessingTemplateStore(tmp_db)
for key in _BUILTIN_LOOKS:
tpl = store.get_template(f"pp_builtin_{key}")
for fi in tpl.filters:
assert FilterRegistry.is_registered(fi.filter_id), fi.filter_id
def test_seeding_is_idempotent(tmp_db):
PostprocessingTemplateStore(tmp_db)
store2 = PostprocessingTemplateStore(tmp_db)
ids = [t.id for t in store2.get_all_templates() if t.id.startswith("pp_builtin_")]
assert sorted(ids) == sorted(f"pp_builtin_{k}" for k in _BUILTIN_LOOKS)
def test_builtin_update_is_blocked(tmp_db):
store = PostprocessingTemplateStore(tmp_db)
with pytest.raises(ValueError, match="read-only"):
store.update_template("pp_builtin_vivid", name="Hacked")
def test_builtin_delete_is_blocked(tmp_db):
store = PostprocessingTemplateStore(tmp_db)
with pytest.raises(ValueError, match="cannot be deleted"):
store.delete_template("pp_builtin_vivid")
def test_user_template_still_editable_and_deletable(tmp_db):
store = PostprocessingTemplateStore(tmp_db)
tpl = store.create_template("My Look", filters=[])
assert tpl.is_builtin is False
store.update_template(tpl.id, description="changed")
store.delete_template(tpl.id)
with pytest.raises(ValueError):
store.get_template(tpl.id)
def test_is_builtin_round_trips_through_dict():
tpl = PostprocessingTemplate.from_dict(
{
"id": "pp_x",
"name": "x",
"filters": [],
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00",
"is_builtin": True,
}
)
assert tpl.is_builtin is True
assert tpl.to_dict()["is_builtin"] is True
# legacy dict without the field defaults to False
legacy = PostprocessingTemplate.from_dict(
{
"id": "pp_y",
"name": "y",
"filters": [],
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00",
}
)
assert legacy.is_builtin is False