1 use super::*; 2 3 #[test] 4 fn test_source_description_unmarshal() { 5 let tests = vec![ 6 ( 7 "nil", 8 Bytes::from_static(&[]), 9 SourceDescription::default(), 10 Some(Error::PacketTooShort), 11 ), 12 ( 13 "no chunks", 14 Bytes::from_static(&[ 15 // v=2, p=0, count=1, SDES, len=8 16 0x80, 0xca, 0x00, 0x04, 17 ]), 18 SourceDescription::default(), 19 None, 20 ), 21 ( 22 "missing type", 23 Bytes::from_static(&[ 24 // v=2, p=0, count=1, SDES, len=8 25 0x81, 0xca, 0x00, 0x08, // ssrc=0x00000000 26 0x00, 0x00, 0x00, 0x00, 27 ]), 28 SourceDescription::default(), 29 Some(Error::PacketTooShort), 30 ), 31 ( 32 "bad cname length", 33 Bytes::from_static(&[ 34 // v=2, p=0, count=1, SDES, len=10 35 0x81, 0xca, 0x00, 0x0a, // ssrc=0x00000000 36 0x00, 0x00, 0x00, 0x00, // CNAME, len = 1 37 0x01, 0x01, 38 ]), 39 SourceDescription::default(), 40 Some(Error::PacketTooShort), 41 ), 42 ( 43 "short cname", 44 Bytes::from_static(&[ 45 // v=2, p=0, count=1, SDES, len=9 46 0x81, 0xca, 0x00, 0x09, // ssrc=0x00000000 47 0x00, 0x00, 0x00, 0x00, // CNAME, Missing length 48 0x01, 49 ]), 50 SourceDescription::default(), 51 Some(Error::PacketTooShort), 52 ), 53 ( 54 "no end", 55 Bytes::from_static(&[ 56 // v=2, p=0, count=1, SDES, len=11 57 0x81, 0xca, 0x00, 0x0b, // ssrc=0x00000000 58 0x00, 0x00, 0x00, 0x00, // CNAME, len=1, content=A 59 0x01, 0x02, 0x41, 60 // Missing END 61 ]), 62 SourceDescription::default(), 63 Some(Error::PacketTooShort), 64 ), 65 ( 66 "bad octet count", 67 Bytes::from_static(&[ 68 // v=2, p=0, count=1, SDES, len=10 69 0x81, 0xca, 0x00, 0x0a, // ssrc=0x00000000 70 0x00, 0x00, 0x00, 0x00, // CNAME, len=1 71 0x01, 0x01, 72 ]), 73 SourceDescription::default(), 74 Some(Error::PacketTooShort), 75 ), 76 ( 77 "zero item chunk", 78 Bytes::from_static(&[ 79 // v=2, p=0, count=1, SDES, len=12 80 0x81, 0xca, 0x00, 0x0c, // ssrc=0x01020304 81 0x01, 0x02, 0x03, 0x04, // END + padding 82 0x00, 0x00, 0x00, 0x00, 83 ]), 84 SourceDescription { 85 chunks: vec![SourceDescriptionChunk { 86 source: 0x01020304, 87 items: vec![], 88 }], 89 }, 90 None, 91 ), 92 ( 93 "wrong type", 94 Bytes::from_static(&[ 95 // v=2, p=0, count=1, SR, len=12 96 0x81, 0xc8, 0x00, 0x0c, // ssrc=0x01020304 97 0x01, 0x02, 0x03, 0x04, // END + padding 98 0x00, 0x00, 0x00, 0x00, 99 ]), 100 SourceDescription::default(), 101 Some(Error::WrongType), 102 ), 103 ( 104 "bad count in header", 105 Bytes::from_static(&[ 106 // v=2, p=0, count=1, SDES, len=12 107 0x81, 0xca, 0x00, 0x0c, 108 ]), 109 SourceDescription::default(), 110 Some(Error::InvalidHeader), 111 ), 112 ( 113 "empty string", 114 Bytes::from_static(&[ 115 // v=2, p=0, count=1, SDES, len=12 116 0x81, 0xca, 0x00, 0x0c, // ssrc=0x01020304 117 0x01, 0x02, 0x03, 0x04, // CNAME, len=0 118 0x01, 0x00, // END + padding 119 0x00, 0x00, 120 ]), 121 SourceDescription { 122 chunks: vec![SourceDescriptionChunk { 123 source: 0x01020304, 124 items: vec![SourceDescriptionItem { 125 sdes_type: SdesType::SdesCname, 126 text: Bytes::from_static(b""), 127 }], 128 }], 129 }, 130 None, 131 ), 132 ( 133 "two items", 134 Bytes::from_static(&[ 135 // v=2, p=0, count=1, SDES, len=16 136 0x81, 0xca, 0x00, 0x10, // ssrc=0x10000000 137 0x10, 0x00, 0x00, 0x00, // CNAME, len=1, content=A 138 0x01, 0x01, 0x41, // PHONE, len=1, content=B 139 0x04, 0x01, 0x42, // END + padding 140 0x00, 0x00, 141 ]), 142 SourceDescription { 143 chunks: vec![SourceDescriptionChunk { 144 source: 0x10000000, 145 items: vec![ 146 SourceDescriptionItem { 147 sdes_type: SdesType::SdesCname, 148 text: Bytes::from_static(b"A"), 149 }, 150 SourceDescriptionItem { 151 sdes_type: SdesType::SdesPhone, 152 text: Bytes::from_static(b"B"), 153 }, 154 ], 155 }], 156 }, 157 None, 158 ), 159 ( 160 "two chunks", 161 Bytes::from_static(&[ 162 // v=2, p=0, count=2, SDES, len=24 163 0x82, 0xca, 0x00, 0x18, // ssrc=0x01020304 164 0x01, 0x02, 0x03, 0x04, 165 // Chunk 1 166 // CNAME, len=1, content=A 167 0x01, 0x01, 0x41, // END 168 0x00, // Chunk 2 169 // SSRC 0x05060708 170 0x05, 0x06, 0x07, 0x08, // CNAME, len=3, content=BCD 171 0x01, 0x03, 0x42, 0x43, 0x44, // END 172 0x00, 0x00, 0x00, 173 ]), 174 SourceDescription { 175 chunks: vec![ 176 SourceDescriptionChunk { 177 source: 0x01020304, 178 items: vec![SourceDescriptionItem { 179 sdes_type: SdesType::SdesCname, 180 text: Bytes::from_static(b"A"), 181 }], 182 }, 183 SourceDescriptionChunk { 184 source: 0x05060708, 185 items: vec![SourceDescriptionItem { 186 sdes_type: SdesType::SdesCname, 187 text: Bytes::from_static(b"BCD"), 188 }], 189 }, 190 ], 191 }, 192 None, 193 ), 194 ]; 195 196 for (name, mut data, want, want_error) in tests { 197 let got = SourceDescription::unmarshal(&mut data); 198 199 assert_eq!( 200 got.is_err(), 201 want_error.is_some(), 202 "Unmarshal {name}: err = {got:?}, want {want_error:?}" 203 ); 204 205 if let Some(err) = want_error { 206 let got_err = got.err().unwrap(); 207 assert_eq!( 208 err, got_err, 209 "Unmarshal {name}: err = {got_err:?}, want {err:?}", 210 ); 211 } else { 212 let actual = got.unwrap(); 213 assert_eq!( 214 actual, want, 215 "Unmarshal {name}: got {actual:?}, want {want:?}" 216 ); 217 } 218 } 219 } 220 221 #[test] 222 fn test_source_description_roundtrip() { 223 let mut too_long_text = String::new(); 224 for _ in 0..(1 << 8) { 225 too_long_text += "x"; 226 } 227 228 let mut too_many_chunks = vec![]; 229 for _ in 0..(1 << 5) { 230 too_many_chunks.push(SourceDescriptionChunk::default()); 231 } 232 233 let tests = vec![ 234 ( 235 "valid", 236 SourceDescription { 237 chunks: vec![ 238 SourceDescriptionChunk { 239 source: 1, 240 items: vec![SourceDescriptionItem { 241 sdes_type: SdesType::SdesCname, 242 text: Bytes::from_static(b"[email protected]"), 243 }], 244 }, 245 SourceDescriptionChunk { 246 source: 2, 247 items: vec![ 248 SourceDescriptionItem { 249 sdes_type: SdesType::SdesNote, 250 text: Bytes::from_static(b"some note"), 251 }, 252 SourceDescriptionItem { 253 sdes_type: SdesType::SdesNote, 254 text: Bytes::from_static(b"another note"), 255 }, 256 ], 257 }, 258 ], 259 }, 260 None, 261 ), 262 ( 263 "item without type", 264 SourceDescription { 265 chunks: vec![SourceDescriptionChunk { 266 source: 1, 267 items: vec![SourceDescriptionItem { 268 sdes_type: SdesType::SdesEnd, 269 text: Bytes::from_static(b"[email protected]"), 270 }], 271 }], 272 }, 273 Some(Error::SdesMissingType), 274 ), 275 ( 276 "zero items", 277 SourceDescription { 278 chunks: vec![SourceDescriptionChunk { 279 source: 1, 280 items: vec![], 281 }], 282 }, 283 None, 284 ), 285 ( 286 "email item", 287 SourceDescription { 288 chunks: vec![SourceDescriptionChunk { 289 source: 1, 290 items: vec![SourceDescriptionItem { 291 sdes_type: SdesType::SdesEmail, 292 text: Bytes::from_static(b"[email protected]"), 293 }], 294 }], 295 }, 296 None, 297 ), 298 ( 299 "empty text", 300 SourceDescription { 301 chunks: vec![SourceDescriptionChunk { 302 source: 1, 303 items: vec![SourceDescriptionItem { 304 sdes_type: SdesType::SdesCname, 305 text: Bytes::from_static(b""), 306 }], 307 }], 308 }, 309 None, 310 ), 311 ( 312 "text too long", 313 SourceDescription { 314 chunks: vec![SourceDescriptionChunk { 315 source: 1, 316 items: vec![SourceDescriptionItem { 317 sdes_type: SdesType::SdesCname, 318 text: Bytes::copy_from_slice(too_long_text.as_bytes()), 319 }], 320 }], 321 }, 322 Some(Error::SdesTextTooLong), 323 ), 324 ( 325 "count overflow", 326 SourceDescription { 327 chunks: too_many_chunks, 328 }, 329 Some(Error::TooManyChunks), 330 ), 331 ]; 332 333 for (name, want, want_error) in tests { 334 let got = want.marshal(); 335 336 assert_eq!( 337 got.is_ok(), 338 want_error.is_none(), 339 "Marshal {name}: err = {got:?}, want {want_error:?}" 340 ); 341 342 if let Some(err) = want_error { 343 let got_err = got.err().unwrap(); 344 assert_eq!( 345 err, got_err, 346 "Unmarshal {name} rr: err = {got_err:?}, want {err:?}", 347 ); 348 } else { 349 let mut data = got.ok().unwrap(); 350 let actual = SourceDescription::unmarshal(&mut data) 351 .unwrap_or_else(|_| panic!("Unmarshal {name}")); 352 353 assert_eq!( 354 actual, want, 355 "{name} round trip: got {actual:?}, want {want:?}" 356 ) 357 } 358 } 359 } 360