1 use super::common::*; 2 use super::media::*; 3 use super::session::*; 4 use crate::error::{Error, Result}; 5 6 use std::io::Cursor; 7 use url::Url; 8 9 const CANONICAL_MARSHAL_SDP: &str = "v=0\r\n\ 10 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 11 s=SDP Seminar\r\n\ 12 i=A Seminar on the session description protocol\r\n\ 13 u=http://www.example.com/seminars/sdp.pdf\r\n\ 14 [email protected] (Jane Doe)\r\n\ 15 p=+1 617 555-6011\r\n\ 16 c=IN IP4 224.2.17.12/127\r\n\ 17 b=X-YZ:128\r\n\ 18 b=AS:12345\r\n\ 19 t=2873397496 2873404696\r\n\ 20 t=3034423619 3042462419\r\n\ 21 r=604800 3600 0 90000\r\n\ 22 z=2882844526 -3600 2898848070 0\r\n\ 23 k=prompt\r\n\ 24 a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host\r\n\ 25 a=recvonly\r\n\ 26 m=audio 49170 RTP/AVP 0\r\n\ 27 i=Vivamus a posuere nisl\r\n\ 28 c=IN IP4 203.0.113.1\r\n\ 29 b=X-YZ:128\r\n\ 30 k=prompt\r\n\ 31 a=sendrecv\r\n\ 32 m=video 51372 RTP/AVP 99\r\n\ 33 a=rtpmap:99 h263-1998/90000\r\n"; 34 35 #[test] 36 fn test_unmarshal_marshal() -> Result<()> { 37 let input = CANONICAL_MARSHAL_SDP; 38 let mut reader = Cursor::new(input.as_bytes()); 39 let sdp = SessionDescription::unmarshal(&mut reader)?; 40 let output = sdp.marshal(); 41 assert_eq!(output, input); 42 43 Ok(()) 44 } 45 46 #[test] 47 fn test_marshal() -> Result<()> { 48 let sd = SessionDescription { 49 version: 0, 50 origin: Origin { 51 username: "jdoe".to_string(), 52 session_id: 2890844526, 53 session_version: 2890842807, 54 network_type: "IN".to_string(), 55 address_type: "IP4".to_string(), 56 unicast_address: "10.47.16.5".to_string(), 57 }, 58 session_name: "SDP Seminar".to_string(), 59 session_information: Some("A Seminar on the session description protocol".to_string()), 60 uri: Some(Url::parse("http://www.example.com/seminars/sdp.pdf")?), 61 email_address: Some("[email protected] (Jane Doe)".to_string()), 62 phone_number: Some("+1 617 555-6011".to_string()), 63 connection_information: Some(ConnectionInformation { 64 network_type: "IN".to_string(), 65 address_type: "IP4".to_string(), 66 address: Some(Address { 67 address: "224.2.17.12".to_string(), 68 ttl: Some(127), 69 range: None, 70 }), 71 }), 72 bandwidth: vec![ 73 Bandwidth { 74 experimental: true, 75 bandwidth_type: "YZ".to_string(), 76 bandwidth: 128, 77 }, 78 Bandwidth { 79 experimental: false, 80 bandwidth_type: "AS".to_string(), 81 bandwidth: 12345, 82 }, 83 ], 84 time_descriptions: vec![ 85 TimeDescription { 86 timing: Timing { 87 start_time: 2873397496, 88 stop_time: 2873404696, 89 }, 90 repeat_times: vec![], 91 }, 92 TimeDescription { 93 timing: Timing { 94 start_time: 3034423619, 95 stop_time: 3042462419, 96 }, 97 repeat_times: vec![RepeatTime { 98 interval: 604800, 99 duration: 3600, 100 offsets: vec![0, 90000], 101 }], 102 }, 103 ], 104 time_zones: vec![ 105 TimeZone { 106 adjustment_time: 2882844526, 107 offset: -3600, 108 }, 109 TimeZone { 110 adjustment_time: 2898848070, 111 offset: 0, 112 }, 113 ], 114 encryption_key: Some("prompt".to_string()), 115 attributes: vec![ 116 Attribute::new( 117 "candidate".to_string(), 118 Some("0 1 UDP 2113667327 203.0.113.1 54400 typ host".to_string()), 119 ), 120 Attribute::new("recvonly".to_string(), None), 121 ], 122 media_descriptions: vec![ 123 MediaDescription { 124 media_name: MediaName { 125 media: "audio".to_string(), 126 port: RangedPort { 127 value: 49170, 128 range: None, 129 }, 130 protos: vec!["RTP".to_string(), "AVP".to_string()], 131 formats: vec!["0".to_string()], 132 }, 133 media_title: Some("Vivamus a posuere nisl".to_string()), 134 connection_information: Some(ConnectionInformation { 135 network_type: "IN".to_string(), 136 address_type: "IP4".to_string(), 137 address: Some(Address { 138 address: "203.0.113.1".to_string(), 139 ttl: None, 140 range: None, 141 }), 142 }), 143 bandwidth: vec![Bandwidth { 144 experimental: true, 145 bandwidth_type: "YZ".to_string(), 146 bandwidth: 128, 147 }], 148 encryption_key: Some("prompt".to_string()), 149 attributes: vec![Attribute::new("sendrecv".to_string(), None)], 150 }, 151 MediaDescription { 152 media_name: MediaName { 153 media: "video".to_string(), 154 port: RangedPort { 155 value: 51372, 156 range: None, 157 }, 158 protos: vec!["RTP".to_string(), "AVP".to_string()], 159 formats: vec!["99".to_string()], 160 }, 161 media_title: None, 162 connection_information: None, 163 bandwidth: vec![], 164 encryption_key: None, 165 attributes: vec![Attribute::new( 166 "rtpmap".to_string(), 167 Some("99 h263-1998/90000".to_string()), 168 )], 169 }, 170 ], 171 }; 172 173 let actual = sd.marshal(); 174 assert!( 175 actual == CANONICAL_MARSHAL_SDP, 176 "error:\n\nEXPECTED:\n{}\nACTUAL:\n{}!!!!\n", 177 CANONICAL_MARSHAL_SDP, 178 actual 179 ); 180 181 Ok(()) 182 } 183 184 const BASE_SDP: &str = "v=0\r\n\ 185 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 186 s=SDP Seminar\r\n"; 187 188 const SESSION_INFORMATION_SDP: &str = "v=0\r\n\ 189 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 190 s=SDP Seminar\r\n\ 191 i=A Seminar on the session description protocol\r\n\ 192 t=3034423619 3042462419\r\n"; 193 194 // https://tools.ietf.org/html/rfc4566#section-5 195 // Parsers SHOULD be tolerant and also accept records terminated 196 // with a single newline character. 197 const SESSION_INFORMATION_SDPLFONLY: &str = "v=0\n\ 198 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\n\ 199 s=SDP Seminar\n\ 200 i=A Seminar on the session description protocol\n\ 201 t=3034423619 3042462419\n"; 202 203 // SessionInformationSDPCROnly = "v=0\r" + 204 // "o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r" + 205 // "s=SDP Seminar\r" 206 // "i=A Seminar on the session description protocol\r" + 207 // "t=3034423619 3042462419\r" 208 209 // Other SDP parsers (e.g. one in VLC media player) allow 210 // empty lines. 211 const SESSION_INFORMATION_SDPEXTRA_CRLF: &str = "v=0\r\n\ 212 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 213 \r\n\ 214 s=SDP Seminar\r\n\ 215 \r\n\ 216 i=A Seminar on the session description protocol\r\n\ 217 \r\n\ 218 t=3034423619 3042462419\r\n\ 219 \r\n"; 220 221 const URI_SDP: &str = "v=0\r\n\ 222 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 223 s=SDP Seminar\r\n\ 224 u=http://www.example.com/seminars/sdp.pdf\r\n\ 225 t=3034423619 3042462419\r\n"; 226 227 const EMAIL_ADDRESS_SDP: &str = "v=0\r\n\ 228 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 229 s=SDP Seminar\r\n\ 230 [email protected] (Jane Doe)\r\n\ 231 t=3034423619 3042462419\r\n"; 232 233 const PHONE_NUMBER_SDP: &str = "v=0\r\n\ 234 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 235 s=SDP Seminar\r\n\ 236 p=+1 617 555-6011\r\n\ 237 t=3034423619 3042462419\r\n"; 238 239 const SESSION_CONNECTION_INFORMATION_SDP: &str = "v=0\r\n\ 240 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 241 s=SDP Seminar\r\n\ 242 c=IN IP4 224.2.17.12/127\r\n\ 243 t=3034423619 3042462419\r\n"; 244 245 const SESSION_BANDWIDTH_SDP: &str = "v=0\r\n\ 246 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 247 s=SDP Seminar\r\n\ 248 b=X-YZ:128\r\n\ 249 b=AS:12345\r\n\ 250 t=3034423619 3042462419\r\n"; 251 252 const TIMING_SDP: &str = "v=0\r\n\ 253 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 254 s=SDP Seminar\r\n\ 255 t=2873397496 2873404696\r\n"; 256 257 // Short hand time notation is converted into NTP timestamp format in 258 // seconds. Because of that unittest comparisons will fail as the same time 259 // will be expressed in different units. 260 const REPEAT_TIMES_SDP: &str = "v=0\r\n\ 261 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 262 s=SDP Seminar\r\n\ 263 t=2873397496 2873404696\r\n\ 264 r=604800 3600 0 90000\r\n\ 265 r=3d 2h 0 21h\r\n"; 266 267 const REPEAT_TIMES_SDPEXPECTED: &str = "v=0\r\n\ 268 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 269 s=SDP Seminar\r\n\ 270 t=2873397496 2873404696\r\n\ 271 r=604800 3600 0 90000\r\n\ 272 r=259200 7200 0 75600\r\n"; 273 274 const REPEAT_TIMES_OVERFLOW_SDP: &str = "v=0\r\n\ 275 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 276 s=SDP Seminar\r\n\ 277 t=2873397496 2873404696\r\n\ 278 r=604800 3600 0 90000\r\n\ 279 r=106751991167301d 2h 0 21h\r\n"; 280 281 const REPEAT_TIMES_SDPEXTRA_CRLF: &str = "v=0\r\n\ 282 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 283 s=SDP Seminar\r\n\ 284 t=2873397496 2873404696\r\n\ 285 r=604800 3600 0 90000\r\n\ 286 r=259200 7200 0 75600\r\n\ 287 \r\n"; 288 289 // The expected value looks a bit different for the same reason as mentioned 290 // above regarding RepeatTimes. 291 const TIME_ZONES_SDP: &str = "v=0\r\n\ 292 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 293 s=SDP Seminar\r\n\ 294 t=2873397496 2873404696\r\n\ 295 r=2882844526 -1h 2898848070 0\r\n"; 296 297 const TIME_ZONES_SDPEXPECTED: &str = "v=0\r\n\ 298 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 299 s=SDP Seminar\r\n\ 300 t=2873397496 2873404696\r\n\ 301 r=2882844526 -3600 2898848070 0\r\n"; 302 303 const TIME_ZONES_SDP2: &str = "v=0\r\n\ 304 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 305 s=SDP Seminar\r\n\ 306 t=2873397496 2873404696\r\n\ 307 z=2882844526 -3600 2898848070 0\r\n"; 308 309 const TIME_ZONES_SDP2EXTRA_CRLF: &str = "v=0\r\n\ 310 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 311 s=SDP Seminar\r\n\ 312 t=2873397496 2873404696\r\n\ 313 z=2882844526 -3600 2898848070 0\r\n\ 314 \r\n"; 315 316 const SESSION_ENCRYPTION_KEY_SDP: &str = "v=0\r\n\ 317 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 318 s=SDP Seminar\r\n\ 319 t=2873397496 2873404696\r\n\ 320 k=prompt\r\n"; 321 322 const SESSION_ENCRYPTION_KEY_SDPEXTRA_CRLF: &str = "v=0\r\n\ 323 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 324 s=SDP Seminar\r\n\ 325 t=2873397496 2873404696\r\n\ 326 k=prompt\r\n 327 \r\n"; 328 329 const SESSION_ATTRIBUTES_SDP: &str = "v=0\r\n\ 330 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 331 s=SDP Seminar\r\n\ 332 t=2873397496 2873404696\r\n\ 333 a=rtpmap:96 opus/48000\r\n"; 334 335 const MEDIA_NAME_SDP: &str = "v=0\r\n\ 336 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 337 s=SDP Seminar\r\n\ 338 t=2873397496 2873404696\r\n\ 339 m=video 51372 RTP/AVP 99\r\n\ 340 m=audio 54400 RTP/SAVPF 0 96\r\n"; 341 342 const MEDIA_NAME_SDPEXTRA_CRLF: &str = "v=0\r\n\ 343 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 344 s=SDP Seminar\r\n\ 345 t=2873397496 2873404696\r\n\ 346 m=video 51372 RTP/AVP 99\r\n\ 347 m=audio 54400 RTP/SAVPF 0 96\r\n 348 \r\n"; 349 350 const MEDIA_TITLE_SDP: &str = "v=0\r\n\ 351 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 352 s=SDP Seminar\r\n\ 353 t=2873397496 2873404696\r\n\ 354 m=video 51372 RTP/AVP 99\r\n\ 355 m=audio 54400 RTP/SAVPF 0 96\r\n\ 356 i=Vivamus a posuere nisl\r\n"; 357 358 const MEDIA_CONNECTION_INFORMATION_SDP: &str = "v=0\r\n\ 359 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 360 s=SDP Seminar\r\n\ 361 t=2873397496 2873404696\r\n\ 362 m=video 51372 RTP/AVP 99\r\n\ 363 m=audio 54400 RTP/SAVPF 0 96\r\n\ 364 c=IN IP4 203.0.113.1\r\n"; 365 366 const MEDIA_CONNECTION_INFORMATION_SDPEXTRA_CRLF: &str = "v=0\r\n\ 367 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 368 s=SDP Seminar\r\n\ 369 t=2873397496 2873404696\r\n\ 370 m=video 51372 RTP/AVP 99\r\n\ 371 m=audio 54400 RTP/SAVPF 0 96\r\n\ 372 c=IN IP4 203.0.113.1\r\n\ 373 \r\n"; 374 375 const MEDIA_DESCRIPTION_OUT_OF_ORDER_SDP: &str = "v=0\r\n\ 376 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 377 s=SDP Seminar\r\n\ 378 t=2873397496 2873404696\r\n\ 379 m=video 51372 RTP/AVP 99\r\n\ 380 m=audio 54400 RTP/SAVPF 0 96\r\n\ 381 a=rtpmap:99 h263-1998/90000\r\n\ 382 a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host\r\n\ 383 c=IN IP4 203.0.113.1\r\n\ 384 i=Vivamus a posuere nisl\r\n"; 385 386 const MEDIA_DESCRIPTION_OUT_OF_ORDER_SDPACTUAL: &str = "v=0\r\n\ 387 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 388 s=SDP Seminar\r\n\ 389 t=2873397496 2873404696\r\n\ 390 m=video 51372 RTP/AVP 99\r\n\ 391 m=audio 54400 RTP/SAVPF 0 96\r\n\ 392 i=Vivamus a posuere nisl\r\n\ 393 c=IN IP4 203.0.113.1\r\n\ 394 a=rtpmap:99 h263-1998/90000\r\n\ 395 a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host\r\n"; 396 397 const MEDIA_BANDWIDTH_SDP: &str = "v=0\r\n\ 398 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 399 s=SDP Seminar\r\n\ 400 t=2873397496 2873404696\r\n\ 401 m=video 51372 RTP/AVP 99\r\n\ 402 m=audio 54400 RTP/SAVPF 0 96\r\n\ 403 b=X-YZ:128\r\n\ 404 b=AS:12345\r\n"; 405 406 const MEDIA_ENCRYPTION_KEY_SDP: &str = "v=0\r\n\ 407 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 408 s=SDP Seminar\r\n\ 409 t=2873397496 2873404696\r\n\ 410 m=video 51372 RTP/AVP 99\r\n\ 411 m=audio 54400 RTP/SAVPF 0 96\r\n\ 412 k=prompt\r\n"; 413 414 const MEDIA_ENCRYPTION_KEY_SDPEXTRA_CRLF: &str = "v=0\r\n\ 415 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 416 s=SDP Seminar\r\n\ 417 t=2873397496 2873404696\r\n\ 418 m=video 51372 RTP/AVP 99\r\n\ 419 m=audio 54400 RTP/SAVPF 0 96\r\n\ 420 k=prompt\r\n\ 421 \r\n"; 422 423 const MEDIA_ATTRIBUTES_SDP: &str = "v=0\r\n\ 424 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 425 s=SDP Seminar\r\n\ 426 t=2873397496 2873404696\r\n\ 427 m=video 51372 RTP/AVP 99\r\n\ 428 m=audio 54400 RTP/SAVPF 0 96\r\n\ 429 a=rtpmap:99 h263-1998/90000\r\n\ 430 a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host\r\n\ 431 a=rtcp-fb:97 ccm fir\r\n\ 432 a=rtcp-fb:97 nack\r\n\ 433 a=rtcp-fb:97 nack pli\r\n"; 434 435 const CANONICAL_UNMARSHAL_SDP: &str = "v=0\r\n\ 436 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ 437 s=SDP Seminar\r\n\ 438 i=A Seminar on the session description protocol\r\n\ 439 u=http://www.example.com/seminars/sdp.pdf\r\n\ 440 [email protected] (Jane Doe)\r\n\ 441 p=+1 617 555-6011\r\n\ 442 c=IN IP4 224.2.17.12/127\r\n\ 443 b=X-YZ:128\r\n\ 444 b=AS:12345\r\n\ 445 t=2873397496 2873404696\r\n\ 446 t=3034423619 3042462419\r\n\ 447 r=604800 3600 0 90000\r\n\ 448 z=2882844526 -3600 2898848070 0\r\n\ 449 k=prompt\r\n\ 450 a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host\r\n\ 451 a=recvonly\r\n\ 452 m=audio 49170 RTP/AVP 0\r\n\ 453 i=Vivamus a posuere nisl\r\n\ 454 c=IN IP4 203.0.113.1\r\n\ 455 b=X-YZ:128\r\n\ 456 k=prompt\r\n\ 457 a=sendrecv\r\n\ 458 m=video 51372 RTP/AVP 99\r\n\ 459 a=rtpmap:99 h263-1998/90000\r\n"; 460 461 #[test] 462 fn test_round_trip() -> Result<()> { 463 let tests = vec![ 464 ( 465 "SessionInformationSDPLFOnly", 466 SESSION_INFORMATION_SDPLFONLY, 467 Some(SESSION_INFORMATION_SDP), 468 ), 469 ( 470 "SessionInformationSDPExtraCRLF", 471 SESSION_INFORMATION_SDPEXTRA_CRLF, 472 Some(SESSION_INFORMATION_SDP), 473 ), 474 ("SessionInformation", SESSION_INFORMATION_SDP, None), 475 ("URI", URI_SDP, None), 476 ("EmailAddress", EMAIL_ADDRESS_SDP, None), 477 ("PhoneNumber", PHONE_NUMBER_SDP, None), 478 ( 479 "RepeatTimesSDPExtraCRLF", 480 REPEAT_TIMES_SDPEXTRA_CRLF, 481 Some(REPEAT_TIMES_SDPEXPECTED), 482 ), 483 ( 484 "SessionConnectionInformation", 485 SESSION_CONNECTION_INFORMATION_SDP, 486 None, 487 ), 488 ("SessionBandwidth", SESSION_BANDWIDTH_SDP, None), 489 ("SessionEncryptionKey", SESSION_ENCRYPTION_KEY_SDP, None), 490 ( 491 "SessionEncryptionKeyExtraCRLF", 492 SESSION_ENCRYPTION_KEY_SDPEXTRA_CRLF, 493 Some(SESSION_ENCRYPTION_KEY_SDP), 494 ), 495 ("SessionAttributes", SESSION_ATTRIBUTES_SDP, None), 496 ( 497 "TimeZonesSDP2ExtraCRLF", 498 TIME_ZONES_SDP2EXTRA_CRLF, 499 Some(TIME_ZONES_SDP2), 500 ), 501 ("MediaName", MEDIA_NAME_SDP, None), 502 ( 503 "MediaNameExtraCRLF", 504 MEDIA_NAME_SDPEXTRA_CRLF, 505 Some(MEDIA_NAME_SDP), 506 ), 507 ("MediaTitle", MEDIA_TITLE_SDP, None), 508 ( 509 "MediaConnectionInformation", 510 MEDIA_CONNECTION_INFORMATION_SDP, 511 None, 512 ), 513 ( 514 "MediaConnectionInformationExtraCRLF", 515 MEDIA_CONNECTION_INFORMATION_SDPEXTRA_CRLF, 516 Some(MEDIA_CONNECTION_INFORMATION_SDP), 517 ), 518 ( 519 "MediaDescriptionOutOfOrder", 520 MEDIA_DESCRIPTION_OUT_OF_ORDER_SDP, 521 Some(MEDIA_DESCRIPTION_OUT_OF_ORDER_SDPACTUAL), 522 ), 523 ("MediaBandwidth", MEDIA_BANDWIDTH_SDP, None), 524 ("MediaEncryptionKey", MEDIA_ENCRYPTION_KEY_SDP, None), 525 ( 526 "MediaEncryptionKeyExtraCRLF", 527 MEDIA_ENCRYPTION_KEY_SDPEXTRA_CRLF, 528 Some(MEDIA_ENCRYPTION_KEY_SDP), 529 ), 530 ("MediaAttributes", MEDIA_ATTRIBUTES_SDP, None), 531 ("CanonicalUnmarshal", CANONICAL_UNMARSHAL_SDP, None), 532 ]; 533 534 for (name, sdp_str, expected) in tests { 535 let mut reader = Cursor::new(sdp_str.as_bytes()); 536 let sdp = SessionDescription::unmarshal(&mut reader); 537 if let Ok(sdp) = sdp { 538 let actual = sdp.marshal(); 539 if let Some(expected) = expected { 540 assert_eq!(actual.as_str(), expected, "{}\n{}", name, sdp_str); 541 } else { 542 assert_eq!(actual.as_str(), sdp_str, "{}\n{}", name, sdp_str); 543 } 544 } else { 545 panic!("{}\n{}", name, sdp_str); 546 } 547 } 548 549 Ok(()) 550 } 551 552 #[test] 553 fn test_unmarshal_repeat_times() -> Result<()> { 554 let mut reader = Cursor::new(REPEAT_TIMES_SDP.as_bytes()); 555 let sdp = SessionDescription::unmarshal(&mut reader)?; 556 let actual = sdp.marshal(); 557 assert_eq!(actual.as_str(), REPEAT_TIMES_SDPEXPECTED); 558 Ok(()) 559 } 560 561 #[test] 562 fn test_unmarshal_repeat_times_overflow() -> Result<()> { 563 let mut reader = Cursor::new(REPEAT_TIMES_OVERFLOW_SDP.as_bytes()); 564 let result = SessionDescription::unmarshal(&mut reader); 565 assert!(result.is_err()); 566 assert_eq!( 567 Error::SdpInvalidValue("106751991167301d".to_owned()), 568 result.unwrap_err() 569 ); 570 Ok(()) 571 } 572 573 #[test] 574 fn test_unmarshal_time_zones() -> Result<()> { 575 let mut reader = Cursor::new(TIME_ZONES_SDP.as_bytes()); 576 let sdp = SessionDescription::unmarshal(&mut reader)?; 577 let actual = sdp.marshal(); 578 assert_eq!(actual.as_str(), TIME_ZONES_SDPEXPECTED); 579 Ok(()) 580 } 581 582 #[test] 583 fn test_unmarshal_non_nil_address() -> Result<()> { 584 let input = "v=0\r\no=0 0 0 IN IP4 0\r\ns=0\r\nc=IN IP4\r\nt=0 0\r\n"; 585 let mut reader = Cursor::new(input); 586 let sdp = SessionDescription::unmarshal(&mut reader); 587 if let Ok(sdp) = sdp { 588 let output = sdp.marshal(); 589 assert_eq!(output.as_str(), input); 590 } else { 591 panic!("{}", input); 592 } 593 Ok(()) 594 } 595