import XCTest @testable import Receiver final class JitterBufferTests: XCTestCase { private func packet(seq: Int, ts: Int = 100) -> RtpPacket { RtpPacket(header: RtpHeader(sequenceNumber: seq, timestamp: ts), payload: [UInt8(seq)]) } func testInOrderReleasesImmediately() { let jitter = JitterBuffer() XCTAssertEqual(jitter.push(packet(seq: 1)).map { $0.header.sequenceNumber }, [1]) XCTAssertEqual(jitter.push(packet(seq: 2)).map { $0.header.sequenceNumber }, [2]) XCTAssertEqual(jitter.push(packet(seq: 3)).map { $0.header.sequenceNumber }, [3]) } func testReordersOutOfOrderPackets() { let jitter = JitterBuffer() XCTAssertEqual(jitter.push(packet(seq: 1)).map { $0.header.sequenceNumber }, [1]) XCTAssertTrue(jitter.push(packet(seq: 3)).isEmpty) XCTAssertEqual(jitter.push(packet(seq: 2)).map { $0.header.sequenceNumber }, [2, 3]) } func testOverflowReleasesInOrderAndAdvances() { let jitter = JitterBuffer(maxDepth: 4) XCTAssertEqual(jitter.push(packet(seq: 1)).map { $0.header.sequenceNumber }, [1]) // seq 2 is lost; 3..6 stay buffered (within the depth bound). for seq in 3...6 { XCTAssertTrue(jitter.push(packet(seq: seq)).isEmpty) } // seq 7 overflows the buffer: 3..7 flush in order. XCTAssertEqual(jitter.push(packet(seq: 7)).map { $0.header.sequenceNumber }, [3, 4, 5, 6, 7]) // Delivery continues in order afterwards. XCTAssertEqual(jitter.push(packet(seq: 8)).map { $0.header.sequenceNumber }, [8]) XCTAssertEqual(jitter.push(packet(seq: 9)).map { $0.header.sequenceNumber }, [9]) } func testDiscardsStragglers() { let jitter = JitterBuffer(maxDepth: 4) _ = jitter.push(packet(seq: 1)) for seq in 3...8 { _ = jitter.push(packet(seq: seq)) } XCTAssertTrue(jitter.push(packet(seq: 9)).isNotEmpty) // seq 4 is now far behind the expected sequence: discarded, not delivered. XCTAssertTrue(jitter.push(packet(seq: 4)).isEmpty) // In-order delivery continues from 10. XCTAssertEqual(jitter.push(packet(seq: 10)).map { $0.header.sequenceNumber }, [10]) } func testClearResetsState() { let jitter = JitterBuffer() _ = jitter.push(packet(seq: 5)) jitter.clear() // A completely different sequence now starts fresh. XCTAssertEqual(jitter.push(packet(seq: 100)).map { $0.header.sequenceNumber }, [100]) } }