diff --git a/tests/test_apetag.cpp b/tests/test_apetag.cpp index 577ec4b0..2225ccbd 100644 --- a/tests/test_apetag.cpp +++ b/tests/test_apetag.cpp @@ -79,6 +79,10 @@ public: CPPUNIT_ASSERT_EQUAL(2u, tag.itemListMap()["ARTIST"].values().size()); CPPUNIT_ASSERT_EQUAL(String("artist 1 artist 2"), tag.artist()); CPPUNIT_ASSERT_EQUAL(17u, tag.track()); + const APE::Item &textItem = tag.itemListMap()["TRACK"]; + CPPUNIT_ASSERT_EQUAL(APE::Item::Text, textItem.type()); + CPPUNIT_ASSERT(!textItem.isEmpty()); + CPPUNIT_ASSERT_EQUAL(9 + 5 + 2, textItem.size()); } void testPropertyInterface2() @@ -89,6 +93,8 @@ public: APE::Item item2 = APE::Item(); item2.setType(APE::Item::Binary); + ByteVector binaryData1("first"); + item2.setBinaryData(binaryData1); tag.setItem("TESTBINARY", item2); PropertyMap properties = tag.properties(); @@ -96,6 +102,16 @@ public: CPPUNIT_ASSERT(properties.contains("TRACKNUMBER")); CPPUNIT_ASSERT(!properties.contains("TRACK")); CPPUNIT_ASSERT(tag.itemListMap().contains("TESTBINARY")); + CPPUNIT_ASSERT_EQUAL(binaryData1, + tag.itemListMap()["TESTBINARY"].binaryData()); + ByteVector binaryData2("second"); + tag.setData("TESTBINARY", binaryData2); + const APE::Item &binaryItem = tag.itemListMap()["TESTBINARY"]; + CPPUNIT_ASSERT_EQUAL(APE::Item::Binary, binaryItem.type()); + CPPUNIT_ASSERT(!binaryItem.isEmpty()); + CPPUNIT_ASSERT_EQUAL(9 + 10 + static_cast(binaryData2.size()), + binaryItem.size()); + CPPUNIT_ASSERT_EQUAL(binaryData2, binaryItem.binaryData()); tag.removeUnsupportedProperties(properties.unsupportedData()); CPPUNIT_ASSERT(!tag.itemListMap().contains("TESTBINARY")); diff --git a/tests/test_fileref.cpp b/tests/test_fileref.cpp index 77f5f887..1fc5def9 100644 --- a/tests/test_fileref.cpp +++ b/tests/test_fileref.cpp @@ -39,6 +39,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -79,8 +82,12 @@ class TestFileRef : public CppUnit::TestFixture CPPUNIT_TEST(testWav); CPPUNIT_TEST(testAIFF_1); CPPUNIT_TEST(testAIFF_2); + CPPUNIT_TEST(testWavPack); + CPPUNIT_TEST(testOpus); CPPUNIT_TEST(testUnsupported); CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testAudioProperties); + CPPUNIT_TEST(testDefaultFileExtensions); CPPUNIT_TEST(testFileResolver); CPPUNIT_TEST_SUITE_END(); @@ -100,6 +107,7 @@ public: f.tag()->setTitle("test title"); f.tag()->setGenre("Test!"); f.tag()->setAlbum("albummmm"); + f.tag()->setComment("a comment"); f.tag()->setTrack(5); f.tag()->setYear(2020); f.save(); @@ -111,12 +119,14 @@ public: CPPUNIT_ASSERT_EQUAL(f.tag()->title(), String("test title")); CPPUNIT_ASSERT_EQUAL(f.tag()->genre(), String("Test!")); CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("albummmm")); + CPPUNIT_ASSERT_EQUAL(f.tag()->comment(), String("a comment")); CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)5); CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2020); f.tag()->setArtist("ttest artist"); f.tag()->setTitle("ytest title"); f.tag()->setGenre("uTest!"); f.tag()->setAlbum("ialbummmm"); + f.tag()->setComment("another comment"); f.tag()->setTrack(7); f.tag()->setYear(2080); f.save(); @@ -128,6 +138,7 @@ public: CPPUNIT_ASSERT_EQUAL(f.tag()->title(), String("ytest title")); CPPUNIT_ASSERT_EQUAL(f.tag()->genre(), String("uTest!")); CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("ialbummmm")); + CPPUNIT_ASSERT_EQUAL(f.tag()->comment(), String("another comment")); CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)7); CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2080); } @@ -141,12 +152,14 @@ public: CPPUNIT_ASSERT_EQUAL(f.tag()->title(), String("ytest title")); CPPUNIT_ASSERT_EQUAL(f.tag()->genre(), String("uTest!")); CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("ialbummmm")); + CPPUNIT_ASSERT_EQUAL(f.tag()->comment(), String("another comment")); CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)7); CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2080); f.tag()->setArtist("test artist"); f.tag()->setTitle("test title"); f.tag()->setGenre("Test!"); f.tag()->setAlbum("albummmm"); + f.tag()->setComment("a comment"); f.tag()->setTrack(5); f.tag()->setYear(2020); f.save(); @@ -162,6 +175,7 @@ public: CPPUNIT_ASSERT_EQUAL(f.tag()->title(), String("test title")); CPPUNIT_ASSERT_EQUAL(f.tag()->genre(), String("Test!")); CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("albummmm")); + CPPUNIT_ASSERT_EQUAL(f.tag()->comment(), String("a comment")); CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)5); CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2020); @@ -178,12 +192,14 @@ public: CPPUNIT_ASSERT_EQUAL(f.tag()->title(), String("test title")); CPPUNIT_ASSERT_EQUAL(f.tag()->genre(), String("Test!")); CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("albummmm")); + CPPUNIT_ASSERT_EQUAL(f.tag()->comment(), String("a comment")); CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)5); CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2020); f.tag()->setArtist("ttest artist"); f.tag()->setTitle("ytest title"); f.tag()->setGenre("uTest!"); f.tag()->setAlbum("ialbummmm"); + f.tag()->setComment("another comment"); f.tag()->setTrack(7); f.tag()->setYear(2080); f.save(); @@ -199,6 +215,7 @@ public: CPPUNIT_ASSERT_EQUAL(f.tag()->title(), String("ytest title")); CPPUNIT_ASSERT_EQUAL(f.tag()->genre(), String("uTest!")); CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("ialbummmm")); + CPPUNIT_ASSERT_EQUAL(f.tag()->comment(), String("another comment")); CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)7); CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2080); } @@ -289,6 +306,16 @@ public: fileRefSave("alaw", ".aifc"); } + void testWavPack() + { + fileRefSave("click", ".wv"); + } + + void testOpus() + { + fileRefSave("correctness_gain_silent_output", ".opus"); + } + void testUnsupported() { FileRef f1(TEST_FILE_PATH_C("no-extension")); @@ -309,6 +336,41 @@ public: f = FileRef::create(TEST_FILE_PATH_C("xing.mp3")); CPPUNIT_ASSERT(dynamic_cast(f)); delete f; + + f = FileRef::create(TEST_FILE_PATH_C("test.xm")); + CPPUNIT_ASSERT(dynamic_cast(f)); + delete f; + } + + void testAudioProperties() + { + FileRef f(TEST_FILE_PATH_C("xing.mp3")); + const AudioProperties *audioProperties = f.audioProperties(); + CPPUNIT_ASSERT_EQUAL(2, audioProperties->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(2064, audioProperties->lengthInMilliseconds()); + } + + void testDefaultFileExtensions() + { + const StringList extensions = FileRef::defaultFileExtensions(); + CPPUNIT_ASSERT(extensions.contains("mpc")); + CPPUNIT_ASSERT(extensions.contains("wma")); + CPPUNIT_ASSERT(extensions.contains("ogg")); + CPPUNIT_ASSERT(extensions.contains("spx")); + CPPUNIT_ASSERT(extensions.contains("flac")); + CPPUNIT_ASSERT(extensions.contains("mp3")); + CPPUNIT_ASSERT(extensions.contains("tta")); + CPPUNIT_ASSERT(extensions.contains("m4a")); + CPPUNIT_ASSERT(extensions.contains("3g2")); + CPPUNIT_ASSERT(extensions.contains("m4v")); + CPPUNIT_ASSERT(extensions.contains("wav")); + CPPUNIT_ASSERT(extensions.contains("oga")); + CPPUNIT_ASSERT(extensions.contains("ape")); + CPPUNIT_ASSERT(extensions.contains("aiff")); + CPPUNIT_ASSERT(extensions.contains("aifc")); + CPPUNIT_ASSERT(extensions.contains("wv")); + CPPUNIT_ASSERT(extensions.contains("opus")); + CPPUNIT_ASSERT(extensions.contains("xm")); } void testFileResolver() diff --git a/tests/test_id3v1.cpp b/tests/test_id3v1.cpp index c50c3428..d3f037aa 100644 --- a/tests/test_id3v1.cpp +++ b/tests/test_id3v1.cpp @@ -67,6 +67,8 @@ public: { CPPUNIT_ASSERT_EQUAL(String("Darkwave"), ID3v1::genre(50)); CPPUNIT_ASSERT_EQUAL(100, ID3v1::genreIndex("Humour")); + CPPUNIT_ASSERT(ID3v1::genreList().contains("Heavy Metal")); + CPPUNIT_ASSERT_EQUAL(79, ID3v1::genreMap()["Hard Rock"]); } void testRenamedGenres() diff --git a/tests/test_id3v2.cpp b/tests/test_id3v2.cpp index 243e96ca..f03c82cc 100644 --- a/tests/test_id3v2.cpp +++ b/tests/test_id3v2.cpp @@ -42,6 +42,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -76,16 +79,20 @@ class TestID3v2 : public CppUnit::TestFixture CPPUNIT_TEST(testParseAPIC); CPPUNIT_TEST(testParseAPIC_UTF16_BOM); CPPUNIT_TEST(testParseAPICv22); + CPPUNIT_TEST(testRenderAPIC); CPPUNIT_TEST(testDontRender22); CPPUNIT_TEST(testParseGEOB); + CPPUNIT_TEST(testRenderGEOB); CPPUNIT_TEST(testPOPMtoString); CPPUNIT_TEST(testParsePOPM); CPPUNIT_TEST(testParsePOPMWithoutCounter); CPPUNIT_TEST(testRenderPOPM); CPPUNIT_TEST(testPOPMFromFile); CPPUNIT_TEST(testParseRelativeVolumeFrame); + CPPUNIT_TEST(testRenderRelativeVolumeFrame); CPPUNIT_TEST(testParseUniqueFileIdentifierFrame); CPPUNIT_TEST(testParseEmptyUniqueFileIdentifierFrame); + CPPUNIT_TEST(testRenderUniqueFileIdentifierFrame); CPPUNIT_TEST(testBrokenFrame1); CPPUNIT_TEST(testItunes24FrameSize); CPPUNIT_TEST(testParseUrlLinkFrame); @@ -99,6 +106,12 @@ class TestID3v2 : public CppUnit::TestFixture CPPUNIT_TEST(testRenderSynchronizedLyricsFrame); CPPUNIT_TEST(testParseEventTimingCodesFrame); CPPUNIT_TEST(testRenderEventTimingCodesFrame); + CPPUNIT_TEST(testParseCommentsFrame); + CPPUNIT_TEST(testRenderCommentsFrame); + CPPUNIT_TEST(testParsePodcastFrame); + CPPUNIT_TEST(testRenderPodcastFrame); + CPPUNIT_TEST(testParsePrivateFrame); + CPPUNIT_TEST(testRenderPrivateFrame); CPPUNIT_TEST(testSaveUTF16Comment); CPPUNIT_TEST(testUpdateGenre23_1); CPPUNIT_TEST(testUpdateGenre23_2); @@ -266,6 +279,26 @@ public: delete frame; } + void testRenderAPIC() + { + ID3v2::AttachedPictureFrame f; + f.setTextEncoding(String::UTF8); + f.setMimeType("image/png"); + f.setType(ID3v2::AttachedPictureFrame::BackCover); + f.setDescription("Description"); + f.setPicture("PNG data"); + CPPUNIT_ASSERT_EQUAL( + ByteVector("APIC" + "\x00\x00\x00\x20" + "\x00\x00" + "\x03" + "image/png\x00" + "\x04" + "Description\x00" + "PNG data", 42), + f.render()); + } + void testDontRender22() { ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); @@ -304,6 +337,26 @@ public: CPPUNIT_ASSERT_EQUAL(String("d"), f.description()); } + void testRenderGEOB() + { + ID3v2::GeneralEncapsulatedObjectFrame f; + f.setTextEncoding(String::Latin1); + f.setMimeType("application/octet-stream"); + f.setFileName("test.bin"); + f.setDescription("Description"); + f.setObject(ByteVector(3, '\x01')); + CPPUNIT_ASSERT_EQUAL( + ByteVector("GEOB" + "\x00\x00\x00\x32" + "\x00\x00" + "\x00" + "application/octet-stream\x00" + "test.bin\x00" + "Description\x00" + "\x01\x01\x01", 60), + f.render()); + } + void testParsePOPM() { ID3v2::PopularimeterFrame f(ByteVector("POPM" @@ -392,10 +445,36 @@ public: CPPUNIT_ASSERT_EQUAL(String("ident"), f.identification()); CPPUNIT_ASSERT_EQUAL(15.0f / 512.0f, f.volumeAdjustment(ID3v2::RelativeVolumeFrame::FrontRight)); + CPPUNIT_ASSERT_EQUAL(static_cast(15), + f.volumeAdjustmentIndex(ID3v2::RelativeVolumeFrame::FrontRight)); CPPUNIT_ASSERT_EQUAL((unsigned char)8, f.peakVolume(ID3v2::RelativeVolumeFrame::FrontRight).bitsRepresentingPeak); CPPUNIT_ASSERT_EQUAL(ByteVector("\x45"), f.peakVolume(ID3v2::RelativeVolumeFrame::FrontRight).peakVolume); + const List channels = f.channels(); + CPPUNIT_ASSERT_EQUAL(1U, channels.size()); + CPPUNIT_ASSERT_EQUAL(ID3v2::RelativeVolumeFrame::FrontRight, channels[0]); + } + + void testRenderRelativeVolumeFrame() + { + ID3v2::RelativeVolumeFrame f; + f.setIdentification("ident"); + f.setVolumeAdjustment(15.0f / 512.0f, ID3v2::RelativeVolumeFrame::FrontRight); + ID3v2::RelativeVolumeFrame::PeakVolume peakVolume; + peakVolume.bitsRepresentingPeak = 8; + peakVolume.peakVolume.setData("\x45"); + f.setPeakVolume(peakVolume, ID3v2::RelativeVolumeFrame::FrontRight); + CPPUNIT_ASSERT_EQUAL( + ByteVector("RVA2" + "\x00\x00\x00\x0B" + "\x00\x00" + "ident\x00" + "\x02" + "\x00\x0F" + "\x08" + "\x45", 21), + f.render()); } void testParseUniqueFileIdentifierFrame() @@ -426,6 +505,18 @@ public: f.identifier()); } + void testRenderUniqueFileIdentifierFrame() + { + ID3v2::UniqueFileIdentifierFrame f("owner", "\x01\x02\x03"); + CPPUNIT_ASSERT_EQUAL( + ByteVector("UFID" + "\x00\x00\x00\x09" + "\x00\x00" + "owner\x00" + "\x01\x02\x03", 19), + f.render()); + } + void testParseUrlLinkFrame() { ID3v2::UrlLinkFrame f( @@ -635,6 +726,89 @@ public: f.render()); } + void testParseCommentsFrame() + { + ID3v2::CommentsFrame f( + ByteVector("COMM" + "\x00\x00\x00\x14" + "\x00\x00" + "\x03" + "deu" + "Description\x00" + "Text", 30)); + CPPUNIT_ASSERT_EQUAL(String::UTF8, f.textEncoding()); + CPPUNIT_ASSERT_EQUAL(ByteVector("deu"), f.language()); + CPPUNIT_ASSERT_EQUAL(String("Description"), f.description()); + CPPUNIT_ASSERT_EQUAL(String("Text"), f.text()); + } + + void testRenderCommentsFrame() + { + ID3v2::CommentsFrame f; + f.setTextEncoding(String::UTF16); + f.setLanguage("eng"); + f.setDescription("Description"); + f.setText("Text"); + CPPUNIT_ASSERT_EQUAL( + ByteVector("COMM" + "\x00\x00\x00\x28" + "\x00\x00" + "\x01" + "eng" + "\xff\xfe" "D\0e\0s\0c\0r\0i\0p\0t\0i\0o\0n\0" "\x00\x00" + "\xff\xfe" "T\0e\0x\0t\0", 50), + f.render()); + } + + void testParsePodcastFrame() + { + ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); + ByteVector data = ByteVector("PCST" + "\x00\x00\x00\x04" + "\x00\x00" + "\x00\x00\x00\x00", 14); + const ID3v2::Header header; + CPPUNIT_ASSERT(dynamic_cast( + factory->createFrame(data, &header))); + } + + void testRenderPodcastFrame() + { + ID3v2::PodcastFrame f; + CPPUNIT_ASSERT_EQUAL( + ByteVector("PCST" + "\x00\x00\x00\x04" + "\x00\x00" + "\x00\x00\x00\x00", 14), + f.render()); + } + + void testParsePrivateFrame() + { + ID3v2::PrivateFrame f( + ByteVector("PRIV" + "\x00\x00\x00\x0e" + "\x00\x00" + "WM/Provider\x00" + "TL", 24)); + CPPUNIT_ASSERT_EQUAL(String("WM/Provider"), f.owner()); + CPPUNIT_ASSERT_EQUAL(ByteVector("TL"), f.data()); + } + + void testRenderPrivateFrame() + { + ID3v2::PrivateFrame f; + f.setOwner("WM/Provider"); + f.setData("TL"); + CPPUNIT_ASSERT_EQUAL( + ByteVector("PRIV" + "\x00\x00\x00\x0e" + "\x00\x00" + "WM/Provider\x00" + "TL", 24), + f.render()); + } + void testItunes24FrameSize() { MPEG::File f(TEST_FILE_PATH_C("005411.id3"), false); @@ -1246,6 +1420,16 @@ public: CPPUNIT_ASSERT((unsigned int)0x01 == f.embeddedFrameList().size()); CPPUNIT_ASSERT(f.embeddedFrameList("TIT2").size() == 1); CPPUNIT_ASSERT(f.embeddedFrameList("TIT2")[0]->toString() == "TC1"); + + f.removeChildElement("E"); // not existing + CPPUNIT_ASSERT_EQUAL(2U, f.entryCount()); + f.removeChildElement("C"); + CPPUNIT_ASSERT_EQUAL(1U, f.entryCount()); + CPPUNIT_ASSERT_EQUAL(ByteVector("D"), f.childElements()[0]); + + ID3v2::Frame *frame = f.embeddedFrameList("TIT2")[0]; + f.removeEmbeddedFrame(frame); + CPPUNIT_ASSERT(f.embeddedFrameList("TIT2").isEmpty()); } void testRenderTableOfContentsFrame() diff --git a/tests/test_mpeg.cpp b/tests/test_mpeg.cpp index 240231a4..f3b5c365 100644 --- a/tests/test_mpeg.cpp +++ b/tests/test_mpeg.cpp @@ -58,6 +58,7 @@ class TestMPEG : public CppUnit::TestFixture CPPUNIT_TEST(testFuzzedFile); CPPUNIT_TEST(testFrameOffset); CPPUNIT_TEST(testStripAndProperties); + CPPUNIT_TEST(testProperties); CPPUNIT_TEST(testRepeatedSave1); CPPUNIT_TEST(testRepeatedSave2); CPPUNIT_TEST(testRepeatedSave3); @@ -295,6 +296,93 @@ public: } } + void testProperties() + { + PropertyMap tags; + tags["ALBUM"] = StringList("Album"); + tags["ALBUMARTIST"] = StringList("Album Artist"); + tags["ALBUMARTISTSORT"] = StringList("Album Artist Sort"); + tags["ALBUMSORT"] = StringList("Album Sort"); + tags["ARRANGER"] = StringList("Arranger"); + tags["ARTIST"] = StringList("Artist"); + tags["ARTISTWEBPAGE"] = StringList("Artist Web Page"); + tags["AUDIOSOURCEWEBPAGE"] = StringList("Audio Source Web Page"); + tags["BPM"] = StringList("123"); + tags["COMMENT"] = StringList("Comment"); + tags["COMMENT:CDESC"] = StringList("Comment with Description"); + tags["COMPOSER"] = StringList("Composer"); + tags["CONDUCTOR"] = StringList("Conductor"); + tags["CONTENTGROUP"] = StringList("Content Group"); + tags["COPYRIGHT"] = StringList("2021 Copyright"); + tags["COPYRIGHTURL"] = StringList("Copyright URL"); + tags["DATE"] = StringList("2021-01-03 12:29:23"); + tags["DISCNUMBER"] = StringList("3/5"); + tags["DJMIXER"] = StringList("DJ Mixer"); + tags["ENCODEDBY"] = StringList("Encoded by"); + tags["ENCODING"] = StringList("Encoding"); + tags["ENCODINGTIME"] = StringList("2021-01-03 13:48:44"); + tags["ENGINEER"] = StringList("Engineer"); + tags["FILETYPE"] = StringList("File Type"); + tags["FILEWEBPAGE"] = StringList("File Web Page"); + tags["GENRE"] = StringList("Genre"); + tags["GROUPING"] = StringList("Grouping"); + tags["INITIALKEY"] = StringList("Dbm"); + tags["ISRC"] = StringList("UKAAA0500001"); + tags["LABEL"] = StringList("Label"); + tags["LANGUAGE"] = StringList("eng"); + tags["LENGTH"] = StringList("1234"); + tags["LYRICIST"] = StringList("Lyricist"); + tags["LYRICS:LDESC"] = StringList("Lyrics"); + tags["MEDIA"] = StringList("Media"); + tags["MIXER"] = StringList("Mixer"); + tags["MOOD"] = StringList("Mood"); + tags["MOVEMENTNAME"] = StringList("Movement Name"); + tags["MOVEMENTNUMBER"] = StringList("2"); + tags["ORIGINALALBUM"] = StringList("Original Album"); + tags["ORIGINALARTIST"] = StringList("Original Artist"); + tags["ORIGINALDATE"] = StringList("2021-01-03 13:52:19"); + tags["ORIGINALFILENAME"] = StringList("Original Filename"); + tags["ORIGINALLYRICIST"] = StringList("Original Lyricist"); + tags["OWNER"] = StringList("Owner"); + tags["PAYMENTWEBPAGE"] = StringList("Payment Web Page"); + tags["PERFORMER:DRUMS"] = StringList("Drummer"); + tags["PERFORMER:GUITAR"] = StringList("Guitarist"); + tags["PLAYLISTDELAY"] = StringList("10"); + tags["PODCAST"] = StringList(); + tags["PODCASTCATEGORY"] = StringList("Podcast Category"); + tags["PODCASTDESC"] = StringList("Podcast Description"); + tags["PODCASTID"] = StringList("Podcast ID"); + tags["PODCASTURL"] = StringList("Podcast URL"); + tags["PRODUCEDNOTICE"] = StringList("2021 Produced Notice"); + tags["PRODUCER"] = StringList("Producer"); + tags["PUBLISHERWEBPAGE"] = StringList("Publisher Web Page"); + tags["RADIOSTATION"] = StringList("Radio Station"); + tags["RADIOSTATIONOWNER"] = StringList("Radio Station Owner"); + tags["REMIXER"] = StringList("Remixer"); + tags["SUBTITLE"] = StringList("Subtitle"); + tags["TITLE"] = StringList("Title"); + tags["TITLESORT"] = StringList("Title Sort"); + tags["TRACKNUMBER"] = StringList("2/4"); + tags["URL:UDESC"] = StringList("URL"); + + ScopedFileCopy copy("xing", ".mp3"); + { + MPEG::File f(copy.fileName().c_str()); + PropertyMap properties = f.properties(); + CPPUNIT_ASSERT(properties.isEmpty()); + f.setProperties(tags); + f.save(); + } + { + const MPEG::File f(copy.fileName().c_str()); + PropertyMap properties = f.properties(); + if (tags != properties) { + CPPUNIT_ASSERT_EQUAL(tags.toString(), properties.toString()); + } + CPPUNIT_ASSERT(tags == properties); + } + } + void testRepeatedSave1() { ScopedFileCopy copy("xing", ".mp3");