2017-05-20 23:34:45 +02:00
|
|
|
#include "./helper.h"
|
2017-05-20 21:15:48 +02:00
|
|
|
#include "./overall.h"
|
|
|
|
|
|
|
|
#include "../abstracttrack.h"
|
|
|
|
#include "../id3/id3v1tag.h"
|
|
|
|
#include "../id3/id3v2tag.h"
|
2018-03-07 01:17:50 +01:00
|
|
|
#include "../mpegaudio/mpegaudioframe.h"
|
2017-05-20 21:15:48 +02:00
|
|
|
|
2017-05-20 23:37:33 +02:00
|
|
|
namespace Mp3TestFlags {
|
2018-03-07 01:17:50 +01:00
|
|
|
enum TestFlag {
|
2017-05-20 23:37:33 +02:00
|
|
|
ForceRewring = 0x1,
|
|
|
|
Id3v2AndId3v1 = 0x2,
|
|
|
|
PaddingConstraints = 0x4,
|
|
|
|
Id3v1Only = 0x8,
|
|
|
|
RemoveTag = Id3v2AndId3v1 & Id3v1Only,
|
2017-05-20 23:58:58 +02:00
|
|
|
UseId3v24 = 0x10,
|
2017-05-20 23:37:33 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-05-20 21:15:48 +02:00
|
|
|
/*!
|
|
|
|
* \brief Checks "mtx-test-data/mp3/id3-tag-and-xing-header.mp3"
|
|
|
|
*/
|
|
|
|
void OverallTests::checkMp3Testfile1()
|
|
|
|
{
|
|
|
|
CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::MpegAudioFrames);
|
|
|
|
const auto tracks = m_fileInfo.tracks();
|
|
|
|
CPPUNIT_ASSERT(tracks.size() == 1);
|
2018-03-07 01:17:50 +01:00
|
|
|
for (const auto &track : tracks) {
|
2017-05-20 21:15:48 +02:00
|
|
|
CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
|
|
|
|
CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Mpeg1Audio);
|
|
|
|
CPPUNIT_ASSERT(track->format().sub == SubFormats::Mpeg1Layer3);
|
|
|
|
CPPUNIT_ASSERT(track->channelCount() == 2);
|
|
|
|
CPPUNIT_ASSERT(track->channelConfig() == static_cast<byte>(MpegChannelMode::JointStereo));
|
|
|
|
CPPUNIT_ASSERT(track->samplingFrequency() == 44100);
|
|
|
|
CPPUNIT_ASSERT(track->duration().seconds() == 3);
|
|
|
|
}
|
|
|
|
const auto tags = m_fileInfo.tags();
|
2018-03-07 01:17:50 +01:00
|
|
|
switch (m_tagStatus) {
|
2017-05-20 21:15:48 +02:00
|
|
|
case TagStatus::Original:
|
|
|
|
CPPUNIT_ASSERT(m_fileInfo.id3v1Tag());
|
|
|
|
CPPUNIT_ASSERT(m_fileInfo.id3v2Tags().size() == 1);
|
|
|
|
CPPUNIT_ASSERT(tags.size() == 2);
|
2018-03-07 01:17:50 +01:00
|
|
|
for (const auto &tag : tags) {
|
2017-05-20 21:15:48 +02:00
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::TrackPosition).toPositionInSet().position() == 4);
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Year).toString() == "1984");
|
2018-03-07 01:17:50 +01:00
|
|
|
switch (tag->type()) {
|
2017-05-20 21:15:48 +02:00
|
|
|
case TagType::Id3v1Tag:
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Title).toString() == "Cohesion");
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Artist).toString() == "Minutemen");
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Album).toString() == "Double Nickels On The Dime");
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Genre).toString() == "Punk Rock");
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Comment).toString() == "ExactAudioCopy v0.95b4");
|
|
|
|
break;
|
|
|
|
case TagType::Id3v2Tag:
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Title).dataEncoding() == TagTextEncoding::Utf16LittleEndian);
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Title).toWString() == u"Cohesion");
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Title).toString(TagTextEncoding::Utf8) == "Cohesion");
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Artist).toWString() == u"Minutemen");
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Artist).toString(TagTextEncoding::Utf8) == "Minutemen");
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Album).toWString() == u"Double Nickels On The Dime");
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Album).toString(TagTextEncoding::Utf8) == "Double Nickels On The Dime");
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Genre).toWString() == u"Punk Rock");
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Genre).toString(TagTextEncoding::Utf8) == "Punk Rock");
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Comment).toWString() == u"ExactAudioCopy v0.95b4");
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Comment).toString(TagTextEncoding::Utf8) == "ExactAudioCopy v0.95b4");
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::TrackPosition).toPositionInSet().total() == 43);
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Length).toTimeSpan().isNull());
|
|
|
|
CPPUNIT_ASSERT(tag->value(KnownField::Lyricist).isEmpty());
|
|
|
|
break;
|
2018-03-07 01:17:50 +01:00
|
|
|
default:;
|
2017-05-20 21:15:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TagStatus::TestMetaDataPresent:
|
|
|
|
checkMp3TestMetaData();
|
|
|
|
break;
|
|
|
|
case TagStatus::Removed:
|
2017-06-06 23:26:20 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL(0_st, tracks.size());
|
2017-05-20 21:15:48 +02:00
|
|
|
}
|
|
|
|
|
2018-03-05 17:49:29 +01:00
|
|
|
CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
|
2017-05-20 21:15:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Checks whether test meta data for MP3 files has been applied correctly.
|
|
|
|
*/
|
|
|
|
void OverallTests::checkMp3TestMetaData()
|
|
|
|
{
|
|
|
|
using namespace Mp3TestFlags;
|
|
|
|
|
|
|
|
// check whether tags are assigned according to the current test mode
|
|
|
|
Id3v1Tag *id3v1Tag = nullptr;
|
|
|
|
Id3v2Tag *id3v2Tag = nullptr;
|
2018-03-07 01:17:50 +01:00
|
|
|
if (m_mode & Id3v2AndId3v1) {
|
2017-05-20 21:15:48 +02:00
|
|
|
CPPUNIT_ASSERT(id3v1Tag = m_fileInfo.id3v1Tag());
|
|
|
|
CPPUNIT_ASSERT(id3v2Tag = m_fileInfo.id3v2Tags().at(0).get());
|
2018-03-07 01:17:50 +01:00
|
|
|
} else if (m_mode & Id3v1Only) {
|
2017-05-20 21:15:48 +02:00
|
|
|
CPPUNIT_ASSERT(id3v1Tag = m_fileInfo.id3v1Tag());
|
|
|
|
CPPUNIT_ASSERT(m_fileInfo.id3v2Tags().empty());
|
|
|
|
} else {
|
|
|
|
CPPUNIT_ASSERT(!m_fileInfo.id3v1Tag());
|
|
|
|
CPPUNIT_ASSERT(id3v2Tag = m_fileInfo.id3v2Tags().at(0).get());
|
|
|
|
}
|
|
|
|
|
|
|
|
// check common test meta data
|
2018-03-07 01:17:50 +01:00
|
|
|
if (id3v1Tag) {
|
2017-05-20 23:34:45 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL(m_testTitle, id3v1Tag->value(KnownField::Title));
|
|
|
|
CPPUNIT_ASSERT_EQUAL(m_testComment.toString(), id3v1Tag->value(KnownField::Comment).toString()); // ignore encoding here
|
|
|
|
CPPUNIT_ASSERT_EQUAL(m_testAlbum, id3v1Tag->value(KnownField::Album));
|
|
|
|
CPPUNIT_ASSERT_EQUAL(m_preservedMetaData.front(), id3v1Tag->value(KnownField::Artist));
|
|
|
|
m_preservedMetaData.pop();
|
2017-05-20 21:15:48 +02:00
|
|
|
}
|
2018-03-07 01:17:50 +01:00
|
|
|
if (id3v2Tag) {
|
2017-05-20 23:34:45 +02:00
|
|
|
const TagValue &titleValue = id3v2Tag->value(KnownField::Title);
|
|
|
|
const TagValue &commentValue = id3v2Tag->value(KnownField::Comment);
|
2017-05-20 23:58:58 +02:00
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
if (m_mode & UseId3v24) {
|
2017-05-20 23:58:58 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL(m_testTitle, titleValue);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(m_testComment, commentValue);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(m_testAlbum, id3v2Tag->value(KnownField::Album));
|
|
|
|
CPPUNIT_ASSERT_EQUAL(m_preservedMetaData.front(), id3v2Tag->value(KnownField::Artist));
|
|
|
|
// TODO: check more fields
|
|
|
|
} else {
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("not attempted to use UTF-8 in ID3v2.3", titleValue.dataEncoding() == TagTextEncoding::Utf16LittleEndian);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(m_testTitle.toString(), titleValue.toString(TagTextEncoding::Utf8));
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("not attempted to use UTF-8 in ID3v2.3", commentValue.dataEncoding() == TagTextEncoding::Utf16LittleEndian);
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("not attempted to use UTF-8 in ID3v2.3", commentValue.descriptionEncoding() == TagTextEncoding::Utf16LittleEndian);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(m_testComment.toString(), commentValue.toString(TagTextEncoding::Utf8));
|
2018-03-07 01:17:50 +01:00
|
|
|
CPPUNIT_ASSERT_EQUAL_MESSAGE(
|
|
|
|
"description is also converted to UTF-16", "s\0o\0m\0e\0 \0d\0e\0s\0c\0r\0i\0p\0t\0i\0\xf3\0n\0"s, commentValue.description());
|
2017-05-20 23:58:58 +02:00
|
|
|
CPPUNIT_ASSERT_EQUAL(m_testAlbum.toString(TagTextEncoding::Utf8), id3v2Tag->value(KnownField::Album).toString(TagTextEncoding::Utf8));
|
|
|
|
CPPUNIT_ASSERT_EQUAL(m_preservedMetaData.front(), id3v2Tag->value(KnownField::Artist));
|
|
|
|
// TODO: check more fields
|
|
|
|
}
|
|
|
|
|
2017-05-20 23:34:45 +02:00
|
|
|
m_preservedMetaData.pop();
|
|
|
|
}
|
|
|
|
|
2017-05-20 21:15:48 +02:00
|
|
|
// test ID3v1 specific test meta data
|
2018-03-07 01:17:50 +01:00
|
|
|
if (id3v1Tag) {
|
2017-05-20 21:15:48 +02:00
|
|
|
CPPUNIT_ASSERT(id3v1Tag->value(KnownField::TrackPosition).toPositionInSet().position() == m_testPosition.toPositionInSet().position());
|
|
|
|
}
|
|
|
|
// test ID3v2 specific test meta data
|
2018-03-07 01:17:50 +01:00
|
|
|
if (id3v2Tag) {
|
2017-05-20 21:15:48 +02:00
|
|
|
CPPUNIT_ASSERT(id3v2Tag->value(KnownField::TrackPosition) == m_testPosition);
|
|
|
|
CPPUNIT_ASSERT(id3v2Tag->value(KnownField::DiskPosition) == m_testPosition);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Checks whether padding constraints are met.
|
|
|
|
*/
|
|
|
|
void OverallTests::checkMp3PaddingConstraints()
|
|
|
|
{
|
|
|
|
using namespace Mp3TestFlags;
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
if (!(m_mode & Id3v1Only)) {
|
|
|
|
if (m_mode & PaddingConstraints) {
|
|
|
|
if (m_mode & ForceRewring) {
|
2017-05-20 21:15:48 +02:00
|
|
|
CPPUNIT_ASSERT(m_fileInfo.paddingSize() == 4096);
|
|
|
|
} else {
|
|
|
|
CPPUNIT_ASSERT(m_fileInfo.paddingSize() >= 1024);
|
|
|
|
CPPUNIT_ASSERT(m_fileInfo.paddingSize() <= (4096 + 1024));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// adding padding is not possible if no ID3v2 tag is present
|
|
|
|
}
|
|
|
|
// TODO: check rewriting behaviour
|
|
|
|
}
|
|
|
|
|
|
|
|
void OverallTests::setMp3TestMetaData()
|
|
|
|
{
|
|
|
|
using namespace Mp3TestFlags;
|
|
|
|
|
|
|
|
// ensure tags are assigned according to the current test mode
|
|
|
|
Id3v1Tag *id3v1Tag = nullptr;
|
|
|
|
Id3v2Tag *id3v2Tag = nullptr;
|
2018-03-07 01:17:50 +01:00
|
|
|
if (m_mode & Id3v2AndId3v1) {
|
2017-05-20 21:15:48 +02:00
|
|
|
id3v1Tag = m_fileInfo.createId3v1Tag();
|
|
|
|
id3v2Tag = m_fileInfo.createId3v2Tag();
|
2018-03-07 01:17:50 +01:00
|
|
|
} else if (m_mode & Id3v1Only) {
|
2017-05-20 21:15:48 +02:00
|
|
|
id3v1Tag = m_fileInfo.createId3v1Tag();
|
|
|
|
m_fileInfo.removeAllId3v2Tags();
|
|
|
|
} else {
|
|
|
|
m_fileInfo.removeId3v1Tag();
|
|
|
|
id3v2Tag = m_fileInfo.createId3v2Tag();
|
|
|
|
}
|
2018-03-07 01:17:50 +01:00
|
|
|
if (!(m_mode & Id3v1Only) && m_mode & UseId3v24) {
|
2017-05-20 23:58:58 +02:00
|
|
|
id3v2Tag->setVersion(4, 0);
|
|
|
|
}
|
2017-05-20 21:15:48 +02:00
|
|
|
|
|
|
|
// assign some test meta data
|
2018-03-07 01:17:50 +01:00
|
|
|
for (Tag *tag : initializer_list<Tag *>{ id3v1Tag, id3v2Tag }) {
|
|
|
|
if (tag) {
|
2017-05-20 21:15:48 +02:00
|
|
|
tag->setValue(KnownField::Title, m_testTitle);
|
|
|
|
tag->setValue(KnownField::Comment, m_testComment);
|
|
|
|
tag->setValue(KnownField::Album, m_testAlbum);
|
|
|
|
m_preservedMetaData.push(tag->value(KnownField::Artist));
|
|
|
|
tag->setValue(KnownField::TrackPosition, m_testPosition);
|
|
|
|
tag->setValue(KnownField::DiskPosition, m_testPosition);
|
|
|
|
// TODO: set more fields
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Tests the MP3 parser via MediaFileInfo.
|
|
|
|
*/
|
|
|
|
void OverallTests::testMp3Parsing()
|
|
|
|
{
|
|
|
|
cerr << endl << "MP3 parser" << endl;
|
|
|
|
m_fileInfo.setForceFullParse(false);
|
|
|
|
m_tagStatus = TagStatus::Original;
|
|
|
|
parseFile(TestUtilities::testFilePath("mtx-test-data/mp3/id3-tag-and-xing-header.mp3"), &OverallTests::checkMp3Testfile1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef PLATFORM_UNIX
|
|
|
|
/*!
|
|
|
|
* \brief Tests the MP3 maker via MediaFileInfo.
|
|
|
|
* \remarks Relies on the parser to check results.
|
|
|
|
*/
|
|
|
|
void OverallTests::testMp3Making()
|
|
|
|
{
|
|
|
|
// full parse is required to determine padding
|
|
|
|
m_fileInfo.setForceFullParse(true);
|
|
|
|
|
|
|
|
// do the test under different conditions
|
2018-03-07 01:17:50 +01:00
|
|
|
for (m_mode = 0; m_mode != 0x20; ++m_mode) {
|
2017-05-20 21:15:48 +02:00
|
|
|
using namespace Mp3TestFlags;
|
|
|
|
|
|
|
|
// setup test conditions
|
|
|
|
m_fileInfo.setForceRewrite(m_mode & ForceRewring);
|
2018-03-07 01:17:50 +01:00
|
|
|
if (m_mode & UseId3v24) {
|
|
|
|
if (m_mode & Id3v1Only) {
|
2017-05-20 23:58:58 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2017-05-20 21:15:48 +02:00
|
|
|
m_fileInfo.setTagPosition(ElementPosition::Keep);
|
|
|
|
m_fileInfo.setIndexPosition(ElementPosition::Keep);
|
|
|
|
m_fileInfo.setPreferredPadding(m_mode & PaddingConstraints ? 4096 : 0);
|
|
|
|
m_fileInfo.setMinPadding(m_mode & PaddingConstraints ? 1024 : 0);
|
|
|
|
m_fileInfo.setMaxPadding(m_mode & PaddingConstraints ? (4096 + 1024) : static_cast<size_t>(-1));
|
|
|
|
m_fileInfo.setForceTagPosition(false);
|
|
|
|
m_fileInfo.setForceIndexPosition(false);
|
|
|
|
|
|
|
|
// print test conditions
|
|
|
|
list<string> testConditions;
|
2018-03-07 01:17:50 +01:00
|
|
|
if (m_mode & ForceRewring) {
|
2017-05-20 21:15:48 +02:00
|
|
|
testConditions.emplace_back("forcing rewrite");
|
|
|
|
}
|
2018-03-07 01:17:50 +01:00
|
|
|
if (m_mode & Id3v2AndId3v1) {
|
|
|
|
if (m_mode & RemoveTag) {
|
2017-05-20 21:15:48 +02:00
|
|
|
testConditions.emplace_back("removing tag");
|
|
|
|
} else {
|
|
|
|
testConditions.emplace_back("ID3v1 and ID3v2");
|
|
|
|
}
|
2018-03-07 01:17:50 +01:00
|
|
|
} else if (m_mode & Id3v1Only) {
|
2017-05-20 21:15:48 +02:00
|
|
|
testConditions.emplace_back("ID3v1 only");
|
|
|
|
} else {
|
|
|
|
testConditions.emplace_back("ID3v2 only");
|
|
|
|
}
|
2018-03-07 01:17:50 +01:00
|
|
|
if (m_mode & PaddingConstraints) {
|
2017-05-20 21:15:48 +02:00
|
|
|
testConditions.emplace_back("padding constraints");
|
|
|
|
}
|
2018-03-07 01:17:50 +01:00
|
|
|
if (m_mode & UseId3v24) {
|
2017-05-20 23:58:58 +02:00
|
|
|
testConditions.emplace_back("use ID3v2.4");
|
|
|
|
}
|
2017-05-20 21:15:48 +02:00
|
|
|
cerr << endl << "MP3 maker - testmode " << m_mode << ": " << joinStrings(testConditions, ", ") << endl;
|
|
|
|
|
|
|
|
// do actual tests
|
|
|
|
m_tagStatus = (m_mode & RemoveTag) ? TagStatus::Removed : TagStatus::TestMetaDataPresent;
|
|
|
|
void (OverallTests::*modifyRoutine)(void) = (m_mode & RemoveTag) ? &OverallTests::removeAllTags : &OverallTests::setMp3TestMetaData;
|
|
|
|
makeFile(TestUtilities::workingCopyPath("mtx-test-data/mp3/id3-tag-and-xing-header.mp3"), modifyRoutine, &OverallTests::checkMp3Testfile1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|