from __future__ import annotations import io from PIL import Image import pytest from spriteforge.studio.models import Asset, GenerationRecipe, StyleBible from spriteforge.studio.store import ProjectStore def png(color=(12, 34, 56, 255)) -> bytes: image = Image.new("RGBA", (8, 6), color) output = io.BytesIO() image.save(output, "PNG") return output.getvalue() def test_project_asset_candidate_approval_roundtrip(tmp_path): store = ProjectStore.create(tmp_path / "art", "horror_ops", "Horror Ops") store.update_style(StyleBible(description="industrial biomechanical horror")) store.add_asset(Asset(id="field_agent", name="Field Agent", kind="character", target_width=60, target_height=60)) reference = store.import_png(png(), "reference") store.attach_reference("field_agent", reference) _, shot = store.add_shot("field_agent", "idle", 0, 0) candidate_media = store.import_png(png((90, 10, 10, 255)), "candidate") recipe = GenerationRecipe(provider="test", model="fake", seed=7, prompt="agent", width=256, height=256, reference_hashes=[reference.hash]) _, candidate = store.add_candidate("field_agent", shot.id, candidate_media, recipe) store.decide("field_agent", shot.id, candidate.id, "approved") project = store.load() saved = project.assets[0].shots[0] assert saved.approved_candidate_id == candidate.id assert saved.candidates[0].decision == "approved" assert store.media_path(saved.candidates[0].image.path).is_file() def test_media_is_content_addressed_and_canonicalized(tmp_path): store = ProjectStore.create(tmp_path / "art", "test_project", "Test") first = store.import_png(png(), "reference") second = store.import_png(png(), "candidate") assert first.hash == second.hash assert first.path == second.path def test_store_rejects_escape_and_duplicate_asset(tmp_path): store = ProjectStore.create(tmp_path / "art", "test_project", "Test") asset = Asset(id="agent", name="Agent", kind="character", target_width=60, target_height=60) store.add_asset(asset) with pytest.raises(ValueError, match="already exists"): store.add_asset(asset) with pytest.raises(ValueError, match="escapes"): store.media_path("../secret.png")