75 lines
3.9 KiB
Python
75 lines
3.9 KiB
Python
import hashlib
|
|
from pathlib import Path
|
|
import numpy as np
|
|
import pytest
|
|
|
|
from spriteforge.backends import BackendContext, create_backend
|
|
from spriteforge.backends.procedural import generator_names
|
|
from spriteforge.manifest import AssetSpec
|
|
from spriteforge.postprocess import build_palette, encode_frames, normalize_asset
|
|
|
|
def spec(generator:str,**params)->AssetSpec:
|
|
return AssetSpec(backend="procedural",generator=generator,params=params,dirs=1,seed=123)
|
|
|
|
@pytest.mark.parametrize("name",["floor_tile","wall_tile","decal"])
|
|
def test_generators_are_deterministic_and_nonempty(name):
|
|
backend=create_backend("procedural");context=BackendContext(Path.cwd(),"test")
|
|
a=backend.generate(spec(name),context);b=backend.generate(spec(name),context)
|
|
assert np.array_equal(a.frames[0].rgba,b.frames[0].rgba)
|
|
assert np.count_nonzero(a.frames[0].rgba[...,3])>0
|
|
assert a.frames[0].rgba.dtype==np.uint8
|
|
|
|
def test_seed_changes_noise():
|
|
backend=create_backend("procedural");context=BackendContext(Path.cwd(),"test")
|
|
a=backend.generate(spec("floor_tile"),context)
|
|
changed=spec("floor_tile").model_copy(update={"seed":124})
|
|
b=backend.generate(changed,context)
|
|
assert not np.array_equal(a.frames[0].rgba,b.frames[0].rgba)
|
|
|
|
def test_variants_and_postprocess_streams():
|
|
raw=create_backend("procedural").generate(spec("decal",variants=3,width=31,height=17),BackendContext(Path.cwd(),"x"))
|
|
normalized=normalize_asset(raw,"24x12")
|
|
palette=build_palette([normalized]);frames=encode_frames(normalized,palette,dither=True)
|
|
assert len(frames)==3 and len(palette)==256
|
|
assert all(f.width<=24 and f.height<=12 for f in frames)
|
|
assert all(f.normals_xy is not None and f.depth is not None for f in frames)
|
|
|
|
def test_explicit_source_scale_downsamples_small_supersampled_silhouette():
|
|
raw=create_backend("procedural").generate(spec("decal",width=40,height=20),BackendContext(Path.cwd(),"x"))
|
|
normalized=normalize_asset(raw,"96x112",0.25)
|
|
frame=normalized.frames[0]
|
|
assert frame.rgba.shape[1]<=10 and frame.rgba.shape[0]<=5
|
|
|
|
def test_unknown_generator_is_textual():
|
|
with pytest.raises(ValueError,match="available"):
|
|
create_backend("procedural").generate(spec("missing"),BackendContext(Path.cwd(),"x"))
|
|
|
|
def test_unknown_generator_parameter_is_rejected():
|
|
with pytest.raises(ValueError,match="heigth"):
|
|
create_backend("procedural").generate(spec("wall_tile",heigth=20),BackendContext(Path.cwd(),"x"))
|
|
|
|
def test_registry_contains_three_generators():
|
|
assert {"floor_tile","wall_tile","decal"}<=set(generator_names())
|
|
|
|
def test_single_frame_generator_still_refuses_extra_directions():
|
|
turned=spec("floor_tile").model_copy(update={"dirs":4})
|
|
with pytest.raises(ValueError,match="dirs: 1"):
|
|
create_backend("procedural").generate(turned,BackendContext(Path.cwd(),"x"))
|
|
|
|
# Слепки старых генераторов: расширение бэкенда последовательностями не имеет
|
|
# права поменять ни один байт уже собранных ассетов.
|
|
GOLDEN={"floor_tile":("4d1c4610ac48af25d8acdc8f33f6f75416ca493b764dbc45d35afd5d99d38cf5",{"width":32,"height":16,"variants":2}),
|
|
"wall_tile":("3d89b51db3989e1c9fad63a3f0682d504a8f7a5055a4ab94c19a69351c344096",{"width":32,"top_height":16,"height":24}),
|
|
"decal":("654dc4cff086dafb1285914e78120055e2b9adbcfd0697011968b6176697c17f",{"width":24,"height":12})}
|
|
|
|
@pytest.mark.parametrize("name",sorted(GOLDEN))
|
|
def test_existing_generators_are_byte_identical(name):
|
|
digest,params=GOLDEN[name]
|
|
frozen=AssetSpec(backend="procedural",generator=name,params=params,dirs=1,seed=77,fps=10)
|
|
asset=create_backend("procedural").generate(frozen,BackendContext(Path.cwd(),"t"))
|
|
hasher=hashlib.sha256()
|
|
for frame in asset.frames:
|
|
hasher.update(frame.rgba.tobytes())
|
|
hasher.update(str((frame.pivot_x,frame.pivot_y,frame.duration_ms)).encode())
|
|
assert hasher.hexdigest()==digest
|