C++ Utilities  5.11.0
Useful C++ classes and routines such as argument parser, IO and conversion utilities
iotests.cpp
Go to the documentation of this file.
1 #include "./testutils.h"
2 
3 #include "../conversion/conversionexception.h"
4 #include "../conversion/stringbuilder.h"
5 
6 #include "../io/ansiescapecodes.h"
7 #include "../io/binaryreader.h"
8 #include "../io/binarywriter.h"
9 #include "../io/bitreader.h"
10 #include "../io/buffersearch.h"
11 #include "../io/copy.h"
12 #include "../io/inifile.h"
13 #include "../io/misc.h"
14 #include "../io/nativefilestream.h"
15 #include "../io/path.h"
16 
17 #include <cppunit/TestFixture.h>
18 #include <cppunit/extensions/HelperMacros.h>
19 
20 #include <algorithm>
21 #include <fstream>
22 #include <regex>
23 #include <sstream>
24 
25 #ifdef PLATFORM_WINDOWS
26 #include <cstdio>
27 #endif
28 
29 #ifdef PLATFORM_UNIX
30 #include <sys/fcntl.h>
31 #include <sys/types.h>
32 #endif
33 
34 using namespace std;
35 using namespace CppUtilities;
36 using namespace CppUtilities::Literals;
37 using namespace CPPUNIT_NS;
38 
42 class IoTests : public TestFixture {
43  CPPUNIT_TEST_SUITE(IoTests);
44  CPPUNIT_TEST(testBinaryReader);
45  CPPUNIT_TEST(testBinaryWriter);
46  CPPUNIT_TEST(testBitReader);
47  CPPUNIT_TEST(testBufferSearch);
48  CPPUNIT_TEST(testPathUtilities);
49  CPPUNIT_TEST(testIniFile);
50  CPPUNIT_TEST(testAdvancedIniFile);
51  CPPUNIT_TEST(testCopy);
52  CPPUNIT_TEST(testReadFile);
53  CPPUNIT_TEST(testWriteFile);
54  CPPUNIT_TEST(testAnsiEscapeCodes);
55 #ifdef CPP_UTILITIES_USE_NATIVE_FILE_BUFFER
56  CPPUNIT_TEST(testNativeFileStream);
57 #endif
58  CPPUNIT_TEST_SUITE_END();
59 
60 public:
61  void setUp() override;
62  void tearDown() override;
63 
64  void testBinaryReader();
65  void testBinaryWriter();
66  void testBitReader();
67  void testBufferSearch();
68  void testPathUtilities();
69  void testIniFile();
70  void testAdvancedIniFile();
71  void testCopy();
72  void testReadFile();
73  void testWriteFile();
74  void testAnsiEscapeCodes();
75 #ifdef CPP_UTILITIES_USE_NATIVE_FILE_BUFFER
76  void testNativeFileStream();
77 #endif
78 };
79 
81 
83 {
84 }
85 
87 {
88 }
89 
94 {
95  // read test file
96  fstream testFile;
97  testFile.exceptions(ios_base::failbit | ios_base::badbit);
98  testFile.open(testFilePath("some_data"), ios_base::in | ios_base::binary);
99  BinaryReader reader(&testFile);
100  CPPUNIT_ASSERT_EQUAL(static_cast<istream::pos_type>(398), reader.readStreamsize());
101  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(0x0102u), reader.readUInt16LE());
102  CPPUNIT_ASSERT_EQUAL(static_cast<istream::pos_type>(396), reader.readRemainingBytes());
103  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint16_t>(0x0102u), reader.readUInt16BE());
104  CPPUNIT_ASSERT_EQUAL(0x010203u, reader.readUInt24LE());
105  CPPUNIT_ASSERT_EQUAL(0x010203u, reader.readUInt24BE());
106  CPPUNIT_ASSERT_EQUAL(0x01020304u, reader.readUInt32LE());
107  CPPUNIT_ASSERT_EQUAL(0x01020304u, reader.readUInt32BE());
108  CPPUNIT_ASSERT_EQUAL(0x0102030405u, reader.readUInt40LE());
109  CPPUNIT_ASSERT_EQUAL(0x0102030405u, reader.readUInt40BE());
110  CPPUNIT_ASSERT_EQUAL(0x01020304050607u, reader.readUInt56LE());
111  CPPUNIT_ASSERT_EQUAL(0x01020304050607u, reader.readUInt56BE());
112  CPPUNIT_ASSERT_EQUAL(0x0102030405060708u, reader.readUInt64LE());
113  CPPUNIT_ASSERT_EQUAL(0x0102030405060708u, reader.readUInt64BE());
114  testFile.seekg(0);
115  CPPUNIT_ASSERT_EQUAL(reader.readInt16LE(), static_cast<std::int16_t>(0x0102));
116  CPPUNIT_ASSERT_EQUAL(reader.readInt16BE(), static_cast<std::int16_t>(0x0102));
117  CPPUNIT_ASSERT_EQUAL(0x010203, reader.readInt24LE());
118  CPPUNIT_ASSERT_EQUAL(0x010203, reader.readInt24BE());
119  CPPUNIT_ASSERT_EQUAL(0x01020304, reader.readInt32LE());
120  CPPUNIT_ASSERT_EQUAL(0x01020304, reader.readInt32BE());
121  CPPUNIT_ASSERT_EQUAL(0x0102030405, reader.readInt40LE());
122  CPPUNIT_ASSERT_EQUAL(0x0102030405, reader.readInt40BE());
123  CPPUNIT_ASSERT_EQUAL(0x01020304050607, reader.readInt56LE());
124  CPPUNIT_ASSERT_EQUAL(0x01020304050607, reader.readInt56BE());
125  CPPUNIT_ASSERT_EQUAL(0x0102030405060708, reader.readInt64LE());
126  CPPUNIT_ASSERT_EQUAL(0x0102030405060708, reader.readInt64BE());
127  CPPUNIT_ASSERT_EQUAL(1.125f, reader.readFloat32LE());
128  CPPUNIT_ASSERT_EQUAL(1.625, reader.readFloat64LE());
129  CPPUNIT_ASSERT_EQUAL(1.125f, reader.readFloat32BE());
130  CPPUNIT_ASSERT_EQUAL(reader.readFloat64BE(), 1.625);
131  CPPUNIT_ASSERT_EQUAL(false, reader.readBool());
132  CPPUNIT_ASSERT_EQUAL(true, reader.readBool());
133  CPPUNIT_ASSERT_EQUAL("abc"s, reader.readString(3));
134  CPPUNIT_ASSERT_EQUAL(reader.readLengthPrefixedString(), "ABC"s);
135  CPPUNIT_ASSERT_EQUAL("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901"
136  "23456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123"
137  "45678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345"
138  "678901234567890123456789"s,
139  reader.readLengthPrefixedString());
140  CPPUNIT_ASSERT_EQUAL("def"s, reader.readTerminatedString());
141  testFile.seekg(-4, ios_base::cur);
142  CPPUNIT_ASSERT_EQUAL("def"s, reader.readTerminatedString(5, 0));
143  CPPUNIT_ASSERT_THROW(reader.readLengthPrefixedString(), ConversionException);
144  CPPUNIT_ASSERT_MESSAGE("pos in stream not advanced on conversion error", reader.readByte() == 0);
145 
146  // test ownership
147  reader.setStream(nullptr, true);
148  reader.setStream(new fstream(), true);
149  BinaryReader reader2(reader);
150  CPPUNIT_ASSERT(reader2.stream() == reader.stream());
151  CPPUNIT_ASSERT(!reader2.hasOwnership());
152  reader.setStream(&testFile, false);
153  reader.setStream(new fstream(), true);
154 }
155 
160 {
161  // prepare reading expected data
162  fstream testFile;
163  testFile.exceptions(ios_base::failbit | ios_base::badbit);
164  testFile.open(testFilePath("some_data"), ios_base::in | ios_base::binary);
165 
166  // prepare output stream
167  stringstream outputStream(ios_base::in | ios_base::out | ios_base::binary);
168  outputStream.exceptions(ios_base::failbit | ios_base::badbit);
169  char testData[397];
170  outputStream.rdbuf()->pubsetbuf(testData, sizeof(testData));
171 
172  // write test data
173  BinaryWriter writer(&outputStream);
174  writer.writeUInt16LE(0x0102u);
175  writer.writeUInt16BE(0x0102u);
176  writer.writeUInt24LE(0x010203u);
177  writer.writeUInt24BE(0x010203u);
178  writer.writeUInt32LE(0x01020304u);
179  writer.writeUInt32BE(0x01020304u);
180  writer.writeUInt40LE(0x0102030405u);
181  writer.writeUInt40BE(0x0102030405u);
182  writer.writeUInt56LE(0x01020304050607u);
183  writer.writeUInt56BE(0x01020304050607u);
184  writer.writeUInt64LE(0x0102030405060708u);
185  writer.writeUInt64BE(0x0102030405060708u);
186 
187  // test written values
188  for (char c : testData) {
189  CPPUNIT_ASSERT(c == static_cast<char>(testFile.get()));
190  if (testFile.tellg() >= 58) {
191  break;
192  }
193  }
194  testFile.seekg(0);
195  outputStream.seekp(0);
196 
197  // write more test data
198  writer.writeInt16LE(0x0102);
199  writer.writeInt16BE(0x0102);
200  writer.writeInt24LE(0x010203);
201  writer.writeInt24BE(0x010203);
202  writer.writeInt32LE(0x01020304);
203  writer.writeInt32BE(0x01020304);
204  writer.writeInt40LE(0x0102030405);
205  writer.writeInt40BE(0x0102030405);
206  writer.writeInt56LE(0x01020304050607);
207  writer.writeInt56BE(0x01020304050607);
208  writer.writeInt64LE(0x0102030405060708);
209  writer.writeInt64BE(0x0102030405060708);
210  writer.writeFloat32LE(1.125);
211  writer.writeFloat64LE(1.625);
212  writer.writeFloat32BE(1.125);
213  writer.writeFloat64BE(1.625);
214  writer.writeBool(false);
215  writer.writeBool(true);
216  writer.writeString("abc");
217  writer.writeLengthPrefixedString("ABC");
218  writer.writeLengthPrefixedString("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
219  "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901"
220  "234567890123456789012345678901234567890123456789012345678901234567890123456789");
221  writer.writeTerminatedString("def");
222 
223  // test written values
224  for (char c : testData) {
225  CPPUNIT_ASSERT(c == static_cast<char>(testFile.get()));
226  }
227 
228  // test ownership
229  writer.setStream(nullptr, true);
230  writer.setStream(new fstream(), true);
231  BinaryWriter writer2(writer);
232  CPPUNIT_ASSERT(writer2.stream() == writer.stream());
233  CPPUNIT_ASSERT(!writer2.hasOwnership());
234  writer.setStream(&testFile, false);
235  writer.setStream(new fstream(), true);
236 }
237 
242 {
243  const std::uint8_t testData[] = { 0x81, 0x90, 0x3C, 0x44, 0x28, 0x00, 0x44, 0x10, 0x20, 0xFF, 0xFA };
244  BitReader reader(reinterpret_cast<const char *>(testData), sizeof(testData));
245  CPPUNIT_ASSERT(reader.readBit() == 1);
246  reader.skipBits(6);
247  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(3), reader.showBits<std::uint8_t>(2));
248  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(3), reader.readBits<std::uint8_t>(2));
249  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint32_t>(0x103C4428 << 1), reader.readBits<std::uint32_t>(32));
250  reader.align();
251  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(0x44), reader.readBits<std::uint8_t>(8));
252  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(7), reader.readUnsignedExpGolombCodedBits<std::uint8_t>());
253  CPPUNIT_ASSERT_EQUAL(static_cast<std::int8_t>(4), reader.readSignedExpGolombCodedBits<std::int8_t>());
254  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(0), reader.readBit());
255  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(0), reader.readBit());
256  reader.skipBits(8 + 4);
257  CPPUNIT_ASSERT_EQUAL(4_st, reader.bitsAvailable());
258  CPPUNIT_ASSERT_EQUAL(static_cast<std::uint8_t>(0xA), reader.readBits<std::uint8_t>(4));
259  CPPUNIT_ASSERT_THROW(reader.readBit(), std::ios_base::failure);
260  CPPUNIT_ASSERT_THROW(reader.skipBits(1), std::ios_base::failure);
261  reader.reset(reinterpret_cast<const char *>(testData), sizeof(testData));
262  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(8 * sizeof(testData)), reader.bitsAvailable());
263 }
264 
269 {
270  // setup search to test
271  auto expectedResult = std::string();
272  auto hasResult = false;
273  auto bs = BufferSearch("Updated version: ", "\e\n", "Starting build", [&](BufferSearch &, std::string &&result) {
274  CPPUNIT_ASSERT_EQUAL(expectedResult, result);
275  CPPUNIT_ASSERT_MESSAGE("callback only invoked once", !hasResult);
276  hasResult = true;
277  });
278 
279  // feed data into the search
280  char buffer[30];
281  bs(buffer, 0);
282  CPPUNIT_ASSERT(!hasResult);
283  std::strcpy(buffer, "Starting Updated");
284  bs(std::string_view(buffer, 16));
285  CPPUNIT_ASSERT(!hasResult);
286  std::strcpy(buffer, " version: some ");
287  bs(buffer, 15);
288  CPPUNIT_ASSERT(!hasResult);
289  expectedResult = "some version number";
290  std::strcpy(buffer, "version number\emore chars");
291  bs(buffer, 25);
292  CPPUNIT_ASSERT(hasResult);
293  hasResult = false;
294  std::strcpy(buffer, "... Starting build ...");
295  bs(buffer, 22);
296  CPPUNIT_ASSERT(!hasResult);
297 }
298 
303 {
304  CPPUNIT_ASSERT_EQUAL("libc++utilities.so"s, fileName("C:\\libs\\libc++utilities.so"));
305  CPPUNIT_ASSERT_EQUAL("libc++utilities.so"s, fileName("C:\\libs/libc++utilities.so"));
306  CPPUNIT_ASSERT_EQUAL("libc++utilities.so"s, fileName("/usr/lib/libc++utilities.so"));
307  CPPUNIT_ASSERT_EQUAL("libc++utilities.so"s, fileName("libc++utilities.so"));
308  CPPUNIT_ASSERT_EQUAL("/usr/lib/"s, directory("/usr/lib/libc++utilities.so"));
309  CPPUNIT_ASSERT_EQUAL(string(), directory("libc++utilities.so"));
310  CPPUNIT_ASSERT_EQUAL("C:\\libs\\"s, directory("C:\\libs\\libc++utilities.so"));
311  CPPUNIT_ASSERT_EQUAL("C:\\libs/"s, directory("C:\\libs/libc++utilities.so"));
312  string invalidPath("lib/c++uti*lities.so?");
313  removeInvalidChars(invalidPath);
314  CPPUNIT_ASSERT(invalidPath == "libc++utilities.so");
315 }
316 
321 {
322  // prepare reading test file
323  fstream inputFile;
324  inputFile.exceptions(ios_base::failbit | ios_base::badbit);
325  inputFile.open(testFilePath("test.ini"), ios_base::in);
326 
327  IniFile ini;
328  ini.parse(inputFile);
329  const auto globalScope = ini.data().at(0);
330  const auto scope1 = ini.data().at(1);
331  const auto scope2 = ini.data().at(2);
332  CPPUNIT_ASSERT(globalScope.first.empty());
333  CPPUNIT_ASSERT(globalScope.second.find("key0") != globalScope.second.cend());
334  CPPUNIT_ASSERT(globalScope.second.find("key0")->second == "value 0");
335  CPPUNIT_ASSERT(globalScope.second.find("key1") == globalScope.second.cend());
336  CPPUNIT_ASSERT(scope1.first == "scope 1");
337  CPPUNIT_ASSERT(scope1.second.find("key1") != scope1.second.cend());
338  CPPUNIT_ASSERT(scope1.second.find("key1")->second == "value 1");
339  CPPUNIT_ASSERT(scope1.second.find("key2") != scope1.second.cend());
340  CPPUNIT_ASSERT(scope1.second.find("key2")->second == "value=2");
341  CPPUNIT_ASSERT(scope2.first == "scope 2");
342  CPPUNIT_ASSERT(scope2.second.find("key5") == scope2.second.cend());
343 
344  // write values to another file
345  fstream outputFile;
346  outputFile.exceptions(ios_base::failbit | ios_base::badbit);
347  outputFile.open(workingCopyPath("output.ini", WorkingCopyMode::NoCopy), ios_base::out | ios_base::trunc);
348  ini.make(outputFile);
349 
350  // parse written values (again)
351  outputFile.close();
352  outputFile.open(workingCopyPath("output.ini", WorkingCopyMode::NoCopy), ios_base::in);
353  IniFile ini2;
354  ini2.parse(outputFile);
355  CPPUNIT_ASSERT(ini.data() == ini2.data());
356 }
357 
362 {
363  // prepare reading test file
364  fstream inputFile;
365  inputFile.exceptions(ios_base::failbit | ios_base::badbit);
366  inputFile.open(testFilePath("pacman.conf"), ios_base::in);
367 
368  // parse the test file
369  AdvancedIniFile ini;
370  ini.parse(inputFile);
371 
372  // check whether scope data is as expected
373  CPPUNIT_ASSERT_EQUAL_MESSAGE("5 scopes (taking implicit empty section at the end into account)", 5_st, ini.sections.size());
374  auto options = ini.findSection("options");
375  CPPUNIT_ASSERT(options != ini.sectionEnd());
377  "comment block before section", "# Based on.*\n.*# GENERAL OPTIONS\n#\n"s, std::regex::extended, options->precedingCommentBlock);
378  CPPUNIT_ASSERT_EQUAL(7_st, options->fields.size());
379  CPPUNIT_ASSERT_EQUAL("HoldPkg"s, options->fields[0].key);
380  CPPUNIT_ASSERT_EQUAL("pacman glibc"s, options->fields[0].value);
381  CPPUNIT_ASSERT_MESSAGE("value present", options->fields[0].flags & IniFileFieldFlags::HasValue);
382  TESTUTILS_ASSERT_LIKE_FLAGS("comment block between section header and first field",
383  "# The following paths are.*\n.*#HookDir = /etc/pacman\\.d/hooks/\n"s, std::regex::extended, options->fields[0].precedingCommentBlock);
384  CPPUNIT_ASSERT_EQUAL(""s, options->fields[0].followingInlineComment);
385  CPPUNIT_ASSERT_EQUAL("Foo"s, options->fields[1].key);
386  CPPUNIT_ASSERT_EQUAL("bar"s, options->fields[1].value);
387  CPPUNIT_ASSERT_MESSAGE("value present", options->fields[1].flags & IniFileFieldFlags::HasValue);
388  TESTUTILS_ASSERT_LIKE_FLAGS("comment block between fields", "#XferCommand.*\n.*#CleanMethod = KeepInstalled\n"s, std::regex::extended,
389  options->fields[1].precedingCommentBlock);
390  CPPUNIT_ASSERT_EQUAL("# inline comment"s, options->fields[1].followingInlineComment);
391  CPPUNIT_ASSERT_EQUAL("CheckSpace"s, options->fields[3].key);
392  CPPUNIT_ASSERT_EQUAL(""s, options->fields[3].value);
393  CPPUNIT_ASSERT_MESSAGE("no value present", !(options->fields[3].flags & IniFileFieldFlags::HasValue));
394  TESTUTILS_ASSERT_LIKE_FLAGS("empty lines in comments preserved", "\n# Pacman.*\n.*\n\n#NoUpgrade =\n.*#TotalDownload\n"s, std::regex::extended,
395  options->fields[3].precedingCommentBlock);
396  CPPUNIT_ASSERT_EQUAL(""s, options->fields[3].followingInlineComment);
397  auto extraScope = ini.findSection(options, "extra");
398  CPPUNIT_ASSERT(extraScope != ini.sectionEnd());
399  CPPUNIT_ASSERT_EQUAL_MESSAGE("comment block which is only an empty line", "\n"s, extraScope->precedingCommentBlock);
400  CPPUNIT_ASSERT_EQUAL_MESSAGE("inline comment after scope", "# an inline comment after a scope name"s, extraScope->followingInlineComment);
401  CPPUNIT_ASSERT_EQUAL(1_st, extraScope->fields.size());
402  CPPUNIT_ASSERT(ini.sections.back().flags & IniFileSectionFlags::Implicit);
403  TESTUTILS_ASSERT_LIKE_FLAGS("comment block after last field present in implicitly added last scope", "\n# If you.*\n.*custompkgs\n"s,
404  std::regex::extended, ini.sections.back().precedingCommentBlock);
405 
406  // test finding a field from file level and const access
407  const auto *const constIniFile = &ini;
408  auto includeField = constIniFile->findField("extra", "Include");
409  CPPUNIT_ASSERT(includeField.has_value());
410  CPPUNIT_ASSERT_EQUAL("Include"s, includeField.value()->key);
411  CPPUNIT_ASSERT_EQUAL("/etc/pacman.d/mirrorlist"s, includeField.value()->value);
412  CPPUNIT_ASSERT_MESSAGE("field not present", !constIniFile->findField("extra", "Includ").has_value());
413  CPPUNIT_ASSERT_MESSAGE("scope not present", !constIniFile->findField("extr", "Includ").has_value());
414 
415  // write values again; there shouldn't be a difference as the parser and the writer are supposed to
416  // preserve the order of all elements and comments
417  std::stringstream newFile;
418  ini.make(newFile);
419  std::string originalContents;
420  inputFile.clear();
421  inputFile.seekg(std::ios_base::beg);
422  originalContents.assign((istreambuf_iterator<char>(inputFile)), istreambuf_iterator<char>());
423  CPPUNIT_ASSERT_EQUAL(originalContents, newFile.str());
424 }
425 
430 {
431  // prepare streams
432  fstream testFile;
433  testFile.exceptions(ios_base::failbit | ios_base::badbit);
434  testFile.open(testFilePath("some_data"), ios_base::in | ios_base::binary);
435  stringstream outputStream(ios_base::in | ios_base::out | ios_base::binary);
436  outputStream.exceptions(ios_base::failbit | ios_base::badbit);
437 
438  // copy
439  CopyHelper<13> copyHelper;
440  copyHelper.copy(testFile, outputStream, 50);
441 
442  // test
443  testFile.seekg(0);
444  for (auto i = 0; i < 50; ++i) {
445  CPPUNIT_ASSERT(testFile.get() == outputStream.get());
446  }
447 }
448 
453 {
454  // read a file successfully
455  const string iniFilePath(testFilePath("test.ini"));
456  CPPUNIT_ASSERT_EQUAL("# file for testing INI parser\n"
457  "key0=value 0\n"
458  "\n"
459  "[scope 1]\n"
460  "key1=value 1 # comment\n"
461  "key2=value=2\n"
462  "key3=value 3\n"
463  "\n"
464  "[scope 2]\n"
465  "key4=value 4\n"
466  "#key5=value 5\n"
467  "key6=value 6\n"s,
468  readFile(iniFilePath));
469 
470  // fail by exceeding max size
471  CPPUNIT_ASSERT_THROW(readFile(iniFilePath, 10), std::ios_base::failure);
472 
473  // handle UTF-8 in path and file contents correctly via NativeFileStream
474 #if !defined(PLATFORM_WINDOWS) || defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER)
475  CPPUNIT_ASSERT_EQUAL("file with non-ASCII character 'ä' in its name\n"s, readFile(testFilePath("täst.txt")));
476 #endif
477 }
478 
483 {
484  const string path(workingCopyPath("test.ini", WorkingCopyMode::NoCopy));
485  writeFile(path, "some contents");
486  CPPUNIT_ASSERT_EQUAL("some contents"s, readFile(path));
487 }
488 
493 {
494  stringstream ss1;
495  EscapeCodes::enabled = true;
496  ss1 << EscapeCodes::Phrases::Error << "some error" << EscapeCodes::Phrases::End;
497  ss1 << EscapeCodes::Phrases::Warning << "some warning" << EscapeCodes::Phrases::End;
498  ss1 << EscapeCodes::Phrases::Info << "some info" << EscapeCodes::Phrases::End;
499  ss1 << EscapeCodes::Phrases::ErrorMessage << "Arch-style error" << EscapeCodes::Phrases::End;
500  ss1 << EscapeCodes::Phrases::WarningMessage << "Arch-style warning" << EscapeCodes::Phrases::End;
501  ss1 << EscapeCodes::Phrases::PlainMessage << "Arch-style message" << EscapeCodes::Phrases::End;
502  ss1 << EscapeCodes::Phrases::SuccessMessage << "Arch-style success" << EscapeCodes::Phrases::End;
503  ss1 << EscapeCodes::Phrases::SubMessage << "Arch-style sub-message" << EscapeCodes::Phrases::End;
504  ss1 << EscapeCodes::color(EscapeCodes::Color::Blue, EscapeCodes::Color::Red, EscapeCodes::TextAttribute::Blink)
505  << "blue, blinking text on red background" << EscapeCodes::TextAttribute::Reset << '\n';
506  cout << "\noutput for formatting with ANSI escape codes:\n" << ss1.str() << "---------------------------------------------\n";
507  fstream("/tmp/test.txt", ios_base::out | ios_base::trunc) << ss1.str();
508  CPPUNIT_ASSERT_EQUAL("\e[1;31mError: \e[0m\e[1msome error\e[0m\n"
509  "\e[1;33mWarning: \e[0m\e[1msome warning\e[0m\n"
510  "\e[1;34mInfo: \e[0m\e[1msome info\e[0m\n"
511  "\e[1;31m==> ERROR: \e[0m\e[1mArch-style error\e[0m\n"
512  "\e[1;33m==> WARNING: \e[0m\e[1mArch-style warning\e[0m\n"
513  " \e[0m\e[1mArch-style message\e[0m\n"
514  "\e[1;32m==> \e[0m\e[1mArch-style success\e[0m\n"
515  "\e[1;32m -> \e[0m\e[1mArch-style sub-message\e[0m\n"
516  "\e[5;34;41mblue, blinking text on red background\e[0m\n"s,
517  ss1.str());
518 
519  stringstream ss2;
520  EscapeCodes::enabled = false;
521  ss2 << EscapeCodes::Phrases::Info << "some info" << EscapeCodes::Phrases::End;
522  CPPUNIT_ASSERT_EQUAL("Info: some info\n"s, ss2.str());
523 }
524 
525 #ifdef CPP_UTILITIES_USE_NATIVE_FILE_BUFFER
529 void IoTests::testNativeFileStream()
530 {
531  // open file by path
532  const auto txtFilePath(workingCopyPath("täst.txt"));
533  NativeFileStream fileStream;
534  fileStream.exceptions(ios_base::badbit | ios_base::failbit);
535  CPPUNIT_ASSERT(!fileStream.is_open());
536  fileStream.open(txtFilePath, ios_base::in);
537  CPPUNIT_ASSERT(fileStream.is_open());
538 #if defined(PLATFORM_WINDOWS) && defined(CPP_UTILITIES_USE_BOOST_IOSTREAMS)
539  CPPUNIT_ASSERT(fileStream.fileHandle() != nullptr);
540 #else
541  CPPUNIT_ASSERT(fileStream.fileDescriptor() != -1);
542 #endif
543  CPPUNIT_ASSERT_EQUAL(static_cast<char>(fileStream.get()), 'f');
544  fileStream.seekg(0, ios_base::end);
545  CPPUNIT_ASSERT_EQUAL(fileStream.tellg(), static_cast<NativeFileStream::pos_type>(47));
546  fileStream.close();
547  CPPUNIT_ASSERT(!fileStream.is_open());
548  try {
549  fileStream.open("non existing file", ios_base::in | ios_base::out | ios_base::binary);
550  CPPUNIT_FAIL("expected exception");
551  } catch (const std::ios_base::failure &failure) {
552 #ifdef PLATFORM_WINDOWS
553 #ifdef CPP_UTILITIES_USE_BOOST_IOSTREAMS
554  TESTUTILS_ASSERT_LIKE("expected error with some message", "CreateFileW failed: .+", failure.what());
555 #else
556  TESTUTILS_ASSERT_LIKE("expected error with some message", "_wopen failed: .+", failure.what());
557 #endif
558 #else
559  TESTUTILS_ASSERT_LIKE("expected error with some message", "open failed: .+", failure.what());
560 #endif
561  }
562  fileStream.clear();
563 
564  // open file from file descriptor
565 #ifndef PLATFORM_WINDOWS
566  auto readWriteFileDescriptor = open(txtFilePath.data(), O_RDWR);
567  CPPUNIT_ASSERT(readWriteFileDescriptor);
568  fileStream.open(readWriteFileDescriptor, ios_base::in | ios_base::out | ios_base::binary);
569  CPPUNIT_ASSERT(fileStream.is_open());
570  CPPUNIT_ASSERT_EQUAL(static_cast<char>(fileStream.get()), 'f');
571  fileStream.seekg(0, ios_base::end);
572  CPPUNIT_ASSERT_EQUAL(fileStream.tellg(), static_cast<NativeFileStream::pos_type>(47));
573  fileStream.flush();
574  fileStream.close();
575  CPPUNIT_ASSERT(!fileStream.is_open());
576 #endif
577  try {
578  fileStream.open(-1, ios_base::in | ios_base::out | ios_base::binary);
579  fileStream.get();
580  CPPUNIT_FAIL("expected exception");
581  } catch (const std::ios_base::failure &failure) {
582 #ifndef PLATFORM_WINDOWS
584  "expected error message", "(basic_ios::clear|failed reading: Bad file descriptor): iostream error"s, string(failure.what()));
585 #else
586  CPP_UTILITIES_UNUSED(failure)
587 #endif
588  }
589  fileStream.clear();
590 
591  // append + write file via path
592  NativeFileStream fileStream2;
593  fileStream2.exceptions(ios_base::failbit | ios_base::badbit);
594  fileStream2.open(txtFilePath, ios_base::in | ios_base::out | ios_base::app);
595  CPPUNIT_ASSERT(fileStream2.is_open());
596  fileStream2 << "foo";
597  fileStream2.flush();
598  fileStream2.close();
599  CPPUNIT_ASSERT(!fileStream2.is_open());
600  CPPUNIT_ASSERT_EQUAL("file with non-ASCII character 'ä' in its name\nfoo"s, readFile(txtFilePath, 50));
601 
602  // truncate + write file via path
603  fileStream2.open(txtFilePath, ios_base::out | ios_base::trunc);
604  CPPUNIT_ASSERT(fileStream2.is_open());
605  fileStream2 << "bar";
606  fileStream2.close();
607  CPPUNIT_ASSERT(!fileStream2.is_open());
608  CPPUNIT_ASSERT_EQUAL("bar"s, readFile(txtFilePath, 4));
609 
610  // append + write via file descriptor from file handle
611 #ifdef PLATFORM_WINDOWS
612  const auto wideTxtFilePath = NativeFileStream::makeWidePath(txtFilePath);
613  const auto appendFileHandle = _wfopen(wideTxtFilePath.get(), L"a+");
614 #else
615  const auto appendFileHandle = fopen(txtFilePath.data(), "a");
616 #endif
617  CPPUNIT_ASSERT(appendFileHandle);
618  fileStream2.open(fileno(appendFileHandle), ios_base::out | ios_base::app);
619  CPPUNIT_ASSERT(fileStream2.is_open());
620  fileStream2 << "foo";
621  fileStream2.close();
622  CPPUNIT_ASSERT(!fileStream2.is_open());
623  CPPUNIT_ASSERT_EQUAL("barfoo"s, readFile(txtFilePath, 7));
624 }
625 #endif
#define CPP_UTILITIES_UNUSED(x)
Prevents warnings about unused variables.
Definition: global.h:92
Reads primitive data types from a std::istream.
Definition: binaryreader.h:11
std::int64_t readInt64LE()
Reads a 64-bit little endian signed integer from the current stream and advances the current position...
Definition: binaryreader.h:505
float readFloat32BE()
Reads a 32-bit big endian floating point value from the current stream and advances the current posit...
Definition: binaryreader.h:379
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...
Definition: binaryreader.h:514
std::string readLengthPrefixedString()
Reads a length prefixed string from the current stream.
Definition: binaryreader.h:580
std::int64_t readInt40LE()
Reads a 40-bit little endian signed integer from the current stream and advances the current position...
Definition: binaryreader.h:457
std::int32_t readInt32BE()
Reads a 32-bit big endian signed integer from the current stream and advances the current position of...
Definition: binaryreader.h:285
std::int32_t readInt24LE()
Reads a 24-bit little endian signed integer from the current stream and advances the current position...
Definition: binaryreader.h:415
std::uint32_t readUInt32LE()
Reads a 32-bit little endian unsigned integer from the current stream and advances the current positi...
Definition: binaryreader.h:448
std::uint16_t readUInt16LE()
Reads a 16-bit little endian unsigned integer from the current stream and advances the current positi...
Definition: binaryreader.h:406
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 ...
Definition: binaryreader.h:341
bool readBool()
Reads a boolean value from the current stream and advances the current position of the stream by one ...
Definition: binaryreader.h:570
std::uint32_t readUInt24BE()
Reads a 24-bit big endian unsigned integer from the current stream and advances the current position ...
Definition: binaryreader.h:275
std::int32_t readInt32LE()
Reads a 32-bit little endian signed integer from the current stream and advances the current position...
Definition: binaryreader.h:439
const std::istream * stream() const
Returns a pointer to the stream the reader will read from when calling one of the read-methods.
Definition: binaryreader.h:148
std::int16_t readInt16BE()
Reads a 16-bit big endian signed integer from the current stream and advances the current position of...
Definition: binaryreader.h:243
std::uint32_t readUInt24LE()
Reads a 24-bit little endian unsigned integer from the current stream and advances the current positi...
Definition: binaryreader.h:429
std::int64_t readInt56LE()
Reads a 56-bit little endian signed integer from the current stream and advances the current position...
Definition: binaryreader.h:481
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 ...
Definition: binaryreader.h:360
bool hasOwnership() const
Returns whether the reader takes ownership over the assigned stream.
Definition: binaryreader.h:160
std::uint64_t readUInt40LE()
Reads a 40-bit little endian unsigned integer from the current stream and advances the current positi...
Definition: binaryreader.h:471
std::uint64_t readUInt56LE()
Reads a 56-bit little endian unsigned integer from the current stream and advances the current positi...
Definition: binaryreader.h:495
std::uint16_t readUInt16BE()
Reads a 16-bit big endian unsigned integer from the current stream and advances the current position ...
Definition: binaryreader.h:252
std::int32_t readInt24BE()
Reads a 24-bit big endian signed integer from the current stream and advances the current position of...
Definition: binaryreader.h:261
std::int64_t readInt40BE()
Reads a 40-bit big endian signed integer from the current stream and advances the current position of...
Definition: binaryreader.h:303
double readFloat64BE()
Reads a 64-bit big endian floating point value from the current stream and advances the current posit...
Definition: binaryreader.h:388
std::uint32_t readUInt32BE()
Reads a 32-bit big endian unsigned integer from the current stream and advances the current position ...
Definition: binaryreader.h:294
std::int64_t readInt56BE()
Reads a 56-bit big endian signed integer from the current stream and advances the current position of...
Definition: binaryreader.h:327
std::int16_t readInt16LE()
Reads a 16-bit little endian signed integer from the current stream and advances the current position...
Definition: binaryreader.h:397
double readFloat64LE()
Reads a 64-bit little endian floating point value from the current stream and advances the current po...
Definition: binaryreader.h:542
std::int64_t readInt64BE()
Reads a 64-bit big endian signed integer from the current stream and advances the current position of...
Definition: binaryreader.h:351
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 ...
Definition: binaryreader.h:317
float readFloat32LE()
Reads a 32-bit little endian floating point value from the current stream and advances the current po...
Definition: binaryreader.h:533
std::uint8_t readByte()
Reads a single byte/unsigned character from the current stream and advances the current position of t...
Definition: binaryreader.h:560
Writes primitive data types to a std::ostream.
Definition: binarywriter.h:14
void writeFloat32LE(float value)
Writes a 32-bit little endian floating point value to the current stream and advances the current pos...
Definition: binarywriter.h:517
void writeUInt40BE(std::uint64_t value)
Writes a 40-bit big endian unsigned integer to the current stream and advances the current position o...
Definition: binarywriter.h:318
void writeUInt64LE(std::uint64_t value)
Writes a 64-bit little endian unsigned integer to the current stream and advances the current positio...
Definition: binarywriter.h:499
void writeInt40LE(std::int64_t value)
Writes a 40-bit big endian signed integer to the current stream and advances the current position of ...
Definition: binarywriter.h:451
void writeUInt40LE(std::uint64_t value)
Writes a 40-bit big endian unsigned integer to the current stream and advances the current position o...
Definition: binarywriter.h:461
void writeInt64BE(std::int64_t value)
Writes a 64-bit big endian signed integer to the current stream and advances the current position of ...
Definition: binarywriter.h:347
void writeInt32LE(std::int32_t value)
Writes a 32-bit little endian signed integer to the current stream and advances the current position ...
Definition: binarywriter.h:432
bool hasOwnership() const
Returns whether the writer takes ownership over the assigned stream.
Definition: binarywriter.h:157
void writeUInt24LE(std::uint32_t value)
Writes a 24-bit little endian unsigned integer to the current stream and advances the current positio...
Definition: binarywriter.h:422
void writeFloat32BE(float value)
Writes a 32-bit big endian floating point value to the current stream and advances the current positi...
Definition: binarywriter.h:374
void writeInt24BE(std::int32_t value)
Writes a 24-bit big endian signed integer to the current stream and advances the current position of ...
Definition: binarywriter.h:269
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...
Definition: binarywriter.h:338
void writeUInt32BE(std::uint32_t value)
Writes a 32-bit big endian unsigned integer to the current stream and advances the current position o...
Definition: binarywriter.h:298
void writeFloat64BE(double value)
Writes a 64-bit big endian floating point value to the current stream and advances the current positi...
Definition: binarywriter.h:383
void writeFloat64LE(double value)
Writes a 64-bit little endian floating point value to the current stream and advances the current pos...
Definition: binarywriter.h:526
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...
Definition: binarywriter.h:535
void writeUInt56LE(std::uint64_t value)
Writes a 56-bit big endian unsigned integer to the current stream and advances the current position o...
Definition: binarywriter.h:481
void writeInt56LE(std::int64_t value)
Writes a 56-bit big endian signed integer to the current stream and advances the current position of ...
Definition: binarywriter.h:471
const std::ostream * stream() const
Returns a pointer to the stream the writer will write to when calling one of the write-methods.
Definition: binarywriter.h:145
void writeUInt16BE(std::uint16_t value)
Writes a 16-bit big endian unsigned integer to the current stream and advances the current position o...
Definition: binarywriter.h:259
void writeUInt64BE(std::uint64_t value)
Writes a 64-bit big endian unsigned integer to the current stream and advances the current position o...
Definition: binarywriter.h:356
void writeInt56BE(std::int64_t value)
Writes a 56-bit big endian signed integer to the current stream and advances the current position of ...
Definition: binarywriter.h:328
void writeInt16LE(std::int16_t value)
Writes a 16-bit little endian signed integer to the current stream and advances the current position ...
Definition: binarywriter.h:392
void writeUInt32LE(std::uint32_t value)
Writes a 32-bit little endian unsigned integer to the current stream and advances the current positio...
Definition: binarywriter.h:441
void writeUInt16LE(std::uint16_t value)
Writes a 16-bit little endian unsigned integer to the current stream and advances the current positio...
Definition: binarywriter.h:401
void writeInt16BE(std::int16_t value)
Writes a 16-bit big endian signed integer to the current stream and advances the current position of ...
Definition: binarywriter.h:250
void writeLengthPrefixedString(const std::string &value)
Writes the length of a string and the string itself to the current stream.
Definition: binarywriter.h:555
void writeInt24LE(std::int32_t value)
Writes a 24-bit little endian signed integer to the current stream and advances the current position ...
Definition: binarywriter.h:411
void writeUInt24BE(std::uint32_t value)
Writes a 24-bit big endian unsigned integer to the current stream and advances the current position o...
Definition: binarywriter.h:279
void writeTerminatedString(const std::string &value)
Writes a terminated string to the current stream and advances the current position of the stream by t...
Definition: binarywriter.h:543
void writeInt64LE(std::int64_t value)
Writes a 64-bit little endian signed integer to the current stream and advances the current position ...
Definition: binarywriter.h:490
void writeInt32BE(std::int32_t value)
Writes a 32-bit big endian signed integer to the current stream and advances the current position of ...
Definition: binarywriter.h:289
void writeInt40BE(std::int64_t value)
Writes a 40-bit big endian signed integer to the current stream and advances the current position of ...
Definition: binarywriter.h:308
void writeBool(bool value)
Writes a boolean value to the current stream and advances the current position of the stream by one b...
Definition: binarywriter.h:242
The BitReader class provides bitwise reading of buffered data.
Definition: bitreader.h:13
void reset(const char *buffer, std::size_t bufferSize)
Resets the reader.
Definition: bitreader.h:148
std::uint8_t readBit()
Reads the one bit from the buffer advancing the current position by one bit.
Definition: bitreader.h:89
void skipBits(std::size_t bitCount)
Skips the specified number of bits without reading it.
Definition: bitreader.cpp:18
void align()
Re-establishes alignment.
Definition: bitreader.h:171
std::size_t bitsAvailable()
Returns the number of bits which are still available to read.
Definition: bitreader.h:137
intType readSignedExpGolombCodedBits()
Reads "Exp-Golomb coded" bits (signed).
Definition: bitreader.h:119
intType readUnsignedExpGolombCodedBits()
Reads "Exp-Golomb coded" bits (unsigned).
Definition: bitreader.h:102
intType readBits(std::uint8_t bitCount)
Reads the specified number of bits from the buffer advancing the current position by bitCount bits.
Definition: bitreader.h:67
intType showBits(std::uint8_t bitCount)
Reads the specified number of bits from the buffer without advancing the current position.
Definition: bitreader.h:128
The BufferSearch struct invokes a callback if an initially given search term occurs in consecutively ...
Definition: buffersearch.h:15
The ConversionException class is thrown by the various conversion functions of this library when a co...
The CopyHelper class helps to copy bytes from one stream to another.
Definition: copy.h:16
void copy(std::istream &input, std::ostream &output, std::size_t count)
Copies count bytes from input to output.
Definition: copy.h:43
The IniFile class allows parsing and writing INI files.
Definition: inifile.h:16
void parse(std::istream &inputStream)
Parses all data from the specified inputStream.
Definition: inifile.cpp:40
ScopeList & data()
Returns the data of the file.
Definition: inifile.h:46
void make(std::ostream &outputStream)
Write the current data to the specified outputStream.
Definition: inifile.cpp:159
The IoTests class tests classes and functions provided by the files inside the io directory.
Definition: iotests.cpp:42
void testBufferSearch()
Tests the BufferSearch class.
Definition: iotests.cpp:268
void testBinaryReader()
Tests the most important methods of the BinaryReader.
Definition: iotests.cpp:93
void testAnsiEscapeCodes()
Tests formatting functions of CppUtilities::EscapeCodes namespace.
Definition: iotests.cpp:492
void testIniFile()
Tests IniFile.
Definition: iotests.cpp:320
void testBitReader()
Tests the BitReader class.
Definition: iotests.cpp:241
void testBinaryWriter()
Tests the most important methods of the BinaryWriter.
Definition: iotests.cpp:159
void setUp() override
Definition: iotests.cpp:82
void testCopy()
Tests CopyHelper.
Definition: iotests.cpp:429
void testPathUtilities()
Tests fileName() and removeInvalidChars().
Definition: iotests.cpp:302
void tearDown() override
Definition: iotests.cpp:86
void testWriteFile()
Tests writeFile().
Definition: iotests.cpp:482
void testReadFile()
Tests readFile().
Definition: iotests.cpp:452
void testAdvancedIniFile()
Tests AdvancedIniFile.
Definition: iotests.cpp:361
CPPUNIT_TEST_SUITE_REGISTRATION(IoTests)
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.
Definition: testutils.h:317
Contains all utilities provides 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.
Definition: misc.cpp:16
CPP_UTILITIES_EXPORT std::string testFilePath(const std::string &relativeTestFilePath)
Convenience function to invoke TestApplication::testFilePath().
Definition: testutils.h:148
CPP_UTILITIES_EXPORT std::string workingCopyPath(const std::string &relativeTestFilePath, WorkingCopyMode mode=WorkingCopyMode::CreateCopy)
Convenience function to invoke TestApplication::workingCopyPath().
Definition: testutils.h:166
CPP_UTILITIES_EXPORT std::string directory(const std::string &path)
Returns the directory of the specified path string (including trailing slash).
Definition: path.cpp:35
CPP_UTILITIES_EXPORT std::string fileName(const std::string &path)
Returns the file name and extension of the specified path string.
Definition: path.cpp:15
CPP_UTILITIES_EXPORT void writeFile(std::string_view path, std::string_view contents)
Writes all contents to the specified file in a single call.
Definition: misc.cpp:39
std::fstream NativeFileStream
CPP_UTILITIES_EXPORT void removeInvalidChars(std::string &fileName)
Removes invalid characters from the specified fileName.
Definition: path.cpp:57
The AdvancedIniFile class allows parsing and writing INI files.
Definition: inifile.h:79
void make(std::ostream &outputStream, IniFileMakeOptions options=IniFileMakeOptions::None)
Write the current data to the specified outputStream.
Definition: inifile.cpp:412
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.
Definition: inifile.h:170
void parse(std::istream &inputStream, IniFileParseOptions options=IniFileParseOptions::None)
Parses all data from the specified inputStream.
Definition: inifile.cpp:217
SectionList::iterator sectionEnd()
Returns an iterator that points one past the last section.
Definition: inifile.h:154
SectionList::iterator findSection(std::string_view sectionName)
Returns an iterator to the first section with the name sectionName.
Definition: inifile.h:122
#define TESTUTILS_ASSERT_LIKE_FLAGS(message, expectedRegex, regexFlags, actualString)
Asserts whether the specified string matches the specified regex.
Definition: testutils.h:277
#define TESTUTILS_ASSERT_LIKE(message, expectedRegex, actualString)
Asserts whether the specified string matches the specified regex.
Definition: testutils.h:287
constexpr int i