Tag Parser  8.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 
9 using namespace TestUtilities;
10 
11 #include <cppunit/TestFixture.h>
12 #include <cppunit/extensions/HelperMacros.h>
13 
14 using namespace std;
15 using namespace TagParser;
16 using namespace ConversionUtilities;
17 using namespace ChronoUtilities;
18 
19 using namespace CPPUNIT_NS;
20 
24 class TagValueTests : public TestFixture {
25  CPPUNIT_TEST_SUITE(TagValueTests);
26  CPPUNIT_TEST(testBasics);
27  CPPUNIT_TEST(testBinary);
28  CPPUNIT_TEST(testInteger);
29  CPPUNIT_TEST(testPositionInSet);
30  CPPUNIT_TEST(testTimeSpan);
31  CPPUNIT_TEST(testDateTime);
32  CPPUNIT_TEST(testString);
33  CPPUNIT_TEST(testEqualityOperator);
34  CPPUNIT_TEST_SUITE_END();
35 
36 public:
37  void setUp();
38  void tearDown();
39 
40  void testBasics();
41  void testBinary();
42  void testInteger();
43  void testPositionInSet();
44  void testTimeSpan();
45  void testDateTime();
46  void testString();
47  void testEqualityOperator();
48 };
49 
51 
53 {
54 }
55 
57 {
58 }
59 
61 {
62  CPPUNIT_ASSERT(TagValue::empty().isEmpty());
63  CPPUNIT_ASSERT_EQUAL(TagDataType::Undefined, TagValue().type());
64 }
65 
67 {
68  const TagValue binary("123", 3, TagDataType::Binary);
69  CPPUNIT_ASSERT_EQUAL(TagDataType::Binary, binary.type());
70  CPPUNIT_ASSERT_EQUAL("123"s, string(binary.dataPointer(), binary.dataSize()));
71  CPPUNIT_ASSERT_THROW(binary.toString(), ConversionException);
72  CPPUNIT_ASSERT_THROW(binary.toInteger(), ConversionException);
73  CPPUNIT_ASSERT_THROW(binary.toPositionInSet(), ConversionException);
74  CPPUNIT_ASSERT_THROW(binary.toStandardGenreIndex(), ConversionException);
75 }
76 
78 {
79  // positive number
80  TagValue integer(42);
81  CPPUNIT_ASSERT(!integer.isEmpty());
82  CPPUNIT_ASSERT_EQUAL(TagDataType::Integer, integer.type());
83  CPPUNIT_ASSERT_EQUAL(static_cast<int32>(42), integer.toInteger());
84  CPPUNIT_ASSERT_EQUAL("42"s, integer.toString());
85  integer.assignInteger(2);
86  CPPUNIT_ASSERT_EQUAL("Country"s, string(Id3Genres::stringFromIndex(integer.toStandardGenreIndex())));
87  integer.assignInteger(Id3Genres::emptyGenreIndex());
88  CPPUNIT_ASSERT_EQUAL(Id3Genres::emptyGenreIndex(), integer.toStandardGenreIndex());
89  integer.clearData();
90  CPPUNIT_ASSERT_EQUAL(Id3Genres::emptyGenreIndex(), integer.toStandardGenreIndex());
91 
92  // negative number
93  integer.assignInteger(-25);
94  CPPUNIT_ASSERT_EQUAL("-25"s, integer.toString());
95  CPPUNIT_ASSERT_EQUAL(PositionInSet(-25), integer.toPositionInSet());
96  CPPUNIT_ASSERT_THROW(integer.toStandardGenreIndex(), ConversionException);
97 
98  // zero
99  integer.assignInteger(0);
100  CPPUNIT_ASSERT_MESSAGE("explicitely assigned zero not considered empty", !integer.isEmpty());
101  CPPUNIT_ASSERT_EQUAL("0"s, integer.toString());
102  CPPUNIT_ASSERT_EQUAL(DateTime(), integer.toDateTime());
103  CPPUNIT_ASSERT_EQUAL(TimeSpan(), integer.toTimeSpan());
104 
105  // empty value treatet as zero when using to...() methods
106  integer.clearData();
107  CPPUNIT_ASSERT_MESSAGE("cleared vale considered empty", integer.isEmpty());
108  CPPUNIT_ASSERT_EQUAL_MESSAGE("only date (but not type) cleared"s, TagDataType::Integer, integer.type());
109  CPPUNIT_ASSERT_EQUAL(static_cast<int32>(0), integer.toInteger());
110  CPPUNIT_ASSERT_EQUAL(string(), integer.toString());
111  CPPUNIT_ASSERT_EQUAL(DateTime(), integer.toDateTime());
112  CPPUNIT_ASSERT_EQUAL(TimeSpan(), integer.toTimeSpan());
113 }
114 
116 {
117  const TagValue test(PositionInSet(4, 23));
118  CPPUNIT_ASSERT_EQUAL(PositionInSet(4, 23), test.toPositionInSet());
119  CPPUNIT_ASSERT_THROW(test.toInteger(), ConversionException);
120  CPPUNIT_ASSERT_EQUAL("4/23"s, test.toString());
121  CPPUNIT_ASSERT_THROW(test.toStandardGenreIndex(), ConversionException);
122  CPPUNIT_ASSERT_THROW(test.toDateTime(), ConversionException);
123  CPPUNIT_ASSERT_THROW(test.toTimeSpan(), ConversionException);
124 }
125 
127 {
128  const TimeSpan fiveMinutes(TimeSpan::fromMinutes(5));
129  TagValue timeSpan;
130  timeSpan.assignTimeSpan(fiveMinutes);
131  CPPUNIT_ASSERT_EQUAL(fiveMinutes, timeSpan.toTimeSpan());
132  CPPUNIT_ASSERT_EQUAL(fiveMinutes.toString(), timeSpan.toString());
133  CPPUNIT_ASSERT_THROW(timeSpan.toInteger(), ConversionException);
134  CPPUNIT_ASSERT_THROW(timeSpan.toDateTime(), ConversionException);
135  CPPUNIT_ASSERT_THROW(timeSpan.toPositionInSet(), ConversionException);
136 }
137 
139 {
140  const DateTime now(DateTime::now());
141  TagValue dateTime;
142  dateTime.assignDateTime(now);
143  CPPUNIT_ASSERT_EQUAL(now, dateTime.toDateTime());
144  CPPUNIT_ASSERT_EQUAL(now.toString(), 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("types might differ"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("encoding must be equal if relevant for types"s,
199  TagValue("\0\x31\0\x35", 4, TagTextEncoding::Utf16BigEndian) != TagValue("15", 2, TagTextEncoding::Latin1));
200  CPPUNIT_ASSERT_EQUAL_MESSAGE(
201  "encoding is ignored when not relevant for types"s, TagValue("\0\x31\0\x35", 4, TagTextEncoding::Utf16BigEndian), TagValue(15));
202 
203  // meta-data
204  TagValue withDescription(15);
205  withDescription.setDescription("test");
206  CPPUNIT_ASSERT_MESSAGE("meta-data must be equal"s, withDescription != TagValue(15));
207  TagValue withDescription2(withDescription);
208  CPPUNIT_ASSERT_EQUAL(withDescription, withDescription2);
209  withDescription2.setMimeType("foo/bar");
210  CPPUNIT_ASSERT(withDescription != withDescription2);
211  withDescription.setMimeType(withDescription2.mimeType());
212  CPPUNIT_ASSERT_EQUAL(withDescription, withDescription2);
213 }
void setMimeType(const std::string &mimeType)
Sets the MIME type.
Definition: tagvalue.h:482
The TagValueTests class tests the TagParser::TagValue class.
Definition: tagvalue.cpp:24
The PositionInSet class describes the position of an element in a set which consists of a certain num...
Definition: positioninset.h:21
int toStandardGenreIndex() const
Converts the value of the current TagValue object to its equivalent standard genre index.
Definition: tagvalue.cpp:212
void setUp()
Definition: tagvalue.cpp:52
bool isEmpty() const
Returns an indication whether an value is assigned.
Definition: tagvalue.h:389
const std::string & mimeType() const
Returns the MIME type.
Definition: tagvalue.h:472
std::size_t dataSize() const
Returns the size of the assigned value in bytes.
Definition: tagvalue.h:421
void assignDateTime(ChronoUtilities::DateTime value)
Assigns the given DateTime value.
Definition: tagvalue.h:334
ChronoUtilities::TimeSpan toTimeSpan() const
Converts the value of the current TagValue object to its equivalent TimeSpan representation.
Definition: tagvalue.cpp:291
void testBinary()
Definition: tagvalue.cpp:66
PositionInSet toPositionInSet() const
Converts the value of the current TagValue object to its equivalent PositionInSet representation.
Definition: tagvalue.cpp:253
char * dataPointer()
Returns a pointer to the raw data assigned to the current instance.
Definition: tagvalue.h:432
void testDateTime()
Definition: tagvalue.cpp:138
TagDataType type() const
Returns the type of the assigned value.
Definition: tagvalue.h:353
ChronoUtilities::DateTime toDateTime() const
Converts the value of the current TagValue object to its equivalent DateTime representation.
Definition: tagvalue.cpp:319
int32 toInteger() const
Converts the value of the current TagValue object to its equivalent integer representation.
Definition: tagvalue.cpp:177
void testTimeSpan()
Definition: tagvalue.cpp:126
void assignInteger(int value)
Assigns the given integer value.
Definition: tagvalue.cpp:639
void tearDown()
Definition: tagvalue.cpp:56
void clearData()
Clears the assigned data.
Definition: tagvalue.h:400
void testInteger()
Definition: tagvalue.cpp:77
CPPUNIT_TEST_SUITE_REGISTRATION(TagValueTests)
void testBasics()
Definition: tagvalue.cpp:60
void setDescription(const std::string &value, TagTextEncoding encoding=TagTextEncoding::Latin1)
Sets the description.
Definition: tagvalue.h:461
void testPositionInSet()
Definition: tagvalue.cpp:115
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:365
void assignTimeSpan(ChronoUtilities::TimeSpan value)
Assigns the given TimeSpan value.
Definition: tagvalue.h:326
The TagValue class wraps values of different types.
Definition: tagvalue.h:65
void testString()
Definition: tagvalue.cpp:150
void testEqualityOperator()
Definition: tagvalue.cpp:193
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:9