""" Tests for ResultCollector — ordered reassembly, out-of-order buffering, duplicates. Demonstrates: TDD (Interview Topic 8) — testing algorithms (heapq reassembly). """ import pytest from core.chunker.collector import ResultCollector from core.chunker.exceptions import ReassemblyError class TestResultCollector: def test_in_order_emission(self, make_result): """Results arriving in order are emitted immediately.""" collector = ResultCollector(total_chunks=3) emitted = collector.add(make_result(0)) assert len(emitted) == 1 assert emitted[0].sequence == 0 emitted = collector.add(make_result(1)) assert len(emitted) == 1 emitted = collector.add(make_result(2)) assert len(emitted) == 1 assert collector.is_complete def test_out_of_order_buffering(self, make_result): """Out-of-order results are buffered until gaps fill.""" collector = ResultCollector(total_chunks=3) # Arrive: 2, 0, 1 emitted = collector.add(make_result(2)) assert len(emitted) == 0 assert collector.buffered_count == 1 emitted = collector.add(make_result(0)) assert len(emitted) == 1 # Only 0 emitted, 1 still missing emitted = collector.add(make_result(1)) assert len(emitted) == 2 # 1 and 2 now emittable assert collector.is_complete def test_reverse_order(self, make_result): """All results arrive in reverse — only last add emits everything.""" collector = ResultCollector(total_chunks=4) for seq in [3, 2, 1]: emitted = collector.add(make_result(seq)) assert len(emitted) == 0 emitted = collector.add(make_result(0)) assert len(emitted) == 4 assert collector.is_complete def test_duplicate_raises(self, make_result): """Duplicate sequence number raises ReassemblyError.""" collector = ResultCollector(total_chunks=3) collector.add(make_result(0)) with pytest.raises(ReassemblyError, match="Duplicate"): collector.add(make_result(0)) def test_emitted_count(self, make_result): """emitted_count tracks correctly.""" collector = ResultCollector(total_chunks=3) assert collector.emitted_count == 0 collector.add(make_result(0)) assert collector.emitted_count == 1 collector.add(make_result(2)) # buffered assert collector.emitted_count == 1 collector.add(make_result(1)) # releases 1 and 2 assert collector.emitted_count == 3 def test_get_ordered_results(self, make_result): """get_ordered_results returns all emitted results in order.""" collector = ResultCollector(total_chunks=3) collector.add(make_result(2)) collector.add(make_result(0)) collector.add(make_result(1)) ordered = collector.get_ordered_results() assert [r.sequence for r in ordered] == [0, 1, 2] def test_avg_processing_time(self, make_result): """Average processing time from sliding window.""" collector = ResultCollector(total_chunks=2) collector.add(make_result(0, processing_time=0.1)) collector.add(make_result(1, processing_time=0.3)) assert abs(collector.avg_processing_time - 0.2) < 0.001 def test_not_complete_when_partial(self, make_result): """is_complete is False until all chunks emitted.""" collector = ResultCollector(total_chunks=3) collector.add(make_result(0)) collector.add(make_result(1)) assert not collector.is_complete