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);
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);
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());
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());
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);
135 unsignedInteger.clearData();
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());
200 const auto tagValue =
TagValue(
Popularity{ .user =
"foo", .rating = 40.0, .playCounter = 123, .scale = TagType::VorbisComment });
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());
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);
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);
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);
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));
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 };
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);
295 CPPUNIT_ASSERT_MESSAGE(
"popularity not equal"s, first !=
TagValue(
Popularity({ .rating = 200 })));
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);
305 CPPUNIT_ASSERT(withDescription != withDescription2);
306 withDescription.setMimeType(withDescription2.
mimeType());
307 CPPUNIT_ASSERT_EQUAL(withDescription, withDescription2);
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));
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);
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);
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);
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);