4 #include "../abstracttrack.h" 5 #include "../id3/id3v1tag.h" 6 #include "../id3/id3v2tag.h" 7 #include "../mpegaudio/mpegaudioframe.h" 25 void OverallTests::checkMp3Testfile1()
28 const auto tracks = m_fileInfo.
tracks();
29 CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
30 for (
const auto &track : tracks) {
34 CPPUNIT_ASSERT_EQUAL(static_cast<uint16>(2), track->channelCount());
35 CPPUNIT_ASSERT_EQUAL(static_cast<byte>(MpegChannelMode::JointStereo), track->channelConfig());
36 CPPUNIT_ASSERT_EQUAL(44100u, track->samplingFrequency());
37 CPPUNIT_ASSERT_EQUAL(3, track->duration().seconds());
39 const auto tags = m_fileInfo.
tags();
40 switch (m_tagStatus) {
42 CPPUNIT_ASSERT(m_fileInfo.
id3v1Tag());
43 CPPUNIT_ASSERT_EQUAL(1_st, m_fileInfo.
id3v2Tags().size());
44 CPPUNIT_ASSERT_EQUAL(2_st, tags.size());
45 for (
const auto &tag : tags) {
48 switch (tag->type()) {
49 case TagType::Id3v1Tag:
52 CPPUNIT_ASSERT_EQUAL(
"Double Nickels On The Dime"s, tag->value(
KnownField::Album).toString());
54 CPPUNIT_ASSERT_EQUAL(
"ExactAudioCopy v0.95b4"s, tag->value(
KnownField::Comment).toString());
56 case TagType::Id3v2Tag:
57 CPPUNIT_ASSERT_EQUAL(TagTextEncoding::Utf16LittleEndian, tag->value(
KnownField::Title).dataEncoding());
62 CPPUNIT_ASSERT_EQUAL(u
"Double Nickels On The Dime"s, tag->value(
KnownField::Album).toWString());
66 CPPUNIT_ASSERT_EQUAL(u
"ExactAudioCopy v0.95b4"s, tag->value(
KnownField::Comment).toWString());
69 CPPUNIT_ASSERT(tag->value(KnownField::Length).toTimeSpan().isNull());
77 checkMp3TestMetaData();
80 CPPUNIT_ASSERT_EQUAL(0_st, tracks.size());
83 CPPUNIT_ASSERT(m_diag.
level() <= DiagLevel::Information);
89 void OverallTests::checkMp3Testfile2()
92 const auto tracks = m_fileInfo.
tracks();
93 CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
94 for (
const auto &track : tracks) {
98 CPPUNIT_ASSERT_EQUAL(static_cast<uint16>(2), track->channelCount());
99 CPPUNIT_ASSERT_EQUAL(static_cast<byte>(MpegChannelMode::Stereo), track->channelConfig());
100 CPPUNIT_ASSERT_EQUAL(44100u, track->samplingFrequency());
101 CPPUNIT_ASSERT_EQUAL(20, track->duration().seconds());
103 const auto tags = m_fileInfo.
tags();
105 switch (m_tagStatus) {
108 CPPUNIT_ASSERT(!m_fileInfo.
id3v1Tag());
109 CPPUNIT_ASSERT_EQUAL(1_st, m_fileInfo.
id3v2Tags().size());
110 CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
111 for (
const auto &tag : tags) {
112 if (tag->type() != TagType::Id3v2Tag) {
113 CPPUNIT_FAIL(argsToString(
"no ", tag->typeName(),
" tag expected"));
115 const auto *
const id3v2Tag =
static_cast<const Id3v2Tag *
>(tag);
118 CPPUNIT_ASSERT_EQUAL(expectId3v24 ? 4 : 3, static_cast<int>(id3v2Tag->majorVersion()));
119 CPPUNIT_ASSERT_EQUAL(
126 CPPUNIT_ASSERT_EQUAL(
"Lavf57.83.100"s, tag->value(KnownField::EncoderSettings).toString(
TagTextEncoding::Utf8));
130 CPPUNIT_ASSERT(tag->value(KnownField::Length).toTimeSpan().isNull());
134 const auto &fields = id3v2Tag->fields();
136 CPPUNIT_ASSERT_MESSAGE(
"genre field present"s, genreFields.first != genreFields.second);
137 const auto &genreField = genreFields.first->second;
138 const auto &additionalValues = genreField.additionalValues();
141 CPPUNIT_ASSERT_EQUAL(1_st, additionalValues.size());
145 CPPUNIT_ASSERT_EQUAL(3_st, additionalValues.size());
150 CPPUNIT_ASSERT_MESSAGE(
"exactly one genre field present"s, ++genreFields.first == genreFields.second);
163 CPPUNIT_ASSERT_EQUAL(2_st, genres.size());
167 CPPUNIT_ASSERT_EQUAL(4_st, genres.size());
176 CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
180 CPPUNIT_ASSERT(m_diag.
level() <= DiagLevel::Information);
184 CPPUNIT_ASSERT(m_diag.
level() <= DiagLevel::Warning);
185 int warningCount = 0;
186 for (
const auto &msg : m_diag) {
187 if (msg.level() != DiagLevel::Warning) {
191 TESTUTILS_ASSERT_LIKE(
"context",
"(parsing|making) (TPE1|TCON)( frame)?", msg.context());
192 TESTUTILS_ASSERT_LIKE(
"message",
193 "Multiple strings (found|assigned) .*" 194 "Additional (values \"Second Artist Example\" and \"3rd Artist Example\" are|" 195 "value \"Example\" is) " 196 "supposed to be ignored.",
199 CPPUNIT_ASSERT_EQUAL_MESSAGE(
"exactly 4 warnings present", 4, warningCount);
205 void OverallTests::checkMp3TestMetaData()
213 CPPUNIT_ASSERT(id3v1Tag = m_fileInfo.id3v1Tag());
214 CPPUNIT_ASSERT(id3v2Tag = m_fileInfo.id3v2Tags().at(0).get());
216 CPPUNIT_ASSERT(id3v1Tag = m_fileInfo.id3v1Tag());
217 CPPUNIT_ASSERT(m_fileInfo.id3v2Tags().empty());
219 CPPUNIT_ASSERT(!m_fileInfo.id3v1Tag());
220 CPPUNIT_ASSERT(id3v2Tag = m_fileInfo.id3v2Tags().at(0).get());
229 m_preservedMetaData.pop();
236 CPPUNIT_ASSERT_EQUAL(m_testTitle, titleValue);
237 CPPUNIT_ASSERT_EQUAL(m_testComment, commentValue);
242 CPPUNIT_ASSERT_EQUAL_MESSAGE(
"not attempted to use UTF-8 in ID3v2.3", TagTextEncoding::Utf16LittleEndian, titleValue.
dataEncoding());
244 CPPUNIT_ASSERT_EQUAL_MESSAGE(
"not attempted to use UTF-8 in ID3v2.3", TagTextEncoding::Utf16LittleEndian, commentValue.
dataEncoding());
245 CPPUNIT_ASSERT_EQUAL_MESSAGE(
246 "not attempted to use UTF-8 in ID3v2.3", TagTextEncoding::Utf16LittleEndian, commentValue.
descriptionEncoding());
248 CPPUNIT_ASSERT_EQUAL_MESSAGE(
249 "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());
255 m_preservedMetaData.pop();
272 void OverallTests::checkMp3PaddingConstraints()
279 CPPUNIT_ASSERT_EQUAL(static_cast<uint64>(4096), m_fileInfo.paddingSize());
281 CPPUNIT_ASSERT(m_fileInfo.paddingSize() >= 1024);
282 CPPUNIT_ASSERT(m_fileInfo.paddingSize() <= (4096 + 1024));
294 void OverallTests::setMp3TestMetaData1()
302 id3v1Tag = m_fileInfo.createId3v1Tag();
303 id3v2Tag = m_fileInfo.createId3v2Tag();
305 id3v1Tag = m_fileInfo.createId3v1Tag();
306 m_fileInfo.removeAllId3v2Tags();
308 m_fileInfo.removeId3v1Tag();
309 id3v2Tag = m_fileInfo.createId3v2Tag();
316 for (
Tag *
const tag : initializer_list<Tag *>{ id3v1Tag, id3v2Tag }) {
333 void OverallTests::setMp3TestMetaData2()
337 CPPUNIT_ASSERT_EQUAL(1_st, m_fileInfo.id3v2Tags().size());
338 auto &id3v2Tag(m_fileInfo.id3v2Tags().front());
341 CPPUNIT_ASSERT_EQUAL(2_st, artists.size());
351 cerr << endl <<
"MP3 parser" << endl;
354 parseFile(TestUtilities::testFilePath(
"mtx-test-data/mp3/id3-tag-and-xing-header.mp3"), &OverallTests::checkMp3Testfile1);
355 parseFile(TestUtilities::testFilePath(
"misc/multiple_id3v2_4_values.mp3"), &OverallTests::checkMp3Testfile2);
363 void OverallTests::testMp3Making()
369 for (m_mode = 0; m_mode != 0x20; ++m_mode) {
379 m_fileInfo.setTagPosition(ElementPosition::Keep);
380 m_fileInfo.setIndexPosition(ElementPosition::Keep);
383 m_fileInfo.setMaxPadding(m_mode &
PaddingConstraints ? (4096 + 1024) : numeric_limits<size_t>::max());
384 m_fileInfo.setForceTagPosition(
false);
385 m_fileInfo.setForceIndexPosition(
false);
388 list<string> testConditions;
390 testConditions.emplace_back(
"forcing rewrite");
394 testConditions.emplace_back(
"removing tag");
396 testConditions.emplace_back(
"ID3v1 and ID3v2");
399 testConditions.emplace_back(
"ID3v1 only");
401 testConditions.emplace_back(
"ID3v2 only");
404 testConditions.emplace_back(
"padding constraints");
407 testConditions.emplace_back(
"use ID3v2.4");
409 cerr << endl <<
"MP3 maker - testmode " << m_mode <<
": " << joinStrings(testConditions,
", ") << endl;
413 makeFile(TestUtilities::workingCopyPath(
"mtx-test-data/mp3/id3-tag-and-xing-header.mp3"),
414 (m_mode &
RemoveTag) ? &OverallTests::removeAllTags : &OverallTests::setMp3TestMetaData1, &OverallTests::checkMp3Testfile1);
415 makeFile(TestUtilities::workingCopyPath(
"misc/multiple_id3v2_4_values.mp3"),
416 (m_mode &
RemoveTag) ? &OverallTests::removeAllTags : &OverallTests::setMp3TestMetaData2, &OverallTests::checkMp3Testfile2);
TagTextEncoding dataEncoding() const
Returns the data encoding.
bool setValues(const IdentifierType &id, const std::vector< TagValue > &values)
Assigns the given values to the field with the specified id.
The Tag class is used to store, read and write tag information.
const TagValue & value(const IdentifierType &id) const
Returns the value of the field with the specified id.
TagTextEncoding descriptionEncoding() const
Returns the description encoding.
const std::string & description() const
Returns the description.
constexpr int32 position() const
Returns the element position of the current instance.
std::vector< const TagValue * > values(const IdentifierType &id) const
Returns the values of the field with the specified id.
DiagLevel level() const
Returns the worst diag level present in the container.
PositionInSet toPositionInSet() const
Converts the value of the current TagValue object to its equivalent PositionInSet representation...
void testMp3Parsing()
Tests the MP3 parser via MediaFileInfo.
Implementation of TagParser::Tag for ID3v2 tags.
Implementation of TagParser::Tag for ID3v1 tags.
std::string toString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::string representation.
The TagValue class wraps values of different types.
void setVersion(byte majorVersion, byte revisionVersion)
Sets the version to the specified majorVersion and the specified revisionVersion. ...
const TagValue & value(KnownField value) const override
Returns the value of the specified field.