feat: add dog effect

- Ignores input, returns dog.mkv from immutable URL
- Downloads from art-source with hash verification
- Caches downloaded file locally
- 5 automated tests (all passing)

Owner: @giles@artdag.rose-ash.com

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gilesb
2026-01-07 01:11:35 +00:00
commit a071084055
6 changed files with 274 additions and 0 deletions

117
dog/test_effect.py Normal file
View File

@@ -0,0 +1,117 @@
#!/usr/bin/env python3
"""
Automated tests for the dog effect.
Test plan:
1. Test that effect ignores input and returns dog.mkv
2. Test that output hash matches expected DOG_HASH
3. Test idempotence: dog(dog(x)) == dog(x)
4. Test with different inputs produce same output
"""
import hashlib
import tempfile
import unittest
from pathlib import Path
from effect import effect_dog, DOG_HASH, file_hash
class TestDogEffect(unittest.TestCase):
"""Tests for the dog effect."""
def setUp(self):
"""Create temp directory for tests."""
self.temp_dir = tempfile.mkdtemp()
self.temp_path = Path(self.temp_dir)
def tearDown(self):
"""Clean up temp directory."""
import shutil
shutil.rmtree(self.temp_dir, ignore_errors=True)
def test_returns_dog_video(self):
"""Test that effect returns dog.mkv with correct hash."""
# Create a dummy input file
input_path = self.temp_path / "dummy_input.txt"
input_path.write_text("This is a dummy input that should be ignored")
output_path = self.temp_path / "output"
result = effect_dog(input_path, output_path, {})
# Verify output exists
self.assertTrue(result.exists(), "Output file should exist")
# Verify hash
output_hash = file_hash(result)
self.assertEqual(output_hash, DOG_HASH, "Output hash should match DOG_HASH")
def test_ignores_input(self):
"""Test that different inputs produce the same output."""
# Input 1: text file
input1 = self.temp_path / "input1.txt"
input1.write_text("Input 1")
output1 = self.temp_path / "output1"
result1 = effect_dog(input1, output1, {})
# Input 2: different text file
input2 = self.temp_path / "input2.txt"
input2.write_text("Completely different input 2")
output2 = self.temp_path / "output2"
result2 = effect_dog(input2, output2, {})
# Both outputs should have same hash
self.assertEqual(file_hash(result1), file_hash(result2),
"Different inputs should produce same output")
def test_idempotence(self):
"""Test that dog(dog(x)) == dog(x)."""
# First application
input_path = self.temp_path / "input.txt"
input_path.write_text("Original input")
output1 = self.temp_path / "output1"
result1 = effect_dog(input_path, output1, {})
hash1 = file_hash(result1)
# Second application (using first output as input)
output2 = self.temp_path / "output2"
result2 = effect_dog(result1, output2, {})
hash2 = file_hash(result2)
self.assertEqual(hash1, hash2, "dog(dog(x)) should equal dog(x)")
def test_output_extension(self):
"""Test that output has .mkv extension."""
input_path = self.temp_path / "input.txt"
input_path.write_text("test")
output_path = self.temp_path / "output"
result = effect_dog(input_path, output_path, {})
self.assertEqual(result.suffix, ".mkv", "Output should have .mkv extension")
def test_caching(self):
"""Test that second call uses cache (faster)."""
import time
input_path = self.temp_path / "input.txt"
input_path.write_text("test")
# First call (may download)
output1 = self.temp_path / "output1"
start1 = time.time()
effect_dog(input_path, output1, {})
time1 = time.time() - start1
# Second call (should use cache)
output2 = self.temp_path / "output2"
start2 = time.time()
effect_dog(input_path, output2, {})
time2 = time.time() - start2
# Second call should be faster (or at least not much slower)
# We're not strictly asserting this as network conditions vary
print(f"First call: {time1:.3f}s, Second call: {time2:.3f}s")
if __name__ == "__main__":
unittest.main()