7#ifndef CPP_UTILITIES_NO_ICONV
11std::ostream &
operator<<(std::ostream &out,
const std::wstring &s)
14#ifdef CONVERSION_UTILITIES_IS_BYTE_ORDER_LITTLE_ENDIAN
19 (
reinterpret_cast<const char *
>(s.data()), s.size() * (
sizeof(std::wstring::value_type) /
sizeof(
char)));
20 out.write(utf8.first.get(),
static_cast<std::streamsize
>(utf8.second));
39#ifdef CPP_UTILITIES_USE_LIBARCHIVE
43#include <cppunit/TestFixture.h>
44#include <cppunit/extensions/HelperMacros.h>
52#ifdef PLATFORM_WINDOWS
63using namespace CPPUNIT_NS;
82#ifdef CPP_UTILITIES_USE_NATIVE_FILE_BUFFER
83 CPPUNIT_TEST(testNativeFileStream);
85#ifdef CPP_UTILITIES_USE_LIBARCHIVE
86 CPPUNIT_TEST(testExtractingArchive);
88 CPPUNIT_TEST_SUITE_END();
91 void setUp()
override;
106#ifdef CPP_UTILITIES_USE_NATIVE_FILE_BUFFER
107 void testNativeFileStream();
109#ifdef CPP_UTILITIES_USE_LIBARCHIVE
110 void testExtractingArchive();
131 testFile.exceptions(ios_base::failbit | ios_base::badbit);
132 testFile.open(
testFilePath(
"some_data"), ios_base::in | ios_base::binary);
134 CPPUNIT_ASSERT_EQUAL(
static_cast<istream::pos_type
>(398), reader.
readStreamsize());
135 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint16_t
>(0x0102u), reader.
readUInt16LE());
136 CPPUNIT_ASSERT_EQUAL(
static_cast<istream::pos_type
>(396), reader.
readRemainingBytes());
137 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint16_t
>(0x0102u), reader.
readUInt16BE());
140 CPPUNIT_ASSERT_EQUAL(0x01020304u, reader.
readUInt32LE());
141 CPPUNIT_ASSERT_EQUAL(0x01020304u, reader.
readUInt32BE());
142 CPPUNIT_ASSERT_EQUAL(0x0102030405u, reader.
readUInt40LE());
143 CPPUNIT_ASSERT_EQUAL(0x0102030405u, reader.
readUInt40BE());
144 CPPUNIT_ASSERT_EQUAL(0x01020304050607u, reader.
readUInt56LE());
145 CPPUNIT_ASSERT_EQUAL(0x01020304050607u, reader.
readUInt56BE());
146 CPPUNIT_ASSERT_EQUAL(0x0102030405060708u, reader.
readUInt64LE());
147 CPPUNIT_ASSERT_EQUAL(0x0102030405060708u, reader.
readUInt64BE());
149 CPPUNIT_ASSERT_EQUAL(reader.
readInt16LE(),
static_cast<std::int16_t
>(0x0102));
150 CPPUNIT_ASSERT_EQUAL(reader.
readInt16BE(),
static_cast<std::int16_t
>(0x0102));
151 CPPUNIT_ASSERT_EQUAL(0x010203, reader.
readInt24LE());
152 CPPUNIT_ASSERT_EQUAL(0x010203, reader.
readInt24BE());
153 CPPUNIT_ASSERT_EQUAL(0x01020304, reader.
readInt32LE());
154 CPPUNIT_ASSERT_EQUAL(0x01020304, reader.
readInt32BE());
155 CPPUNIT_ASSERT_EQUAL(0x0102030405, reader.
readInt40LE());
156 CPPUNIT_ASSERT_EQUAL(0x0102030405, reader.
readInt40BE());
157 CPPUNIT_ASSERT_EQUAL(0x01020304050607, reader.
readInt56LE());
158 CPPUNIT_ASSERT_EQUAL(0x01020304050607, reader.
readInt56BE());
159 CPPUNIT_ASSERT_EQUAL(0x0102030405060708, reader.
readInt64LE());
160 CPPUNIT_ASSERT_EQUAL(0x0102030405060708, reader.
readInt64BE());
165 CPPUNIT_ASSERT_EQUAL(
false, reader.
readBool());
166 CPPUNIT_ASSERT_EQUAL(
true, reader.
readBool());
167 CPPUNIT_ASSERT_EQUAL(
"abc"s, reader.
readString(3));
169 CPPUNIT_ASSERT_EQUAL(
"01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901"
170 "23456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123"
171 "45678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345"
172 "678901234567890123456789"s,
175 testFile.seekg(-4, ios_base::cur);
178 CPPUNIT_ASSERT_MESSAGE(
"pos in stream not advanced on conversion error", reader.
readByte() == 0);
197 testFile.exceptions(ios_base::failbit | ios_base::badbit);
198 testFile.open(
testFilePath(
"some_data"), ios_base::in | ios_base::binary);
201 stringstream outputStream(ios_base::in | ios_base::out | ios_base::binary);
202 outputStream.exceptions(ios_base::failbit | ios_base::badbit);
204#if defined(__GLIBCXX__) && !defined(_LIBCPP_VERSION)
205#define USE_RDBUF_DIRECTLY
206 outputStream.rdbuf()->pubsetbuf(testData,
sizeof(testData));
224#ifndef USE_RDBUF_DIRECTLY
225 outputStream.seekg(0);
226 outputStream.read(testData, 58);
230 for (
char c : testData) {
231 const auto pos =
static_cast<std::size_t
>(testFile.tellg());
236 testFile.read(&expected, 1);
240 outputStream.seekp(0);
263 writer.
writeLengthPrefixedString(
"012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
264 "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901"
265 "234567890123456789012345678901234567890123456789012345678901234567890123456789");
268#ifndef USE_RDBUF_DIRECTLY
269 outputStream.seekg(0);
270 outputStream.read(testData, 58);
274 for (
char c : testData) {
275 const auto pos =
static_cast<std::size_t
>(testFile.tellg());
280 testFile.read(&expected, 1);
299 const std::uint8_t testData[] = { 0x81, 0x90, 0x3C, 0x44, 0x28, 0x00, 0x44, 0x10, 0x20, 0xFF, 0xFA };
300 BitReader reader(
reinterpret_cast<const char *
>(testData),
sizeof(testData));
301 CPPUNIT_ASSERT(reader.
readBit() == 1);
303 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint8_t
>(3), reader.
showBits<std::uint8_t>(2));
304 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint8_t
>(3), reader.
readBits<std::uint8_t>(2));
305 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint32_t
>(0x103C4428 << 1), reader.
readBits<std::uint32_t>(32));
307 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint8_t
>(0x44), reader.
readBits<std::uint8_t>(8));
310 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint8_t
>(0), reader.
readBit());
311 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint8_t
>(0), reader.
readBit());
314 CPPUNIT_ASSERT_EQUAL(
static_cast<std::uint8_t
>(0xA), reader.
readBits<std::uint8_t>(4));
315 CPPUNIT_ASSERT_THROW(reader.
readBit(), std::ios_base::failure);
316 CPPUNIT_ASSERT_THROW(reader.
skipBits(1), std::ios_base::failure);
317 reader.
reset(
reinterpret_cast<const char *
>(testData),
sizeof(testData));
318 CPPUNIT_ASSERT_EQUAL(
static_cast<std::size_t
>(8 *
sizeof(testData)), reader.
bitsAvailable());
327 auto expectedResult = std::string();
328 auto hasResult =
false;
330 CPPUNIT_ASSERT_EQUAL(expectedResult, result);
331 CPPUNIT_ASSERT_MESSAGE(
"callback only invoked once", !hasResult);
336 char buffer[30] = { 0 };
338 CPPUNIT_ASSERT(!hasResult);
339 std::strcpy(buffer,
"Starting Updated");
340 CPPUNIT_ASSERT(bs.process(std::string_view(buffer, 16)) ==
nullptr);
341 CPPUNIT_ASSERT(!hasResult);
342 std::strcpy(buffer,
" version: some ");
344 CPPUNIT_ASSERT(!hasResult);
345 expectedResult =
"some version number";
346 std::strcpy(buffer,
"version number\tmore chars");
347 CPPUNIT_ASSERT_EQUAL(
static_cast<std::ptrdiff_t
>(14), bs.process(buffer, 25) - buffer);
348 CPPUNIT_ASSERT(hasResult);
350 std::strcpy(buffer,
"... Starting build ...");
352 CPPUNIT_ASSERT(!hasResult);
360 CPPUNIT_ASSERT_EQUAL(
"libc++utilities.so"s,
fileName(
"C:\\libs\\libc++utilities.so"));
361 CPPUNIT_ASSERT_EQUAL(
"libc++utilities.so"s,
fileName(
"C:\\libs/libc++utilities.so"));
362 CPPUNIT_ASSERT_EQUAL(
"libc++utilities.so"s,
fileName(
"/usr/lib/libc++utilities.so"));
363 CPPUNIT_ASSERT_EQUAL(
"libc++utilities.so"s,
fileName(
"libc++utilities.so"));
364 CPPUNIT_ASSERT_EQUAL(
"/usr/lib/"s,
directory(
"/usr/lib/libc++utilities.so"));
365 CPPUNIT_ASSERT_EQUAL(
string(),
directory(
"libc++utilities.so"));
366 CPPUNIT_ASSERT_EQUAL(
"C:\\libs\\"s,
directory(
"C:\\libs\\libc++utilities.so"));
367 CPPUNIT_ASSERT_EQUAL(
"C:\\libs/"s,
directory(
"C:\\libs/libc++utilities.so"));
368 string invalidPath(
"lib/c++uti*lities.so?");
370 CPPUNIT_ASSERT(invalidPath ==
"libc++utilities.so");
372 const auto input = std::string_view(
"some/path/täst");
373 const auto expected = input;
375#ifdef PLATFORM_WINDOWS
376#ifndef CPP_UTILITIES_NO_ICONV
377 const auto outputAsUtf8 =
convertUtf16LEToUtf8(
reinterpret_cast<const char *
>(output.data()), output.size() * 2);
378 const auto outputView = std::string_view(outputAsUtf8.first.get(), outputAsUtf8.second);
379 CPPUNIT_ASSERT_EQUAL_MESSAGE(
"makeNativePath()", expected, outputView);
385 CPPUNIT_ASSERT_EQUAL_MESSAGE(
"makeNativePath()", expected, output);
396 inputFile.exceptions(ios_base::failbit | ios_base::badbit);
400 ini.
parse(inputFile);
401 const auto globalScope = ini.
data().at(0);
402 const auto scope1 = ini.
data().at(1);
403 const auto scope2 = ini.
data().at(2);
404 CPPUNIT_ASSERT(globalScope.first.empty());
405 CPPUNIT_ASSERT(globalScope.second.find(
"key0") != globalScope.second.cend());
406 CPPUNIT_ASSERT(globalScope.second.find(
"key0")->second ==
"value 0");
407 CPPUNIT_ASSERT(globalScope.second.find(
"key1") == globalScope.second.cend());
408 CPPUNIT_ASSERT(scope1.first ==
"scope 1");
409 CPPUNIT_ASSERT(scope1.second.find(
"key1") != scope1.second.cend());
410 CPPUNIT_ASSERT(scope1.second.find(
"key1")->second ==
"value 1");
411 CPPUNIT_ASSERT(scope1.second.find(
"key2") != scope1.second.cend());
412 CPPUNIT_ASSERT(scope1.second.find(
"key2")->second ==
"value=2");
413 CPPUNIT_ASSERT(scope2.first ==
"scope 2");
414 CPPUNIT_ASSERT(scope2.second.find(
"key5") == scope2.second.cend());
418 outputFile.exceptions(ios_base::failbit | ios_base::badbit);
420 ini.
make(outputFile);
426 ini2.
parse(outputFile);
427 CPPUNIT_ASSERT(ini.
data() == ini2.
data());
437 inputFile.exceptions(ios_base::failbit | ios_base::badbit);
438 inputFile.open(
testFilePath(
"pacman.conf"), ios_base::in);
442 ini.
parse(inputFile);
445 CPPUNIT_ASSERT_EQUAL_MESSAGE(
"5 scopes (taking implicit empty section at the end into account)", 5_st, ini.
sections.size());
448#if !defined(PLATFORM_WINDOWS) || defined(PLATFORM_MINGW) || defined(PLATFORM_CYGWIN)
449#define STD_REGEX_WORKS
451 "comment block before section",
"# Based on.*\n.*# GENERAL OPTIONS\n#\n"s, std::regex::extended, options->precedingCommentBlock);
453 CPPUNIT_ASSERT_EQUAL(7_st, options->fields.size());
454 CPPUNIT_ASSERT_EQUAL(
"HoldPkg"s, options->fields[0].key);
455 CPPUNIT_ASSERT_EQUAL(
"pacman glibc"s, options->fields[0].value);
457#ifdef STD_REGEX_WORKS
459 "# The following paths are.*\n.*#HookDir = /etc/pacman\\.d/hooks/\n"s, std::regex::extended, options->fields[0].precedingCommentBlock);
461 CPPUNIT_ASSERT_EQUAL(
""s, options->fields[0].followingInlineComment);
462 CPPUNIT_ASSERT_EQUAL(
"Foo"s, options->fields[1].key);
463 CPPUNIT_ASSERT_EQUAL(
"bar"s, options->fields[1].value);
465#ifdef STD_REGEX_WORKS
466 TESTUTILS_ASSERT_LIKE_FLAGS(
"comment block between fields",
"#XferCommand.*\n.*#CleanMethod = KeepInstalled\n"s, std::regex::extended,
467 options->fields[1].precedingCommentBlock);
469 CPPUNIT_ASSERT_EQUAL(
"# inline comment"s, options->fields[1].followingInlineComment);
470 CPPUNIT_ASSERT_EQUAL(
"CheckSpace"s, options->fields[3].key);
471 CPPUNIT_ASSERT_EQUAL(
""s, options->fields[3].value);
473#ifdef STD_REGEX_WORKS
474 TESTUTILS_ASSERT_LIKE_FLAGS(
"empty lines in comments preserved",
"\n# Pacman.*\n.*\n\n#NoUpgrade =\n.*#TotalDownload\n"s, std::regex::extended,
475 options->fields[3].precedingCommentBlock);
477 CPPUNIT_ASSERT_EQUAL(
""s, options->fields[3].followingInlineComment);
478 auto extraScope = ini.
findSection(options,
"extra");
479 CPPUNIT_ASSERT(extraScope != ini.
sectionEnd());
480 CPPUNIT_ASSERT_EQUAL_MESSAGE(
"comment block which is only an empty line",
"\n"s, extraScope->precedingCommentBlock);
481 CPPUNIT_ASSERT_EQUAL_MESSAGE(
"inline comment after scope",
"# an inline comment after a scope name"s, extraScope->followingInlineComment);
482 CPPUNIT_ASSERT_EQUAL(1_st, extraScope->fields.size());
484#ifdef STD_REGEX_WORKS
485 TESTUTILS_ASSERT_LIKE_FLAGS(
"comment block after last field present in implicitly added last scope",
"\n# If you.*\n.*custompkgs\n"s,
486 std::regex::extended, ini.
sections.back().precedingCommentBlock);
490 const auto *
const constIniFile = &ini;
491 auto includeField = constIniFile->
findField(
"extra",
"Include");
492 CPPUNIT_ASSERT(includeField.has_value());
493 CPPUNIT_ASSERT_EQUAL(
"Include"s, includeField.value()->key);
494 CPPUNIT_ASSERT_EQUAL(
"/etc/pacman.d/mirrorlist"s, includeField.value()->value);
495 CPPUNIT_ASSERT_MESSAGE(
"field not present", !constIniFile->findField(
"extra",
"Includ").has_value());
496 CPPUNIT_ASSERT_MESSAGE(
"scope not present", !constIniFile->findField(
"extr",
"Includ").has_value());
500 std::stringstream newFile;
502 std::string originalContents;
504 inputFile.seekg(std::ios_base::beg);
508 originalContents.assign((istreambuf_iterator<char>(inputFile)), istreambuf_iterator<char>());
510 CPPUNIT_ASSERT_EQUAL(originalContents, newFile.str());
519 auto testFile = std::fstream();
520 testFile.exceptions(ios_base::failbit | ios_base::badbit);
521 testFile.open(
testFilePath(
"some_data"), ios_base::in | ios_base::binary);
522 auto outputStream = std::stringstream(ios_base::in | ios_base::out | ios_base::binary);
523 outputStream.exceptions(ios_base::failbit | ios_base::badbit);
527 copyHelper.copy(testFile, outputStream, 50);
528 CPPUNIT_ASSERT_EQUAL(
static_cast<std::fstream::pos_type
>(0), outputStream.tellg());
529 CPPUNIT_ASSERT_EQUAL(
static_cast<std::fstream::pos_type
>(50), outputStream.tellp());
530 CPPUNIT_ASSERT_EQUAL(
static_cast<std::fstream::pos_type
>(50), testFile.tellg());
531 CPPUNIT_ASSERT_EQUAL(
static_cast<std::fstream::pos_type
>(50), testFile.tellp());
535 for (
auto i = 0;
i < 50; ++
i) {
536 CPPUNIT_ASSERT_EQUAL(testFile.get(), outputStream.get());
547 testFile.exceptions(ios_base::failbit | ios_base::badbit);
548 testFile.open(
testFilePath(
"some_data"), ios_base::in | ios_base::binary);
551 outputStream.exceptions(ios_base::failbit | ios_base::badbit);
552 outputStream.open(outputPath, ios_base::out | ios_base::binary);
556 copyHelper.copy(testFile, outputStream, 50);
557 CPPUNIT_ASSERT(outputStream.is_open());
558 CPPUNIT_ASSERT(testFile.is_open());
561 CPPUNIT_ASSERT_EQUAL(
static_cast<std::fstream::pos_type
>(50), outputStream.tellg());
562 CPPUNIT_ASSERT_EQUAL(
static_cast<std::fstream::pos_type
>(50), outputStream.tellp());
563 CPPUNIT_ASSERT_EQUAL(
static_cast<std::fstream::pos_type
>(50), testFile.tellg());
564 CPPUNIT_ASSERT_EQUAL(
static_cast<std::fstream::pos_type
>(50), testFile.tellp());
567 const auto aFewMoreBytes =
"a few more bytes"sv;
568 outputStream << aFewMoreBytes;
569 outputStream.close();
570 outputStream.open(outputPath, ios_base::in | ios_base::binary);
574 for (
auto i = 0;
i < 50; ++
i) {
575 CPPUNIT_ASSERT_EQUAL(testFile.get(), outputStream.get());
577 auto tail = std::string(aFewMoreBytes.size(),
'0');
578 outputStream.read(tail.data(),
static_cast<std::streamsize
>(tail.size()));
579 CPPUNIT_ASSERT_EQUAL(aFewMoreBytes, std::string_view(tail.data(), tail.size()));
582 auto percentage = 0.0;
583 const auto isAborted = [] {
return false; };
584 const auto callback = [&percentage](
double p) { percentage = p; };
586 outputStream.close();
587 outputStream.open(outputPath, ios_base::out | ios_base::trunc | ios_base::binary);
588 copyHelper.callbackCopy(testFile, outputStream, 50, isAborted, callback);
589 CPPUNIT_ASSERT_EQUAL(1.0, percentage);
592 CPPUNIT_ASSERT(outputStream.is_open());
593 CPPUNIT_ASSERT(testFile.is_open());
594 CPPUNIT_ASSERT_EQUAL(
static_cast<std::fstream::pos_type
>(50), outputStream.tellg());
595 CPPUNIT_ASSERT_EQUAL(
static_cast<std::fstream::pos_type
>(50), outputStream.tellp());
596 CPPUNIT_ASSERT_EQUAL(
static_cast<std::fstream::pos_type
>(50), testFile.tellg());
597 CPPUNIT_ASSERT_EQUAL(
static_cast<std::fstream::pos_type
>(50), testFile.tellp());
598 outputStream << aFewMoreBytes;
599 outputStream.close();
600 outputStream.open(outputPath, ios_base::in | ios_base::binary);
602 for (
auto i = 0;
i < 50; ++
i) {
603 CPPUNIT_ASSERT_EQUAL(testFile.get(), outputStream.get());
605 tail.assign(aFewMoreBytes.size(),
'0');
606 outputStream.read(tail.data(),
static_cast<std::streamsize
>(tail.size()));
607 CPPUNIT_ASSERT_EQUAL(aFewMoreBytes, std::string_view(tail.data(), tail.size()));
617 CPPUNIT_ASSERT_EQUAL(
"# file for testing INI parser\n"
621 "key1=value 1 # comment\n"
632 CPPUNIT_ASSERT_THROW(
readFile(iniFilePath, 10), std::ios_base::failure);
635#if !defined(PLATFORM_WINDOWS) || defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER)
636 CPPUNIT_ASSERT_EQUAL(
"file with non-ASCII character 'ä' in its name\n"s,
readFile(
testFilePath(
"täst.txt")));
647 CPPUNIT_ASSERT_EQUAL(
"some contents"s,
readFile(path));
667 cout <<
"\noutput for formatting with ANSI escape codes:\n" << ss1.str() <<
"---------------------------------------------\n";
668 CPPUNIT_ASSERT_EQUAL(
"\033[1;31mError: \033[0m\033[1msome error\033[0m\n"
669 "\033[1;33mWarning: \033[0m\033[1msome warning\033[0m\n"
670 "\033[1;34mInfo: \033[0m\033[1msome info\033[0m\n"
671 "\033[1;31m==> ERROR: \033[0m\033[1mArch-style error\033[0m\n"
672 "\033[1;33m==> WARNING: \033[0m\033[1mArch-style warning\033[0m\n"
673 " \033[0m\033[1mArch-style message\033[0m\n"
674 "\033[1;32m==> \033[0m\033[1mArch-style success\033[0m\n"
675 "\033[1;32m -> \033[0m\033[1mArch-style sub-message\033[0m\n"
676 "\033[5;34;41mblue, blinking text on red background\033[0m\n"s,
682 CPPUNIT_ASSERT_EQUAL(
"Info: some info\n"s, ss2.str());
685#ifdef CPP_UTILITIES_USE_NATIVE_FILE_BUFFER
689void IoTests::testNativeFileStream()
695 fileStream.exceptions(ios_base::badbit | ios_base::failbit);
696 CPPUNIT_ASSERT(!fileStream.is_open());
697 fileStream.open(txtFilePath, ios_base::in);
698 CPPUNIT_ASSERT(fileStream.is_open());
699#if defined(PLATFORM_WINDOWS) && defined(CPP_UTILITIES_USE_BOOST_IOSTREAMS)
700 CPPUNIT_ASSERT(fileStream.fileHandle() !=
nullptr);
702 CPPUNIT_ASSERT(fileStream.fileDescriptor() != -1);
704 CPPUNIT_ASSERT_EQUAL(
static_cast<char>(fileStream.get()),
'f');
705 fileStream.seekg(0, ios_base::end);
706 CPPUNIT_ASSERT_EQUAL(fileStream.tellg(),
static_cast<NativeFileStream::pos_type
>(47));
708 CPPUNIT_ASSERT(!fileStream.is_open());
710 fileStream.open(
"non existing file", ios_base::in | ios_base::out | ios_base::binary);
711 CPPUNIT_FAIL(
"expected exception");
712 }
catch (
const std::ios_base::failure &failure) {
713#ifdef PLATFORM_WINDOWS
714#ifdef CPP_UTILITIES_USE_BOOST_IOSTREAMS
726#ifndef PLATFORM_WINDOWS
727 auto readWriteFileDescriptor = open(txtFilePath.data(), O_RDWR);
728 CPPUNIT_ASSERT(readWriteFileDescriptor);
729 fileStream.open(readWriteFileDescriptor, ios_base::in | ios_base::out | ios_base::binary);
730 CPPUNIT_ASSERT(fileStream.is_open());
731 CPPUNIT_ASSERT_EQUAL(
static_cast<char>(fileStream.get()),
'f');
732 fileStream.seekg(0, ios_base::end);
733 CPPUNIT_ASSERT_EQUAL(fileStream.tellg(),
static_cast<NativeFileStream::pos_type
>(47));
736 CPPUNIT_ASSERT(!fileStream.is_open());
739 fileStream.open(-1, ios_base::in | ios_base::out | ios_base::binary);
741 CPPUNIT_FAIL(
"expected exception");
742 }
catch (
const std::ios_base::failure &failure) {
743#ifndef PLATFORM_WINDOWS
745 "expected error message",
"(basic_ios::clear|failed reading: Bad file descriptor): iostream error"s,
string(failure.what()));
754 fileStream2.exceptions(ios_base::failbit | ios_base::badbit);
755 fileStream2.open(txtFilePath, ios_base::in | ios_base::out | ios_base::app);
756 CPPUNIT_ASSERT(fileStream2.is_open());
757 fileStream2 <<
"foo";
760 CPPUNIT_ASSERT(!fileStream2.is_open());
761 CPPUNIT_ASSERT_EQUAL(
"file with non-ASCII character 'ä' in its name\nfoo"s,
readFile(txtFilePath, 50));
764 fileStream2.open(txtFilePath, ios_base::out | ios_base::trunc);
765 CPPUNIT_ASSERT(fileStream2.is_open());
766 fileStream2 <<
"bar";
768 CPPUNIT_ASSERT(!fileStream2.is_open());
769 CPPUNIT_ASSERT_EQUAL(
"bar"s,
readFile(txtFilePath, 4));
772#ifdef PLATFORM_WINDOWS
773 const auto wideTxtFilePath = NativeFileStream::makeWidePath(txtFilePath);
774 const auto appendFileHandle = _wfopen(wideTxtFilePath.get(), L
"a+");
776 const auto appendFileHandle = fopen(txtFilePath.data(),
"a");
778 CPPUNIT_ASSERT(appendFileHandle);
779 fileStream2.open(fileno(appendFileHandle), ios_base::out | ios_base::app);
780 CPPUNIT_ASSERT(fileStream2.is_open());
781 fileStream2 <<
"foo";
783 CPPUNIT_ASSERT(!fileStream2.is_open());
784 CPPUNIT_ASSERT_EQUAL(
"barfoo"s,
readFile(txtFilePath, 7));
788#ifdef CPP_UTILITIES_USE_LIBARCHIVE
789void IoTests::testExtractingArchive()
791 const auto archivePath =
testFilePath(
"archive-test.zip");
793 const auto &root = archiveContents.at(std::string());
794 const auto &subdir = archiveContents.at(
"subdir");
795 const auto &subsubdir = archiveContents.at(
"subdir/foo");
797 CPPUNIT_ASSERT_EQUAL(1_st, root.size());
798 CPPUNIT_ASSERT_EQUAL(
"test.txt"s, root.at(0).name);
799 CPPUNIT_ASSERT_EQUAL(ArchiveFileType::Regular, root.at(0).type);
803 CPPUNIT_ASSERT_EQUAL(2024, root.at(0).modificationTime.year());
804 CPPUNIT_ASSERT_EQUAL(3, root.at(0).modificationTime.month());
805 CPPUNIT_ASSERT_EQUAL(
"testfile\n"s, root.at(0).content);
807 CPPUNIT_ASSERT_EQUAL(1_st, subdir.size());
808 CPPUNIT_ASSERT_EQUAL(
"nested-testfile.txt"s, subdir.at(0).name);
809 CPPUNIT_ASSERT_EQUAL(ArchiveFileType::Regular, subdir.at(0).type);
810 CPPUNIT_ASSERT_EQUAL(
"some file\n"s, subdir.at(0).content);
812 CPPUNIT_ASSERT_EQUAL(1_st, subsubdir.size());
813 CPPUNIT_ASSERT_EQUAL(
"bar"s, subsubdir.at(0).name);
814 CPPUNIT_ASSERT_EQUAL(ArchiveFileType::Regular, subsubdir.at(0).type);
815 CPPUNIT_ASSERT_EQUAL(std::string(), subsubdir.at(0).content);
#define CPP_UTILITIES_WARNING_PUSH
Causes GCC/Clang to remember the state of the diagnostics.
#define CPP_UTILITIES_WARNING_POP
Causes GCC/Clang to restore the previous state of the diagnostics.
#define CPP_UTILITIES_WARNING_DISABLE(text)
Causes GCC/Clang to suppress the specified diagnostic.
#define CPP_UTILITIES_UNUSED(x)
Prevents warnings about unused variables.
Reads primitive data types from a std::istream.
std::int64_t readInt64LE()
Reads a 64-bit little endian signed integer from the current stream and advances the current position...
float readFloat32BE()
Reads a 32-bit big endian floating point value from the current stream and advances the current posit...
std::string readTerminatedString(std::uint8_t termination=0)
Reads a terminated string from the current stream.
std::string readString(std::size_t length)
Reads a string from the current stream of the given length from the stream and advances the current p...
std::uint64_t readUInt64LE()
Reads a 64-bit little endian unsigned integer from the current stream and advances the current positi...
std::string readLengthPrefixedString()
Reads a length prefixed string from the current stream.
std::int64_t readInt40LE()
Reads a 40-bit little endian signed integer from the current stream and advances the current position...
std::int32_t readInt32BE()
Reads a 32-bit big endian signed integer from the current stream and advances the current position of...
std::int32_t readInt24LE()
Reads a 24-bit little endian signed integer from the current stream and advances the current position...
std::uint32_t readUInt32LE()
Reads a 32-bit little endian unsigned integer from the current stream and advances the current positi...
std::uint16_t readUInt16LE()
Reads a 16-bit little endian unsigned integer from the current stream and advances the current positi...
void setStream(std::istream *stream, bool giveOwnership=false)
Assigns the stream the reader will read from when calling one of the read-methods.
std::uint64_t readUInt56BE()
Reads a 56-bit big endian unsigned integer from the current stream and advances the current position ...
bool readBool()
Reads a boolean value from the current stream and advances the current position of the stream by one ...
std::uint32_t readUInt24BE()
Reads a 24-bit big endian unsigned integer from the current stream and advances the current position ...
std::int32_t readInt32LE()
Reads a 32-bit little endian signed integer from the current stream and advances the current position...
const std::istream * stream() const
Returns a pointer to the stream the reader will read from when calling one of the read-methods.
std::int16_t readInt16BE()
Reads a 16-bit big endian signed integer from the current stream and advances the current position of...
std::uint32_t readUInt24LE()
Reads a 24-bit little endian unsigned integer from the current stream and advances the current positi...
std::int64_t readInt56LE()
Reads a 56-bit little endian signed integer from the current stream and advances the current position...
std::istream::pos_type readRemainingBytes()
Returns the number of remaining bytes in the stream from the current offset.
std::uint64_t readUInt64BE()
Reads a 64-bit big endian unsigned integer from the current stream and advances the current position ...
bool hasOwnership() const
Returns whether the reader takes ownership over the assigned stream.
std::uint64_t readUInt40LE()
Reads a 40-bit little endian unsigned integer from the current stream and advances the current positi...
std::uint64_t readUInt56LE()
Reads a 56-bit little endian unsigned integer from the current stream and advances the current positi...
std::uint16_t readUInt16BE()
Reads a 16-bit big endian unsigned integer from the current stream and advances the current position ...
std::int32_t readInt24BE()
Reads a 24-bit big endian signed integer from the current stream and advances the current position of...
std::int64_t readInt40BE()
Reads a 40-bit big endian signed integer from the current stream and advances the current position of...
double readFloat64BE()
Reads a 64-bit big endian floating point value from the current stream and advances the current posit...
std::uint32_t readUInt32BE()
Reads a 32-bit big endian unsigned integer from the current stream and advances the current position ...
std::int64_t readInt56BE()
Reads a 56-bit big endian signed integer from the current stream and advances the current position of...
std::int16_t readInt16LE()
Reads a 16-bit little endian signed integer from the current stream and advances the current position...
double readFloat64LE()
Reads a 64-bit little endian floating point value from the current stream and advances the current po...
std::int64_t readInt64BE()
Reads a 64-bit big endian signed integer from the current stream and advances the current position of...
std::istream::pos_type readStreamsize()
Returns the size of the assigned stream.
std::uint64_t readUInt40BE()
Reads a 40-bit big endian unsigned integer from the current stream and advances the current position ...
float readFloat32LE()
Reads a 32-bit little endian floating point value from the current stream and advances the current po...
std::uint8_t readByte()
Reads a single byte/unsigned character from the current stream and advances the current position of t...
Writes primitive data types to a std::ostream.
void writeFloat32LE(float value)
Writes a 32-bit little endian floating point value to the current stream and advances the current pos...
void writeUInt40BE(std::uint64_t value)
Writes a 40-bit big endian unsigned integer to the current stream and advances the current position o...
void writeUInt64LE(std::uint64_t value)
Writes a 64-bit little endian unsigned integer to the current stream and advances the current positio...
void writeInt40LE(std::int64_t value)
Writes a 40-bit big endian signed integer to the current stream and advances the current position of ...
void writeUInt40LE(std::uint64_t value)
Writes a 40-bit big endian unsigned integer to the current stream and advances the current position o...
void writeInt64BE(std::int64_t value)
Writes a 64-bit big endian signed integer to the current stream and advances the current position of ...
void writeInt32LE(std::int32_t value)
Writes a 32-bit little endian signed integer to the current stream and advances the current position ...
bool hasOwnership() const
Returns whether the writer takes ownership over the assigned stream.
void writeUInt24LE(std::uint32_t value)
Writes a 24-bit little endian unsigned integer to the current stream and advances the current positio...
void writeFloat32BE(float value)
Writes a 32-bit big endian floating point value to the current stream and advances the current positi...
void writeInt24BE(std::int32_t value)
Writes a 24-bit big endian signed integer to the current stream and advances the current position of ...
void setStream(std::ostream *stream, bool giveOwnership=false)
Assigns the stream the writer will write to when calling one of the write-methods.
void writeUInt56BE(std::uint64_t value)
Writes a 56-bit big endian unsigned integer to the current stream and advances the current position o...
void writeUInt32BE(std::uint32_t value)
Writes a 32-bit big endian unsigned integer to the current stream and advances the current position o...
void writeFloat64BE(double value)
Writes a 64-bit big endian floating point value to the current stream and advances the current positi...
void writeFloat64LE(double value)
Writes a 64-bit little endian floating point value to the current stream and advances the current pos...
void writeString(const std::string &value)
Writes a string to the current stream and advances the current position of the stream by the length o...
void writeUInt56LE(std::uint64_t value)
Writes a 56-bit big endian unsigned integer to the current stream and advances the current position o...
void writeInt56LE(std::int64_t value)
Writes a 56-bit big endian signed integer to the current stream and advances the current position of ...
const std::ostream * stream() const
Returns a pointer to the stream the writer will write to when calling one of the write-methods.
void writeUInt16BE(std::uint16_t value)
Writes a 16-bit big endian unsigned integer to the current stream and advances the current position o...
void writeUInt64BE(std::uint64_t value)
Writes a 64-bit big endian unsigned integer to the current stream and advances the current position o...
void writeInt56BE(std::int64_t value)
Writes a 56-bit big endian signed integer to the current stream and advances the current position of ...
void writeInt16LE(std::int16_t value)
Writes a 16-bit little endian signed integer to the current stream and advances the current position ...
void writeUInt32LE(std::uint32_t value)
Writes a 32-bit little endian unsigned integer to the current stream and advances the current positio...
void writeUInt16LE(std::uint16_t value)
Writes a 16-bit little endian unsigned integer to the current stream and advances the current positio...
void writeInt16BE(std::int16_t value)
Writes a 16-bit big endian signed integer to the current stream and advances the current position of ...
void writeLengthPrefixedString(const std::string &value)
Writes the length of a string and the string itself to the current stream.
void writeInt24LE(std::int32_t value)
Writes a 24-bit little endian signed integer to the current stream and advances the current position ...
void writeUInt24BE(std::uint32_t value)
Writes a 24-bit big endian unsigned integer to the current stream and advances the current position o...
void writeTerminatedString(const std::string &value)
Writes a terminated string to the current stream and advances the current position of the stream by t...
void writeInt64LE(std::int64_t value)
Writes a 64-bit little endian signed integer to the current stream and advances the current position ...
void writeInt32BE(std::int32_t value)
Writes a 32-bit big endian signed integer to the current stream and advances the current position of ...
void writeInt40BE(std::int64_t value)
Writes a 40-bit big endian signed integer to the current stream and advances the current position of ...
void writeBool(bool value)
Writes a boolean value to the current stream and advances the current position of the stream by one b...
The BitReader class provides bitwise reading of buffered data.
void reset(const char *buffer, std::size_t bufferSize)
Resets the reader.
std::uint8_t readBit()
Reads the one bit from the buffer advancing the current position by one bit.
void skipBits(std::size_t bitCount)
Skips the specified number of bits without reading it.
void align()
Re-establishes alignment.
std::size_t bitsAvailable()
Returns the number of bits which are still available to read.
intType readSignedExpGolombCodedBits()
Reads "Exp-Golomb coded" bits (signed).
intType readUnsignedExpGolombCodedBits()
Reads "Exp-Golomb coded" bits (unsigned).
intType readBits(std::uint8_t bitCount)
Reads the specified number of bits from the buffer advancing the current position by bitCount bits.
intType showBits(std::uint8_t bitCount)
Reads the specified number of bits from the buffer without advancing the current position.
The BufferSearch struct invokes a callback if an initially given search term occurs in consecutively ...
BufferSearch(std::string_view searchTerm, std::string_view terminationChars, std::string_view giveUpTerm, CallbackType &&callback)
Constructs a new BufferSearch.
The ConversionException class is thrown by the various conversion functions of this library when a co...
CopyHelper()
Constructs a new copy helper.
static DateTime fromDate(int year=1, int month=1, int day=1)
Constructs a DateTime to the specified year, month, and day.
The IniFile class allows parsing and writing INI files.
void parse(std::istream &inputStream)
Parses all data from the specified inputStream.
ScopeList & data()
Returns the data of the file.
void make(std::ostream &outputStream)
Write the current data to the specified outputStream.
The IoTests class tests classes and functions provided by the files inside the io directory.
void testBufferSearch()
Tests the BufferSearch class.
void testBinaryReader()
Tests the most important methods of the BinaryReader.
void testAnsiEscapeCodes()
Tests formatting functions of CppUtilities::EscapeCodes namespace.
void testIniFile()
Tests IniFile.
void testBitReader()
Tests the BitReader class.
void testBinaryWriter()
Tests the most important methods of the BinaryWriter.
void testCopyWithNativeFileStream()
Tests CopyHelper in combination with NativeFileStream.
void testCopy()
Tests CopyHelper.
void testPathUtilities()
Tests fileName() and removeInvalidChars().
void testWriteFile()
Tests writeFile().
void testReadFile()
Tests readFile().
void testAdvancedIniFile()
Tests AdvancedIniFile.
CPPUNIT_TEST_SUITE_REGISTRATION(ConversionTests)
constexpr auto color(Color foreground, Color background, TextAttribute displayAttribute=TextAttribute::Reset)
CPP_UTILITIES_EXPORT bool enabled
Controls whether the functions inside the EscapeCodes namespace actually make use of escape codes.
Contains literals to ease asserting with CPPUNIT_ASSERT_EQUAL.
Contains all utilities provided by the c++utilities library.
CPP_UTILITIES_EXPORT std::string readFile(const std::string &path, std::string::size_type maxSize=std::string::npos)
Reads all contents of the specified file in a single call.
CPP_UTILITIES_EXPORT std::string testFilePath(const std::string &relativeTestFilePath)
Convenience function to invoke TestApplication::testFilePath().
CPP_UTILITIES_EXPORT std::string workingCopyPath(const std::string &relativeTestFilePath, WorkingCopyMode mode=WorkingCopyMode::CreateCopy)
Convenience function to invoke TestApplication::workingCopyPath().
CPP_UTILITIES_EXPORT StringData convertUtf16LEToUtf8(const char *inputBuffer, std::size_t inputBufferSize)
Converts the specified UTF-16 (little-endian) string to UTF-8.
CPP_UTILITIES_EXPORT FileMap extractFiles(std::string_view archivePath, const FilePredicate &isFileRelevant=FilePredicate())
Extracts the specified archive.
CPP_UTILITIES_EXPORT std::ostream & operator<<(std::ostream &out, Indentation indentation)
CPP_UTILITIES_EXPORT StringData convertUtf16BEToUtf8(const char *inputBuffer, std::size_t inputBufferSize)
Converts the specified UTF-16 (big-endian) string to UTF-8.
std::fstream NativeFileStream
StringType argsToString(Args &&...args)
AsHexNumber< T > asHexNumber(const T &value)
Wraps a value to be printed using the hex system in the error case when asserted with cppunit (or sim...
CPP_UTILITIES_EXPORT void writeFile(std::string_view path, std::string_view contents)
Writes all contents to the specified file in a single call.
CPP_UTILITIES_EXPORT void removeInvalidChars(std::string &fileName)
Removes invalid characters from the specified fileName.
CPP_UTILITIES_EXPORT std::string fileName(const std::string &path)
Returns the file name and extension of the specified path string.
NativePathStringView makeNativePath(PathStringView path)
Returns path in the platform's native encoding.
CPP_UTILITIES_EXPORT std::string directory(const std::string &path)
Returns the directory of the specified path string (including trailing slash).
The AdvancedIniFile class allows parsing and writing INI files.
void make(std::ostream &outputStream, IniFileMakeOptions options=IniFileMakeOptions::None)
Write the current data to the specified outputStream.
std::optional< FieldList::iterator > findField(std::string_view sectionName, std::string_view key)
Returns an iterator to the first field within the first section with matching sectionName and key.
void parse(std::istream &inputStream, IniFileParseOptions options=IniFileParseOptions::None)
Parses all data from the specified inputStream.
SectionList::iterator sectionEnd()
Returns an iterator that points one past the last section.
SectionList::iterator findSection(std::string_view sectionName)
Returns an iterator to the first section with the name sectionName.
#define TESTUTILS_ASSERT_LIKE_FLAGS(message, expectedRegex, regexFlags, actualString)
Asserts whether the specified string matches the specified regex.
#define TESTUTILS_ASSERT_LIKE(message, expectedRegex, actualString)
Asserts whether the specified string matches the specified regex.