""" Tests for Processor implementations — ChecksumProcessor, SimulatedDecodeProcessor, CompositeProcessor. Demonstrates: TDD (Interview Topic 8) — ABC contract, parametrized tests. """ import pytest from core.chunker.exceptions import ChunkChecksumError from core.chunker.models import Chunk from core.chunker.processor import ( ChecksumProcessor, CompositeProcessor, Processor, SimulatedDecodeProcessor, ) class TestChecksumProcessor: def test_valid_time_range(self, sample_chunk): """Valid time range passes.""" proc = ChecksumProcessor() result = proc.process(sample_chunk) assert result.success is True assert result.checksum_valid is True assert result.processing_time > 0 def test_invalid_time_range(self): """Invalid time range raises ChunkChecksumError.""" chunk = Chunk( sequence=0, start_time=10.0, end_time=10.0, # zero duration source_path="/fake.mp4", duration=0.0, ) proc = ChecksumProcessor() with pytest.raises(ChunkChecksumError) as exc_info: proc.process(chunk) assert exc_info.value.sequence == 0 def test_sequence_preserved(self, make_chunk): """Result carries the chunk's sequence number.""" chunk = make_chunk(42) proc = ChecksumProcessor() result = proc.process(chunk) assert result.sequence == 42 class TestSimulatedDecodeProcessor: def test_processes_successfully(self, sample_chunk): """Simulated decode always succeeds.""" proc = SimulatedDecodeProcessor(ms_per_second=1.0) result = proc.process(sample_chunk) assert result.success is True assert result.processing_time > 0 def test_time_proportional_to_duration(self): """Longer chunks take longer.""" short = Chunk(0, 0.0, 1.0, "/fake.mp4", 1.0) long = Chunk(1, 0.0, 10.0, "/fake.mp4", 10.0) proc = SimulatedDecodeProcessor(ms_per_second=50.0) r_short = proc.process(short) r_long = proc.process(long) assert r_long.processing_time > r_short.processing_time class TestCompositeProcessor: def test_chains_processors(self, sample_chunk): """Composite runs all processors in sequence.""" proc = CompositeProcessor([ ChecksumProcessor(), SimulatedDecodeProcessor(ms_per_second=1.0), ]) result = proc.process(sample_chunk) assert result.success is True def test_stops_on_failure(self): """If first processor raises, composite propagates the error.""" bad_chunk = Chunk(0, 10.0, 10.0, "/fake.mp4", 0.0) # invalid range proc = CompositeProcessor([ ChecksumProcessor(), SimulatedDecodeProcessor(ms_per_second=1.0), ]) with pytest.raises(ChunkChecksumError): proc.process(bad_chunk) def test_requires_at_least_one(self): """Empty processor list raises ValueError.""" with pytest.raises(ValueError, match="at least one"): CompositeProcessor([]) def test_is_processor(self): """CompositeProcessor is a Processor.""" proc = CompositeProcessor([ChecksumProcessor()]) assert isinstance(proc, Processor)