Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added tests/taglib/data/alaw.aifc
Binary file not shown.
Binary file added tests/taglib/data/empty.aiff
Binary file not shown.
Binary file added tests/taglib/data/excessive_alloc.aif
Binary file not shown.
Binary file added tests/taglib/data/segfault.aif
Binary file not shown.
3 changes: 3 additions & 0 deletions tests/taglib/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub(crate) mod utils;

mod test_aiff;
106 changes: 106 additions & 0 deletions tests/taglib/test_aiff.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use std::fs::File;
use std::io::Read;

use crate::temp_file;
use lofty::{Accessor, AudioFile, FileType};

#[test]
#[ignore]
fn test_aiff_properties() {
let file = lofty::read_from_path("tests/taglib/data/empty.aiff", true).unwrap();

assert_eq!(file.file_type(), FileType::AIFF);

let properties = file.properties();
assert_eq!(properties.duration().as_secs(), 0);
// Durations are +/- 1ms due to rounding.
// Originaly here is 67ms
assert_eq!(properties.duration().as_millis(), 66);
assert_eq!(properties.audio_bitrate(), Some(706));
assert_eq!(properties.sample_rate(), Some(44100));
assert_eq!(properties.channels(), Some(1));
assert_eq!(properties.bit_depth(), Some(16));
// CPPUNIT_ASSERT_EQUAL(2941U, f.audioProperties()->sampleFrames());
// CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isAiffC());
}

#[test]
#[ignore]
fn test_aifc_properties() {
let file = lofty::read_from_path("tests/taglib/data/alaw.aifc", true).unwrap();

assert_eq!(file.file_type(), FileType::AIFF);

let properties = file.properties();
assert_eq!(properties.duration().as_secs(), 0);
assert_eq!(properties.duration().as_millis(), 37);
assert_eq!(properties.audio_bitrate(), Some(355));
assert_eq!(properties.sample_rate(), Some(44100));
assert_eq!(properties.channels(), Some(1));
assert_eq!(properties.bit_depth(), Some(16));
// CPPUNIT_ASSERT_EQUAL(1622U, f.audioProperties()->sampleFrames());
// CPPUNIT_ASSERT_EQUAL(true, f.audioProperties()->isAiffC());
// CPPUNIT_ASSERT_EQUAL(ByteVector("ALAW"), f.audioProperties()->compressionType());
// CPPUNIT_ASSERT_EQUAL(String("SGI CCITT G.711 A-law"), f.audioProperties()->compressionName());
}

#[test]
#[ignore]
fn test_save_id3v2() {
let mut file = temp_file!("tests/taglib/data/empty.aiff");

{
let mut tfile = lofty::read_from(&mut file, true).unwrap();

assert_eq!(tfile.file_type(), FileType::AIFF);

assert!(tfile.tag(&lofty::TagType::Id3v2).is_none());

let mut tag = lofty::Tag::new(lofty::TagType::Id3v2);
tag.set_title("TitleXXX".to_string());
tfile.insert_tag(tag);
tfile.save_to(&mut file).unwrap();
}

{
let mut tfile = lofty::read_from(&mut file, true).unwrap();

assert_eq!(tfile.file_type(), FileType::AIFF);

let mut tag = tfile.tag(&lofty::TagType::Id3v2).unwrap().to_owned();
assert_eq!(tag.title(), Some("TitleXXX"));
tag.set_title("".to_string());
tfile.insert_tag(tag);
tfile.save_to(&mut file).unwrap();
}

{
let tfile = lofty::read_from(&mut file, true).unwrap();

assert_eq!(tfile.file_type(), FileType::AIFF);

assert!(tfile.tag(&lofty::TagType::Id3v2).is_none());
}
}

#[test]
#[ignore]
fn test_fuzzed_file1() {
let mut file = File::open("tests/taglib/data/segfault.aif").unwrap();

let mut buf = [0; 12];
file.read_exact(&mut buf).unwrap();

assert_eq!(FileType::from_buffer(&buf).unwrap(), FileType::AIFF);
}

#[test]
#[ignore]
fn test_fuzzed_file2() {
let mut file = File::open("tests/taglib/data/excessive_alloc.aif").unwrap();

let mut buf = [0; 12];
file.read_exact(&mut buf).unwrap();

assert_eq!(FileType::from_buffer(&buf).unwrap(), FileType::AIFF);
}
94 changes: 94 additions & 0 deletions tests/taglib/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#[macro_export]
macro_rules! temp_file {
($path:tt) => {{
use std::io::{Seek, Write};
let mut file = tempfile::tempfile().unwrap();
file.write_all(&std::fs::read($path).unwrap()).unwrap();

file.seek(std::io::SeekFrom::Start(0)).unwrap();

file
}};
}

#[macro_export]
macro_rules! verify_artist {
($file:ident, $method:ident, $expected_value:literal, $item_count:expr) => {{
println!("VERIFY: Expecting `{}` to have {} items, with an artist of \"{}\"", stringify!($method), $item_count, $expected_value);

verify_artist!($file, $method(), $expected_value, $item_count)
}};
($file:ident, $method:ident, $arg:path, $expected_value:literal, $item_count:expr) => {{
println!("VERIFY: Expecting `{}` to have {} items, with an artist of \"{}\"", stringify!($arg), $item_count, $expected_value);

verify_artist!($file, $method($arg), $expected_value, $item_count)
}};
($file:ident, $method:ident($($arg:path)?), $expected_value:literal, $item_count:expr) => {{
assert!($file.$method($(&$arg)?).is_some());

let tag = $file.$method($(&$arg)?).unwrap();

assert_eq!(tag.item_count(), $item_count);

assert_eq!(
tag.get_item_ref(&ItemKey::TrackArtist),
Some(&TagItem::new(
ItemKey::TrackArtist,
ItemValue::Text(String::from($expected_value))
))
);

tag
}};
}

#[macro_export]
macro_rules! set_artist {
($tagged_file:ident, $method:ident, $expected_value:literal, $item_count:expr => $file_write:ident, $new_value:literal) => {
let tag = verify_artist!($tagged_file, $method, $expected_value, $item_count);
println!(
"WRITE: Writing artist \"{}\" to {}\n",
$new_value,
stringify!($method)
);
set_artist!($file_write, $new_value, tag)
};
($tagged_file:ident, $method:ident, $arg:path, $expected_value:literal, $item_count:expr => $file_write:ident, $new_value:literal) => {
let tag = verify_artist!($tagged_file, $method, $arg, $expected_value, $item_count);
println!(
"WRITE: Writing artist \"{}\" to {}\n",
$new_value,
stringify!($arg)
);
set_artist!($file_write, $new_value, tag)
};
($file_write:ident, $new_value:literal, $tag:ident) => {
$tag.insert_item_unchecked(TagItem::new(
ItemKey::TrackArtist,
ItemValue::Text(String::from($new_value)),
));

$file_write.seek(std::io::SeekFrom::Start(0)).unwrap();

$tag.save_to(&mut $file_write).unwrap();
};
}

#[macro_export]
macro_rules! remove_tag {
($path:tt, $tag_type:path) => {
let mut file = temp_file!($path);

let tagged_file = lofty::read_from(&mut file, false).unwrap();
assert!(tagged_file.tag(&$tag_type).is_some());

file.seek(std::io::SeekFrom::Start(0)).unwrap();

$tag_type.remove_from(&mut file).unwrap();

file.seek(std::io::SeekFrom::Start(0)).unwrap();

let tagged_file = lofty::read_from(&mut file, false).unwrap();
assert!(tagged_file.tag(&$tag_type).is_none());
};
}