Skip to content

Commit ae74360

Browse files
committed
Tests: Add TagLib WAV tests
1 parent 3d94455 commit ae74360

10 files changed

+359
-0
lines changed

tests/taglib/data/alaw.wav

55.5 KB
Binary file not shown.

tests/taglib/data/duplicate_tags.wav

16.7 KB
Binary file not shown.

tests/taglib/data/float64.wav

67 KB
Binary file not shown.

tests/taglib/data/infloop.wav

13.9 KB
Binary file not shown.
14.4 KB
Binary file not shown.

tests/taglib/data/segfault.wav

30 Bytes
Binary file not shown.

tests/taglib/data/uint8we.wav

46.1 KB
Binary file not shown.

tests/taglib/data/zero-size-chunk.wav

1 KB
Binary file not shown.

tests/taglib/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ mod test_mpeg;
1313
mod test_speex;
1414
mod test_wavpack;
1515
mod test_xiphcomment;
16+
mod test_wav;

tests/taglib/test_wav.rs

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
use crate::temp_file;
2+
use lofty::id3::v2::{ID3v2Tag, ID3v2Version};
3+
use lofty::iff::wav::{RIFFInfoList, WavFile, WavFormat};
4+
use lofty::{Accessor, AudioFile, ParseOptions, TagType};
5+
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
6+
7+
#[test]
8+
fn test_pcm_properties() {
9+
let mut file = temp_file!("tests/taglib/data/empty.wav");
10+
let f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
11+
assert_eq!(f.properties().duration().as_secs(), 3);
12+
assert_eq!(f.properties().duration().as_millis(), 3675);
13+
assert_eq!(f.properties().bitrate(), 32);
14+
assert_eq!(f.properties().channels(), 2);
15+
assert_eq!(f.properties().sample_rate(), 1000);
16+
assert_eq!(f.properties().bit_depth(), 16);
17+
// TODO: assert_eq!(f.properties().total_samples(), 3675);
18+
assert_eq!(*f.properties().format(), WavFormat::PCM);
19+
}
20+
21+
#[test]
22+
fn test_alaw_properties() {
23+
let mut file = temp_file!("tests/taglib/data/alaw.wav");
24+
let f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
25+
assert_eq!(f.properties().duration().as_secs(), 3);
26+
assert_eq!(f.properties().duration().as_millis(), 3550);
27+
assert_eq!(f.properties().bitrate(), 128);
28+
assert_eq!(f.properties().channels(), 2);
29+
assert_eq!(f.properties().sample_rate(), 8000);
30+
assert_eq!(f.properties().bit_depth(), 8);
31+
// TODO: assert_eq!(f.properties().total_samples(), 28400);
32+
assert_eq!(*f.properties().format(), WavFormat::Other(6));
33+
}
34+
35+
#[test]
36+
fn test_float_properties() {
37+
let mut file = temp_file!("tests/taglib/data/float64.wav");
38+
let f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
39+
assert_eq!(f.properties().duration().as_secs(), 0);
40+
assert_eq!(f.properties().duration().as_millis(), 97);
41+
assert_eq!(f.properties().bitrate(), 5645);
42+
assert_eq!(f.properties().channels(), 2);
43+
assert_eq!(f.properties().sample_rate(), 44100);
44+
assert_eq!(f.properties().bit_depth(), 64);
45+
// TODO: assert_eq!(f.properties().total_samples(), 4281);
46+
assert_eq!(*f.properties().format(), WavFormat::IEEE_FLOAT);
47+
}
48+
49+
#[test]
50+
fn test_float_without_fact_chunk_properties() {
51+
let mut wav_data = std::fs::read("tests/taglib/data/float64.wav").unwrap();
52+
assert_eq!(&wav_data[36..40], b"fact");
53+
54+
// Remove the fact chunk by renaming it to fakt
55+
wav_data[38] = b'k';
56+
57+
let f = WavFile::read_from(&mut Cursor::new(wav_data), ParseOptions::new()).unwrap();
58+
assert_eq!(f.properties().duration().as_secs(), 0);
59+
assert_eq!(f.properties().duration().as_millis(), 97);
60+
assert_eq!(f.properties().bitrate(), 5645);
61+
assert_eq!(f.properties().channels(), 2);
62+
assert_eq!(f.properties().sample_rate(), 44100);
63+
assert_eq!(f.properties().bit_depth(), 64);
64+
// TODO: assert_eq!(f.properties().total_samples(), 4281);
65+
assert_eq!(*f.properties().format(), WavFormat::IEEE_FLOAT);
66+
}
67+
68+
#[test]
69+
fn test_zero_size_data_chunk() {
70+
let mut file = temp_file!("tests/taglib/data/zero-size-chunk.wav");
71+
let _f = WavFile::read_from(&mut file, ParseOptions::new().read_properties(false)).unwrap();
72+
}
73+
74+
#[test]
75+
fn test_id3v2_tag() {
76+
let mut file = temp_file!("tests/taglib/data/empty.wav");
77+
78+
{
79+
let mut f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
80+
file.rewind().unwrap();
81+
assert!(f.id3v2().is_none());
82+
83+
let mut id3v2 = ID3v2Tag::default();
84+
id3v2.set_title(String::from("Title"));
85+
id3v2.set_artist(String::from("Artist"));
86+
f.set_id3v2(id3v2);
87+
f.save_to(&mut file).unwrap();
88+
assert!(f.id3v2().is_some());
89+
}
90+
file.rewind().unwrap();
91+
{
92+
let mut f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
93+
file.rewind().unwrap();
94+
assert!(f.id3v2().is_some());
95+
96+
assert_eq!(f.id3v2().unwrap().title().as_deref(), Some("Title"));
97+
assert_eq!(f.id3v2().unwrap().artist().as_deref(), Some("Artist"));
98+
99+
f.id3v2_mut().unwrap().remove_title();
100+
f.id3v2_mut().unwrap().remove_artist();
101+
f.save_to(&mut file).unwrap();
102+
}
103+
file.rewind().unwrap();
104+
{
105+
let f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
106+
assert!(f.id3v2().is_none());
107+
}
108+
}
109+
110+
#[test]
111+
#[ignore] // TODO: Support writing ID3v2.3
112+
fn test_save_id3v23() {
113+
let mut file = temp_file!("tests/taglib/data/empty.wav");
114+
115+
let xxx = "X".repeat(254);
116+
{
117+
let mut f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
118+
assert!(f.id3v2().is_none());
119+
120+
f.id3v2_mut().unwrap().set_title(xxx.clone());
121+
f.id3v2_mut().unwrap().set_artist(String::from("Artist A"));
122+
123+
// f.save(RIFF::WAV::File::AllTags, File::StripOthers, ID3v2::v3);
124+
// assert!(f.id3v2().is_some());
125+
}
126+
{
127+
let f2 = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
128+
let tag = f2.id3v2().unwrap();
129+
assert_eq!(tag.original_version(), ID3v2Version::V3);
130+
assert_eq!(tag.artist().as_deref(), Some("Artist A"));
131+
assert_eq!(tag.title().as_deref(), Some(&*xxx));
132+
}
133+
}
134+
135+
#[test]
136+
fn test_info_tag() {
137+
let mut file = temp_file!("tests/taglib/data/empty.wav");
138+
139+
{
140+
let mut f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
141+
file.rewind().unwrap();
142+
assert!(f.riff_info().is_none());
143+
144+
let mut riff_info = RIFFInfoList::default();
145+
riff_info.set_title(String::from("Title"));
146+
riff_info.set_artist(String::from("Artist"));
147+
f.set_riff_info(riff_info);
148+
149+
f.save_to(&mut file).unwrap();
150+
}
151+
file.rewind().unwrap();
152+
{
153+
let mut f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
154+
file.rewind().unwrap();
155+
assert!(f.riff_info().is_some());
156+
assert_eq!(f.riff_info().unwrap().title().as_deref(), Some("Title"));
157+
assert_eq!(f.riff_info().unwrap().artist().as_deref(), Some("Artist"));
158+
159+
f.riff_info_mut().unwrap().remove_title();
160+
f.riff_info_mut().unwrap().remove_artist();
161+
162+
f.save_to(&mut file).unwrap();
163+
}
164+
file.rewind().unwrap();
165+
{
166+
let f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
167+
assert!(f.riff_info().is_none());
168+
}
169+
}
170+
171+
#[test]
172+
fn test_strip_tags() {
173+
let mut file = temp_file!("tests/taglib/data/empty.wav");
174+
175+
{
176+
let mut f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
177+
file.rewind().unwrap();
178+
179+
let mut id3v2 = ID3v2Tag::default();
180+
id3v2.set_title(String::from("test title"));
181+
f.set_id3v2(id3v2);
182+
183+
let mut riff_info = RIFFInfoList::default();
184+
riff_info.set_title(String::from("test title"));
185+
f.set_riff_info(riff_info);
186+
187+
f.save_to(&mut file).unwrap();
188+
}
189+
file.rewind().unwrap();
190+
{
191+
let f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
192+
file.rewind().unwrap();
193+
assert!(f.id3v2().is_some());
194+
assert!(f.riff_info().is_some());
195+
196+
TagType::RIFFInfo.remove_from(&mut file).unwrap();
197+
}
198+
file.rewind().unwrap();
199+
{
200+
let mut f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
201+
file.rewind().unwrap();
202+
assert!(f.id3v2().is_some());
203+
assert!(f.riff_info().is_none());
204+
205+
let mut riff_info = RIFFInfoList::default();
206+
riff_info.set_title(String::from("test title"));
207+
f.set_riff_info(riff_info);
208+
209+
f.save_to(&mut file).unwrap();
210+
}
211+
file.rewind().unwrap();
212+
{
213+
let f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
214+
file.rewind().unwrap();
215+
assert!(f.id3v2().is_some());
216+
assert!(f.riff_info().is_some());
217+
218+
TagType::ID3v2.remove_from(&mut file).unwrap();
219+
}
220+
file.rewind().unwrap();
221+
{
222+
let f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
223+
assert!(f.id3v2().is_none());
224+
assert!(f.riff_info().is_some());
225+
}
226+
}
227+
228+
#[test]
229+
fn test_duplicate_tags() {
230+
let mut file = temp_file!("tests/taglib/data/duplicate_tags.wav");
231+
232+
let f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
233+
assert_eq!(file.seek(SeekFrom::End(0)).unwrap(), 17052);
234+
file.rewind().unwrap();
235+
236+
// duplicate_tags.wav has duplicate ID3v2/INFO tags.
237+
// title() returns "Title2" if can't skip the second tag.
238+
239+
assert!(f.id3v2().is_some());
240+
assert_eq!(f.id3v2().unwrap().title().as_deref(), Some("Title1"));
241+
242+
assert!(f.riff_info().is_some());
243+
assert_eq!(f.riff_info().unwrap().title().as_deref(), Some("Title1"));
244+
245+
f.save_to(&mut file).unwrap();
246+
assert_eq!(file.seek(SeekFrom::End(0)).unwrap(), 15898);
247+
248+
let mut file_bytes = Vec::new();
249+
file.rewind().unwrap();
250+
file.read_to_end(&mut file_bytes).unwrap();
251+
252+
assert_eq!(
253+
file_bytes.windows(6).position(|window| window == b"Title2"),
254+
None
255+
);
256+
}
257+
258+
#[test]
259+
fn test_fuzzed_file1() {
260+
let mut file = temp_file!("tests/taglib/data/infloop.wav");
261+
let f1 = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
262+
// The file has problems:
263+
// Chunk 'ISTt' has invalid size (larger than the file size).
264+
// Its properties can nevertheless be read.
265+
let properties = f1.properties();
266+
assert_eq!(1, properties.channels());
267+
assert_eq!(88, properties.bitrate());
268+
assert_eq!(8, properties.bit_depth());
269+
assert_eq!(11025, properties.sample_rate());
270+
assert!(f1.riff_info().is_none());
271+
assert!(f1.id3v2().is_none());
272+
}
273+
274+
#[test]
275+
fn test_fuzzed_file2() {
276+
let mut file = temp_file!("tests/taglib/data/segfault.wav");
277+
let _f2 = WavFile::read_from(&mut file, ParseOptions::new().read_properties(false)).unwrap();
278+
}
279+
280+
#[test]
281+
#[ignore] // TODO: Doesn't pass, need to check what TagLib is doing here
282+
fn test_file_with_garbage_appended() {
283+
let mut file = temp_file!("tests/taglib/data/empty.wav");
284+
let contents_before_modification;
285+
{
286+
file.seek(SeekFrom::End(0)).unwrap();
287+
288+
let garbage = b"12345678";
289+
file.write_all(garbage).unwrap();
290+
file.rewind().unwrap();
291+
292+
let mut file_contents = Vec::new();
293+
file.read_to_end(&mut file_contents).unwrap();
294+
295+
contents_before_modification = file_contents;
296+
}
297+
file.rewind().unwrap();
298+
{
299+
let mut f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
300+
file.rewind().unwrap();
301+
302+
let mut id3v2 = ID3v2Tag::default();
303+
id3v2.set_title(String::from("ID3v2 Title"));
304+
f.set_id3v2(id3v2);
305+
306+
let mut riff_info = RIFFInfoList::default();
307+
riff_info.set_title(String::from("INFO Title"));
308+
f.set_riff_info(riff_info);
309+
310+
f.save_to(&mut file).unwrap();
311+
}
312+
file.rewind().unwrap();
313+
{
314+
TagType::ID3v2.remove_from(&mut file).unwrap();
315+
file.rewind().unwrap();
316+
TagType::RIFFInfo.remove_from(&mut file).unwrap();
317+
}
318+
file.rewind().unwrap();
319+
{
320+
let mut contents_after_modification = Vec::new();
321+
file.read_to_end(&mut contents_after_modification).unwrap();
322+
assert_eq!(contents_before_modification, contents_after_modification);
323+
}
324+
}
325+
326+
#[test]
327+
#[ignore]
328+
fn test_strip_and_properties() {
329+
// Marker test, Lofty does not replicate the properties API
330+
}
331+
332+
#[test]
333+
fn test_pcm_with_fact_chunk() {
334+
let mut file = temp_file!("tests/taglib/data/pcm_with_fact_chunk.wav");
335+
let f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
336+
assert_eq!(f.properties().duration().as_secs(), 3);
337+
assert_eq!(f.properties().duration().as_millis(), 3675);
338+
assert_eq!(f.properties().bitrate(), 32);
339+
assert_eq!(f.properties().channels(), 2);
340+
assert_eq!(f.properties().sample_rate(), 1000);
341+
assert_eq!(f.properties().bit_depth(), 16);
342+
// TODO: assert_eq!(f.properties().total_samples(), 3675);
343+
assert_eq!(*f.properties().format(), WavFormat::PCM);
344+
}
345+
346+
#[test]
347+
fn test_wave_format_extensible() {
348+
let mut file = temp_file!("tests/taglib/data/uint8we.wav");
349+
let f = WavFile::read_from(&mut file, ParseOptions::new()).unwrap();
350+
assert_eq!(f.properties().duration().as_secs(), 2);
351+
assert_eq!(f.properties().duration().as_millis(), 2937);
352+
assert_eq!(f.properties().bitrate(), 128);
353+
assert_eq!(f.properties().channels(), 2);
354+
assert_eq!(f.properties().sample_rate(), 8000);
355+
assert_eq!(f.properties().bit_depth(), 8);
356+
// TODO: assert_eq!(f.properties().total_samples(), 23493);
357+
assert_eq!(*f.properties().format(), WavFormat::PCM);
358+
}

0 commit comments

Comments
 (0)