summaryrefslogtreecommitdiffstats
path: root/third_party/rust/webrtc-sdp/src/attribute_type_tests.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/webrtc-sdp/src/attribute_type_tests.rs')
-rw-r--r--third_party/rust/webrtc-sdp/src/attribute_type_tests.rs1102
1 files changed, 1102 insertions, 0 deletions
diff --git a/third_party/rust/webrtc-sdp/src/attribute_type_tests.rs b/third_party/rust/webrtc-sdp/src/attribute_type_tests.rs
new file mode 100644
index 0000000000..077327a513
--- /dev/null
+++ b/third_party/rust/webrtc-sdp/src/attribute_type_tests.rs
@@ -0,0 +1,1102 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+extern crate url;
+use super::*;
+use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+
+macro_rules! make_check_parse {
+ ($attr_type:ty, $attr_kind:path) => {
+ |attr_str: &str| -> $attr_type {
+ match parse_attribute(attr_str) {
+ Ok(SdpType::Attribute($attr_kind(attr))) => attr,
+ Err(e) => panic!("{}", e),
+ _ => unreachable!(),
+ }
+ }
+ };
+
+ ($attr_kind:path) => {
+ |attr_str: &str| -> SdpAttribute {
+ match parse_attribute(attr_str) {
+ Ok(SdpType::Attribute($attr_kind)) => $attr_kind,
+ Err(e) => panic!("{}", e),
+ _ => unreachable!(),
+ }
+ }
+ };
+}
+
+macro_rules! make_check_parse_and_serialize {
+ ($check_parse_func:ident, $attr_kind:path) => {
+ |attr_str: &str| {
+ let parsed = $attr_kind($check_parse_func(attr_str));
+ assert_eq!(parsed.to_string(), attr_str.to_string());
+ }
+ };
+
+ ($check_parse_func:ident) => {
+ |attr_str: &str| {
+ let parsed = $check_parse_func(attr_str);
+ assert_eq!(parsed.to_string(), attr_str.to_string());
+ }
+ };
+}
+
+#[test]
+fn test_parse_attribute_candidate_and_serialize() {
+ let check_parse = make_check_parse!(SdpAttributeCandidate, SdpAttribute::Candidate);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Candidate);
+
+ check_parse_and_serialize("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ host");
+ check_parse_and_serialize("candidate:foo 1 UDP 2122252543 172.16.156.106 49760 typ host");
+ check_parse_and_serialize("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host");
+ check_parse_and_serialize("candidate:0 1 TCP 2122252543 ::1 49760 typ host");
+ check_parse_and_serialize("candidate:0 1 TCP 2122252543 2001:db8:4860::4444 49760 typ host");
+ check_parse_and_serialize("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ srflx");
+ check_parse_and_serialize("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ prflx");
+ check_parse_and_serialize("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ relay");
+ check_parse_and_serialize(
+ "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype active",
+ );
+ check_parse_and_serialize(
+ "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype passive",
+ );
+ check_parse_and_serialize(
+ "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype so",
+ );
+ check_parse_and_serialize(
+ "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host ufrag foobar",
+ );
+ check_parse_and_serialize(
+ "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host network-cost 50",
+ );
+ check_parse_and_serialize("candidate:1 1 UDP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 generation 0");
+ check_parse_and_serialize(
+ "candidate:1 1 UDP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665",
+ );
+ check_parse_and_serialize("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive");
+ check_parse_and_serialize("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1");
+ check_parse_and_serialize("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1 ufrag +DGd");
+ check_parse_and_serialize("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1 ufrag +DGd network-cost 1");
+ check_parse_and_serialize(
+ "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host unsupported foo",
+ );
+ check_parse_and_serialize("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host unsupported foo more_unsupported bar");
+
+ let candidate = check_parse("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1 ufrag +DGd network-cost 1 unsupported foo");
+ assert_eq!(candidate.foundation, "1".to_string());
+ assert_eq!(candidate.component, 1);
+ assert_eq!(candidate.transport, SdpAttributeCandidateTransport::Tcp);
+ assert_eq!(candidate.priority, 1_685_987_071);
+ assert_eq!(
+ candidate.address,
+ Address::from_str("24.23.204.141").unwrap()
+ );
+ assert_eq!(candidate.port, 54609);
+ assert_eq!(candidate.c_type, SdpAttributeCandidateType::Srflx);
+ assert_eq!(
+ candidate.raddr,
+ Some(Address::from_str("192.168.1.4").unwrap())
+ );
+ assert_eq!(candidate.rport, Some(61665));
+ assert_eq!(
+ candidate.tcp_type,
+ Some(SdpAttributeCandidateTcpType::Passive)
+ );
+ assert_eq!(candidate.generation, Some(1));
+ assert_eq!(candidate.ufrag, Some("+DGd".to_string()));
+ assert_eq!(candidate.networkcost, Some(1));
+ assert_eq!(
+ candidate.unknown_extensions,
+ vec![("unsupported".to_string(), "foo".to_string())]
+ )
+}
+
+#[test]
+fn test_anonymize_attribute_candidate() -> Result<(), SdpParserInternalError> {
+ let mut anon = StatefulSdpAnonymizer::new();
+ let candidate_1 = parse_attribute("candidate:0 1 TCP 2122252543 ::8 49760 typ host")?;
+ let candidate_2 =
+ parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 19361 typ srflx")?;
+ let candidate_3 = parse_attribute("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1 ufrag +DGd")?;
+ if let SdpType::Attribute(SdpAttribute::Candidate(candidate)) = candidate_1 {
+ let masked = candidate.masked_clone(&mut anon);
+ assert!(masked.address == Address::Ip(IpAddr::V6(Ipv6Addr::from(1))));
+ assert!(masked.port == 1);
+ } else {
+ unreachable!();
+ }
+
+ if let SdpType::Attribute(SdpAttribute::Candidate(candidate)) = candidate_2 {
+ let masked = candidate.masked_clone(&mut anon);
+ assert!(masked.address == Address::Ip(IpAddr::V4(Ipv4Addr::from(1))));
+ assert!(masked.port == 2);
+ } else {
+ unreachable!();
+ }
+
+ if let SdpType::Attribute(SdpAttribute::Candidate(candidate)) = candidate_3 {
+ let masked = candidate.masked_clone(&mut anon);
+ assert!(masked.address == Address::Ip(IpAddr::V4(Ipv4Addr::from(2))));
+ assert!(masked.port == 3);
+ assert!(masked.raddr.unwrap() == Address::Ip(IpAddr::V4(Ipv4Addr::from(3))));
+ assert!(masked.rport.unwrap() == 4);
+ } else {
+ unreachable!();
+ }
+ Ok(())
+}
+
+#[test]
+fn test_parse_attribute_candidate_errors() {
+ assert!(parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ").is_err());
+ assert!(
+ parse_attribute("candidate:0 foo UDP 2122252543 172.16.156.106 49760 typ host").is_err()
+ );
+ assert!(parse_attribute("candidate:0 1 FOO 2122252543 172.16.156.106 49760 typ host").is_err());
+ assert!(parse_attribute("candidate:0 1 UDP foo 172.16.156.106 49760 typ host").is_err());
+ assert!(parse_attribute("candidate:0 1 UDP 2122252543 372.16.356 49760 typ host").is_err());
+ assert!(parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 70000 typ host").is_err());
+ assert!(
+ parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 49760 type host").is_err()
+ );
+ assert!(parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ fost").is_err());
+ assert!(parse_attribute(
+ "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host unsupported"
+ )
+ .is_err());
+ assert!(parse_attribute(
+ "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host network-cost"
+ )
+ .is_err());
+ assert!(parse_attribute("candidate:1 1 UDP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 generation B").is_err());
+ assert!(parse_attribute(
+ "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host network-cost C"
+ )
+ .is_err());
+ assert!(parse_attribute(
+ "candidate:1 1 UDP 1685987071 24.23.204.141 54609 typ srflx raddr 1%92.168.1 rport 61665"
+ )
+ .is_err());
+ assert!(parse_attribute(
+ "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype foobar"
+ )
+ .is_err());
+ assert!(parse_attribute(
+ "candidate:1 1 UDP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 70000"
+ )
+ .is_err());
+}
+
+#[test]
+fn test_parse_dtls_message() {
+ let check_parse = make_check_parse!(SdpAttributeDtlsMessage, SdpAttribute::DtlsMessage);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::DtlsMessage);
+
+ check_parse_and_serialize("dtls-message:client SGVsbG8gV29ybGQ=");
+ check_parse_and_serialize("dtls-message:server SGVsbG8gV29ybGQ=");
+ check_parse_and_serialize("dtls-message:client IGlzdCBl/W4gUeiBtaXQg+JSB1bmQCAkJJkSNEQ=");
+ check_parse_and_serialize("dtls-message:server IGlzdCBl/W4gUeiBtaXQg+JSB1bmQCAkJJkSNEQ=");
+
+ match check_parse("dtls-message:client SGVsbG8gV29ybGQ=") {
+ SdpAttributeDtlsMessage::Client(x) => {
+ assert_eq!(x, "SGVsbG8gV29ybGQ=");
+ }
+ _ => {
+ unreachable!();
+ }
+ }
+
+ match check_parse("dtls-message:server SGVsbG8gV29ybGQ=") {
+ SdpAttributeDtlsMessage::Server(x) => {
+ assert_eq!(x, "SGVsbG8gV29ybGQ=");
+ }
+ _ => {
+ unreachable!();
+ }
+ }
+
+ assert!(parse_attribute("dtls-message:client").is_err());
+ assert!(parse_attribute("dtls-message:server").is_err());
+ assert!(parse_attribute("dtls-message:unsupported SGVsbG8gV29ybGQ=").is_err());
+}
+
+#[test]
+fn test_parse_attribute_end_of_candidates() {
+ let check_parse = make_check_parse!(SdpAttribute::EndOfCandidates);
+ let check_parse_and_serialize = make_check_parse_and_serialize!(check_parse);
+
+ check_parse_and_serialize("end-of-candidates");
+ assert!(parse_attribute("end-of-candidates foobar").is_err());
+}
+
+#[test]
+fn test_parse_attribute_extmap() {
+ let check_parse = make_check_parse!(SdpAttributeExtmap, SdpAttribute::Extmap);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Extmap);
+
+ check_parse_and_serialize("extmap:1/sendonly urn:ietf:params:rtp-hdrext:ssrc-audio-level");
+ check_parse_and_serialize("extmap:2/sendrecv urn:ietf:params:rtp-hdrext:ssrc-audio-level");
+ check_parse_and_serialize(
+ "extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time",
+ );
+ check_parse_and_serialize(
+ "extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time ext_attributes",
+ );
+
+ assert!(parse_attribute("extmap:1/sendrecv").is_err());
+ assert!(
+ parse_attribute("extmap:a/sendrecv urn:ietf:params:rtp-hdrext:ssrc-audio-level").is_err()
+ );
+ assert!(
+ parse_attribute("extmap:4/unsupported urn:ietf:params:rtp-hdrext:ssrc-audio-level")
+ .is_err()
+ );
+
+ let mut bad_char =
+ String::from("extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time ");
+ bad_char.push(0x00 as char);
+ assert!(parse_attribute(&bad_char).is_err());
+}
+
+#[test]
+fn test_parse_attribute_fingerprint() {
+ let check_parse = make_check_parse!(SdpAttributeFingerprint, SdpAttribute::Fingerprint);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Fingerprint);
+
+ check_parse_and_serialize(
+ "fingerprint:sha-1 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC",
+ );
+ check_parse_and_serialize(
+ "fingerprint:sha-224 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:\
+ 27:97:EB:0B:23:73:AC:BC",
+ );
+ check_parse_and_serialize(
+ "fingerprint:sha-256 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:\
+ 27:97:EB:0B:23:73:AC:BC:CD:34:D1:62",
+ );
+ check_parse_and_serialize(
+ "fingerprint:sha-384 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:\
+ 27:97:EB:0B:23:73:AC:BC:CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:\
+ 27:97:EB:0B:23:73:AC:BC",
+ );
+ check_parse_and_serialize(
+ "fingerprint:sha-512 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:\
+ 97:EB:0B:23:73:AC:BC:CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:\
+ EB:0B:23:73:AC:BC:27:97:EB:0B:23:73:AC:BC:27:97:EB:0B:23:73:\
+ BC:EB:0B:23",
+ );
+
+ assert!(parse_attribute("fingerprint:sha-1").is_err());
+ assert!(parse_attribute(
+ "fingerprint:unsupported CD:34:D1:62:16:95:7B:B7:EB:74:E1:39:27:97:EB:0B:23:73:AC:BC"
+ )
+ .is_err());
+ assert!(parse_attribute(
+ "fingerprint:sha-1 CDA:34:D1:62:16:95:7B:B7:EB:74:E1:39:27:97:EB:0B:23:73:AC:BC"
+ )
+ .is_err());
+ assert!(parse_attribute(
+ "fingerprint:sha-1 CD:34:D1:62:16:95:7B:B7:EB:74:E1:39:27:97:EB:0B:23:73:AC:"
+ )
+ .is_err());
+ assert!(parse_attribute(
+ "fingerprint:sha-1 CD:34:D1:62:16:95:7B:B7:EB:74:E1:39:27:97:EB:0B:23:73:AC"
+ )
+ .is_err());
+ assert!(parse_attribute(
+ "fingerprint:sha-1 CX:34:D1:62:16:95:7B:B7:EB:74:E1:39:27:97:EB:0B:23:73:AC:BC"
+ )
+ .is_err());
+
+ assert!(parse_attribute(
+ "fingerprint:sha-1 0xCD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC"
+ )
+ .is_err());
+ assert!(parse_attribute(
+ "fingerprint:sha-1 CD:0x34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC"
+ )
+ .is_err());
+ assert!(parse_attribute(
+ "fingerprint:sha-1 CD::D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC"
+ )
+ .is_err());
+ assert!(parse_attribute(
+ "fingerprint:sha-1 CD:0000A:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC"
+ )
+ .is_err());
+ assert!(parse_attribute(
+ "fingerprint:sha-1 CD:B:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC"
+ )
+ .is_err());
+}
+
+#[test]
+fn test_parse_attribute_fmtp() {
+ let check_parse = make_check_parse!(SdpAttributeFmtp, SdpAttribute::Fmtp);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Fmtp);
+
+ check_parse_and_serialize("fmtp:109 maxplaybackrate=46000;stereo=1;useinbandfec=1");
+ check_parse_and_serialize(
+ "fmtp:126 profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1",
+ );
+ check_parse_and_serialize("fmtp:66 0-15");
+ check_parse_and_serialize("fmtp:109 0-15,66");
+ check_parse_and_serialize("fmtp:66 111/115");
+ assert!(parse_attribute("fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1").is_ok());
+ assert!(parse_attribute("fmtp:109 maxplaybackrate=48000; stereo=1; useinbandfec=1").is_ok());
+ assert!(parse_attribute("fmtp:109 maxplaybackrate=48000; stereo=1;useinbandfec=1").is_ok());
+ check_parse_and_serialize("fmtp:8 maxplaybackrate=46000");
+ check_parse_and_serialize("fmtp:8 maxaveragebitrate=46000");
+ check_parse_and_serialize("fmtp:8 maxaveragebitrate=46000;ptime=60;minptime=20;maxptime=120");
+ check_parse_and_serialize(
+ "fmtp:8 max-cpb=1234;max-dpb=32000;max-br=3;max-mbps=46000;usedtx=1;cbr=1",
+ );
+ assert!(parse_attribute("fmtp:77 ").is_err());
+ assert!(parse_attribute("fmtp:109 stereo=2;").is_err());
+ assert!(parse_attribute("fmtp:109 111/129;").is_err());
+ assert!(parse_attribute("fmtp:109 packetization-mode=3;").is_err());
+ assert!(parse_attribute("fmtp:109 maxplaybackrate=48000stereo=1;").is_err());
+ assert!(parse_attribute("fmtp:8 ;maxplaybackrate=48000").is_ok());
+ assert!(parse_attribute("fmtp:8 packetization-mode=2;;maxplaybackrate=48000").is_ok());
+ assert!(parse_attribute("fmtp:8 packetization-mode=2; maxplaybackrate=48000").is_ok());
+ assert!(parse_attribute("fmtp:8 maxplaybackrate=48000;").is_ok());
+ assert!(parse_attribute("fmtp:8 x-google-start-bitrate=800; maxplaybackrate=48000;").is_ok());
+ check_parse_and_serialize("fmtp:97 apt=96");
+ check_parse_and_serialize("fmtp:97 apt=96;rtx-time=3000");
+ check_parse_and_serialize(
+ "fmtp:102 packetization-mode=1;sprop-parameter-sets=Z0LAFYyNQKD5APCIRqA=,aM48gA==",
+ );
+}
+
+#[test]
+fn test_anonymize_attribute_fingerprint() -> Result<(), SdpParserInternalError> {
+ let mut anon = StatefulSdpAnonymizer::new();
+ if let SdpType::Attribute(SdpAttribute::Fingerprint(print)) = parse_attribute(
+ "fingerprint:sha-1 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC",
+ )? {
+ assert!(print.masked_clone(&mut anon).to_string() == "sha-1 00:00:00:00:00:00:00:01");
+ } else {
+ unreachable!();
+ }
+ Ok(())
+}
+
+#[test]
+fn test_parse_attribute_group() {
+ let check_parse = make_check_parse!(SdpAttributeGroup, SdpAttribute::Group);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Group);
+
+ check_parse_and_serialize("group:LS");
+ check_parse_and_serialize("group:LS 1 2");
+ check_parse_and_serialize("group:FID 1 2");
+ check_parse_and_serialize("group:SRF 1 2");
+ check_parse_and_serialize("group:FEC S1 R1");
+ check_parse_and_serialize("group:ANAT S1 R1");
+ check_parse_and_serialize("group:DDP L1 L2 L3");
+ check_parse_and_serialize("group:BUNDLE sdparta_0 sdparta_1 sdparta_2");
+
+ assert!(parse_attribute("group:").is_err());
+ assert!(matches!(
+ parse_attribute("group:NEVER_SUPPORTED_SEMANTICS"),
+ Err(SdpParserInternalError::Unsupported(_))
+ ));
+}
+
+#[test]
+fn test_parse_attribute_bundle_only() {
+ let check_parse = make_check_parse!(SdpAttribute::BundleOnly);
+ let check_parse_and_serialize = make_check_parse_and_serialize!(check_parse);
+
+ check_parse_and_serialize("bundle-only");
+
+ assert!(parse_attribute("bundle-only foobar").is_err());
+}
+
+#[test]
+fn test_parse_attribute_ice_lite() {
+ let check_parse = make_check_parse!(SdpAttribute::IceLite);
+ let check_parse_and_serialize = make_check_parse_and_serialize!(check_parse);
+
+ check_parse_and_serialize("ice-lite");
+
+ assert!(parse_attribute("ice-lite foobar").is_err());
+}
+
+#[test]
+fn test_parse_attribute_extmap_allow_mixed() {
+ let check_parse = make_check_parse!(SdpAttribute::ExtmapAllowMixed);
+ let check_parse_and_serialize = make_check_parse_and_serialize!(check_parse);
+
+ check_parse_and_serialize("extmap-allow-mixed");
+
+ assert!(parse_attribute("extmap-allow-mixed 100").is_err());
+}
+
+#[test]
+fn test_parse_attribute_ice_mismatch() {
+ let check_parse = make_check_parse!(SdpAttribute::IceMismatch);
+ let check_parse_and_serialize = make_check_parse_and_serialize!(check_parse);
+
+ check_parse_and_serialize("ice-mismatch");
+
+ assert!(parse_attribute("ice-mismatch foobar").is_err());
+}
+
+#[test]
+fn test_parse_attribute_ice_options() {
+ let check_parse = make_check_parse!(Vec<String>, SdpAttribute::IceOptions);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::IceOptions);
+
+ check_parse_and_serialize("ice-options:trickle");
+
+ assert!(parse_attribute("ice-options:").is_err());
+}
+
+#[test]
+fn test_parse_attribute_ice_pacing() {
+ let check_parse = make_check_parse!(u64, SdpAttribute::IcePacing);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::IcePacing);
+
+ check_parse_and_serialize("ice-pacing:50");
+
+ assert!(parse_attribute("ice-pacing:").is_err());
+ assert!(parse_attribute("ice-pacing:10000000000").is_err());
+ assert!(parse_attribute("ice-pacing:50 100").is_err());
+ assert!(parse_attribute("ice-pacing:foobar").is_err());
+}
+
+#[test]
+fn test_parse_attribute_ice_pwd() {
+ let check_parse = make_check_parse!(String, SdpAttribute::IcePwd);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::IcePwd);
+
+ check_parse_and_serialize("ice-pwd:e3baa26dd2fa5030d881d385f1e36cce");
+
+ assert!(parse_attribute("ice-pwd:").is_err());
+}
+
+#[test]
+fn test_parse_attribute_ice_ufrag() {
+ let check_parse = make_check_parse!(String, SdpAttribute::IceUfrag);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::IceUfrag);
+
+ check_parse_and_serialize("ice-ufrag:58b99ead");
+
+ assert!(parse_attribute("ice-ufrag:").is_err());
+}
+
+#[test]
+fn test_parse_attribute_identity() {
+ let check_parse = make_check_parse!(String, SdpAttribute::Identity);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Identity);
+
+ check_parse_and_serialize("identity:eyJpZHAiOnsiZG9tYWluIjoiZXhhbXBsZS5vcmciLCJwcm90b2NvbCI6ImJvZ3VzIn0sImFzc2VydGlvbiI6IntcImlkZW50aXR5XCI6XCJib2JAZXhhbXBsZS5vcmdcIixcImNvbnRlbnRzXCI6XCJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3l6XCIsXCJzaWduYXR1cmVcIjpcIjAxMDIwMzA0MDUwNlwifSJ9");
+
+ assert!(parse_attribute("identity:").is_err());
+}
+
+#[test]
+fn test_parse_attribute_imageattr() {
+ let check_parse = make_check_parse!(SdpAttributeImageAttr, SdpAttribute::ImageAttr);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::ImageAttr);
+
+ check_parse_and_serialize("imageattr:120 send * recv *");
+ check_parse_and_serialize("imageattr:99 send [x=320,y=240] recv [x=320,y=240]");
+ check_parse_and_serialize(
+ "imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]",
+ );
+ check_parse_and_serialize("imageattr:97 send [x=[480:16:800],y=[320:16:640],par=[1.2-1.3],q=0.6] [x=[176:8:208],y=[144:8:176],par=[1.2-1.3]] recv *");
+ assert!(parse_attribute("imageattr:97 recv [x=800,y=640,sar=1.1] send [x=330,y=250]").is_ok());
+
+ check_parse_and_serialize("imageattr:99 send [x=320,y=240]");
+ assert!(parse_attribute("imageattr:100 recv [x=320,y=240]").is_ok());
+ assert!(parse_attribute("imageattr:97 recv [x=800,y=640,sar=1.1,foo=[123,456],q=0.5] send [x=330,y=250,bar=foo,sar=[20-40]]").is_ok());
+ assert!(parse_attribute("imageattr:97 recv [x=800,y=640,sar=1.1,foo=abc xyz,q=0.5] send [x=330,y=250,bar=foo,sar=[20-40]]").is_ok());
+
+ assert!(parse_attribute("imageattr:").is_err());
+ assert!(parse_attribute("imageattr:100").is_err());
+ assert!(parse_attribute("imageattr:120 send * recv * send *").is_err());
+ assert!(parse_attribute("imageattr:99 send [x=320]").is_err());
+ assert!(parse_attribute("imageattr:99 recv [y=240]").is_err());
+ assert!(parse_attribute("imageattr:99 send [x=320,y=240").is_err());
+ assert!(parse_attribute("imageattr:99 send x=320,y=240]").is_err());
+ assert!(parse_attribute("imageattr:97 send [x=800,y=640,sar=1.1] send [x=330,y=250]").is_err());
+}
+
+#[test]
+fn test_parse_attribute_imageattr_recv_and_verify() {
+ let check_parse = make_check_parse!(SdpAttributeImageAttr, SdpAttribute::ImageAttr);
+
+ let imageattr = check_parse(
+ "imageattr:* recv [x=800,y=[50,80,30],sar=1.1] send [x=330,y=250,sar=[1.1,1.3,1.9],q=0.1]",
+ );
+ assert_eq!(imageattr.pt, SdpAttributePayloadType::Wildcard);
+ match imageattr.recv {
+ SdpAttributeImageAttrSetList::Sets(sets) => {
+ assert_eq!(sets.len(), 1);
+
+ let set = &sets[0];
+ assert_eq!(
+ set.x,
+ SdpAttributeImageAttrXyRange::DiscreteValues(vec![800])
+ );
+ assert_eq!(
+ set.y,
+ SdpAttributeImageAttrXyRange::DiscreteValues(vec![50, 80, 30])
+ );
+ assert_eq!(set.par, None);
+ assert_eq!(
+ set.sar,
+ Some(SdpAttributeImageAttrSRange::DiscreteValues(vec![1.1]))
+ );
+ assert_eq!(set.q, None);
+ }
+ _ => {
+ unreachable!();
+ }
+ }
+ match imageattr.send {
+ SdpAttributeImageAttrSetList::Sets(sets) => {
+ assert_eq!(sets.len(), 1);
+
+ let set = &sets[0];
+ assert_eq!(
+ set.x,
+ SdpAttributeImageAttrXyRange::DiscreteValues(vec![330])
+ );
+ assert_eq!(
+ set.y,
+ SdpAttributeImageAttrXyRange::DiscreteValues(vec![250])
+ );
+ assert_eq!(set.par, None);
+ assert_eq!(
+ set.sar,
+ Some(SdpAttributeImageAttrSRange::DiscreteValues(vec![
+ 1.1, 1.3, 1.9,
+ ]))
+ );
+ assert_eq!(set.q, Some(0.1));
+ }
+ _ => {
+ unreachable!();
+ }
+ }
+}
+
+#[test]
+fn test_parse_attribute_imageattr_send_and_verify() {
+ let check_parse = make_check_parse!(SdpAttributeImageAttr, SdpAttribute::ImageAttr);
+
+ let imageattr = check_parse(
+ "imageattr:97 send [x=[480:16:800],y=[100,200,300],par=[1.2-1.3],q=0.6] [x=1080,y=[144:176],sar=[0.5-0.7]] recv *"
+ );
+ assert_eq!(imageattr.pt, SdpAttributePayloadType::PayloadType(97));
+ match imageattr.send {
+ SdpAttributeImageAttrSetList::Sets(sets) => {
+ assert_eq!(sets.len(), 2);
+
+ let first_set = &sets[0];
+ assert_eq!(
+ first_set.x,
+ SdpAttributeImageAttrXyRange::Range(480, 800, Some(16))
+ );
+ assert_eq!(
+ first_set.y,
+ SdpAttributeImageAttrXyRange::DiscreteValues(vec![100, 200, 300])
+ );
+ assert_eq!(
+ first_set.par,
+ Some(SdpAttributeImageAttrPRange { min: 1.2, max: 1.3 })
+ );
+ assert_eq!(first_set.sar, None);
+ assert_eq!(first_set.q, Some(0.6));
+
+ let second_set = &sets[1];
+ assert_eq!(
+ second_set.x,
+ SdpAttributeImageAttrXyRange::DiscreteValues(vec![1080])
+ );
+ assert_eq!(
+ second_set.y,
+ SdpAttributeImageAttrXyRange::Range(144, 176, None)
+ );
+ assert_eq!(second_set.par, None);
+ assert_eq!(
+ second_set.sar,
+ Some(SdpAttributeImageAttrSRange::Range(0.5, 0.7))
+ );
+ assert_eq!(second_set.q, None);
+ }
+ _ => {
+ unreachable!();
+ }
+ }
+ assert_eq!(imageattr.recv, SdpAttributeImageAttrSetList::Wildcard);
+}
+
+#[test]
+fn test_parse_attribute_inactive() {
+ let check_parse = make_check_parse!(SdpAttribute::Inactive);
+ let check_parse_and_serialize = make_check_parse_and_serialize!(check_parse);
+
+ check_parse_and_serialize("inactive");
+ assert!(parse_attribute("inactive foobar").is_err());
+}
+
+#[test]
+fn test_parse_attribute_label() {
+ let check_parse = make_check_parse!(String, SdpAttribute::Label);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Label);
+
+ check_parse_and_serialize("label:1");
+ check_parse_and_serialize("label:foobar");
+ check_parse_and_serialize("label:foobar barfoo");
+
+ assert!(parse_attribute("label:").is_err());
+}
+
+#[test]
+fn test_parse_attribute_maxptime() {
+ let check_parse = make_check_parse!(u64, SdpAttribute::MaxPtime);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::MaxPtime);
+
+ check_parse_and_serialize("maxptime:60");
+
+ assert!(parse_attribute("maxptime:").is_err());
+ assert!(parse_attribute("maxptime:60 100").is_err());
+ assert!(parse_attribute("maxptime:foobar").is_err());
+}
+
+#[test]
+fn test_parse_attribute_mid() {
+ let check_parse = make_check_parse!(String, SdpAttribute::Mid);
+ let check_parse_and_serialize = make_check_parse_and_serialize!(check_parse, SdpAttribute::Mid);
+
+ check_parse_and_serialize("mid:sdparta_0");
+ check_parse_and_serialize("mid:sdparta_0 sdparta_1 sdparta_2");
+
+ assert!(parse_attribute("mid:").is_err());
+}
+
+#[test]
+fn test_parse_attribute_msid() {
+ let check_parse = make_check_parse!(SdpAttributeMsid, SdpAttribute::Msid);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Msid);
+
+ check_parse_and_serialize("msid:{5a990edd-0568-ac40-8d97-310fc33f3411}");
+ check_parse_and_serialize(
+ "msid:{5a990edd-0568-ac40-8d97-310fc33f3411} {218cfa1c-617d-2249-9997-60929ce4c405}",
+ );
+
+ assert!(parse_attribute("msid:").is_err());
+}
+
+#[test]
+fn test_parse_attribute_msid_semantics() {
+ let check_parse = make_check_parse!(SdpAttributeMsidSemantic, SdpAttribute::MsidSemantic);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::MsidSemantic);
+
+ check_parse_and_serialize("msid-semantic:WMS *");
+ check_parse_and_serialize("msid-semantic:WMS foo");
+
+ assert!(parse_attribute("msid-semantic:").is_err());
+}
+
+#[test]
+fn test_parse_attribute_ptime() {
+ let check_parse = make_check_parse!(u64, SdpAttribute::Ptime);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Ptime);
+
+ check_parse_and_serialize("ptime:30");
+ assert!(parse_attribute("ptime:").is_err());
+}
+
+#[test]
+fn test_anonymize_remote_candidate() -> Result<(), SdpParserInternalError> {
+ let mut anon = StatefulSdpAnonymizer::new();
+ if let SdpType::Attribute(SdpAttribute::RemoteCandidate(remote)) =
+ parse_attribute("remote-candidates:0 10.0.0.1 5555")?
+ {
+ let masked = remote.masked_clone(&mut anon);
+ assert_eq!(masked.address, Address::Ip(IpAddr::V4(Ipv4Addr::from(1))));
+ assert_eq!(masked.port, 1);
+ } else {
+ unreachable!();
+ }
+ Ok(())
+}
+
+#[test]
+fn test_parse_attribute_rid() {
+ let check_parse = make_check_parse!(SdpAttributeRid, SdpAttribute::Rid);
+ let check_parse_and_serialize = make_check_parse_and_serialize!(check_parse, SdpAttribute::Rid);
+
+ check_parse_and_serialize("rid:foo send pt=10");
+ check_parse_and_serialize("rid:110 send pt=9,10");
+ check_parse_and_serialize("rid:110 send pt=9,10;max-fs=10");
+ check_parse_and_serialize("rid:110 send pt=9,10;max-width=10;depends=1,2,3");
+
+ assert!(
+ parse_attribute("rid:110 send pt=9, 10;max-fs=10;UNKNOWN=100; depends=1, 2, 3").is_ok()
+ );
+ assert!(parse_attribute("rid:110 send max-fs=10").is_ok());
+ assert!(parse_attribute("rid:110 recv max-width=1920;max-height=1080").is_ok());
+
+ check_parse_and_serialize("rid:110 recv max-mbps=420;max-cpb=3;max-dpb=3");
+ check_parse_and_serialize("rid:110 recv scale-down-by=1.35;depends=1,2,3");
+ check_parse_and_serialize("rid:110 recv max-width=10;depends=1,2,3");
+ check_parse_and_serialize("rid:110 recv max-fs=10;UNKNOWN=100;depends=1,2,3");
+
+ assert!(parse_attribute("rid:").is_err());
+ assert!(parse_attribute("rid:120 send pt=").is_err());
+ assert!(parse_attribute("rid:120 send pt=;max-width=10").is_err());
+ assert!(parse_attribute("rid:120 send pt=9;max-width=").is_err());
+ assert!(parse_attribute("rid:120 send pt=9;max-width=;max-width=10").is_err());
+}
+
+#[test]
+fn test_parse_attribute_rid_and_verify() {
+ let check_parse = make_check_parse!(SdpAttributeRid, SdpAttribute::Rid);
+ let check_parse_and_serialize = make_check_parse_and_serialize!(check_parse, SdpAttribute::Rid);
+
+ check_parse_and_serialize("rid:foo send");
+ let mut rid = check_parse("rid:foo send");
+ assert_eq!(rid.id, "foo");
+ assert_eq!(rid.direction, SdpSingleDirection::Send);
+
+ check_parse_and_serialize("rid:110 send pt=9");
+ rid = check_parse("rid:110 send pt=9");
+ assert_eq!(rid.id, "110");
+ assert_eq!(rid.direction, SdpSingleDirection::Send);
+ assert_eq!(rid.formats, vec![9]);
+
+ check_parse_and_serialize("rid:110 send pt=9,10;max-fs=10;UNKNOWN=100;depends=1,2,3");
+ rid = check_parse("rid:110 send pt=9,10;max-fs=10;UNKNOWN=100;depends=1,2,3");
+ assert_eq!(rid.id, "110");
+ assert_eq!(rid.direction, SdpSingleDirection::Send);
+ assert_eq!(rid.formats, vec![9, 10]);
+ assert_eq!(rid.params.max_fs, 10);
+ assert_eq!(rid.params.unknown, vec!["UNKNOWN=100"]);
+ assert_eq!(rid.depends, vec!["1", "2", "3"]);
+
+ check_parse_and_serialize("rid:110 recv max-fps=42;max-fs=10;max-br=3;max-pps=1000");
+ rid = check_parse("rid:110 recv max-fps=42;max-fs=10;max-br=3;max-pps=1000");
+ assert_eq!(rid.id, "110");
+ assert_eq!(rid.direction, SdpSingleDirection::Recv);
+ assert_eq!(rid.params.max_fps, 42);
+ assert_eq!(rid.params.max_fs, 10);
+ assert_eq!(rid.params.max_br, 3);
+ assert_eq!(rid.params.max_pps, 1000);
+}
+
+#[test]
+fn test_parse_attribute_recvonly() {
+ let check_parse = make_check_parse!(SdpAttribute::Recvonly);
+ let check_parse_and_serialize = make_check_parse_and_serialize!(check_parse);
+
+ check_parse_and_serialize("recvonly");
+ assert!(parse_attribute("recvonly foobar").is_err());
+}
+
+#[test]
+fn test_parse_attribute_remote_candidate() {
+ let check_parse = make_check_parse!(SdpAttributeRemoteCandidate, SdpAttribute::RemoteCandidate);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::RemoteCandidate);
+
+ check_parse_and_serialize("remote-candidates:0 10.0.0.1 5555");
+ check_parse_and_serialize("remote-candidates:12345 ::1 5555");
+
+ assert!(parse_attribute("remote-candidates:abc 10.0.0.1 5555").is_err());
+ assert!(parse_attribute("remote-candidates:0 10.0.0.1 70000").is_err());
+ assert!(parse_attribute("remote-candidates:0 10.0.0.1").is_err());
+ assert!(parse_attribute("remote-candidates:0").is_err());
+ assert!(parse_attribute("remote-candidates:").is_err());
+}
+
+#[test]
+fn test_parse_attribute_sendonly() {
+ let check_parse = make_check_parse!(SdpAttribute::Sendonly);
+ let check_parse_and_serialize = make_check_parse_and_serialize!(check_parse);
+
+ check_parse_and_serialize("sendonly");
+ assert!(parse_attribute("sendonly foobar").is_err());
+}
+
+#[test]
+fn test_parse_attribute_sendrecv() {
+ let check_parse = make_check_parse!(SdpAttribute::Sendrecv);
+ let check_parse_and_serialize = make_check_parse_and_serialize!(check_parse);
+
+ check_parse_and_serialize("sendrecv");
+ assert!(parse_attribute("sendrecv foobar").is_err());
+}
+
+#[test]
+fn test_parse_attribute_setup() {
+ let check_parse = make_check_parse!(SdpAttributeSetup, SdpAttribute::Setup);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Setup);
+
+ check_parse_and_serialize("setup:active");
+ check_parse_and_serialize("setup:passive");
+ check_parse_and_serialize("setup:actpass");
+ check_parse_and_serialize("setup:holdconn");
+
+ assert!(parse_attribute("setup:").is_err());
+ assert!(parse_attribute("setup:foobar").is_err());
+}
+
+#[test]
+fn test_parse_attribute_rtcp() {
+ let check_parse = make_check_parse!(SdpAttributeRtcp, SdpAttribute::Rtcp);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Rtcp);
+
+ check_parse_and_serialize("rtcp:5000");
+ check_parse_and_serialize("rtcp:9 IN IP4 0.0.0.0");
+ check_parse_and_serialize("rtcp:9 IN IP6 2001:db8::1");
+
+ assert!(parse_attribute("rtcp:").is_err());
+ assert!(parse_attribute("rtcp:70000").is_err());
+ assert!(parse_attribute("rtcp:9 IN").is_err());
+ assert!(parse_attribute("rtcp:9 IN IP4").is_err());
+ assert!(parse_attribute("rtcp:9 IN IP4 ::1").is_err());
+}
+
+#[test]
+fn test_parse_attribute_rtcp_fb() {
+ let check_parse = make_check_parse!(SdpAttributeRtcpFb, SdpAttribute::Rtcpfb);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Rtcpfb);
+
+ check_parse_and_serialize("rtcp-fb:101 ack rpsi");
+ check_parse_and_serialize("rtcp-fb:101 ack app");
+ check_parse_and_serialize("rtcp-fb:101 ccm");
+ check_parse_and_serialize("rtcp-fb:101 ccm fir");
+ check_parse_and_serialize("rtcp-fb:101 ccm tmmbr");
+ check_parse_and_serialize("rtcp-fb:101 ccm tstr");
+ check_parse_and_serialize("rtcp-fb:101 ccm vbcm");
+ check_parse_and_serialize("rtcp-fb:101 nack");
+ check_parse_and_serialize("rtcp-fb:101 nack sli");
+ check_parse_and_serialize("rtcp-fb:101 nack pli");
+ check_parse_and_serialize("rtcp-fb:101 nack rpsi");
+ check_parse_and_serialize("rtcp-fb:101 nack app");
+ check_parse_and_serialize("rtcp-fb:101 trr-int 1");
+ check_parse_and_serialize("rtcp-fb:101 goog-remb");
+ check_parse_and_serialize("rtcp-fb:101 transport-cc");
+
+ assert!(parse_attribute("rtcp-fb:101 unknown").is_err());
+ assert!(parse_attribute("rtcp-fb:101 ack").is_err());
+ assert!(parse_attribute("rtcp-fb:101 ccm unknwon").is_err());
+ assert!(parse_attribute("rtcp-fb:101 nack unknown").is_err());
+ assert!(parse_attribute("rtcp-fb:101 trr-int").is_err());
+ assert!(parse_attribute("rtcp-fb:101 trr-int a").is_err());
+ assert!(parse_attribute("rtcp-fb:101 goog-remb unknown").is_err());
+ assert!(parse_attribute("rtcp-fb:101 transport-cc unknown").is_err());
+}
+
+#[test]
+fn test_parse_attribute_rtcp_mux() {
+ let check_parse = make_check_parse!(SdpAttribute::RtcpMux);
+ let check_parse_and_serialize = make_check_parse_and_serialize!(check_parse);
+
+ check_parse_and_serialize("rtcp-mux");
+ assert!(parse_attribute("rtcp-mux foobar").is_err());
+}
+
+#[test]
+fn test_parse_attribute_rtcp_mux_only() {
+ let check_parse = make_check_parse!(SdpAttribute::RtcpMuxOnly);
+ let check_parse_and_serialize = make_check_parse_and_serialize!(check_parse);
+
+ check_parse_and_serialize("rtcp-mux-only");
+ assert!(parse_attribute("rtcp-mux-only bar").is_err());
+}
+
+#[test]
+fn test_parse_attribute_rtcp_rsize() {
+ let check_parse = make_check_parse!(SdpAttribute::RtcpRsize);
+ let check_parse_and_serialize = make_check_parse_and_serialize!(check_parse);
+
+ check_parse_and_serialize("rtcp-rsize");
+ assert!(parse_attribute("rtcp-rsize foobar").is_err());
+}
+
+#[test]
+fn test_parse_attribute_rtpmap() {
+ let check_parse = make_check_parse!(SdpAttributeRtpmap, SdpAttribute::Rtpmap);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Rtpmap);
+
+ check_parse_and_serialize("rtpmap:109 opus/48000");
+ check_parse_and_serialize("rtpmap:109 opus/48000/2");
+
+ assert!(parse_attribute("rtpmap: ").is_err());
+ assert!(parse_attribute("rtpmap:109 ").is_err());
+ assert!(parse_attribute("rtpmap:109 opus").is_err());
+ assert!(parse_attribute("rtpmap:128 opus/48000").is_err());
+}
+
+#[test]
+fn test_parse_attribute_sctpmap() {
+ let check_parse = make_check_parse!(SdpAttributeSctpmap, SdpAttribute::Sctpmap);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Sctpmap);
+
+ check_parse_and_serialize("sctpmap:5000 webrtc-datachannel 256");
+
+ assert!(parse_attribute("sctpmap:70000 webrtc-datachannel").is_err());
+ assert!(parse_attribute("sctpmap:70000 webrtc-datachannel 256").is_err());
+ assert!(parse_attribute("sctpmap:5000 unsupported 256").is_err());
+ assert!(parse_attribute("sctpmap:5000 webrtc-datachannel 2a").is_err());
+}
+
+#[test]
+fn test_parse_attribute_sctp_port() {
+ let check_parse = make_check_parse!(u64, SdpAttribute::SctpPort);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::SctpPort);
+
+ check_parse_and_serialize("sctp-port:5000");
+
+ assert!(parse_attribute("sctp-port:").is_err());
+ assert!(parse_attribute("sctp-port:70000").is_err());
+}
+
+#[test]
+fn test_parse_attribute_max_message_size() {
+ let check_parse = make_check_parse!(u64, SdpAttribute::MaxMessageSize);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::MaxMessageSize);
+
+ check_parse_and_serialize("max-message-size:1");
+ check_parse_and_serialize("max-message-size:100000");
+ check_parse_and_serialize("max-message-size:4294967297");
+ check_parse_and_serialize("max-message-size:0");
+
+ assert!(parse_attribute("max-message-size:").is_err());
+ assert!(parse_attribute("max-message-size:abc").is_err());
+}
+
+#[test]
+fn test_parse_attribute_simulcast() {
+ let check_parse = make_check_parse!(SdpAttributeSimulcast, SdpAttribute::Simulcast);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Simulcast);
+
+ check_parse_and_serialize("simulcast:send 1");
+ check_parse_and_serialize("simulcast:recv test");
+ check_parse_and_serialize("simulcast:recv ~test");
+ check_parse_and_serialize("simulcast:recv test;foo");
+ check_parse_and_serialize("simulcast:recv foo,bar");
+ check_parse_and_serialize("simulcast:recv foo,bar;test");
+ check_parse_and_serialize("simulcast:send 1;4,5 recv 6;7");
+ check_parse_and_serialize("simulcast:send 1,2,3;~4,~5 recv 6;~7,~8");
+ // old draft 03 notation used by Firefox 55
+ assert!(parse_attribute("simulcast: send rid=foo;bar").is_ok());
+
+ assert!(parse_attribute("simulcast:").is_err());
+ assert!(parse_attribute("simulcast:send").is_err());
+ assert!(parse_attribute("simulcast:foobar 1").is_err());
+ assert!(parse_attribute("simulcast:send 1 foobar 2").is_err());
+ // old draft 03 notation used by Firefox 55
+ assert!(parse_attribute("simulcast: send foo=8;10").is_err());
+}
+
+#[test]
+fn test_parse_attribute_ssrc() {
+ let check_parse = make_check_parse!(SdpAttributeSsrc, SdpAttribute::Ssrc);
+ let check_parse_and_serialize =
+ make_check_parse_and_serialize!(check_parse, SdpAttribute::Ssrc);
+
+ check_parse_and_serialize("ssrc:2655508255");
+ check_parse_and_serialize("ssrc:2655508255 foo");
+ check_parse_and_serialize("ssrc:2655508255 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}");
+ check_parse_and_serialize("ssrc:2082260239 msid:1d0cdb4e-5934-4f0f-9f88-40392cb60d31 315b086a-5cb6-4221-89de-caf0b038c79d");
+
+ assert!(parse_attribute("ssrc:").is_err());
+ assert!(parse_attribute("ssrc:foo").is_err());
+}
+
+#[test]
+fn test_anonymize_attribute_ssrc() -> Result<(), SdpParserInternalError> {
+ let mut anon = StatefulSdpAnonymizer::new();
+ let parsed = parse_attribute("ssrc:2655508255 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}")?;
+ let (ssrc1, masked) = if let SdpType::Attribute(a) = parsed {
+ let masked = a.masked_clone(&mut anon);
+ match (a, masked) {
+ (SdpAttribute::Ssrc(ssrc), SdpAttribute::Ssrc(masked)) => (ssrc, masked),
+ (_, _) => unreachable!(),
+ }
+ } else {
+ unreachable!()
+ };
+ assert_eq!(ssrc1.id, masked.id);
+ assert_eq!(ssrc1.attribute, masked.attribute);
+ assert_eq!("cname-00000001", masked.value.unwrap());
+
+ let ssrc2 = parse_attribute("ssrc:2082260239 msid:1d0cdb4e-5934-4f0f-9f88-40392cb60d31 315b086a-5cb6-4221-89de-caf0b038c79d")?;
+ if let SdpType::Attribute(SdpAttribute::Ssrc(ssrc2)) = ssrc2 {
+ let masked = ssrc2.masked_clone(&mut anon);
+ assert_eq!(ssrc2.id, masked.id);
+ assert_eq!(ssrc2.attribute, masked.attribute);
+ assert_eq!(ssrc2.value, masked.value);
+ } else {
+ unreachable!()
+ }
+ Ok(())
+}
+
+#[test]
+fn test_parse_attribute_ssrc_group() {
+ let parsed = parse_attribute("ssrc-group:FID 3156517279 2673335628");
+ match parsed {
+ Ok(SdpType::Attribute(attr)) => {
+ assert_eq!(attr.to_string(), "ssrc-group:FID 3156517279 2673335628");
+ let (semantic, ssrcs) = match attr {
+ SdpAttribute::SsrcGroup(semantic, ssrcs) => {
+ let stringified_ssrcs: Vec<String> =
+ ssrcs.iter().map(|ssrc| ssrc.to_string()).collect();
+ (semantic.to_string(), stringified_ssrcs)
+ }
+ _ => unreachable!(),
+ };
+ assert_eq!(semantic, "FID");
+ assert_eq!(ssrcs.len(), 2);
+ assert_eq!(ssrcs[0], "3156517279");
+ assert_eq!(ssrcs[1], "2673335628");
+ }
+ Err(e) => panic!("{}", e),
+ _ => unreachable!(),
+ }
+
+ assert!(parse_attribute("ssrc-group:").is_err());
+ assert!(parse_attribute("ssrc-group:BLAH").is_err());
+ assert!(parse_attribute("ssrc-group:FID").is_err());
+}
+
+#[test]
+fn test_parse_unknown_attribute() {
+ assert!(parse_attribute("unknown").is_err())
+}