Squashed 'core/' content from commit 4957443
git-subtree-dir: core git-subtree-split: 4957443184ae0eb6323635a90a19acffb3e01d07
This commit is contained in:
201
artdag/sexp/test_primitives.py
Normal file
201
artdag/sexp/test_primitives.py
Normal file
@@ -0,0 +1,201 @@
|
||||
"""
|
||||
Tests for Python primitive effects.
|
||||
|
||||
Tests that ascii_art, ascii_zones, and other Python primitives
|
||||
can be executed via the EffectExecutor.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
try:
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
HAS_DEPS = True
|
||||
except ImportError:
|
||||
HAS_DEPS = False
|
||||
|
||||
from .primitives import (
|
||||
ascii_art_frame,
|
||||
ascii_zones_frame,
|
||||
get_primitive,
|
||||
list_primitives,
|
||||
)
|
||||
from .ffmpeg_compiler import FFmpegCompiler
|
||||
|
||||
|
||||
def create_test_video(path: Path, duration: float = 0.5, size: str = "64x64") -> bool:
|
||||
"""Create a short test video using ffmpeg."""
|
||||
cmd = [
|
||||
"ffmpeg", "-y",
|
||||
"-f", "lavfi", "-i", f"testsrc=duration={duration}:size={size}:rate=10",
|
||||
"-c:v", "libx264", "-preset", "ultrafast",
|
||||
str(path)
|
||||
]
|
||||
result = subprocess.run(cmd, capture_output=True)
|
||||
return result.returncode == 0
|
||||
|
||||
|
||||
@pytest.mark.skipif(not HAS_DEPS, reason="numpy/PIL not available")
|
||||
class TestPrimitives:
|
||||
"""Test primitive functions directly."""
|
||||
|
||||
def test_ascii_art_frame_basic(self):
|
||||
"""Test ascii_art_frame produces output of same shape."""
|
||||
frame = np.random.randint(0, 255, (64, 64, 3), dtype=np.uint8)
|
||||
result = ascii_art_frame(frame, char_size=8)
|
||||
assert result.shape == frame.shape
|
||||
assert result.dtype == np.uint8
|
||||
|
||||
def test_ascii_zones_frame_basic(self):
|
||||
"""Test ascii_zones_frame produces output of same shape."""
|
||||
frame = np.random.randint(0, 255, (64, 64, 3), dtype=np.uint8)
|
||||
result = ascii_zones_frame(frame, char_size=8)
|
||||
assert result.shape == frame.shape
|
||||
assert result.dtype == np.uint8
|
||||
|
||||
def test_get_primitive(self):
|
||||
"""Test primitive lookup."""
|
||||
assert get_primitive("ascii_art_frame") is ascii_art_frame
|
||||
assert get_primitive("ascii_zones_frame") is ascii_zones_frame
|
||||
assert get_primitive("nonexistent") is None
|
||||
|
||||
def test_list_primitives(self):
|
||||
"""Test listing primitives."""
|
||||
primitives = list_primitives()
|
||||
assert "ascii_art_frame" in primitives
|
||||
assert "ascii_zones_frame" in primitives
|
||||
assert len(primitives) > 5
|
||||
|
||||
|
||||
class TestFFmpegCompilerPrimitives:
|
||||
"""Test FFmpegCompiler python_primitive mappings."""
|
||||
|
||||
def test_has_python_primitive_ascii_art(self):
|
||||
"""Test ascii_art has python_primitive."""
|
||||
compiler = FFmpegCompiler()
|
||||
assert compiler.has_python_primitive("ascii_art") == "ascii_art_frame"
|
||||
|
||||
def test_has_python_primitive_ascii_zones(self):
|
||||
"""Test ascii_zones has python_primitive."""
|
||||
compiler = FFmpegCompiler()
|
||||
assert compiler.has_python_primitive("ascii_zones") == "ascii_zones_frame"
|
||||
|
||||
def test_has_python_primitive_ffmpeg_effect(self):
|
||||
"""Test FFmpeg effects don't have python_primitive."""
|
||||
compiler = FFmpegCompiler()
|
||||
assert compiler.has_python_primitive("brightness") is None
|
||||
assert compiler.has_python_primitive("blur") is None
|
||||
|
||||
def test_compile_effect_returns_none_for_primitives(self):
|
||||
"""Test compile_effect returns None for primitive effects."""
|
||||
compiler = FFmpegCompiler()
|
||||
assert compiler.compile_effect("ascii_art", {}) is None
|
||||
assert compiler.compile_effect("ascii_zones", {}) is None
|
||||
|
||||
|
||||
@pytest.mark.skipif(not HAS_DEPS, reason="numpy/PIL not available")
|
||||
class TestEffectExecutorPrimitives:
|
||||
"""Test EffectExecutor with Python primitives."""
|
||||
|
||||
def test_executor_loads_primitive(self):
|
||||
"""Test that executor finds primitive effects."""
|
||||
from ..nodes.effect import _get_python_primitive_effect
|
||||
|
||||
effect_fn = _get_python_primitive_effect("ascii_art")
|
||||
assert effect_fn is not None
|
||||
|
||||
effect_fn = _get_python_primitive_effect("ascii_zones")
|
||||
assert effect_fn is not None
|
||||
|
||||
def test_executor_rejects_unknown_effect(self):
|
||||
"""Test that executor returns None for unknown effects."""
|
||||
from ..nodes.effect import _get_python_primitive_effect
|
||||
|
||||
effect_fn = _get_python_primitive_effect("nonexistent_effect")
|
||||
assert effect_fn is None
|
||||
|
||||
def test_execute_ascii_art_effect(self, tmp_path):
|
||||
"""Test executing ascii_art effect on a video."""
|
||||
from ..nodes.effect import EffectExecutor
|
||||
|
||||
# Create test video
|
||||
input_path = tmp_path / "input.mp4"
|
||||
if not create_test_video(input_path):
|
||||
pytest.skip("Could not create test video")
|
||||
|
||||
output_path = tmp_path / "output.mkv"
|
||||
executor = EffectExecutor()
|
||||
|
||||
result = executor.execute(
|
||||
config={"effect": "ascii_art", "char_size": 8},
|
||||
inputs=[input_path],
|
||||
output_path=output_path,
|
||||
)
|
||||
|
||||
assert result.exists()
|
||||
assert result.stat().st_size > 0
|
||||
|
||||
|
||||
def run_all_tests():
|
||||
"""Run tests manually."""
|
||||
import sys
|
||||
|
||||
# Check dependencies
|
||||
if not HAS_DEPS:
|
||||
print("SKIP: numpy/PIL not available")
|
||||
return
|
||||
|
||||
print("Testing primitives...")
|
||||
|
||||
# Test primitive functions
|
||||
frame = np.random.randint(0, 255, (64, 64, 3), dtype=np.uint8)
|
||||
|
||||
print(" ascii_art_frame...", end=" ")
|
||||
result = ascii_art_frame(frame, char_size=8)
|
||||
assert result.shape == frame.shape
|
||||
print("PASS")
|
||||
|
||||
print(" ascii_zones_frame...", end=" ")
|
||||
result = ascii_zones_frame(frame, char_size=8)
|
||||
assert result.shape == frame.shape
|
||||
print("PASS")
|
||||
|
||||
# Test FFmpegCompiler mappings
|
||||
print("\nTesting FFmpegCompiler mappings...")
|
||||
compiler = FFmpegCompiler()
|
||||
|
||||
print(" ascii_art python_primitive...", end=" ")
|
||||
assert compiler.has_python_primitive("ascii_art") == "ascii_art_frame"
|
||||
print("PASS")
|
||||
|
||||
print(" ascii_zones python_primitive...", end=" ")
|
||||
assert compiler.has_python_primitive("ascii_zones") == "ascii_zones_frame"
|
||||
print("PASS")
|
||||
|
||||
# Test executor lookup
|
||||
print("\nTesting EffectExecutor...")
|
||||
try:
|
||||
from ..nodes.effect import _get_python_primitive_effect
|
||||
|
||||
print(" _get_python_primitive_effect(ascii_art)...", end=" ")
|
||||
effect_fn = _get_python_primitive_effect("ascii_art")
|
||||
assert effect_fn is not None
|
||||
print("PASS")
|
||||
|
||||
print(" _get_python_primitive_effect(ascii_zones)...", end=" ")
|
||||
effect_fn = _get_python_primitive_effect("ascii_zones")
|
||||
assert effect_fn is not None
|
||||
print("PASS")
|
||||
|
||||
except ImportError as e:
|
||||
print(f"SKIP: {e}")
|
||||
|
||||
print("\n=== All tests passed ===")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_all_tests()
|
||||
Reference in New Issue
Block a user