1 use super::*;
2 
3 #[test]
test_source_description_unmarshal()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]
test_source_description_roundtrip()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