18#include <c++utilities/conversion/stringbuilder.h>
19#include <c++utilities/tests/testutils.h>
22#include <cppunit/TestFixture.h>
23#include <cppunit/extensions/HelperMacros.h>
30using namespace CppUtilities::Literals;
32using namespace CPPUNIT_NS;
51 CPPUNIT_TEST_SUITE_END();
54 void setUp()
override;
84 static_assert(
Size().
isNull(),
"Size::isNull()");
85 static_assert(!
Size(3, 4).
isNull(),
"Size::isNull()");
88 Size size(1920, 1080);
89 CPPUNIT_ASSERT_EQUAL(
"width: 1920, height: 1080"s, size.
toString());
90 CPPUNIT_ASSERT_EQUAL(
"1080p"s,
string(size.
abbreviation()));
93 CPPUNIT_ASSERT_EQUAL(
"720p"s,
string(size.
abbreviation()));
99 CPPUNIT_ASSERT(target.
isEmpty());
100 CPPUNIT_ASSERT_EQUAL_MESSAGE(
"default level is 50",
static_cast<std::uint64_t
>(50), target.
level());
101 CPPUNIT_ASSERT_EQUAL(
"level 50"s, target.
toString(TagTargetLevel::Unspecified));
102 target =
TagTarget(30, { 1, 2, 3 }, { 4 }, { 5, 6 }, { 7, 8, 9 });
103 CPPUNIT_ASSERT(!target.
isEmpty());
104 const auto mapping = [](std::uint64_t level) {
return level == 30 ? TagTargetLevel::Track : TagTargetLevel::Unspecified; };
105 CPPUNIT_ASSERT_EQUAL(
106 "level 30 'track, song, chapter', track 1, track 2, track 3, chapter 4, edition 5, edition 6, attachment 7, attachment 8, attachment 9"s,
109 CPPUNIT_ASSERT_EQUAL(
"level 40, track 1, track 2, track 3, chapter 4, edition 5, edition 6, attachment 7, attachment 8, attachment 9"s,
112 CPPUNIT_ASSERT_EQUAL(
"level 40 'test', track 1, track 2, track 3, chapter 4, edition 5, edition 6, attachment 7, attachment 8, attachment 9"s,
114 CPPUNIT_ASSERT(target ==
TagTarget(40, { 1, 2, 3 }, { 4 }, { 5, 6 }, { 7, 8, 9 }));
116 CPPUNIT_ASSERT(target.
isEmpty());
121 const unsigned char xzHead[12] = { 0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00, 0x00, 0x04, 0xe6, 0xd6, 0xb4, 0x46 };
124 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Unknown,
parseSignature(
reinterpret_cast<const char *
>(xzHead), 3));
125 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Unknown,
parseSignature(
reinterpret_cast<const char *
>(xzHead), 2));
126 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Unknown,
parseSignature(
reinterpret_cast<const char *
>(xzHead), 0));
128 const auto containerFormat =
parseSignature(
reinterpret_cast<const char *
>(xzHead),
sizeof(xzHead));
129 CPPUNIT_ASSERT_EQUAL(ContainerFormat::Xz, containerFormat);
138 static_assert(!
Margin(0, 2).
isNull(),
"non-empty margin");
140 CPPUNIT_ASSERT_EQUAL(
"top: 1; left: 2; bottom: 3; right: 4"s,
Margin(1, 2, 3, 4).toString());
150 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint16_t
>(16), ratio.
numerator);
151 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint16_t
>(11), ratio.
denominator);
153 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint16_t
>(0), ratio2.
numerator);
154 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint16_t
>(0), ratio2.
denominator);
161 CPPUNIT_ASSERT_EQUAL(
"Advanced Audio Coding"s,
string(aac.
name()));
162 CPPUNIT_ASSERT_EQUAL(
"AAC"s,
string(aac.
abbreviation()));
167 CPPUNIT_ASSERT(aac == GeneralMediaFormat::Aac);
168 CPPUNIT_ASSERT(aac != GeneralMediaFormat::Mpeg1Audio);
169 CPPUNIT_ASSERT_EQUAL(
"Advanced Audio Coding Low Complexity Profile"s,
string(aac.
name()));
170 CPPUNIT_ASSERT_EQUAL(
"MPEG-4 AAC-LC"s,
string(aac.
abbreviation()));
172 CPPUNIT_ASSERT_EQUAL(
"Spectral Band Replication / HE-AAC"s,
string(aac.
extensionName()));
178 CPPUNIT_ASSERT(empty.
isNull());
179 CPPUNIT_ASSERT_EQUAL(0, empty.
position());
180 CPPUNIT_ASSERT_EQUAL(0, empty.
total());
181 CPPUNIT_ASSERT_EQUAL(
""s, empty.
toString());
184 CPPUNIT_ASSERT(!oneOfThree.
isNull());
185 CPPUNIT_ASSERT_EQUAL(1, oneOfThree.
position());
186 CPPUNIT_ASSERT_EQUAL(3, oneOfThree.
total());
187 CPPUNIT_ASSERT_EQUAL(
"1/3"s, oneOfThree.
toString());
190 CPPUNIT_ASSERT(!posOnly.
isNull());
191 CPPUNIT_ASSERT_EQUAL(5, posOnly.
position());
192 CPPUNIT_ASSERT_EQUAL(0, posOnly.
total());
193 CPPUNIT_ASSERT_EQUAL(
"5"s, posOnly.
toString());
196 CPPUNIT_ASSERT(!totalOnly.
isNull());
197 CPPUNIT_ASSERT_EQUAL(0, totalOnly.
position());
198 CPPUNIT_ASSERT_EQUAL(5, totalOnly.
total());
199 CPPUNIT_ASSERT_EQUAL(
"/5"s, totalOnly.
toString());
204 unsigned int steps = 0;
206 unsigned int stepPercentage;
207 unsigned int overallPercentage = 0;
212 step = progress.
step();
220 CPPUNIT_ASSERT_EQUAL(0u, steps);
221 progressFeedback.updateOverallPercentage(25);
222 CPPUNIT_ASSERT_EQUAL(0u, steps);
223 CPPUNIT_ASSERT_EQUAL(25u, overallPercentage);
224 progressFeedback.updateStep(
"foo", 45);
225 CPPUNIT_ASSERT_EQUAL(1u, steps);
226 CPPUNIT_ASSERT_EQUAL(
"foo"s, step);
227 CPPUNIT_ASSERT_EQUAL(45u, stepPercentage);
228 CPPUNIT_ASSERT_EQUAL(25u, overallPercentage);
229 progressFeedback.updateStepPercentage(60);
230 CPPUNIT_ASSERT_EQUAL(1u, steps);
231 CPPUNIT_ASSERT_EQUAL(
"foo"s, step);
232 CPPUNIT_ASSERT_EQUAL(60u, stepPercentage);
233 CPPUNIT_ASSERT_EQUAL(25u, overallPercentage);
234 progressFeedback.updateStepPercentageFromFraction(0.75);
235 CPPUNIT_ASSERT_EQUAL(1u, steps);
236 CPPUNIT_ASSERT_EQUAL(
"foo"s, step);
237 CPPUNIT_ASSERT_EQUAL(75u, stepPercentage);
238 CPPUNIT_ASSERT_EQUAL(25u, overallPercentage);
243 unsigned int steps = 0;
245 unsigned int stepPercentage;
246 unsigned int overallPercentage = 0;
251 step = progress.
step();
259 CPPUNIT_ASSERT(!progressFeedback.isAborted());
260 CPPUNIT_ASSERT_NO_THROW_MESSAGE(
"stop does nothing if not aborted", progressFeedback.stopIfAborted());
261 CPPUNIT_ASSERT_EQUAL(0u, steps);
262 progressFeedback.updateOverallPercentage(25);
263 CPPUNIT_ASSERT_EQUAL(0u, steps);
264 CPPUNIT_ASSERT_EQUAL(25u, overallPercentage);
265 progressFeedback.updateStep(
"foo", 45);
266 CPPUNIT_ASSERT_EQUAL(1u, steps);
267 CPPUNIT_ASSERT_EQUAL(
"foo"s, step);
268 CPPUNIT_ASSERT_EQUAL(45u, stepPercentage);
269 CPPUNIT_ASSERT_EQUAL(25u, overallPercentage);
270 CPPUNIT_ASSERT_NO_THROW_MESSAGE(
"next step continues if not aborted", progressFeedback.nextStepOrStop(
"bar", 33));
271 CPPUNIT_ASSERT_EQUAL(2u, steps);
272 CPPUNIT_ASSERT_EQUAL(
"bar"s, step);
273 CPPUNIT_ASSERT_EQUAL(33u, stepPercentage);
274 CPPUNIT_ASSERT_EQUAL(25u, overallPercentage);
275 progressFeedback.tryToAbort();
276 CPPUNIT_ASSERT(progressFeedback.isAborted());
278 CPPUNIT_ASSERT_EQUAL(2u, steps);
279 CPPUNIT_ASSERT_EQUAL(
"bar"s, step);
280 CPPUNIT_ASSERT_EQUAL(33u, stepPercentage);
281 CPPUNIT_ASSERT_EQUAL(25u, overallPercentage);
287 CPPUNIT_ASSERT_EQUAL(DiagLevel::None, diag.
level());
288 diag.emplace_back(DiagLevel::Warning,
"warning msg",
"context");
289 CPPUNIT_ASSERT_EQUAL(DiagLevel::Warning, diag.
level());
290 CPPUNIT_ASSERT(!diag.
has(DiagLevel::Critical));
291 diag.emplace_back(DiagLevel::Critical,
"critical msg",
"context");
292 CPPUNIT_ASSERT_EQUAL(DiagLevel::Critical, diag.
level());
293 CPPUNIT_ASSERT(diag.
has(DiagLevel::Critical));
298 using namespace BackupHelper;
307 string backupPath1, backupPath2;
308 NativeFileStream backupStream1, backupStream2;
309 createBackupFile(
string(), file.
path(), backupPath1, file.
stream(), backupStream1);
310 CPPUNIT_ASSERT_EQUAL(workingDir +
"/unsupported.bin.bak", backupPath1);
313 file.
stream().open(file.
path(), ios_base::out);
314 file.
stream() <<
"test1" << endl;
317 createBackupFile(
string(), file.
path(), backupPath2, file.
stream(), backupStream2);
318 CPPUNIT_ASSERT_EQUAL(workingDir +
"/unsupported.bin.1.bak", backupPath2);
321 backupStream2.close();
322 remove(backupPath2.data());
323 file.
stream().open(file.
path(), ios_base::out);
324 file.
stream() <<
"test2" << endl;
328 createBackupFile(
"bak", file.
path(), backupPath2, file.
stream(), backupStream2);
329 CPPUNIT_FAIL(
"renaming failed because backup dir does not exist");
330 }
catch (
const std::ios_base::failure &failure) {
331 TESTUTILS_ASSERT_LIKE(
"renaming error",
"Unable to create backup file .* of .* before rewriting it: .*"s,
string(failure.what()));
333 backupStream2.clear();
334 workingCopyPath(
"bak/unsupported.bin", WorkingCopyMode::NoCopy);
335 createBackupFile(
"bak", file.
path(), backupPath2, file.
stream(), backupStream2);
336 CPPUNIT_ASSERT_EQUAL(workingDir +
"/bak/unsupported.bin", backupPath2);
339 backupStream2.close();
340 CPPUNIT_ASSERT_EQUAL_MESSAGE(
"remove " + backupPath2, 0, remove(backupPath2.data()));
341 std::filesystem::remove_all(workingDir +
"/bak");
344 backupStream1.seekg(0, ios_base::end);
345 CPPUNIT_ASSERT_EQUAL(41_st,
static_cast<size_t>(backupStream1.tellg()));
348 restoreOriginalFileFromBackupFile(file.
path(), backupPath1, file.
stream(), backupStream1);
352 file.
stream().seekg(0x1D);
353 CPPUNIT_ASSERT_EQUAL(0x34_st,
static_cast<size_t>(file.
stream().get()));
357 createBackupFile(
string(), file.
path(), backupPath1, file.
stream(), backupStream1);
362 CPPUNIT_ASSERT_THROW(
364 CPPUNIT_ASSERT(diag.
level() < DiagLevel::Critical);
365 CPPUNIT_ASSERT(!diag.empty());
366 CPPUNIT_ASSERT_EQUAL(
"Rewriting the file to apply changed tag information has been aborted."s, diag.front().message());
367 CPPUNIT_ASSERT_EQUAL(
"The original file has been restored."s, diag.back().message());
371 createBackupFile(
string(), file.
path(), backupPath1, file.
stream(), backupStream1);
376 CPPUNIT_ASSERT_THROW(handleFailureAfterFileModified(file, backupPath1, file.
stream(), backupStream1, diag,
"test"),
Failure);
377 CPPUNIT_ASSERT(diag.
level() >= DiagLevel::Critical);
378 CPPUNIT_ASSERT_EQUAL(
"Rewriting the file to apply changed tag information failed."s, diag.front().message());
379 CPPUNIT_ASSERT_EQUAL(
"The original file has been restored."s, diag.back().message());
383 createBackupFile(
string(), file.
path(), backupPath1, file.
stream(), backupStream1);
385 throw std::ios_base::failure(
"simulated IO failure");
386 }
catch (
const std::ios_base::failure &) {
388 CPPUNIT_ASSERT_THROW_MESSAGE(
"IO failure re-thrown",
389 handleFailureAfterFileModified(file, backupPath1, file.
stream(), backupStream1, diag,
"test"), std::ios_base::failure);
390 CPPUNIT_ASSERT(diag.
level() >= DiagLevel::Critical);
391 CPPUNIT_ASSERT_EQUAL(
"An IO error occurred when rewriting the file to apply changed tag information."s, diag.front().message());
392 CPPUNIT_ASSERT_EQUAL(
"The original file has been restored."s, diag.back().message());
395 CPPUNIT_ASSERT_EQUAL(0, remove(file.
path().data()));
404 tag.setVersion(4, 0);
406 if (
const auto fieldId = tag.fieldId(knownField)) {
407 CPPUNIT_ASSERT_EQUAL_MESSAGE(
"reverse mapping for known field exists", knownField, tag.knownField(fieldId));
410 tag.setVersion(2, 0);
412 if (
const auto fieldId = tag.fieldId(knownField)) {
413 CPPUNIT_ASSERT_EQUAL_MESSAGE(
"reverse mapping for known field exists", knownField, tag.knownField(fieldId));
The AbortableProgressFeedback class provides feedback about an ongoing operation via callbacks.
const std::string & path() const
Returns the path of the current file.
static std::string containingDirectory(std::string_view path)
Returns the path of the directory containing the given file.
CppUtilities::NativeFileStream & stream()
Returns the std::fstream for the current instance.
void open(bool readOnly=false)
Opens a std::fstream for the current file.
void close()
A possibly opened std::fstream will be closed.
std::uint8_t stepPercentage() const
Returns the percentage of the current step (initially 0, supposed to be a value from 0 to 100).
const std::string & step() const
Returns the name of the current step (initially empty).
std::uint8_t overallPercentage() const
Returns the overall percentage (initially 0, supposed to be a value from 0 to 100).
The Diagnostics class is a container for DiagMessage.
bool has(DiagLevel level) const
Returns whether there's at least one DiagMessage which is at least as worse as level.
DiagLevel level() const
Returns the worst diag level present in the container.
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
The Margin class defines the four margins of a rectangle.
constexpr bool isNull() const
Returns true if all margins are is 0; otherwise returns false;.
The exception that is thrown when an operation has been stopped and thus not successfully completed b...
The PositionInSet class describes the position of an element in a set which consists of a certain num...
constexpr std::int32_t position() const
Returns the element position of the current instance.
constexpr std::int32_t total() const
Returns the total element count of the current instance.
StringType toString() const
Returns the string representation of the current PositionInSet.
constexpr bool isNull() const
Returns an indication whether both the element position and total element count is 0.
The ProgressFeedback class provides feedback about an ongoing operation via callbacks.
The Size class defines the size of a two-dimensional object using integer point precision.
void setWidth(std::uint32_t value)
Sets the width.
bool constexpr isNull() const
Returns an indication whether both the width and height is 0.
std::string toString() const
Returns the string representation of the current size.
constexpr std::uint32_t resolution() const
Returns the resolution of the current instance (product of with and height).
void setHeight(std::uint32_t value)
Sets the height.
std::string_view abbreviation() const
Returns an abbreviation for the current instance, eg.
The TagTarget class specifies the target of a tag.
std::uint64_t level() const
Returns the level.
std::string toString(const std::function< TagTargetLevel(std::uint64_t)> &tagTargetMapping) const
Returns the string representation of the current instance.
bool isEmpty() const
Returns an indication whether the target is empty.
void clear()
Clears the TagTarget.
void setLevel(std::uint64_t level)
Sets the level.
void setLevelName(const std::string &levelName)
Sets the level name.
The UtilitiesTests class tests various utility classes and functions of the tagparser library.
void testProgressFeedback()
void testFieldConversions()
Tests whether field mappings are consistent.
void testStatusProvider()
void testAbortableProgressFeedback()
Contains all classes and functions of the TagInfo library.
TAG_PARSER_EXPORT std::string_view containerFormatSubversion(ContainerFormat containerFormat)
Returns the subversion of the container format as C-style string.
TAG_PARSER_EXPORT std::string_view containerFormatAbbreviation(ContainerFormat containerFormat, MediaType mediaType=MediaType::Unknown, unsigned int version=0)
Returns the abbreviation of the container format as C-style string considering the specified media ty...
constexpr KnownField nextKnownField(KnownField field)
Returns the next known field skipping any deprecated fields.
TAG_PARSER_EXPORT std::string_view containerFormatName(ContainerFormat containerFormat)
Returns the name of the specified container format as C-style string.
TAG_PARSER_EXPORT ContainerFormat parseSignature(const char *buffer, std::size_t bufferSize)
constexpr KnownField firstKnownField
The first valid entry in the TagParser::KnownField enum.
The AspectRatio struct defines an aspect ratio.
std::uint16_t denominator
constexpr bool isExtended() const
Returns whether numerator and denominator must be read from extended SAR header.
constexpr bool isValid() const
Returns an indication whether the aspect ratio is present and valid.
CPPUNIT_TEST_SUITE_REGISTRATION(UtilitiesTests)