113 lines
3.9 KiB
Python
113 lines
3.9 KiB
Python
from pathlib import Path
|
|
|
|
from server.asset_pool import AssetPool
|
|
|
|
|
|
def _make_pool(tmp_path: Path, max_images: int = 10, max_audio: int = 5) -> AssetPool:
|
|
return AssetPool(
|
|
base_dir=str(tmp_path),
|
|
max_images=max_images,
|
|
max_audio=max_audio,
|
|
)
|
|
|
|
|
|
def _fake_image(tmp_path: Path, pool: AssetPool, severity: float) -> str:
|
|
content = b"fake png data"
|
|
return pool.add_image(content, severity=severity)
|
|
|
|
|
|
def _fake_audio(tmp_path: Path, pool: AssetPool, severity: float) -> str:
|
|
content = b"fake wav data"
|
|
return pool.add_audio(content, severity=severity)
|
|
|
|
|
|
class TestAssetPoolInit:
|
|
def test_creates_directories(self, tmp_path):
|
|
"""Pool creates img/ and audio/ subdirectories."""
|
|
pool = _make_pool(tmp_path)
|
|
assert (tmp_path / "img").is_dir()
|
|
assert (tmp_path / "audio").is_dir()
|
|
|
|
def test_empty_pool(self, tmp_path):
|
|
"""New pool has no assets."""
|
|
pool = _make_pool(tmp_path)
|
|
assert pool.image_count == 0
|
|
assert pool.audio_count == 0
|
|
|
|
|
|
class TestAddAssets:
|
|
def test_add_image(self, tmp_path):
|
|
"""Adding an image increments count and returns a URL path."""
|
|
pool = _make_pool(tmp_path)
|
|
url = _fake_image(tmp_path, pool, severity=1.0)
|
|
assert pool.image_count == 1
|
|
assert url.startswith("/assets/img/")
|
|
assert url.endswith(".png")
|
|
|
|
def test_add_audio(self, tmp_path):
|
|
"""Adding audio increments count and returns a URL path."""
|
|
pool = _make_pool(tmp_path)
|
|
url = _fake_audio(tmp_path, pool, severity=1.0)
|
|
assert pool.audio_count == 1
|
|
assert url.startswith("/assets/audio/")
|
|
assert url.endswith(".wav")
|
|
|
|
def test_file_exists_on_disk(self, tmp_path):
|
|
"""Added assets exist as real files."""
|
|
pool = _make_pool(tmp_path)
|
|
url = _fake_image(tmp_path, pool, severity=1.0)
|
|
filename = url.split("/")[-1]
|
|
assert (tmp_path / "img" / filename).exists()
|
|
|
|
|
|
class TestSelectAssets:
|
|
def test_select_image_by_severity(self, tmp_path):
|
|
"""Selects an image closest to target severity."""
|
|
pool = _make_pool(tmp_path)
|
|
_fake_image(tmp_path, pool, severity=0.5)
|
|
_fake_image(tmp_path, pool, severity=2.0)
|
|
_fake_image(tmp_path, pool, severity=4.0)
|
|
url = pool.select_image(target_severity=1.8)
|
|
assert url is not None
|
|
|
|
def test_select_audio_by_severity(self, tmp_path):
|
|
"""Selects an audio clip closest to target severity."""
|
|
pool = _make_pool(tmp_path)
|
|
_fake_audio(tmp_path, pool, severity=0.5)
|
|
_fake_audio(tmp_path, pool, severity=3.0)
|
|
url = pool.select_audio(target_severity=2.5)
|
|
assert url is not None
|
|
|
|
def test_select_from_empty_returns_none(self, tmp_path):
|
|
"""Selecting from empty pool returns None."""
|
|
pool = _make_pool(tmp_path)
|
|
assert pool.select_image(target_severity=1.0) is None
|
|
assert pool.select_audio(target_severity=1.0) is None
|
|
|
|
|
|
class TestRotation:
|
|
def test_image_rotation(self, tmp_path):
|
|
"""Oldest images are removed when pool exceeds max."""
|
|
pool = _make_pool(tmp_path, max_images=3)
|
|
for i in range(5):
|
|
_fake_image(tmp_path, pool, severity=float(i))
|
|
assert pool.image_count == 3
|
|
|
|
def test_audio_rotation(self, tmp_path):
|
|
"""Oldest audio clips are removed when pool exceeds max."""
|
|
pool = _make_pool(tmp_path, max_audio=2)
|
|
for i in range(4):
|
|
_fake_audio(tmp_path, pool, severity=float(i))
|
|
assert pool.audio_count == 2
|
|
|
|
|
|
class TestStatus:
|
|
def test_status_dict(self, tmp_path):
|
|
"""Status returns pool sizes."""
|
|
pool = _make_pool(tmp_path)
|
|
_fake_image(tmp_path, pool, severity=1.0)
|
|
_fake_audio(tmp_path, pool, severity=1.0)
|
|
status = pool.get_status()
|
|
assert status["image_pool_size"] == 1
|
|
assert status["audio_pool_size"] == 1
|