use crate::rtp::*;
use bytes::Bytes;
#[cfg(test)]
mod packet_structure {
use super::*;
#[test]
fn test_rtp_version_2() {
let mut session = RtpSession::new(12345, 0, 8000);
let packet = session.create_packet(vec![1, 2, 3, 4], 160, false);
assert_eq!(packet.version, 2);
}
#[test]
fn test_minimal_header_size() {
let mut session = RtpSession::new(12345, 0, 8000);
let packet = session.create_packet(vec![0; 10], 160, false);
let bytes = packet.build();
assert!(bytes.len() >= RTP_HEADER_SIZE);
}
#[test]
fn test_parse_minimal_packet() {
let data = [
0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xaa, 0xbb, ];
let packet = RtpPacket::parse(&data).unwrap();
assert_eq!(packet.version, 2);
assert!(!packet.padding);
assert!(!packet.extension);
assert_eq!(packet.payload_type, 0);
assert_eq!(packet.sequence_number, 1);
assert_eq!(packet.timestamp, 160);
assert_eq!(packet.ssrc, 12345);
assert_eq!(packet.payload.len(), 2);
}
#[test]
fn test_reject_invalid_version() {
let data = [
0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xaa, 0xbb,
];
let result = RtpPacket::parse(&data);
assert!(result.is_err());
assert!(matches!(result, Err(RtpParseError::InvalidVersion(1))));
}
#[test]
fn test_reject_truncated_packet() {
let data = [0x80, 0x00, 0x00, 0x01]; let result = RtpPacket::parse(&data);
assert!(result.is_err());
assert!(matches!(result, Err(RtpParseError::TooShort(_))));
}
#[test]
fn test_marker_bit() {
let mut session = RtpSession::new(12345, 0, 8000);
let packet_no_marker = session.create_packet(vec![1, 2, 3], 160, false);
assert!(!packet_no_marker.marker);
let packet_with_marker = session.create_packet(vec![1, 2, 3], 320, true);
assert!(packet_with_marker.marker);
}
#[test]
fn test_payload_type() {
let mut session = RtpSession::new(12345, 96, 8000);
let packet = session.create_packet(vec![0; 10], 160, false);
assert_eq!(packet.payload_type, 96);
}
#[test]
fn test_payload_type_max() {
let data = [
0x80, 0xFF, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xaa,
];
let packet = RtpPacket::parse(&data).unwrap();
assert_eq!(packet.payload_type, 127);
assert!(packet.marker);
}
}
#[cfg(test)]
mod sequence_numbers {
use super::*;
#[test]
fn test_sequence_increment() {
let mut session = RtpSession::new(12345, 0, 8000);
let packet1 = session.create_packet(vec![1], 160, false);
let packet2 = session.create_packet(vec![2], 320, false);
assert_eq!(
packet2.sequence_number,
packet1.sequence_number.wrapping_add(1)
);
}
#[test]
fn test_sequence_wraparound() {
let mut session = RtpSession::new(12345, 0, 8000);
let packet1 = session.create_packet(vec![1], 160, false);
let seq1 = packet1.sequence_number;
assert_eq!(65535_u16.wrapping_add(1), 0);
assert_eq!(seq1.wrapping_add(1), seq1 + 1);
}
#[test]
fn test_sequence_newer() {
assert!(sequence_newer(100, 99));
assert!(sequence_newer(10, 65530));
assert!(!sequence_newer(99, 100));
}
#[test]
fn test_sequence_diff() {
assert_eq!(sequence_diff(100, 99), 1);
assert_eq!(sequence_diff(10, 65535), 11);
assert_eq!(sequence_diff(99, 100), -1);
}
#[test]
fn test_large_sequence_jump() {
let diff = sequence_diff(40000, 7232);
assert_ne!(diff, 0);
}
}
#[cfg(test)]
mod timestamps {
use super::*;
#[test]
fn test_timestamp_increment() {
let mut session = RtpSession::new(12345, 0, 8000);
let packet1 = session.create_packet(vec![0; 160], 160, false);
let ts1 = packet1.timestamp;
let packet2 = session.create_packet(vec![0; 160], 160, false);
let ts2 = packet2.timestamp;
assert_eq!(ts2, ts1 + 160);
}
#[test]
fn test_timestamp_wraparound() {
let ts_near_max = u32::MAX - 100;
let new_ts = ts_near_max.wrapping_add(160);
assert!(new_ts < ts_near_max);
assert_eq!(new_ts, 59); }
#[test]
fn test_timestamp_clock_rate() {
let mut session_8k = RtpSession::new(12345, 0, 8000);
let packet1_8k = session_8k.create_packet(vec![0; 160], 160, false);
let packet2_8k = session_8k.create_packet(vec![0; 160], 160, false);
let mut session_16k = RtpSession::new(12346, 9, 16000);
let packet1_16k = session_16k.create_packet(vec![0; 320], 320, false);
let packet2_16k = session_16k.create_packet(vec![0; 320], 320, false);
assert_eq!(packet2_8k.timestamp, packet1_8k.timestamp + 160);
assert_eq!(packet2_16k.timestamp, packet1_16k.timestamp + 320);
}
}
#[cfg(test)]
mod ssrc_handling {
use super::*;
#[test]
fn test_ssrc_constant() {
let mut session = RtpSession::new(12345, 0, 8000);
let packet1 = session.create_packet(vec![1], 160, false);
let packet2 = session.create_packet(vec![2], 320, false);
assert_eq!(packet1.ssrc, packet2.ssrc);
assert_eq!(packet1.ssrc, 12345);
}
#[test]
fn test_ssrc_collision_detection() {
let _session = RtpSession::new(12345, 0, 8000);
let data = [
0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30,
0x39, 0xaa, 0xbb,
];
let packet = RtpPacket::parse(&data).unwrap();
assert_eq!(packet.ssrc, 12345);
}
#[test]
fn test_different_ssrcs() {
let session1 = RtpSession::new(11111, 0, 8000);
let session2 = RtpSession::new(22222, 0, 8000);
assert_ne!(session1.ssrc(), session2.ssrc());
}
}
#[cfg(test)]
mod csrc_list {
use super::*;
#[test]
fn test_max_csrc_count() {
assert_eq!(MAX_CSRC, 15);
}
#[test]
fn test_parse_with_csrc() {
let data = [
0x82, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0xaa, 0xbb, ];
let packet = RtpPacket::parse(&data).unwrap();
assert_eq!(packet.csrc.len(), 2);
assert_eq!(packet.csrc[0], 1);
assert_eq!(packet.csrc[1], 2);
}
#[test]
fn test_empty_csrc() {
let data = [
0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xaa,
];
let packet = RtpPacket::parse(&data).unwrap();
assert_eq!(packet.csrc.len(), 0);
}
#[test]
fn test_truncated_csrc() {
let data = [
0x82, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0x00, 0x00, 0x00, 0x01, ];
let result = RtpPacket::parse(&data);
assert!(result.is_err());
}
}
#[cfg(test)]
mod padding {
use super::*;
#[test]
fn test_padding_bit() {
let data = [
0xA0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xaa, 0xbb, 0xcc, 0x00, 0x04, ];
let packet = RtpPacket::parse(&data).unwrap();
assert!(packet.padding);
assert_eq!(packet.payload.len(), 1); }
#[test]
fn test_no_padding() {
let data = [
0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xaa, 0xbb,
];
let packet = RtpPacket::parse(&data).unwrap();
assert!(!packet.padding);
assert_eq!(packet.payload.len(), 2);
}
}
#[cfg(test)]
mod extension_header {
use super::*;
#[test]
fn test_extension_header() {
let data = [
0x90, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xAB, 0xCD, 0x00, 0x01, 0x11, 0x22, 0x33, 0x44, 0xaa, 0xbb, ];
let packet = RtpPacket::parse(&data).unwrap();
assert!(packet.extension);
assert!(packet.extension_header.is_some());
let ext = packet.extension_header.unwrap();
assert_eq!(ext.profile, 0xABCD);
assert_eq!(ext.data.len(), 4);
assert_eq!(&ext.data[..], &[0x11, 0x22, 0x33, 0x44]);
}
#[test]
fn test_no_extension() {
let data = [
0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xaa,
];
let packet = RtpPacket::parse(&data).unwrap();
assert!(!packet.extension);
assert!(packet.extension_header.is_none());
}
#[test]
fn test_truncated_extension() {
let data = [
0x90, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xAB, 0xCD, ];
let result = RtpPacket::parse(&data);
assert!(result.is_err());
}
}
#[cfg(test)]
mod packet_building {
use super::*;
#[test]
fn test_build_and_parse_roundtrip() {
let mut session = RtpSession::new(12345, 0, 8000);
let original_payload = vec![0xAA, 0xBB, 0xCC, 0xDD];
let packet = session.create_packet(original_payload.clone(), 160, true);
let bytes = packet.build();
let parsed = RtpPacket::parse(&bytes).unwrap();
assert_eq!(parsed.version, 2);
assert_eq!(parsed.payload_type, 0);
assert_eq!(parsed.ssrc, 12345);
assert!(parsed.marker);
assert_eq!(&parsed.payload[..], &original_payload[..]);
}
#[test]
fn test_build_complex_packet() {
let packet = RtpPacket {
version: 2,
padding: false,
extension: false,
marker: true,
payload_type: 96,
sequence_number: 12345,
timestamp: 987654,
ssrc: 0xDEADBEEF,
csrc: vec![0x1111, 0x2222],
extension_header: None,
payload: Bytes::from_static(&[0xAA, 0xBB, 0xCC]),
};
let bytes = packet.build();
let parsed = RtpPacket::parse(&bytes).unwrap();
assert_eq!(parsed.version, 2);
assert_eq!(parsed.payload_type, 96);
assert_eq!(parsed.sequence_number, 12345);
assert_eq!(parsed.timestamp, 987654);
assert_eq!(parsed.ssrc, 0xDEADBEEF);
assert_eq!(parsed.csrc.len(), 2);
assert_eq!(parsed.csrc[0], 0x1111);
assert_eq!(parsed.csrc[1], 0x2222);
}
}
#[cfg(test)]
mod session_management {
use super::*;
#[test]
fn test_session_creation() {
let session = RtpSession::new(12345, 0, 8000);
assert_eq!(session.ssrc(), 12345);
}
#[test]
fn test_session_tracking() {
let mut session = RtpSession::new(12345, 0, 8000);
let packet1 = session.create_packet(vec![0; 160], 160, false);
let seq1 = packet1.sequence_number;
let ts1 = packet1.timestamp;
let packet2 = session.create_packet(vec![0; 160], 160, false);
assert_eq!(packet2.sequence_number, seq1 + 1);
assert_eq!(packet2.timestamp, ts1 + 160);
}
#[test]
fn test_session_payload_type() {
let mut session = RtpSession::new(12345, 0, 8000);
let packet1 = session.create_packet(vec![0; 10], 160, false);
assert_eq!(packet1.payload_type, 0);
let mut session2 = RtpSession::new(12345, 96, 8000);
let packet2 = session2.create_packet(vec![0; 10], 160, false);
assert_eq!(packet2.payload_type, 96);
}
}
#[cfg(test)]
mod edge_cases {
use super::*;
#[test]
fn test_empty_payload() {
let mut session = RtpSession::new(12345, 0, 8000);
let packet = session.create_packet(vec![], 160, false);
assert_eq!(packet.payload.len(), 0);
let bytes = packet.build();
let parsed = RtpPacket::parse(&bytes).unwrap();
assert_eq!(parsed.payload.len(), 0);
}
#[test]
fn test_large_payload() {
let mut session = RtpSession::new(12345, 0, 8000);
let large_payload = vec![0xAA; 1400]; let packet = session.create_packet(large_payload.clone(), 160, false);
let bytes = packet.build();
let parsed = RtpPacket::parse(&bytes).unwrap();
assert_eq!(parsed.payload.len(), 1400);
}
#[test]
fn test_all_payload_types() {
for pt in 0..=127 {
let mut session = RtpSession::new(12345, pt, 8000);
let packet = session.create_packet(vec![0; 10], 160, false);
assert_eq!(packet.payload_type, pt);
}
}
#[test]
fn test_sequence_boundaries() {
assert_eq!(0_u16.wrapping_sub(1), 65535);
assert_eq!(65535_u16.wrapping_add(1), 0);
let mut session = RtpSession::new(12345, 0, 8000);
let p1 = session.create_packet(vec![1], 160, false);
let p2 = session.create_packet(vec![2], 320, false);
assert_eq!(p2.sequence_number, p1.sequence_number.wrapping_add(1));
}
#[test]
fn test_timestamp_boundaries() {
let ts_max = u32::MAX;
let ts_wrapped = ts_max.wrapping_add(100);
assert_eq!(ts_wrapped, 99);
let mut session = RtpSession::new(12345, 0, 8000);
let p1 = session.create_packet(vec![1], 160, false);
let p2 = session.create_packet(vec![2], 160, false);
assert_eq!(p2.timestamp, p1.timestamp.wrapping_add(160));
}
}