import XCTest @testable import Receiver final class RtpHeaderTests: XCTestCase { func testRoundtrip() { let header = RtpHeader(version: 2, padding: false, extensionHeader: false, csrcCount: 0, marker: true, payloadType: 96, sequenceNumber: 0xABCD, timestamp: 0xDEADBEEF, ssrc: 0x12345678) let wire = header.serialize() XCTAssertEqual(wire.count, 12) XCTAssertEqual(RtpHeader.parse(wire), header) } func testRejectsBadVersion() { var wire = RtpHeader().serialize() wire[0] = (wire[0] & 0x3F) | (1 << 6) XCTAssertNil(RtpHeader.parse(wire)) } func testRejectsShortInput() { let header = RtpHeader() XCTAssertNil(RtpHeader.parse(Array(header.serialize().prefix(11)))) XCTAssertNil(RtpHeader.parse([])) } func testPreservesFlags() { let header = RtpHeader(padding: true, csrcCount: 2, marker: true, payloadType: 63) let parsed = RtpHeader.parse(header.serialize()) XCTAssertEqual(parsed?.padding, true) XCTAssertEqual(parsed?.csrcCount, 2) XCTAssertEqual(parsed?.marker, true) XCTAssertEqual(parsed?.payloadType, 63) } } final class RtpPacketTests: XCTestCase { private func header(seq: Int, marker: Bool = false) -> RtpHeader { RtpHeader(sequenceNumber: seq, payloadType: 96, marker: marker) } func testRoundtripWithPayload() { let packet = RtpPacket(header: header(seq: 7), payload: [0x11, 0x22, 0x33]) let wire = packet.header.serialize() + packet.payload let parsed = RtpPacket.parse(wire) XCTAssertEqual(parsed?.header, header(seq: 7)) XCTAssertEqual(parsed?.payload, [0x11, 0x22, 0x33]) } func testSkipsCsrcList() { let header = RtpHeader(csrcCount: 1, sequenceNumber: 3) let wire = header.serialize() + [0x0A, 0x00, 0x00, 0x01] + [0x99] let parsed = RtpPacket.parse(wire) XCTAssertEqual(parsed?.header.csrcCount, 1) XCTAssertEqual(parsed?.payload, [0x99]) } func testSkipsExtensionHeader() { let header = RtpHeader(extensionHeader: true, sequenceNumber: 4) // profile=0x0001, length=1 word, one word of data. let wire = header.serialize() + [0x00, 0x01, 0x00, 0x01, 0xDE, 0xAD, 0xBE, 0xEF] + [0x77] let parsed = RtpPacket.parse(wire) XCTAssertEqual(parsed?.payload, [0x77]) } func testStripsPadding() { let header = RtpHeader(padding: true, sequenceNumber: 5) // Payload byte, one padding zero, size byte (2 = padding incl. itself). let wire = header.serialize() + [0x55, 0x00, 0x02] let parsed = RtpPacket.parse(wire) XCTAssertEqual(parsed?.payload, [0x55]) } func testRejectsTruncatedCsrcAndExtension() { let csrc = RtpHeader(csrcCount: 1).serialize() XCTAssertNil(RtpPacket.parse(csrc)) // 12 bytes, needs 16 let ext = RtpHeader(extensionHeader: true).serialize() + [0x00, 0x01] XCTAssertNil(RtpPacket.parse(ext)) // extension length field cut off } func testRejectsBadPadding() { let zeroPad = RtpHeader(padding: true).serialize() + [0x00] XCTAssertNil(RtpPacket.parse(zeroPad)) let oversized = RtpHeader(padding: true).serialize() + [0x00, 0x00, 0x05] XCTAssertNil(RtpPacket.parse(oversized)) XCTAssertNil(RtpPacket.parse([UInt8](repeating: 0, count: 11))) } }