Tag Parser 12.4.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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.0));
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 TagValue class wraps values of different types.
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
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.
CPPUNIT_TEST_SUITE_REGISTRATION(TagValueTests)