56 lines
2.3 KiB
Python
56 lines
2.3 KiB
Python
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")
|