From f85ebf4b0d3c83cafa74748852344863442e9696 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Mon, 10 Apr 2023 15:30:31 -0400 Subject: [PATCH] Tests: Add TagLib ID3v2 tests --- tests/taglib/data/005411.id3 | Bin 0 -> 38402 bytes tests/taglib/data/broken-tenc.id3 | Bin 0 -> 400 bytes tests/taglib/data/compressed_id3_frame.mp3 | Bin 0 -> 5000 bytes tests/taglib/data/id3v22-tda.mp3 | Bin 0 -> 4096 bytes tests/taglib/data/unsynch.id3 | Bin 0 -> 320 bytes tests/taglib/data/w000.mp3 | Bin 0 -> 512 bytes tests/taglib/main.rs | 1 + tests/taglib/test_id3v2.rs | 814 +++++++++++++++++++++ 8 files changed, 815 insertions(+) create mode 100644 tests/taglib/data/005411.id3 create mode 100644 tests/taglib/data/broken-tenc.id3 create mode 100644 tests/taglib/data/compressed_id3_frame.mp3 create mode 100644 tests/taglib/data/id3v22-tda.mp3 create mode 100644 tests/taglib/data/unsynch.id3 create mode 100644 tests/taglib/data/w000.mp3 create mode 100644 tests/taglib/test_id3v2.rs diff --git a/tests/taglib/data/005411.id3 b/tests/taglib/data/005411.id3 new file mode 100644 index 0000000000000000000000000000000000000000..ab2e0997a0bcbf27aa169a09fd3f730d8319de9d GIT binary patch literal 38402 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 AdjJ3c literal 0 HcmV?d00001 diff --git a/tests/taglib/data/broken-tenc.id3 b/tests/taglib/data/broken-tenc.id3 new file mode 100644 index 0000000000000000000000000000000000000000..809040506f29b83c48e055251e164c807d3b2997 GIT binary patch literal 400 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 literal 0 HcmV?d00001 diff --git a/tests/taglib/data/w000.mp3 b/tests/taglib/data/w000.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..f9c2261764526ff40aba618a1e9b9933acada5fd GIT binary patch literal 512 zcmdUqQA@)x6ore5`rwm4K<|s750-TE!M*9)BBSeCW@Pvz=}fz@G#PD5?Z5XFd=USE z2R@Q>a&K<3h^EILbb1qJX^PDTNK<)vV{1#9(F5I6-}nAu3@p6AwKcLxwXRV`=ae;M zOL9BaQmM2gtmDzvp%+~{RVXJveLl~}0Vg1sJn}GG{kYrd9gkNb+$H!mI5SISBwz3e z@(Yj{+bdJiyX|-yM@Y^9V-IXL<9QswT!UBHRLate&~^}pN}sr>8$pSbMi`#I%~5m? z*0v~=X*Y~9xGT@o-Cnf578>b(c#>bDK4>}q_ygkWFhSiB2>A1IyyefUko+%w1F}q5 ADgXcg literal 0 HcmV?d00001 diff --git a/tests/taglib/main.rs b/tests/taglib/main.rs index d4d2b9663..25155b940 100644 --- a/tests/taglib/main.rs +++ b/tests/taglib/main.rs @@ -7,6 +7,7 @@ mod test_fileref; mod test_flac; mod test_flacpicture; mod test_id3v1; +mod test_id3v2; mod test_info; mod test_mp4; mod test_mpeg; diff --git a/tests/taglib/test_id3v2.rs b/tests/taglib/test_id3v2.rs new file mode 100644 index 000000000..e183348fc --- /dev/null +++ b/tests/taglib/test_id3v2.rs @@ -0,0 +1,814 @@ +use crate::temp_file; +use lofty::id3::v2::{ + AttachedPictureFrame, CommentFrame, ExtendedTextFrame, ExtendedUrlFrame, Frame, FrameFlags, + FrameId, FrameValue, GEOBInformation, GeneralEncapsulatedObject, ID3v2Tag, ID3v2Version, + Popularimeter, SyncTextContentType, SyncTextInformation, SynchronizedText, TimestampFormat, + UniqueFileIdentifierFrame, UrlLinkFrame, +}; +use lofty::mpeg::MpegFile; +use lofty::{ + Accessor, AudioFile, MimeType, ParseOptions, Picture, PictureType, TagExt, TextEncoding, +}; +use std::borrow::Cow; +use std::io::Seek; + +#[test] +fn test_unsynch_decode() { + let mut file = temp_file!("tests/taglib/data/unsynch.id3"); + let f = MpegFile::read_from(&mut file, ParseOptions::new().read_properties(false)).unwrap(); + + assert!(f.id3v2().is_some()); + assert_eq!( + f.id3v2().unwrap().title().as_deref(), + Some("My babe just cares for me") + ); +} + +#[test] +#[ignore] // TODO: We don't support downgrading 2.4 tags to 2.3 +fn test_downgrade_utf8_for_id3v23_1() {} + +#[test] +#[ignore] // TODO: We don't support downgrading 2.4 tags to 2.3 +fn test_downgrade_utf8_for_id3v23_2() {} + +#[test] +#[ignore] // TODO: Need to think of a nice way to handle multiple UTF-16 values separated by null +fn test_utf16be_delimiter() {} + +#[test] +#[ignore] // TODO: Need to think of a nice way to handle multiple UTF-16 values separated by null +fn test_utf16_delimiter() {} + +#[test] +fn test_broken_frame1() { + let mut file = temp_file!("tests/taglib/data/broken-tenc.id3"); + let f = MpegFile::read_from(&mut file, ParseOptions::new().read_properties(false)).unwrap(); + + assert!(f + .id3v2() + .unwrap() + .contains(&FrameId::Valid(Cow::from("TENC")))); +} + +#[test] +#[ignore] +fn test_read_string_field() { + // Marker test, this is not an API Lofty replicates +} + +#[test] +fn test_parse_apic() { + let f = AttachedPictureFrame::parse( + b"\ + \x00\ + m\x00\ + \x01\ + d\x00\ + \x00", + ID3v2Version::V4, + ) + .unwrap(); + assert_eq!(f.picture.mime_type(), &MimeType::Unknown(String::from("m"))); + assert_eq!(f.picture.pic_type(), PictureType::Icon); + assert_eq!(f.picture.description(), Some("d")); +} + +#[test] +fn test_parse_apic_utf16_bom() { + let f = AttachedPictureFrame::parse( + b"\ + \x01\x69\x6d\x61\x67\x65\ + \x2f\x6a\x70\x65\x67\x00\x00\xfe\xff\x00\x63\x00\x6f\x00\x76\x00\ + \x65\x00\x72\x00\x2e\x00\x6a\x00\x70\x00\x67\x00\x00\xff\xd8\xff", + ID3v2Version::V4, + ) + .unwrap(); + + assert_eq!(f.picture.mime_type(), &MimeType::Jpeg); + assert_eq!(f.picture.pic_type(), PictureType::Other); + assert_eq!(f.picture.description(), Some("cover.jpg")); + assert_eq!(f.picture.data(), b"\xff\xd8\xff"); +} + +#[test] +fn test_parse_apicv22() { + let frame = AttachedPictureFrame::parse( + b"\ + \x00\ + JPG\ + \x01\ + d\x00\ + \x00", + ID3v2Version::V2, + ) + .unwrap(); + + assert_eq!(frame.picture.mime_type(), &MimeType::Jpeg); + assert_eq!(frame.picture.pic_type(), PictureType::Icon); + assert_eq!(frame.picture.description(), Some("d")); +} + +#[test] +fn test_render_apic() { + let f = AttachedPictureFrame { + encoding: TextEncoding::UTF8, + picture: Picture::new_unchecked( + PictureType::CoverBack, + MimeType::Png, + Some(String::from("Description")), + b"PNG data".to_vec(), + ), + }; + + assert_eq!( + f.as_bytes(ID3v2Version::V4).unwrap(), + b"\ + \x03\ + image/png\x00\ + \x04\ + Description\x00\ + PNG data" + ); +} + +#[test] +#[ignore] +fn test_dont_render22() { + // Marker test, not sure what's going on here? +} + +#[test] +fn test_parse_geob() { + let f = GeneralEncapsulatedObject::parse( + b"\ + \x00\ + m\x00\ + f\x00\ + d\x00\ + \x00", + ) + .unwrap(); + assert_eq!(f.information.mime_type.as_deref(), Some("m")); + assert_eq!(f.information.file_name.as_deref(), Some("f")); + assert_eq!(f.information.descriptor.as_deref(), Some("d")); +} + +#[test] +fn test_render_geob() { + let f = GeneralEncapsulatedObject { + information: GEOBInformation { + encoding: TextEncoding::Latin1, + mime_type: Some(String::from("application/octet-stream")), + file_name: Some(String::from("test.bin")), + descriptor: Some(String::from("Description")), + }, + data: vec![0x01; 3], + }; + + assert_eq!( + f.as_bytes(), + b"\ + \x00\ + application/octet-stream\x00\ + test.bin\x00\ + Description\x00\ + \x01\x01\x01" + ); +} + +#[test] +fn test_parse_popm() { + let f = Popularimeter::parse( + b"\ + email@example.com\x00\ + \x02\ + \x00\x00\x00\x03", + ) + .unwrap(); + assert_eq!(f.email, "email@example.com"); + assert_eq!(f.rating, 2); + assert_eq!(f.counter, 3); +} + +#[test] +fn test_parse_popm_without_counter() { + let f = Popularimeter::parse( + b"\ + email@example.com\x00\ + \x02", + ) + .unwrap(); + assert_eq!(f.email, "email@example.com"); + assert_eq!(f.rating, 2); + assert_eq!(f.counter, 0); +} + +#[test] +fn test_render_popm() { + let f = Popularimeter { + email: String::from("email@example.com"), + rating: 2, + counter: 3, + }; + + assert_eq!( + f.as_bytes(), + b"\ + email@example.com\x00\ + \x02\ + \x00\x00\x00\x03" + ); +} + +#[test] +#[ignore] +fn test_popm_to_string() { + // Marker test, Lofty doesn't have a display impl for Popularimeter +} + +#[test] +fn test_popm_from_file() { + let mut file = temp_file!("tests/taglib/data/xing.mp3"); + + let f = Popularimeter { + email: String::from("email@example.com"), + rating: 200, + counter: 3, + }; + + { + let mut foo = MpegFile::read_from(&mut file, ParseOptions::new()).unwrap(); + file.rewind().unwrap(); + + let mut tag = ID3v2Tag::new(); + tag.insert( + Frame::new("POPM", FrameValue::Popularimeter(f), FrameFlags::default()).unwrap(), + ); + foo.set_id3v2(tag); + foo.save_to(&mut file).unwrap(); + } + file.rewind().unwrap(); + { + let bar = MpegFile::read_from(&mut file, ParseOptions::new()).unwrap(); + let popm_frame = bar.id3v2().unwrap().get("POPM").unwrap(); + let popularimeter = match popm_frame.content() { + FrameValue::Popularimeter(popm) => popm, + _ => unreachable!(), + }; + + assert_eq!(popularimeter.email, "email@example.com"); + assert_eq!(popularimeter.rating, 200); + } +} + +#[test] +#[ignore] // TODO: We don't support RVA2 frames yet +fn test_parse_relative_volume_frame() {} + +#[test] +#[ignore] // TODO: We don't support RVA2 frames yet +fn test_render_relative_volume_frame() {} + +#[test] +fn test_parse_unique_file_identifier_frame() { + let f = UniqueFileIdentifierFrame::parse( + &mut &b"\ + owner\x00\ + \x00\x01\x02"[..], + ) + .unwrap() + .unwrap(); + + assert_eq!(f.owner, "owner"); + assert_eq!(f.identifier, &[0x00, 0x01, 0x02]); +} + +#[test] +fn test_parse_empty_unique_file_identifier_frame() { + let f = UniqueFileIdentifierFrame::parse( + &mut &b"\ + \x00\ + "[..], + ); + + // NOTE: TagLib considers a missing owner to be valid, we do not + assert!(f.is_err()); +} + +#[test] +fn test_render_unique_file_identifier_frame() { + let f = UniqueFileIdentifierFrame { + owner: String::from("owner"), + identifier: b"\x01\x02\x03".to_vec(), + }; + + assert_eq!( + f.as_bytes(), + b"\ +owner\x00\ +\x01\x02\x03" + ); +} + +#[test] +fn test_parse_url_link_frame() { + let f = UrlLinkFrame::parse(b"http://example.com").unwrap().unwrap(); + assert_eq!(f.url(), "http://example.com"); +} + +#[test] +fn test_render_url_link_frame() { + let f = UrlLinkFrame::parse(b"http://example.com").unwrap().unwrap(); + assert_eq!(f.as_bytes(), b"http://example.com"); +} + +#[test] +fn test_parse_user_url_link_frame() { + let f = ExtendedUrlFrame::parse( + b"\ + \x00\ + foo\x00\ + http://example.com", + ID3v2Version::V4, + ) + .unwrap() + .unwrap(); + + assert_eq!(f.description, String::from("foo")); + assert_eq!(f.content, String::from("http://example.com")); +} + +#[test] +fn test_render_user_url_link_frame() { + let f = ExtendedUrlFrame { + encoding: TextEncoding::Latin1, + description: String::from("foo"), + content: String::from("http://example.com"), + }; + + assert_eq!( + f.as_bytes(), + b"\ + \x00\ + foo\x00\ + http://example.com" + ); +} + +#[test] +#[ignore] // TODO: We don't support OWNE frames yet +fn test_parse_ownership_frame() {} + +#[test] +#[ignore] // TODO: We don't support OWNE frames yet +fn test_render_ownership_frame() {} + +#[test] +fn test_parse_synchronized_lyrics_frame() { + let f = SynchronizedText::parse( + b"\ + \x00\ +eng\ +\x02\ +\x01\ +foo\x00\ +Example\x00\ +\x00\x00\x04\xd2\ +Lyrics\x00\ +\x00\x00\x11\xd7", + ) + .unwrap(); + + assert_eq!(f.information.encoding, TextEncoding::Latin1); + assert_eq!(f.information.language, *b"eng"); + assert_eq!(f.information.timestamp_format, TimestampFormat::MS); + assert_eq!(f.information.content_type, SyncTextContentType::Lyrics); + assert_eq!(f.information.description.as_deref(), Some("foo")); + + assert_eq!(f.content.len(), 2); + assert_eq!(f.content[0].1, "Example"); + assert_eq!(f.content[0].0, 1234); + assert_eq!(f.content[1].1, "Lyrics"); + assert_eq!(f.content[1].0, 4567); +} + +#[test] +fn test_parse_synchronized_lyrics_frame_with_empty_description() { + let f = SynchronizedText::parse( + b"\ + \x00\ + eng\ + \x02\ + \x01\ + \x00\ + Example\x00\ + \x00\x00\x04\xd2\ + Lyrics\x00\ + \x00\x00\x11\xd7", + ) + .unwrap(); + + assert_eq!(f.information.encoding, TextEncoding::Latin1); + assert_eq!(f.information.language, *b"eng"); + assert_eq!(f.information.timestamp_format, TimestampFormat::MS); + assert_eq!(f.information.content_type, SyncTextContentType::Lyrics); + assert!(f.information.description.is_none()); + + assert_eq!(f.content.len(), 2); + assert_eq!(f.content[0].1, "Example"); + assert_eq!(f.content[0].0, 1234); + assert_eq!(f.content[1].1, "Lyrics"); + assert_eq!(f.content[1].0, 4567); +} + +#[test] +fn test_render_synchronized_lyrics_frame() { + let f = SynchronizedText { + information: SyncTextInformation { + encoding: TextEncoding::Latin1, + language: *b"eng", + timestamp_format: TimestampFormat::MS, + content_type: SyncTextContentType::Lyrics, + description: Some(String::from("foo")), + }, + content: vec![ + (1234, String::from("Example")), + (4567, String::from("Lyrics")), + ], + }; + + assert_eq!( + f.as_bytes().unwrap(), + b"\ + \x00\ + eng\ + \x02\ + \x01\ + foo\x00\ + Example\x00\ + \x00\x00\x04\xd2\ + Lyrics\x00\ + \x00\x00\x11\xd7" + ); +} + +#[test] +#[ignore] // TODO: We don't support ETCO frames yet +fn test_parse_event_timing_codes_frame() {} + +#[test] +#[ignore] // TODO: We don't support ETCO frames yet +fn test_render_event_timing_codes_frame() {} + +#[test] +fn test_parse_comments_frame() { + let f = CommentFrame::parse( + b"\x03\ + deu\ + Description\x00\ + Text", + ID3v2Version::V4, + ) + .unwrap() + .unwrap(); + + assert_eq!(f.encoding, TextEncoding::UTF8); + assert_eq!(f.language, *b"deu"); + assert_eq!(f.description, String::from("Description")); + assert_eq!(f.content, String::from("Text")); +} + +#[test] +fn test_render_comments_frame() { + let f = CommentFrame { + encoding: TextEncoding::UTF16, + language: *b"eng", + description: String::from("Description"), + content: String::from("Text"), + }; + + assert_eq!( + f.as_bytes().unwrap(), + b"\ + \x01\ + eng\ + \xff\xfeD\0e\0s\0c\0r\0i\0p\0t\0i\0o\0n\0\x00\x00\ + \xff\xfeT\0e\0x\0t\0" + ); +} + +#[test] +#[ignore] +fn test_parse_podcast_frame() { + // Marker test, Lofty doesn't have dedicated support for PCST frames, it seems unnecessary +} + +#[test] +#[ignore] +fn test_render_podcast_frame() { + // Marker test, Lofty doesn't have dedicated support for PCST frames, it seems unnecessary +} + +#[test] +#[ignore] // TODO: We don't support PRIV frames yet +fn test_parse_private_frame() {} + +#[test] +#[ignore] // TODO: We don't support PRIV frames yet +fn test_render_private_frame() {} + +#[test] +fn test_parse_user_text_identification_frame() { + let frame_without_description = ExtendedUrlFrame::parse( + b"\ + \x00\ + \x00\ + Text", + ID3v2Version::V4, + ) + .unwrap() + .unwrap(); + + assert_eq!(frame_without_description.description, String::new()); + assert_eq!(frame_without_description.content, String::from("Text")); + + let frame_with_description = ExtendedUrlFrame::parse( + b"\ + \x00\ + Description\x00\ + Text", + ID3v2Version::V4, + ) + .unwrap() + .unwrap(); + assert_eq!( + frame_with_description.description, + String::from("Description") + ); + assert_eq!(frame_with_description.content, String::from("Text")); +} + +#[test] +fn test_render_user_text_identification_frame() { + let mut f = ExtendedTextFrame { + encoding: TextEncoding::Latin1, + description: String::new(), + content: String::from("Text"), + }; + + assert_eq!( + f.as_bytes(), + b"\ + \x00\ + \x00\ + Text" + ); + + f.description = String::from("Description"); + + assert_eq!( + f.as_bytes(), + b"\ + \x00\ + Description\x00\ + Text" + ); +} + +#[test] +#[ignore] // TODO: iTunes, being the great application it is writes unsynchronized integers for sizes. There's no *great* way to detect this. +fn test_itunes_24_frame_size() { + let mut file = temp_file!("tests/taglib/data/005411.id3"); + let f = MpegFile::read_from(&mut file, ParseOptions::new().read_properties(false)).unwrap(); + + assert!(f + .id3v2() + .unwrap() + .contains(&FrameId::Valid(Cow::from("TIT2")))); + assert_eq!( + f.id3v2().unwrap().get_text("TIT2").unwrap(), + "Sunshine Superman" + ); +} + +#[test] +fn test_save_utf16_comment() { + let mut file = temp_file!("tests/taglib/data/xing.mp3"); + + // NOTE: You can change the default encoding in TagLib, Lofty does not support this + { + let mut foo = MpegFile::read_from(&mut file, ParseOptions::new()).unwrap(); + file.rewind().unwrap(); + + let mut tag = ID3v2Tag::new(); + tag.insert( + Frame::new( + "COMM", + CommentFrame { + encoding: TextEncoding::UTF16, + language: *b"eng", + description: String::new(), + content: String::from("Test comment!"), + }, + FrameFlags::default(), + ) + .unwrap(), + ); + foo.set_id3v2(tag); + foo.save_to(&mut file).unwrap(); + } + file.rewind().unwrap(); + { + let bar = MpegFile::read_from(&mut file, ParseOptions::new()).unwrap(); + assert_eq!( + bar.id3v2().unwrap().comment().as_deref(), + Some("Test comment!") + ); + } +} + +#[test] +#[ignore] // TODO: We don't support downgrading to 2.3 tags yet +fn test_update_genre_23_1() {} + +#[test] +#[ignore] +fn test_update_genre23_2() { + // Marker test, Lofty doesn't do additional work with the genre string +} + +#[test] +#[ignore] +fn test_update_genre23_3() { + // Marker test, Lofty doesn't do additional work with the genre string +} + +#[test] +#[ignore] // TODO: We currently just return the genre string as it is in the tag, need to think about whether or not to convert numerical strings +fn test_update_genre_24() {} + +#[test] +fn test_update_date22() { + let mut file = temp_file!("tests/taglib/data/id3v22-tda.mp3"); + let f = MpegFile::read_from(&mut file, ParseOptions::new()).unwrap(); + assert!(f.id3v2().is_some()); + assert_eq!(f.id3v2().unwrap().year(), Some(2010)); +} + +#[test] +#[ignore] // TODO: Determine if this is even worth doing. It is just combining TYE+TDA when upgrading ID3v2.2 to 2.4 +fn test_update_full_date22() { + let mut file = temp_file!("tests/taglib/data/id3v22-tda.mp3"); + let f = MpegFile::read_from(&mut file, ParseOptions::new()).unwrap(); + assert!(f.id3v2().is_some()); + assert_eq!(f.id3v2().unwrap().get_text("TDRC").unwrap(), "2010-04-03"); +} + +#[test] +#[ignore] // TODO: We don't support downgrading 2.4 tags to 2.3 +fn test_downgrade_to_23() {} + +#[test] +fn test_compressed_frame_with_broken_length() { + let mut file = temp_file!("tests/taglib/data/compressed_id3_frame.mp3"); + let f = MpegFile::read_from(&mut file, ParseOptions::new().read_properties(false)).unwrap(); + assert!(f + .id3v2() + .unwrap() + .contains(&FrameId::Valid(Cow::from("APIC")))); + + let frame = f.id3v2().unwrap().get("APIC").unwrap(); + let picture = match frame.content() { + FrameValue::Picture(AttachedPictureFrame { picture, .. }) => picture, + _ => unreachable!(), + }; + + assert_eq!(picture.mime_type(), &MimeType::Bmp); + assert_eq!(picture.pic_type(), PictureType::Other); + assert!(picture.description().is_none()); + assert_eq!(picture.data().len(), 86414); +} + +#[test] +fn test_w000() { + let mut file = temp_file!("tests/taglib/data/w000.mp3"); + let f = MpegFile::read_from(&mut file, ParseOptions::new()).unwrap(); + + assert!(f + .id3v2() + .unwrap() + .contains(&FrameId::Valid(Cow::from("W000")))); + let frame = f.id3v2().unwrap().get("W000").unwrap(); + let url_frame = match frame.content() { + FrameValue::Url(url_frame) => url_frame, + _ => unreachable!(), + }; + assert_eq!(url_frame.url(), "lukas.lalinsky@example.com____"); +} + +#[test] +#[ignore] +fn test_property_interface() { + // Marker test, Lofty does not replicate the property interface +} + +#[test] +#[ignore] +fn test_property_interface2() { + // Marker test, Lofty does not replicate the property interface +} + +#[test] +#[ignore] +fn test_properties_movement() { + // Marker test, Lofty does not replicate the property interface. + // Outside of that, this is simply a text frame parsing test, which is redundant. +} + +#[test] +#[ignore] +fn test_property_grouping() { + // Marker test, Lofty does not replicate the property interface. + // Outside of that, this is simply a text frame parsing test, which is redundant. +} + +#[test] +fn test_delete_frame() { + let mut file = temp_file!("tests/taglib/data/rare_frames.mp3"); + + { + let mut f = MpegFile::read_from(&mut file, ParseOptions::new()).unwrap(); + file.rewind().unwrap(); + + let t = f.id3v2_mut().unwrap(); + t.remove("TCON"); + f.save_to(&mut file).unwrap(); + } + file.rewind().unwrap(); + { + let f2 = MpegFile::read_from(&mut file, ParseOptions::new()).unwrap(); + let t = f2.id3v2().unwrap(); + assert!(!t.contains(&FrameId::Valid(Cow::from("TCON")))); + } +} + +#[test] +fn test_save_and_strip_id3v1_should_not_add_frame_from_id3v1_to_id3v2() { + let mut file = temp_file!("tests/taglib/data/xing.mp3"); + + { + let mut foo = MpegFile::read_from(&mut file, ParseOptions::new()).unwrap(); + file.rewind().unwrap(); + + let mut tag = ID3v2Tag::new(); + tag.set_artist(String::from("Artist")); + foo.set_id3v2(tag); + foo.save_to(&mut file).unwrap(); + } + file.rewind().unwrap(); + { + let mut bar = MpegFile::read_from(&mut file, ParseOptions::new()).unwrap(); + file.rewind().unwrap(); + + bar.id3v2_mut().unwrap().remove("TPE1"); + + bar.save_to(&mut file).unwrap(); + } + file.rewind().unwrap(); + + let f = MpegFile::read_from(&mut file, ParseOptions::new()).unwrap(); + assert!(f.id3v2().is_none()); +} + +#[test] +#[ignore] // TODO: We don't support CHAP frames yet +fn test_parse_chapter_frame() {} + +#[test] +#[ignore] // TODO: We don't support CHAP frames yet +fn test_render_chapter_frame() {} + +#[test] +#[ignore] // TODO: We don't support CTOC frames yet +fn test_parse_table_of_contents_frame() {} + +#[test] +#[ignore] // TODO: We don't support CTOC frames yet +fn test_render_table_of_contents_frame() {} + +#[test] +#[ignore] +fn test_empty_frame() { + // Marker test, Lofty will not remove empty frames, as they can be valid +} + +#[test] +#[ignore] +fn test_duplicate_tags() { + // Marker test, Lofty will combine duplicated tags +} + +#[test] +#[ignore] // TODO: We don't support CTOC frames yet +fn test_parse_toc_frame_with_many_children() {}