Tag Parser 12.1.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
Loading...
Searching...
No Matches
tagvalue.cpp
Go to the documentation of this file.
1#include "./helper.h"
2
3#include "../id3/id3genres.h"
4#include "../tagvalue.h"
5
6#include <c++utilities/chrono/format.h>
7#include <c++utilities/conversion/conversionexception.h>
8
9using namespace CppUtilities;
10
11#include <cppunit/TestFixture.h>
12#include <cppunit/extensions/HelperMacros.h>
13
14using namespace std;
15using namespace CppUtilities;
16using namespace TagParser;
17using namespace CPPUNIT_NS;
18
22class TagValueTests : public TestFixture {
23 CPPUNIT_TEST_SUITE(TagValueTests);
24 CPPUNIT_TEST(testBasics);
25 CPPUNIT_TEST(testBinary);
26 CPPUNIT_TEST(testInteger);
27 CPPUNIT_TEST(testUnsignedInteger);
28 CPPUNIT_TEST(testPositionInSet);
29 CPPUNIT_TEST(testTimeSpan);
30 CPPUNIT_TEST(testDateTime);
31 CPPUNIT_TEST(testDateTimeExpression);
32 CPPUNIT_TEST(testPopularity);
33 CPPUNIT_TEST(testString);
34 CPPUNIT_TEST(testEqualityOperator);
35 CPPUNIT_TEST(testPopularityScaling);
36 CPPUNIT_TEST_SUITE_END();
37
38public:
39 void setUp() override;
40 void tearDown() override;
41
42 void testBasics();
43 void testBinary();
44 void testInteger();
46 void testPositionInSet();
47 void testTimeSpan();
48 void testDateTime();
50 void testPopularity();
51 void testString();
54};
55
57
59{
60}
61
65
67{
68 CPPUNIT_ASSERT(TagValue::empty().isEmpty());
69 CPPUNIT_ASSERT_EQUAL(TagDataType::Undefined, TagValue().type());
70}
71
73{
74 const TagValue binary("123", 3, TagDataType::Binary);
75 CPPUNIT_ASSERT_EQUAL(TagDataType::Binary, binary.type());
76 CPPUNIT_ASSERT_EQUAL("123"s, string(binary.dataPointer(), binary.dataSize()));
77 CPPUNIT_ASSERT_THROW(binary.toString(), ConversionException);
78 CPPUNIT_ASSERT_THROW(binary.toInteger(), ConversionException);
79 CPPUNIT_ASSERT_THROW(binary.toPositionInSet(), ConversionException);
80 CPPUNIT_ASSERT_THROW(binary.toStandardGenreIndex(), ConversionException);
81}
82
84{
85 // positive number
86 auto integer = TagValue(42);
87 CPPUNIT_ASSERT(!integer.isEmpty());
88 CPPUNIT_ASSERT_EQUAL(TagDataType::Integer, integer.type());
89 CPPUNIT_ASSERT_EQUAL(static_cast<std::int32_t>(42), integer.toInteger());
90 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint64_t>(42), integer.toUnsignedInteger());
91 CPPUNIT_ASSERT_EQUAL("42"s, integer.toString());
92 integer.assignInteger(2);
93 CPPUNIT_ASSERT_EQUAL("Country"s, string(Id3Genres::stringFromIndex(integer.toStandardGenreIndex())));
94 integer.assignInteger(Id3Genres::emptyGenreIndex());
95 CPPUNIT_ASSERT_EQUAL(Id3Genres::emptyGenreIndex(), integer.toStandardGenreIndex());
96 integer.clearData();
97 CPPUNIT_ASSERT_EQUAL(Id3Genres::emptyGenreIndex(), integer.toStandardGenreIndex());
98
99 // negative number
100 integer.assignInteger(-25);
101 CPPUNIT_ASSERT_EQUAL("-25"s, integer.toString());
102 CPPUNIT_ASSERT_EQUAL(PositionInSet(-25), integer.toPositionInSet());
103 CPPUNIT_ASSERT_THROW(integer.toStandardGenreIndex(), ConversionException);
104
105 // zero
106 integer.assignInteger(0);
107 CPPUNIT_ASSERT_MESSAGE("explicitly assigned zero not considered empty", !integer.isEmpty());
108 CPPUNIT_ASSERT_EQUAL("0"s, integer.toString());
109 CPPUNIT_ASSERT_EQUAL(DateTime(), integer.toDateTime());
110 CPPUNIT_ASSERT_EQUAL(TimeSpan(), integer.toTimeSpan());
111
112 // empty value treatet as zero when using to...() methods
113 integer.clearData();
114 CPPUNIT_ASSERT_MESSAGE("cleared vale considered empty", integer.isEmpty());
115 CPPUNIT_ASSERT_EQUAL_MESSAGE("only date (but not type) cleared"s, TagDataType::Integer, integer.type());
116 CPPUNIT_ASSERT_EQUAL(static_cast<std::int32_t>(0), integer.toInteger());
117 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint64_t>(0), integer.toUnsignedInteger());
118 CPPUNIT_ASSERT_EQUAL(string(), integer.toString());
119 CPPUNIT_ASSERT_EQUAL(DateTime(), integer.toDateTime());
120 CPPUNIT_ASSERT_EQUAL(TimeSpan(), integer.toTimeSpan());
121}
122
124{
125 auto unsignedInteger = TagValue(static_cast<std::uint64_t>(42ul));
126 CPPUNIT_ASSERT(!unsignedInteger.isEmpty());
127 CPPUNIT_ASSERT_EQUAL(TagDataType::UnsignedInteger, unsignedInteger.type());
128 CPPUNIT_ASSERT_EQUAL(static_cast<std::int32_t>(42), unsignedInteger.toInteger());
129 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint64_t>(42), unsignedInteger.toUnsignedInteger());
130 CPPUNIT_ASSERT_EQUAL("42"s, unsignedInteger.toString());
131 unsignedInteger.assignUnsignedInteger(2);
132 CPPUNIT_ASSERT_EQUAL("Country"s, string(Id3Genres::stringFromIndex(unsignedInteger.toStandardGenreIndex())));
133 unsignedInteger.assignInteger(Id3Genres::emptyGenreIndex());
134 CPPUNIT_ASSERT_EQUAL(Id3Genres::emptyGenreIndex(), unsignedInteger.toStandardGenreIndex());
135 unsignedInteger.clearData();
136 CPPUNIT_ASSERT_EQUAL(Id3Genres::emptyGenreIndex(), unsignedInteger.toStandardGenreIndex());
137
138 // zero
139 unsignedInteger.assignInteger(0);
140 CPPUNIT_ASSERT_MESSAGE("explicitly assigned zero not considered empty", !unsignedInteger.isEmpty());
141 CPPUNIT_ASSERT_EQUAL("0"s, unsignedInteger.toString());
142 CPPUNIT_ASSERT_EQUAL(DateTime(), unsignedInteger.toDateTime());
143 CPPUNIT_ASSERT_EQUAL(TimeSpan(), unsignedInteger.toTimeSpan());
144}
145
147{
148 const TagValue test(PositionInSet(4, 23));
149 CPPUNIT_ASSERT_EQUAL(PositionInSet(4, 23), test.toPositionInSet());
150 CPPUNIT_ASSERT_EQUAL(4, test.toInteger());
151 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint64_t>(4), test.toUnsignedInteger());
152 CPPUNIT_ASSERT_EQUAL("4/23"s, test.toString());
153 CPPUNIT_ASSERT_THROW(test.toStandardGenreIndex(), ConversionException);
154 CPPUNIT_ASSERT_THROW(test.toDateTime(), ConversionException);
155 CPPUNIT_ASSERT_THROW(test.toTimeSpan(), ConversionException);
156}
157
159{
160 const TimeSpan fiveMinutes(TimeSpan::fromMinutes(5));
161 TagValue timeSpan;
162 timeSpan.assignTimeSpan(fiveMinutes);
163 CPPUNIT_ASSERT_EQUAL(timeSpan, TagValue(timeSpan));
164 CPPUNIT_ASSERT_EQUAL(fiveMinutes, timeSpan.toTimeSpan());
165 CPPUNIT_ASSERT_EQUAL(fiveMinutes.toString(), timeSpan.toString());
166 CPPUNIT_ASSERT_THROW(timeSpan.toInteger(), ConversionException);
167 CPPUNIT_ASSERT_THROW(timeSpan.toDateTime(), ConversionException);
168 CPPUNIT_ASSERT_THROW(timeSpan.toPositionInSet(), ConversionException);
169}
170
172{
173 const auto now = DateTime::now();
174 auto value = TagValue();
175 value.assignDateTime(now);
176 CPPUNIT_ASSERT_EQUAL(value, TagValue(value));
177 CPPUNIT_ASSERT_EQUAL(now, value.toDateTime());
178 CPPUNIT_ASSERT_EQUAL(now.toIsoString(), value.toString());
179 CPPUNIT_ASSERT_THROW(value.toInteger(), ConversionException);
180 CPPUNIT_ASSERT_THROW(value.toTimeSpan(), ConversionException);
181 CPPUNIT_ASSERT_THROW(value.toPositionInSet(), ConversionException);
182}
183
185{
186 auto expr = DateTimeExpression::fromIsoString("2007");
187 auto value = TagValue();
188 value.assignDateTimeExpression(expr);
189 CPPUNIT_ASSERT_EQUAL(value, TagValue(expr));
190 CPPUNIT_ASSERT_EQUAL(expr.value, value.toDateTime());
191 CPPUNIT_ASSERT_EQUAL(expr, value.toDateTimeExpression());
192 CPPUNIT_ASSERT_EQUAL(expr.toIsoString(), value.toString());
193 CPPUNIT_ASSERT_THROW(value.toInteger(), ConversionException);
194 CPPUNIT_ASSERT_THROW(value.toTimeSpan(), ConversionException);
195 CPPUNIT_ASSERT_THROW(value.toPositionInSet(), ConversionException);
196}
197
199{
200 const auto tagValue = TagValue(Popularity{ .user = "foo", .rating = 40.0, .playCounter = 123, .scale = TagType::VorbisComment });
201 const auto popularity = tagValue.toPopularity();
202 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to popularity (user)", "foo"s, popularity.user);
203 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to popularity (rating)", 40.0, popularity.rating);
204 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to popularity (play counter)", std::uint64_t(123), popularity.playCounter);
205 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to popularity (scale)", TagType::VorbisComment, popularity.scale);
206 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to string", "foo|40|123"s, tagValue.toString());
207 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to string (only rating)", "43"s, TagValue(Popularity{ .rating = 43 }).toString());
208 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to integer", 40, tagValue.toInteger());
209 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to unsigned integer", static_cast<std::uint64_t>(40), tagValue.toUnsignedInteger());
210 CPPUNIT_ASSERT_THROW_MESSAGE(
211 "failing conversion to other type", TagValue("foo|bar"sv, TagTextEncoding::Latin1).toPopularity(), ConversionException);
212 const auto scaledPopularity = tagValue.toScaledPopularity();
213 CPPUNIT_ASSERT_EQUAL_MESSAGE("rating scaled to generic scale", 2.0, scaledPopularity.rating);
214 CPPUNIT_ASSERT_THROW_MESSAGE(
215 "failed to scale if no scaling for specified format defined", tagValue.toScaledPopularity(TagType::Mp4Tag), ConversionException);
216}
217
219{
220 CPPUNIT_ASSERT_EQUAL("15\xe4"s, TagValue("15ä", 4, TagTextEncoding::Utf8).toString(TagTextEncoding::Latin1));
221 CPPUNIT_ASSERT_EQUAL("15\xe4"s, TagValue("15ä", TagTextEncoding::Utf8, TagTextEncoding::Latin1).toString());
222 CPPUNIT_ASSERT_EQUAL("15ä"s, TagValue("15ä", 4, TagTextEncoding::Utf8).toString(TagTextEncoding::Utf8));
223 CPPUNIT_ASSERT_EQUAL("\x31\0\x35\0"s, TagValue(15).toString(TagTextEncoding::Utf16LittleEndian));
224 CPPUNIT_ASSERT_EQUAL("\0\x31\0\x35"s, TagValue(15).toString(TagTextEncoding::Utf16BigEndian));
225 CPPUNIT_ASSERT_EQUAL(15, TagValue("\0\x31\0\x35"s, TagTextEncoding::Utf16BigEndian).toInteger());
226 CPPUNIT_ASSERT_EQUAL(static_cast<std::uint64_t>(15), TagValue("\0\x31\0\x35"s, TagTextEncoding::Utf16BigEndian).toUnsignedInteger());
227 CPPUNIT_ASSERT_EQUAL_MESSAGE(
228 "original encoding preserved", "15ä"s, TagValue("15ä", 4, TagTextEncoding::Utf8).toString(TagTextEncoding::Unspecified));
229 CPPUNIT_ASSERT_EQUAL_MESSAGE("original encoding preserved", "\0\x31\0\x35"s,
230 TagValue("\0\x31\0\x35", 4, TagTextEncoding::Utf16BigEndian).toString(TagTextEncoding::Unspecified));
231 CPPUNIT_ASSERT_EQUAL_MESSAGE(
232 "UTF-8 BOM truncated", "täst"s, TagValue("\xef\xbb\xbftäst", 8, TagTextEncoding::Utf8).toString(TagTextEncoding::Unspecified));
233 CPPUNIT_ASSERT_EQUAL_MESSAGE("UTF-16 LE BOM truncated", "\0t\0\xe4\0s\0t"s,
234 TagValue("\xff\xfe\0t\0\xe4\0s\0t", 10, TagTextEncoding::Utf16LittleEndian).toString(TagTextEncoding::Unspecified));
235 CPPUNIT_ASSERT_EQUAL_MESSAGE("UTF-16 BE BOM truncated", "t\0\xe4\0s\0t\0"s,
236 TagValue("\xfe\xfft\0\xe4\0s\0t\0", 10, TagTextEncoding::Utf16BigEndian).toString(TagTextEncoding::Unspecified));
237 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion via c'tor", "15\xe4"s,
238 TagValue("\xef\xbb\xbf\x31\x35ä", 7, TagTextEncoding::Utf8, TagTextEncoding::Latin1).toString(TagTextEncoding::Unspecified));
239 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to int", -15, TagValue(" - 156", 5, TagTextEncoding::Utf8).toInteger());
240 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to int", 15, TagValue("\0\x31\0\x35", 4, TagTextEncoding::Utf16BigEndian).toInteger());
241 CPPUNIT_ASSERT_THROW_MESSAGE("failing conversion to int", TagValue("15ä", 4, TagTextEncoding::Utf8).toInteger(), ConversionException);
242 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to pos", PositionInSet(4, 15), TagValue("4 / 15", 6, TagTextEncoding::Utf8).toPositionInSet());
243 CPPUNIT_ASSERT_EQUAL_MESSAGE(
244 "conversion to pos", PositionInSet(15), TagValue("\0\x31\0\x35", 4, TagTextEncoding::Utf16BigEndian).toPositionInSet());
245 CPPUNIT_ASSERT_THROW_MESSAGE("failing conversion pos", TagValue("a4 / 15", 7, TagTextEncoding::Utf8).toPositionInSet(), ConversionException);
246 CPPUNIT_ASSERT_EQUAL_MESSAGE(
247 "conversion to date time", DateTime::fromDate(2004, 4, 15), TagValue("2004-04-15", 10, TagTextEncoding::Utf8).toDateTime());
248 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to date time expression", DateTimeExpression::fromIsoString("2004-04"),
249 TagValue("2004-04-15", 7, TagTextEncoding::Utf8).toDateTimeExpression());
250 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to date from UTF-16", DateTime::fromDate(2015, 4, 15),
251 TagValue("\0\x32\0\x30\0\x31\0\x35\0\x2d\0\x30\0\x34\0\x2d\0\x31\0\x35", 20, TagTextEncoding::Utf16BigEndian).toDateTime());
252 CPPUNIT_ASSERT_THROW_MESSAGE("failing conversion to date", TagValue("_", 1, TagTextEncoding::Utf8).toDateTime(), ConversionException);
253 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to time span", TimeSpan::fromHours(1.5), TagValue("01:30:00", 10, TagTextEncoding::Utf8).toTimeSpan());
254 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to time span from UTF-16", TimeSpan::fromHours(1.5),
255 TagValue("\0\x31\0\x3a\0\x33\0\x30\0\x3a\0\x30\0\x30", 14, TagTextEncoding::Utf16BigEndian).toTimeSpan());
256 CPPUNIT_ASSERT_THROW_MESSAGE("failing conversion to time span", TagValue("_", 1, TagTextEncoding::Utf8).toTimeSpan(), ConversionException);
257 CPPUNIT_ASSERT_EQUAL_MESSAGE(
258 "conversion to genre from index", 15, TagValue("\0\x31\0\x35", 4, TagTextEncoding::Utf16BigEndian).toStandardGenreIndex());
259 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to genre from name", 2, TagValue("Country", 7, TagTextEncoding::Latin1).toStandardGenreIndex());
260 CPPUNIT_ASSERT_THROW_MESSAGE(
261 "failing conversion to genre", TagValue("Kountry", 7, TagTextEncoding::Latin1).toStandardGenreIndex(), ConversionException);
262 const auto popularity = TagValue("foo|42|123"sv).toPopularity();
263 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to popularity (user)", "foo"s, popularity.user);
264 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to popularity (rating)", 42.0, popularity.rating);
265 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to popularity (play counter)", std::uint64_t(123), popularity.playCounter);
266 CPPUNIT_ASSERT_THROW_MESSAGE("failing conversion to popularity", TagValue("foo|bar"sv).toPopularity(), ConversionException);
267}
268
270{
271 CPPUNIT_ASSERT_MESSAGE("equality requires identical types or identical string representation"s, TagValue(0) != TagValue::empty());
272 CPPUNIT_ASSERT_EQUAL_MESSAGE("comparison of equal types"s, TagValue(15), TagValue(15));
273 CPPUNIT_ASSERT_EQUAL_MESSAGE("types might differ"s, TagValue("15", 2, TagTextEncoding::Latin1), TagValue(15));
274 CPPUNIT_ASSERT_MESSAGE("but some types shall never be considered equal"s, TagValue(DateTime(0)) != TagValue(TimeSpan(0)));
275 CPPUNIT_ASSERT_EQUAL_MESSAGE("comparison of equal UTF-16 strings"s, TagValue("\x31\0\x32\0", 4, TagTextEncoding::Utf16LittleEndian),
276 TagValue("\x31\0\x32\0", 4, TagTextEncoding::Utf16LittleEndian));
277 CPPUNIT_ASSERT_MESSAGE("comparison of different UTF-16 strings"s,
278 TagValue("\x31\0\x33\0", 4, TagTextEncoding::Utf16LittleEndian) != TagValue("\x31\0\x32\0", 4, TagTextEncoding::Utf16LittleEndian));
279 CPPUNIT_ASSERT_EQUAL_MESSAGE(
280 "comparison of equal binary data"s, TagValue("\x31\0\x32\0", 4, TagDataType::Binary), TagValue("\x31\0\x32\0", 4, TagDataType::Binary));
281 CPPUNIT_ASSERT_MESSAGE(
282 "comparison of different binary data"s, TagValue("\x31\0\x33\0", 4, TagDataType::Binary) != TagValue("\x31\0\x32\0", 4, TagDataType::Binary));
283 CPPUNIT_ASSERT_EQUAL_MESSAGE("different encodings are converted if neccassary"s, TagValue("\0\x31\0\x35", 4, TagTextEncoding::Utf16BigEndian),
284 TagValue("15", 2, TagTextEncoding::Latin1));
285 CPPUNIT_ASSERT_EQUAL_MESSAGE(
286 "encoding is ignored when not relevant for types"s, TagValue("\0\x31\0\x35", 4, TagTextEncoding::Utf16BigEndian), TagValue(15));
287 const TagValue fooTagValue("foo", 3, TagDataType::Text), fOoTagValue("fOo", 3, TagDataType::Text);
288 CPPUNIT_ASSERT_MESSAGE("string comparison case-sensitive by default"s, fooTagValue != fOoTagValue);
289 CPPUNIT_ASSERT_MESSAGE("case-insensitive string comparison"s, fooTagValue.compareTo(fOoTagValue, TagValueComparisionFlags::CaseInsensitive));
290 const auto popularity = Popularity{ .user = "some user", .rating = 200, .playCounter = 0 };
291 const auto first = TagValue(popularity), second = TagValue(popularity);
292 CPPUNIT_ASSERT_EQUAL_MESSAGE("comparison of equal popularity (string and binary representation)"s, TagValue("some user|200.0"sv), first);
293 CPPUNIT_ASSERT_EQUAL_MESSAGE("comparison of equal popularity (only binary representation)"s, first, second);
294 CPPUNIT_ASSERT_MESSAGE("default-popularity not equal to empty tag value"s, TagValue(Popularity()) != TagValue());
295 CPPUNIT_ASSERT_MESSAGE("popularity not equal"s, first != TagValue(Popularity({ .rating = 200 })));
296
297 // meta-data
298 TagValue withDescription(15);
299 withDescription.setDescription("test");
300 CPPUNIT_ASSERT_MESSAGE("meta-data must be equal"s, withDescription != TagValue(15));
301 CPPUNIT_ASSERT_MESSAGE("different meta-data ignored"s, withDescription.compareTo(TagValue(15), TagValueComparisionFlags::IgnoreMetaData));
302 TagValue withDescription2(withDescription);
303 CPPUNIT_ASSERT_EQUAL(withDescription, withDescription2);
304 withDescription2.setMimeType("foo/bar");
305 CPPUNIT_ASSERT(withDescription != withDescription2);
306 withDescription.setMimeType(withDescription2.mimeType());
307 CPPUNIT_ASSERT_EQUAL(withDescription, withDescription2);
308 withDescription2.setDescription("Test");
309 CPPUNIT_ASSERT_MESSAGE("meta-data case must match by default"s, withDescription != withDescription2);
310 CPPUNIT_ASSERT_MESSAGE("meta-data case ignored"s, withDescription.compareTo(withDescription2, TagValueComparisionFlags::CaseInsensitive));
311}
312
314{
315 const auto genericZero = Popularity{ .rating = 0.0, .scale = TagType::Unspecified };
316 const auto genericMin = Popularity{ .rating = 1.0, .scale = TagType::Unspecified };
317 const auto genericMax = Popularity{ .rating = 5.0, .scale = TagType::Unspecified };
318 const auto genericMiddle = Popularity{ .rating = 3.0, .scale = TagType::Unspecified };
319 const auto id3zero = Popularity{ .rating = 0.0, .scale = TagType::Id3v2Tag };
320 const auto id3min = Popularity{ .rating = 1.0, .scale = TagType::Id3v2Tag };
321 const auto id3max = Popularity{ .rating = 255.0, .scale = TagType::Id3v2Tag };
322 const auto id3middle = Popularity{ .rating = 128.0, .scale = TagType::Id3v2Tag };
323 const auto vorbisZero = Popularity{ .rating = 0.0, .scale = TagType::VorbisComment };
324 const auto vorbisMin = Popularity{ .rating = 20.0, .scale = TagType::VorbisComment };
325 const auto vorbisMax = Popularity{ .rating = 100.0, .scale = TagType::OggVorbisComment };
326 const auto vorbisMiddle = Popularity{ .rating = 60.0, .scale = TagType::OggVorbisComment };
327 const auto mkvMin = Popularity{ .rating = 0.0, .scale = TagType::MatroskaTag };
328 const auto mkvMax = Popularity{ .rating = 5.0, .scale = TagType::MatroskaTag };
329 const auto mkvMiddle = Popularity{ .rating = 2.5, .scale = TagType::MatroskaTag };
330 for (const auto &rawZero : { id3zero, vorbisZero }) {
331 CPPUNIT_ASSERT_EQUAL_MESSAGE("zero: raw to generic", genericZero.rating, rawZero.scaled(TagType::Unspecified).rating);
332 CPPUNIT_ASSERT_EQUAL_MESSAGE("zero: generic to raw ", rawZero.rating, genericZero.scaled(rawZero.scale).rating);
333 }
334 for (const auto &rawMin : { id3min, vorbisMin, mkvMin }) {
335 CPPUNIT_ASSERT_EQUAL_MESSAGE("min: raw to generic", genericMin.rating, rawMin.scaled(TagType::Unspecified).rating);
336 CPPUNIT_ASSERT_EQUAL_MESSAGE("min: generic to raw ", rawMin.rating, genericMin.scaled(rawMin.scale).rating);
337 }
338 for (const auto &rawMax : { id3max, vorbisMax, mkvMax }) {
339 CPPUNIT_ASSERT_EQUAL_MESSAGE("max: raw to generic", genericMax.rating, rawMax.scaled(TagType::Unspecified).rating);
340 CPPUNIT_ASSERT_EQUAL_MESSAGE("max: generic to raw ", rawMax.rating, genericMax.scaled(rawMax.scale).rating);
341 }
342 for (const auto &rawMiddle : { id3middle, vorbisMiddle, mkvMiddle }) {
343 CPPUNIT_ASSERT_EQUAL_MESSAGE("middle: raw to generic", genericMiddle.rating, rawMiddle.scaled(TagType::Unspecified).rating);
344 CPPUNIT_ASSERT_EQUAL_MESSAGE("middle: generic to raw ", rawMiddle.rating, genericMiddle.scaled(rawMiddle.scale).rating);
345 }
346}
static constexpr int emptyGenreIndex()
Returns the preferred genre index to indicate that no genre is set at all.
Definition id3genres.h:45
static std::string_view stringFromIndex(int index)
Returns the genre name for the specified numerical denotation as C-style string.
Definition id3genres.h:27
The PositionInSet class describes the position of an element in a set which consists of a certain num...
The TagValue class wraps values of different types.
Definition tagvalue.h:147
void setMimeType(std::string_view mimeType)
Sets the MIME type.
Definition tagvalue.h:602
const std::string & mimeType() const
Returns the MIME type.
Definition tagvalue.h:590
bool compareTo(const TagValue &other, TagValueComparisionFlags options=TagValueComparisionFlags::None) const
Returns whether both instances are equal.
Definition tagvalue.cpp:354
CppUtilities::DateTime toDateTime() const
Converts the value of the current TagValue object to its equivalent DateTime representation (using th...
Definition tagvalue.cpp:763
void setDescription(std::string_view value, TagTextEncoding encoding=TagTextEncoding::Latin1)
Sets the description.
Definition tagvalue.h:577
std::uint64_t toUnsignedInteger() const
Definition tagvalue.cpp:582
std::int32_t toInteger() const
Converts the value of the current TagValue object to its equivalent integer representation.
Definition tagvalue.cpp:540
PositionInSet toPositionInSet() const
Converts the value of the current TagValue object to its equivalent PositionInSet representation.
Definition tagvalue.cpp:675
TagDataType type() const
Returns the type of the assigned value.
Definition tagvalue.h:433
void assignTimeSpan(CppUtilities::TimeSpan value)
Assigns the given TimeSpan value.
Definition tagvalue.h:398
Popularity toPopularity() const
Converts the value of the current TagValue object to its equivalent Popularity representation.
Definition tagvalue.cpp:841
std::size_t dataSize() const
Returns the size of the assigned value in bytes.
Definition tagvalue.h:522
std::string toString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::string representation.
Definition tagvalue.h:450
static const TagValue & empty()
Returns a default-constructed TagValue where TagValue::isNull() and TagValue::isEmpty() both return t...
int toStandardGenreIndex() const
Converts the value of the current TagValue object to its equivalent standard genre index.
Definition tagvalue.cpp:625
CppUtilities::TimeSpan toTimeSpan() const
Converts the value of the current TagValue object to its equivalent TimeSpan representation.
Definition tagvalue.cpp:724
char * dataPointer()
Returns a pointer to the raw data assigned to the current instance.
Definition tagvalue.h:533
The TagValueTests class tests the TagParser::TagValue class.
Definition tagvalue.cpp:22
void testBasics()
Definition tagvalue.cpp:66
void testTimeSpan()
Definition tagvalue.cpp:158
void tearDown() override
Definition tagvalue.cpp:62
void testDateTimeExpression()
Definition tagvalue.cpp:184
void testUnsignedInteger()
Definition tagvalue.cpp:123
void setUp() override
Definition tagvalue.cpp:58
void testBinary()
Definition tagvalue.cpp:72
void testInteger()
Definition tagvalue.cpp:83
void testDateTime()
Definition tagvalue.cpp:171
void testPositionInSet()
Definition tagvalue.cpp:146
void testPopularityScaling()
Definition tagvalue.cpp:313
void testEqualityOperator()
Definition tagvalue.cpp:269
void testPopularity()
Definition tagvalue.cpp:198
void testString()
Definition tagvalue.cpp:218
Contains all classes and functions of the TagInfo library.
Definition aaccodebook.h:10
The Popularity class contains a value for ID3v2's "Popularimeter" field.
Definition tagvalue.h:72
std::string user
The user who gave the rating / played the file, e.g. identified by e-mail address.
Definition tagvalue.h:74
double rating
The rating on a tag type specific scale.
Definition tagvalue.h:76
CPPUNIT_TEST_SUITE_REGISTRATION(TagValueTests)