Tag Parser 11.2.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
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(testPositionInSet);
28 CPPUNIT_TEST(testTimeSpan);
29 CPPUNIT_TEST(testDateTime);
30 CPPUNIT_TEST(testString);
31 CPPUNIT_TEST(testEqualityOperator);
32 CPPUNIT_TEST_SUITE_END();
33
34public:
35 void setUp() override;
36 void tearDown() override;
37
38 void testBasics();
39 void testBinary();
40 void testInteger();
41 void testPositionInSet();
42 void testTimeSpan();
43 void testDateTime();
44 void testString();
46};
47
49
51{
52}
53
55{
56}
57
59{
60 CPPUNIT_ASSERT(TagValue::empty().isEmpty());
61 CPPUNIT_ASSERT_EQUAL(TagDataType::Undefined, TagValue().type());
62}
63
65{
66 const TagValue binary("123", 3, TagDataType::Binary);
67 CPPUNIT_ASSERT_EQUAL(TagDataType::Binary, binary.type());
68 CPPUNIT_ASSERT_EQUAL("123"s, string(binary.dataPointer(), binary.dataSize()));
69 CPPUNIT_ASSERT_THROW(binary.toString(), ConversionException);
70 CPPUNIT_ASSERT_THROW(binary.toInteger(), ConversionException);
71 CPPUNIT_ASSERT_THROW(binary.toPositionInSet(), ConversionException);
72 CPPUNIT_ASSERT_THROW(binary.toStandardGenreIndex(), ConversionException);
73}
74
76{
77 // positive number
78 TagValue integer(42);
79 CPPUNIT_ASSERT(!integer.isEmpty());
80 CPPUNIT_ASSERT_EQUAL(TagDataType::Integer, integer.type());
81 CPPUNIT_ASSERT_EQUAL(static_cast<std::int32_t>(42), integer.toInteger());
82 CPPUNIT_ASSERT_EQUAL("42"s, integer.toString());
83 integer.assignInteger(2);
84 CPPUNIT_ASSERT_EQUAL("Country"s, string(Id3Genres::stringFromIndex(integer.toStandardGenreIndex())));
85 integer.assignInteger(Id3Genres::emptyGenreIndex());
86 CPPUNIT_ASSERT_EQUAL(Id3Genres::emptyGenreIndex(), integer.toStandardGenreIndex());
87 integer.clearData();
88 CPPUNIT_ASSERT_EQUAL(Id3Genres::emptyGenreIndex(), integer.toStandardGenreIndex());
89
90 // negative number
91 integer.assignInteger(-25);
92 CPPUNIT_ASSERT_EQUAL("-25"s, integer.toString());
93 CPPUNIT_ASSERT_EQUAL(PositionInSet(-25), integer.toPositionInSet());
94 CPPUNIT_ASSERT_THROW(integer.toStandardGenreIndex(), ConversionException);
95
96 // zero
97 integer.assignInteger(0);
98 CPPUNIT_ASSERT_MESSAGE("explicitly assigned zero not considered empty", !integer.isEmpty());
99 CPPUNIT_ASSERT_EQUAL("0"s, integer.toString());
100 CPPUNIT_ASSERT_EQUAL(DateTime(), integer.toDateTime());
101 CPPUNIT_ASSERT_EQUAL(TimeSpan(), integer.toTimeSpan());
102
103 // empty value treatet as zero when using to...() methods
104 integer.clearData();
105 CPPUNIT_ASSERT_MESSAGE("cleared vale considered empty", integer.isEmpty());
106 CPPUNIT_ASSERT_EQUAL_MESSAGE("only date (but not type) cleared"s, TagDataType::Integer, integer.type());
107 CPPUNIT_ASSERT_EQUAL(static_cast<std::int32_t>(0), integer.toInteger());
108 CPPUNIT_ASSERT_EQUAL(string(), integer.toString());
109 CPPUNIT_ASSERT_EQUAL(DateTime(), integer.toDateTime());
110 CPPUNIT_ASSERT_EQUAL(TimeSpan(), integer.toTimeSpan());
111}
112
114{
115 const TagValue test(PositionInSet(4, 23));
116 CPPUNIT_ASSERT_EQUAL(PositionInSet(4, 23), test.toPositionInSet());
117 CPPUNIT_ASSERT_EQUAL(test.toInteger(), 4);
118 CPPUNIT_ASSERT_EQUAL("4/23"s, test.toString());
119 CPPUNIT_ASSERT_THROW(test.toStandardGenreIndex(), ConversionException);
120 CPPUNIT_ASSERT_THROW(test.toDateTime(), ConversionException);
121 CPPUNIT_ASSERT_THROW(test.toTimeSpan(), ConversionException);
122}
123
125{
126 const TimeSpan fiveMinutes(TimeSpan::fromMinutes(5));
127 TagValue timeSpan;
128 timeSpan.assignTimeSpan(fiveMinutes);
129 CPPUNIT_ASSERT_EQUAL(timeSpan, TagValue(timeSpan));
130 CPPUNIT_ASSERT_EQUAL(fiveMinutes, timeSpan.toTimeSpan());
131 CPPUNIT_ASSERT_EQUAL(fiveMinutes.toString(), timeSpan.toString());
132 CPPUNIT_ASSERT_THROW(timeSpan.toInteger(), ConversionException);
133 CPPUNIT_ASSERT_THROW(timeSpan.toDateTime(), ConversionException);
134 CPPUNIT_ASSERT_THROW(timeSpan.toPositionInSet(), ConversionException);
135}
136
138{
139 const DateTime now(DateTime::now());
140 TagValue dateTime;
141 dateTime.assignDateTime(now);
142 CPPUNIT_ASSERT_EQUAL(dateTime, TagValue(dateTime));
143 CPPUNIT_ASSERT_EQUAL(now, dateTime.toDateTime());
144 CPPUNIT_ASSERT_EQUAL(now.toString(DateTimeOutputFormat::IsoOmittingDefaultComponents), dateTime.toString());
145 CPPUNIT_ASSERT_THROW(dateTime.toInteger(), ConversionException);
146 CPPUNIT_ASSERT_THROW(dateTime.toTimeSpan(), ConversionException);
147 CPPUNIT_ASSERT_THROW(dateTime.toPositionInSet(), ConversionException);
148}
149
151{
152 CPPUNIT_ASSERT_EQUAL("15\xe4"s, TagValue("15ä", 4, TagTextEncoding::Utf8).toString(TagTextEncoding::Latin1));
153 CPPUNIT_ASSERT_EQUAL("15\xe4"s, TagValue("15ä", TagTextEncoding::Utf8, TagTextEncoding::Latin1).toString());
154 CPPUNIT_ASSERT_EQUAL("15ä"s, TagValue("15ä", 4, TagTextEncoding::Utf8).toString(TagTextEncoding::Utf8));
155 CPPUNIT_ASSERT_EQUAL("\x31\0\x35\0"s, TagValue(15).toString(TagTextEncoding::Utf16LittleEndian));
156 CPPUNIT_ASSERT_EQUAL("\0\x31\0\x35"s, TagValue(15).toString(TagTextEncoding::Utf16BigEndian));
157 CPPUNIT_ASSERT_EQUAL(15, TagValue("\0\x31\0\x35"s, TagTextEncoding::Utf16BigEndian).toInteger());
158 CPPUNIT_ASSERT_EQUAL_MESSAGE(
159 "original encoding preserved", "15ä"s, TagValue("15ä", 4, TagTextEncoding::Utf8).toString(TagTextEncoding::Unspecified));
160 CPPUNIT_ASSERT_EQUAL_MESSAGE("original encoding preserved", "\0\x31\0\x35"s,
161 TagValue("\0\x31\0\x35", 4, TagTextEncoding::Utf16BigEndian).toString(TagTextEncoding::Unspecified));
162 CPPUNIT_ASSERT_EQUAL_MESSAGE(
163 "UTF-8 BOM truncated", "täst"s, TagValue("\xef\xbb\xbftäst", 8, TagTextEncoding::Utf8).toString(TagTextEncoding::Unspecified));
164 CPPUNIT_ASSERT_EQUAL_MESSAGE("UTF-16 LE BOM truncated", "\0t\0\xe4\0s\0t"s,
165 TagValue("\xff\xfe\0t\0\xe4\0s\0t", 10, TagTextEncoding::Utf16LittleEndian).toString(TagTextEncoding::Unspecified));
166 CPPUNIT_ASSERT_EQUAL_MESSAGE("UTF-16 BE BOM truncated", "t\0\xe4\0s\0t\0"s,
167 TagValue("\xfe\xfft\0\xe4\0s\0t\0", 10, TagTextEncoding::Utf16BigEndian).toString(TagTextEncoding::Unspecified));
168 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion via c'tor", "15\xe4"s,
169 TagValue("\xef\xbb\xbf\x31\x35ä", 7, TagTextEncoding::Utf8, TagTextEncoding::Latin1).toString(TagTextEncoding::Unspecified));
170 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to int", -15, TagValue(" - 156", 5, TagTextEncoding::Utf8).toInteger());
171 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to int", 15, TagValue("\0\x31\0\x35", 4, TagTextEncoding::Utf16BigEndian).toInteger());
172 CPPUNIT_ASSERT_THROW_MESSAGE("failing conversion to int", TagValue("15ä", 4, TagTextEncoding::Utf8).toInteger(), ConversionException);
173 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to pos", PositionInSet(4, 15), TagValue("4 / 15", 6, TagTextEncoding::Utf8).toPositionInSet());
174 CPPUNIT_ASSERT_EQUAL_MESSAGE(
175 "conversion to pos", PositionInSet(15), TagValue("\0\x31\0\x35", 4, TagTextEncoding::Utf16BigEndian).toPositionInSet());
176 CPPUNIT_ASSERT_THROW_MESSAGE("failing conversion pos", TagValue("a4 / 15", 7, TagTextEncoding::Utf8).toPositionInSet(), ConversionException);
177 CPPUNIT_ASSERT_EQUAL_MESSAGE(
178 "conversion to date", DateTime::fromDate(2004, 4, 15), TagValue("2004-04-15", 10, TagTextEncoding::Utf8).toDateTime());
179 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to date from UTF-16", DateTime::fromDate(2015, 4, 15),
180 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());
181 CPPUNIT_ASSERT_THROW_MESSAGE("failing conversion to date", TagValue("_", 1, TagTextEncoding::Utf8).toDateTime(), ConversionException);
182 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to time span", TimeSpan::fromHours(1.5), TagValue("01:30:00", 10, TagTextEncoding::Utf8).toTimeSpan());
183 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to time span from UTF-16", TimeSpan::fromHours(1.5),
184 TagValue("\0\x31\0\x3a\0\x33\0\x30\0\x3a\0\x30\0\x30", 14, TagTextEncoding::Utf16BigEndian).toTimeSpan());
185 CPPUNIT_ASSERT_THROW_MESSAGE("failing conversion to time span", TagValue("_", 1, TagTextEncoding::Utf8).toTimeSpan(), ConversionException);
186 CPPUNIT_ASSERT_EQUAL_MESSAGE(
187 "conversion to genre from index", 15, TagValue("\0\x31\0\x35", 4, TagTextEncoding::Utf16BigEndian).toStandardGenreIndex());
188 CPPUNIT_ASSERT_EQUAL_MESSAGE("conversion to genre from name", 2, TagValue("Country", 7, TagTextEncoding::Latin1).toStandardGenreIndex());
189 CPPUNIT_ASSERT_THROW_MESSAGE(
190 "failing conversion to genre", TagValue("Kountry", 7, TagTextEncoding::Latin1).toStandardGenreIndex(), ConversionException);
191}
192
194{
195 CPPUNIT_ASSERT_MESSAGE("equality requires identical types or identical string representation"s, TagValue(0) != TagValue::empty());
196 CPPUNIT_ASSERT_EQUAL_MESSAGE("comparison of equal types"s, TagValue(15), TagValue(15));
197 CPPUNIT_ASSERT_EQUAL_MESSAGE("types might differ"s, TagValue("15", 2, TagTextEncoding::Latin1), TagValue(15));
198 CPPUNIT_ASSERT_MESSAGE("but some types shall never be considered equal"s, TagValue(DateTime(0)) != TagValue(TimeSpan(0)));
199 CPPUNIT_ASSERT_EQUAL_MESSAGE("comparison of equal UTF-16 strings"s, TagValue("\x31\0\x32\0", 4, TagTextEncoding::Utf16LittleEndian),
200 TagValue("\x31\0\x32\0", 4, TagTextEncoding::Utf16LittleEndian));
201 CPPUNIT_ASSERT_MESSAGE("comparison of different UTF-16 strings"s,
202 TagValue("\x31\0\x33\0", 4, TagTextEncoding::Utf16LittleEndian) != TagValue("\x31\0\x32\0", 4, TagTextEncoding::Utf16LittleEndian));
203 CPPUNIT_ASSERT_EQUAL_MESSAGE(
204 "comparison of equal binary data"s, TagValue("\x31\0\x32\0", 4, TagDataType::Binary), TagValue("\x31\0\x32\0", 4, TagDataType::Binary));
205 CPPUNIT_ASSERT_MESSAGE(
206 "comparison of different binary data"s, TagValue("\x31\0\x33\0", 4, TagDataType::Binary) != TagValue("\x31\0\x32\0", 4, TagDataType::Binary));
207 CPPUNIT_ASSERT_EQUAL_MESSAGE("different encodings are converted if neccassary"s, TagValue("\0\x31\0\x35", 4, TagTextEncoding::Utf16BigEndian),
208 TagValue("15", 2, TagTextEncoding::Latin1));
209 CPPUNIT_ASSERT_EQUAL_MESSAGE(
210 "encoding is ignored when not relevant for types"s, TagValue("\0\x31\0\x35", 4, TagTextEncoding::Utf16BigEndian), TagValue(15));
211 const TagValue fooTagValue("foo", 3, TagDataType::Text), fOoTagValue("fOo", 3, TagDataType::Text);
212 CPPUNIT_ASSERT_MESSAGE("string comparison case-sensitive by default"s, fooTagValue != fOoTagValue);
213 CPPUNIT_ASSERT_MESSAGE("case-insensitive string comparison"s, fooTagValue.compareTo(fOoTagValue, TagValueComparisionFlags::CaseInsensitive));
214
215 // meta-data
216 TagValue withDescription(15);
217 withDescription.setDescription("test");
218 CPPUNIT_ASSERT_MESSAGE("meta-data must be equal"s, withDescription != TagValue(15));
219 CPPUNIT_ASSERT_MESSAGE("different meta-data ignored"s, withDescription.compareTo(TagValue(15), TagValueComparisionFlags::IgnoreMetaData));
220 TagValue withDescription2(withDescription);
221 CPPUNIT_ASSERT_EQUAL(withDescription, withDescription2);
222 withDescription2.setMimeType("foo/bar");
223 CPPUNIT_ASSERT(withDescription != withDescription2);
224 withDescription.setMimeType(withDescription2.mimeType());
225 CPPUNIT_ASSERT_EQUAL(withDescription, withDescription2);
226 withDescription2.setDescription("Test");
227 CPPUNIT_ASSERT_MESSAGE("meta-data case must match by default"s, withDescription != withDescription2);
228 CPPUNIT_ASSERT_MESSAGE("meta-data case ignored"s, withDescription.compareTo(withDescription2, TagValueComparisionFlags::CaseInsensitive));
229}
The PositionInSet class describes the position of an element in a set which consists of a certain num...
Definition: positioninset.h:21
The TagValue class wraps values of different types.
Definition: tagvalue.h:95
void setMimeType(std::string_view mimeType)
Sets the MIME type.
Definition: tagvalue.h:637
const std::string & mimeType() const
Returns the MIME type.
Definition: tagvalue.h:625
void assignInteger(int value)
Assigns the given integer value.
Definition: tagvalue.cpp:821
bool compareTo(const TagValue &other, TagValueComparisionFlags options=TagValueComparisionFlags::None) const
Returns whether both instances are equal.
Definition: tagvalue.cpp:181
CppUtilities::DateTime toDateTime() const
Converts the value of the current TagValue object to its equivalent DateTime representation.
Definition: tagvalue.cpp:467
void setDescription(std::string_view value, TagTextEncoding encoding=TagTextEncoding::Latin1)
Sets the description.
Definition: tagvalue.h:612
std::int32_t toInteger() const
Converts the value of the current TagValue object to its equivalent integer representation.
Definition: tagvalue.cpp:322
PositionInSet toPositionInSet() const
Converts the value of the current TagValue object to its equivalent PositionInSet representation.
Definition: tagvalue.cpp:401
TagDataType type() const
Returns the type of the assigned value.
Definition: tagvalue.h:468
void assignTimeSpan(CppUtilities::TimeSpan value)
Assigns the given TimeSpan value.
Definition: tagvalue.h:441
void assignDateTime(CppUtilities::DateTime value)
Assigns the given DateTime value.
Definition: tagvalue.h:449
std::size_t dataSize() const
Returns the size of the assigned value in bytes.
Definition: tagvalue.h:557
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:485
void clearData()
Clears the assigned data.
Definition: tagvalue.h:536
bool isEmpty() const
Returns whether no or an empty value is assigned.
Definition: tagvalue.h:525
int toStandardGenreIndex() const
Converts the value of the current TagValue object to its equivalent standard genre index.
Definition: tagvalue.cpp:360
CppUtilities::TimeSpan toTimeSpan() const
Converts the value of the current TagValue object to its equivalent TimeSpan representation.
Definition: tagvalue.cpp:439
char * dataPointer()
Returns a pointer to the raw data assigned to the current instance.
Definition: tagvalue.h:568
The TagValueTests class tests the TagParser::TagValue class.
Definition: tagvalue.cpp:22
void testBasics()
Definition: tagvalue.cpp:58
void testTimeSpan()
Definition: tagvalue.cpp:124
void tearDown() override
Definition: tagvalue.cpp:54
void setUp() override
Definition: tagvalue.cpp:50
void testBinary()
Definition: tagvalue.cpp:64
void testInteger()
Definition: tagvalue.cpp:75
void testDateTime()
Definition: tagvalue.cpp:137
void testPositionInSet()
Definition: tagvalue.cpp:113
void testEqualityOperator()
Definition: tagvalue.cpp:193
void testString()
Definition: tagvalue.cpp:150
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:10
CPPUNIT_TEST_SUITE_REGISTRATION(TagValueTests)