C++ Utilities  5.10.5
Useful C++ classes and routines such as argument parser, IO and conversion utilities
conversiontests.cpp
Go to the documentation of this file.
1 #include "../conversion/binaryconversion.h"
2 #include "../conversion/stringbuilder.h"
3 #include "../conversion/stringconversion.h"
4 #include "../tests/testutils.h"
5 
6 using namespace CppUtilities;
7 
8 #include <cppunit/TestFixture.h>
9 #include <cppunit/extensions/HelperMacros.h>
10 
11 #include <functional>
12 #include <initializer_list>
13 #include <random>
14 #include <sstream>
15 
16 #ifdef CPP_UTILITIES_USE_STANDARD_FILESYSTEM
17 #include <filesystem>
18 #endif
19 
20 using namespace std;
21 
22 using namespace CPPUNIT_NS;
23 
24 // compile-time checks for binary conversion
25 static_assert(toSynchsafeInt(255) == 383, "toSynchsafeInt()");
26 static_assert(toNormalInt(383) == 255, "toNormalInt()");
27 static_assert(swapOrder(static_cast<std::uint16_t>(0xABCD)) == 0xCDAB, "swapOrder(uint16)");
28 static_assert(swapOrder(0xABCDEF12u) == 0x12EFCDABu, "swapOrder(uint32)");
29 static_assert(swapOrder(0xABCDEF1234567890ul) == 0x9078563412EFCDABul, "swapOrder(uint64)");
30 
34 class ConversionTests : public TestFixture {
35  CPPUNIT_TEST_SUITE(ConversionTests);
36  CPPUNIT_TEST(testConversionException);
37  CPPUNIT_TEST(testEndianness);
38  CPPUNIT_TEST(testBinaryConversions);
39  CPPUNIT_TEST(testSwapOrderFunctions);
40  CPPUNIT_TEST(testStringEncodingConversions);
41  CPPUNIT_TEST(testStringConversions);
42  CPPUNIT_TEST(testStringBuilder);
43  CPPUNIT_TEST_SUITE_END();
44 
45 public:
47 
48  void setUp()
49  {
50  }
51  void tearDown()
52  {
53  }
54 
55  void testConversionException();
56  void testEndianness();
57  void testBinaryConversions();
58  void testSwapOrderFunctions();
59  void testStringEncodingConversions();
60  void testStringConversions();
61  void testStringBuilder();
62 
63 private:
64  template <typename intType>
65  void testConversion(const char *message, function<void(intType, char *)> vice, function<intType(const char *)> verca, intType min, intType max);
66 
67  char m_buff[8];
68  random_device m_randomDevice;
69  mt19937 m_randomEngine;
70 };
71 
73 
75  : m_randomDevice()
76  , m_randomEngine(m_randomDevice())
77 {
78 }
79 
81 {
82  CPPUNIT_ASSERT(!strcmp("unable to convert", ConversionException().what()));
83 }
84 
89 {
90  union {
91  uint32_t integer;
92  char characters[4];
93  } test = { 0x01020304 };
94 #if defined(CONVERSION_UTILITIES_BYTE_ORDER_BIG_ENDIAN)
95  // test whether macro definitions are consistent
96  CPPUNIT_ASSERT(CONVERSION_UTILITIES_IS_BYTE_ORDER_BIG_ENDIAN == true);
97  CPPUNIT_ASSERT(CONVERSION_UTILITIES_IS_BYTE_ORDER_LITTLE_ENDIAN == false);
98  // test whether byte order assumption is correct
99  CPPUNIT_ASSERT_MESSAGE("Byte order assumption (big-endian) is wrong", test.characters[0] == 0x01);
100 #elif defined(CONVERSION_UTILITIES_BYTE_ORDER_LITTLE_ENDIAN)
101  // test whether macro definitions are consistent
102  CPPUNIT_ASSERT(CONVERSION_UTILITIES_IS_BYTE_ORDER_BIG_ENDIAN == false);
103  CPPUNIT_ASSERT(CONVERSION_UTILITIES_IS_BYTE_ORDER_LITTLE_ENDIAN == true);
104  // test whether byte order assumption is correct
105  CPPUNIT_ASSERT_MESSAGE("Byte order assumption (little-endian) is wrong", test.characters[0] == 0x04);
106 #else
107  CPPUNIT_FAIL("There is not valid byte order assumption");
108 #endif
109 }
110 
111 template <typename intType>
112 void ConversionTests::testConversion(
113  const char *message, function<void(intType, char *)> vice, function<intType(const char *)> versa, intType min, intType max)
114 {
115  const intType random = uniform_int_distribution<intType>(min, max)(m_randomEngine);
116  stringstream msg;
117  msg << message << '(' << hex << '0' << 'x' << random << ')';
118  vice(random, m_buff);
119  CPPUNIT_ASSERT_MESSAGE(msg.str(), versa(m_buff) == random);
120 }
121 
122 #define TEST_TYPE(endianness, function) decltype(endianness::function(m_buff))
123 
124 #define TEST_CONVERSION(function, endianness) \
125  testConversion<TEST_TYPE(endianness, function)>("testing " #function, \
126  static_cast<void (*)(TEST_TYPE(endianness, function), char *)>(&endianness::getBytes), endianness::function, \
127  numeric_limits<TEST_TYPE(endianness, function)>::min(), numeric_limits<TEST_TYPE(endianness, function)>::max())
128 
129 #define TEST_BE_CONVERSION(function) TEST_CONVERSION(function, BE)
130 
131 #define TEST_LE_CONVERSION(function) TEST_CONVERSION(function, LE)
132 
133 #define TEST_CUSTOM_CONVERSION(vice, versa, endianness, min, max) \
134  testConversion<TEST_TYPE(endianness, versa)>( \
135  "testing " #versa, static_cast<void (*)(TEST_TYPE(endianness, versa), char *)>(&endianness::vice), endianness::versa, min, max)
136 
144 {
145  // test to...() / getBytes() with random numbers
146  for (auto b = 1; b < 100; ++b) {
147  TEST_BE_CONVERSION(toUInt16);
148  TEST_BE_CONVERSION(toUInt32);
149  TEST_BE_CONVERSION(toUInt64);
150  TEST_LE_CONVERSION(toUInt16);
151  TEST_LE_CONVERSION(toUInt32);
152  TEST_LE_CONVERSION(toUInt64);
153  TEST_BE_CONVERSION(toInt16);
154  TEST_BE_CONVERSION(toInt32);
155  TEST_BE_CONVERSION(toInt64);
156  TEST_LE_CONVERSION(toInt16);
157  TEST_LE_CONVERSION(toInt32);
158  TEST_LE_CONVERSION(toInt64);
159  TEST_CUSTOM_CONVERSION(getBytes24, toUInt24, BE, 0, 0xFFFFFF);
160  TEST_CUSTOM_CONVERSION(getBytes24, toUInt24, LE, 0, 0xFFFFFF);
161  }
162 }
163 
168 {
169  CPPUNIT_ASSERT(swapOrder(static_cast<std::uint16_t>(0x7825)) == 0x2578);
170  CPPUNIT_ASSERT(swapOrder(static_cast<std::uint32_t>(0x12345678)) == 0x78563412);
171  CPPUNIT_ASSERT(swapOrder(static_cast<std::uint64_t>(0x1122334455667788)) == 0x8877665544332211);
172 }
173 
177 void assertEqual(const char *message, const std::uint8_t *expectedValues, size_t expectedSize, const StringData &actualValues)
178 {
179  // check whether number of elements matches
180  CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expectedSize, actualValues.second);
181  // check whether contents match
182  auto *end = expectedValues + expectedSize;
183  auto *i = reinterpret_cast<std::uint8_t *>(actualValues.first.get());
184  for (; expectedValues != end; ++expectedValues, ++i) {
185  CPPUNIT_ASSERT_EQUAL_MESSAGE(message, asHexNumber(*expectedValues), asHexNumber(*i));
186  }
187 }
188 
189 #if CONVERSION_UTILITIES_IS_BYTE_ORDER_LITTLE_ENDIAN == true
190 #define LE_STR_FOR_ENDIANNESS(name) name##LE##String
191 #define BE_STR_FOR_ENDIANNESS(name) name##BE##String
192 #elif CONVERSION_UTILITIES_IS_BYTE_ORDER_BIG_ENDIAN == true
193 #define LE_STR_FOR_ENDIANNESS(name) name##BE##String
194 #define BE_STR_FOR_ENDIANNESS(name) name##LE##String
195 #endif
196 
211 {
212  // define test string "ABCD" for the different encodings
213  const std::uint8_t simpleString[] = { 'A', 'B', 'C', 'D' };
214  const std::uint16_t simpleUtf16LEString[] = { 0x0041, 0x0042, 0x0043, 0x0044 };
215  const std::uint16_t simpleUtf16BEString[] = { 0x4100, 0x4200, 0x4300, 0x4400 };
216  // define test string "ABĂ–CD" for the different encodings
217  const std::uint8_t latin1String[] = { 'A', 'B', 0xD6, 'C', 'D' };
218  const std::uint8_t utf8String[] = { 'A', 'B', 0xC3, 0x96, 'C', 'D' };
219  const std::uint16_t utf16LEString[] = { 0x0041, 0x0042, 0x00D6, 0x0043, 0x0044 };
220  const std::uint16_t utf16BEString[] = { 0x4100, 0x4200, 0xD600, 0x4300, 0x4400 };
221  // test conversion to UTF-8
222  assertEqual("Latin-1 to UTF-8 (simple)", simpleString, 4, convertLatin1ToUtf8(reinterpret_cast<const char *>(simpleString), 4));
223  assertEqual("Latin-1 to UTF-8", utf8String, 6, convertLatin1ToUtf8(reinterpret_cast<const char *>(latin1String), 5));
224  assertEqual(
225  "UTF-16LE to UTF-8 (simple)", simpleString, 4, convertUtf16LEToUtf8(reinterpret_cast<const char *>(LE_STR_FOR_ENDIANNESS(simpleUtf16)), 8));
226  assertEqual("UTF-16LE to UTF-8", utf8String, 6, convertUtf16LEToUtf8(reinterpret_cast<const char *>(LE_STR_FOR_ENDIANNESS(utf16)), 10));
227  assertEqual(
228  "UTF-16BE to UTF-8 (simple)", simpleString, 4, convertUtf16BEToUtf8(reinterpret_cast<const char *>(BE_STR_FOR_ENDIANNESS(simpleUtf16)), 8));
229  assertEqual("UTF-16BE to UTF-8", utf8String, 6, convertUtf16BEToUtf8(reinterpret_cast<const char *>(BE_STR_FOR_ENDIANNESS(utf16)), 10));
230  // test conversion from UTF-8
231  assertEqual("UTF-8 to Latin-1 (simple)", simpleString, 4, convertUtf8ToLatin1(reinterpret_cast<const char *>(simpleString), 4));
232  assertEqual("UTF-8 to Latin-1", latin1String, 5, convertUtf8ToLatin1(reinterpret_cast<const char *>(utf8String), 6));
233  assertEqual("UTF-8 to UFT-16LE (simple)", reinterpret_cast<const std::uint8_t *>(LE_STR_FOR_ENDIANNESS(simpleUtf16)), 8,
234  convertUtf8ToUtf16LE(reinterpret_cast<const char *>(simpleString), 4));
235  assertEqual("UTF-8 to UFT-16LE", reinterpret_cast<const std::uint8_t *>(LE_STR_FOR_ENDIANNESS(utf16)), 10,
236  convertUtf8ToUtf16LE(reinterpret_cast<const char *>(utf8String), 6));
237  assertEqual("UTF-8 to UFT-16BE (simple)", reinterpret_cast<const std::uint8_t *>(BE_STR_FOR_ENDIANNESS(simpleUtf16)), 8,
238  convertUtf8ToUtf16BE(reinterpret_cast<const char *>(simpleString), 4));
239  assertEqual("UTF-8 to UFT-16BE", reinterpret_cast<const std::uint8_t *>(BE_STR_FOR_ENDIANNESS(utf16)), 10,
240  convertUtf8ToUtf16BE(reinterpret_cast<const char *>(utf8String), 6));
241  CPPUNIT_ASSERT_THROW(convertString("invalid charset", "UTF-8", "foo", 3, 1.0f), ConversionException);
242 }
243 
248 {
249  // stringToNumber() / numberToString() with zero and random numbers
250  CPPUNIT_ASSERT_EQUAL("0"s, numberToString<unsigned int>(0));
251  CPPUNIT_ASSERT_EQUAL("0"s, numberToString<signed int>(0));
252  uniform_int_distribution<std::int64_t> randomDistSigned(numeric_limits<std::int64_t>::min());
253  uniform_int_distribution<std::uint64_t> randomDistUnsigned(0);
254  const string stringMsg("string"), wideStringMsg("wide string"), bufferMsg("buffer");
255  for (std::uint8_t b = 1; b < 100; ++b) {
256  auto signedRandom = randomDistSigned(m_randomEngine);
257  auto unsignedRandom = randomDistUnsigned(m_randomEngine);
258  for (const auto base : initializer_list<std::uint8_t>{ 2, 8, 10, 16 }) {
259  const auto asString = numberToString<std::uint64_t, string>(unsignedRandom, base);
260  const auto asWideString = numberToString<std::uint64_t, wstring>(unsignedRandom, base);
261  CPPUNIT_ASSERT_EQUAL_MESSAGE(stringMsg, unsignedRandom, stringToNumber<std::uint64_t>(asString, base));
262  CPPUNIT_ASSERT_EQUAL_MESSAGE(wideStringMsg, unsignedRandom, stringToNumber<std::uint64_t>(asWideString, base));
263  CPPUNIT_ASSERT_EQUAL_MESSAGE(bufferMsg, unsignedRandom, bufferToNumber<std::uint64_t>(asString.data(), asString.size(), base));
264  }
265  for (const auto base : initializer_list<std::uint8_t>{ 10 }) {
266  const auto asString = numberToString<std::int64_t, string>(signedRandom, static_cast<string::value_type>(base));
267  const auto asWideString = numberToString<std::int64_t, wstring>(signedRandom, base);
268  CPPUNIT_ASSERT_EQUAL_MESSAGE(stringMsg, signedRandom, stringToNumber<std::int64_t>(asString, base));
269  CPPUNIT_ASSERT_EQUAL_MESSAGE(wideStringMsg, signedRandom, stringToNumber<std::int64_t>(asWideString, base));
270  CPPUNIT_ASSERT_EQUAL_MESSAGE(bufferMsg, signedRandom, bufferToNumber<std::int64_t>(asString.data(), asString.size(), base));
271  }
272  }
273 
274  // stringToNumber() with spaces at the beginning, leading zeroes, different types and other corner cases
275  CPPUNIT_ASSERT_EQUAL(1, stringToNumber<std::int32_t>("01"));
276  CPPUNIT_ASSERT_EQUAL(1, stringToNumber<std::int32_t>(L"01"s));
277  CPPUNIT_ASSERT_EQUAL(1, stringToNumber<std::int32_t>(u"01"s));
278  CPPUNIT_ASSERT_EQUAL(-23, stringToNumber<std::int32_t>(" - 023"s));
279  CPPUNIT_ASSERT_EQUAL(-23, bufferToNumber<std::int32_t>(" - 023", 6));
280  CPPUNIT_ASSERT_EQUAL(1u, stringToNumber<std::uint32_t>("01"));
281  CPPUNIT_ASSERT_EQUAL(1u, stringToNumber<std::uint32_t>(L"01"s));
282  CPPUNIT_ASSERT_EQUAL(1u, stringToNumber<std::uint32_t>(u"01"s));
283  CPPUNIT_ASSERT_EQUAL(23u, stringToNumber<std::uint32_t>(" 023"s));
284  CPPUNIT_ASSERT_EQUAL(23u, bufferToNumber<std::uint32_t>(" 023", 5));
285  CPPUNIT_ASSERT_EQUAL(255u, stringToNumber<std::uint32_t>("fF", 16));
286  CPPUNIT_ASSERT_THROW_MESSAGE("character out of range", stringToNumber<std::uint32_t>("fF", 15), ConversionException);
287  CPPUNIT_ASSERT_THROW_MESSAGE("invalid character", stringToNumber<std::uint32_t>("(", 15), ConversionException);
288 #ifdef __GNUC__ // overflow detection only supported on GCC and Clang
289  CPPUNIT_ASSERT_THROW_MESSAGE("overflow", stringToNumber<std::uint32_t>("100000000", 16), ConversionException);
290  CPPUNIT_ASSERT_THROW_MESSAGE("underflow", stringToNumber<std::int32_t>("-80000001", 16), ConversionException);
291  CPPUNIT_ASSERT_EQUAL_MESSAGE("positive limit", 0xFFFFFFFFu, stringToNumber<std::uint32_t>("FFFFFFFF", 16));
292  CPPUNIT_ASSERT_EQUAL_MESSAGE("negative limit", -2147483647, stringToNumber<std::int32_t>("-2147483647", 10));
293 #endif
294 
295  // stringToNumber() / numberToString() with floating point numbers
296  CPPUNIT_ASSERT_EQUAL(1.5f, stringToNumber<float>(numberToString(1.5f)));
297  CPPUNIT_ASSERT_EQUAL(1.5, stringToNumber<double>(numberToString(1.5)));
298  CPPUNIT_ASSERT_EQUAL(-10.25, stringToNumber<double>("-10.25"));
299 
300  // interpretIntegerAsString()
301  CPPUNIT_ASSERT_EQUAL("TEST"s, interpretIntegerAsString<std::uint32_t>(0x54455354));
302 
303  // splitString() / joinStrings()
304  vector<string> splitTestExpected({ "1", "2,3" });
305  vector<string> splitTestActual = splitString<vector<string>>("1,2,3"s, ","s, EmptyPartsTreat::Keep, 2);
306  CPPUNIT_ASSERT_EQUAL(splitTestExpected, splitTestActual);
307  splitTestActual = splitStringSimple<vector<string>>("1,2,3"s, ","s, 2);
308  CPPUNIT_ASSERT_EQUAL(splitTestExpected, splitTestActual);
309  splitTestExpected = { "12", "34", "56", "" };
310  splitTestActual = splitString<vector<string>>("12,34,56,"s, ","s);
311  CPPUNIT_ASSERT_EQUAL(splitTestExpected, splitTestActual);
312  splitTestActual = splitStringSimple<vector<string>>("12,34,56,"s, ","s);
313  CPPUNIT_ASSERT_EQUAL(splitTestExpected, splitTestActual);
314  splitTestExpected = { "1", "2,3", "4,,5" };
315  splitTestActual = splitString<vector<string>>("1,2,,3,4,,5"s, ","s, EmptyPartsTreat::Merge, 3);
316  CPPUNIT_ASSERT_EQUAL(splitTestExpected, splitTestActual);
317  string splitJoinTest = joinStrings(splitString<vector<string>>(",a,,ab,ABC,s"s, ","s, EmptyPartsTreat::Keep), " "s, false, "("s, ")"s);
318  CPPUNIT_ASSERT_EQUAL("() (a) () (ab) (ABC) (s)"s, splitJoinTest);
319  splitJoinTest = joinStrings(splitString<vector<string>>(",a,,ab,ABC,s"s, ","s, EmptyPartsTreat::Keep), " "s, true, "("s, ")"s);
320  CPPUNIT_ASSERT_EQUAL("(a) (ab) (ABC) (s)"s, splitJoinTest);
321  splitJoinTest = joinStrings(splitStringSimple<vector<string>>(",a,,ab,ABC,s"s, ","s), " "s, true, "("s, ")"s);
322  CPPUNIT_ASSERT_EQUAL("(a) (ab) (ABC) (s)"s, splitJoinTest);
323  splitJoinTest = joinStrings(splitString<vector<string>>(",a,,ab,ABC,s"s, ","s, EmptyPartsTreat::Omit), " "s, false, "("s, ")"s);
324  CPPUNIT_ASSERT_EQUAL("(a) (ab) (ABC) (s)"s, splitJoinTest);
325  splitJoinTest = joinStrings(splitString<vector<string>>(",a,,ab,ABC,s"s, ","s, EmptyPartsTreat::Merge), " "s, false, "("s, ")"s);
326  CPPUNIT_ASSERT_EQUAL("(a,ab) (ABC) (s)"s, splitJoinTest);
327 
328  // findAndReplace()
329  string findReplaceTest("findAndReplace()");
330  findAndReplace<string>(findReplaceTest, "And", "Or");
331  CPPUNIT_ASSERT_EQUAL("findOrReplace()"s, findReplaceTest);
332 
333  // startsWith()
334  CPPUNIT_ASSERT(!startsWith(findReplaceTest, "findAnd"));
335  CPPUNIT_ASSERT(startsWith(findReplaceTest, "findOr"));
336  CPPUNIT_ASSERT(!startsWith(findReplaceTest, "findAnd"s));
337  CPPUNIT_ASSERT(startsWith(findReplaceTest, "findOr"s));
338  CPPUNIT_ASSERT(startsWith("test"s, "test"s));
339  CPPUNIT_ASSERT(startsWith("test"s, "test"));
340  CPPUNIT_ASSERT(!startsWith("test"s, "tests"s));
341  CPPUNIT_ASSERT(!startsWith("test"s, "tests"));
342 
343  // endsWith()
344  CPPUNIT_ASSERT(!endsWith(findReplaceTest, "AndReplace()"));
345  CPPUNIT_ASSERT(endsWith(findReplaceTest, "OrReplace()"));
346  CPPUNIT_ASSERT(!endsWith(findReplaceTest, "AndReplace()"s));
347  CPPUNIT_ASSERT(endsWith(findReplaceTest, "OrReplace()"s));
348  CPPUNIT_ASSERT(endsWith("test"s, "test"s));
349  CPPUNIT_ASSERT(endsWith("test"s, "test"));
350  CPPUNIT_ASSERT(!endsWith("test"s, " test"s));
351  CPPUNIT_ASSERT(!endsWith("test"s, " test"));
352 
353  // containsSubstrings()
354  CPPUNIT_ASSERT(containsSubstrings<string>("this string contains foo and bar", { "foo", "bar" }));
355  CPPUNIT_ASSERT(!containsSubstrings<string>("this string contains foo and bar", { "bar", "foo" }));
356 
357  // truncateString()
358  string truncateTest("foo bar ");
359  truncateString(truncateTest, ' ');
360  CPPUNIT_ASSERT_EQUAL("foo"s, truncateTest);
361 
362  // encodeBase64() / decodeBase64() with random data
363  uniform_int_distribution<std::uint8_t> randomDistChar;
364  std::uint8_t originalBase64Data[4047];
365  for (std::uint8_t &c : originalBase64Data) {
366  c = randomDistChar(m_randomEngine);
367  }
368  auto encodedBase64Data = encodeBase64(originalBase64Data, sizeof(originalBase64Data));
369  auto decodedBase64Data = decodeBase64(encodedBase64Data.data(), static_cast<std::uint32_t>(encodedBase64Data.size()));
370  CPPUNIT_ASSERT(decodedBase64Data.second == sizeof(originalBase64Data));
371  for (unsigned int i = 0; i < sizeof(originalBase64Data); ++i) {
372  CPPUNIT_ASSERT(decodedBase64Data.first[i] == originalBase64Data[i]);
373  }
374  // test padding
375  encodedBase64Data = encodeBase64(originalBase64Data, sizeof(originalBase64Data) - 1);
376  CPPUNIT_ASSERT_EQUAL('=', encodedBase64Data.at(encodedBase64Data.size() - 1));
377  CPPUNIT_ASSERT_NO_THROW(decodeBase64(encodedBase64Data.data(), static_cast<std::uint32_t>(encodedBase64Data.size())));
378  encodedBase64Data = encodeBase64(originalBase64Data, sizeof(originalBase64Data) - 2);
379  CPPUNIT_ASSERT_EQUAL('=', encodedBase64Data.at(encodedBase64Data.size() - 1));
380  CPPUNIT_ASSERT_EQUAL('=', encodedBase64Data.at(encodedBase64Data.size() - 2));
381  CPPUNIT_ASSERT_NO_THROW(decodeBase64(encodedBase64Data.data(), static_cast<std::uint32_t>(encodedBase64Data.size())));
382  // test check for invalid size
383  CPPUNIT_ASSERT_THROW(decodeBase64(encodedBase64Data.data(), 3), ConversionException);
384 
385  // dataSizeToString(), bitrateToString()
386  CPPUNIT_ASSERT_EQUAL("512 bytes"s, dataSizeToString(512ull));
387  CPPUNIT_ASSERT_EQUAL("2.50 KiB"s, dataSizeToString((2048ull + 512ull)));
388  CPPUNIT_ASSERT_EQUAL("2.50 KiB (2560 byte)"s, dataSizeToString((2048ull + 512ull), true));
389  CPPUNIT_ASSERT_EQUAL("2.50 MiB"s, dataSizeToString((2048ull + 512ull) * 1024ull));
390  CPPUNIT_ASSERT_EQUAL("2.50 GiB"s, dataSizeToString((2048ull + 512ull) * 1024ull * 1024ull));
391  CPPUNIT_ASSERT_EQUAL("2.50 TiB"s, dataSizeToString((2048ull + 512ull) * 1024ull * 1024ull * 1024ull));
392  CPPUNIT_ASSERT_EQUAL("128 bit/s"s, bitrateToString(0.128, false));
393  CPPUNIT_ASSERT_EQUAL("128 kbit/s"s, bitrateToString(128.0, false));
394  CPPUNIT_ASSERT_EQUAL("128 Mbit/s"s, bitrateToString(128.0 * 1e3, false));
395  CPPUNIT_ASSERT_EQUAL("128 Gbit/s"s, bitrateToString(128.0 * 1e6, false));
396  CPPUNIT_ASSERT_EQUAL("16 byte/s"s, bitrateToString(0.128, true));
397  CPPUNIT_ASSERT_EQUAL("16 KiB/s"s, bitrateToString(128.0, true));
398  CPPUNIT_ASSERT_EQUAL("16 MiB/s"s, bitrateToString(128.0 * 1e3, true));
399  CPPUNIT_ASSERT_EQUAL("16 GiB/s"s, bitrateToString(128.0 * 1e6, true));
400 }
401 
403 
404 struct ConvertibleToString {
405  operator std::string() const;
406 };
407 
408 struct StringThatDoesNotLikeToBeCopiedOrMoved : public std::string {
409  explicit StringThatDoesNotLikeToBeCopiedOrMoved(const char *value)
410  : std::string(value)
411  {
412  }
413  [[noreturn]] StringThatDoesNotLikeToBeCopiedOrMoved(const StringThatDoesNotLikeToBeCopiedOrMoved &other)
414  : std::string(other)
415  {
416  CPPUNIT_FAIL("attempt to copy string: " + other);
417  }
418  [[noreturn]] StringThatDoesNotLikeToBeCopiedOrMoved(StringThatDoesNotLikeToBeCopiedOrMoved &&other)
419  : std::string(std::move(other))
420  {
421  CPPUNIT_FAIL("attempt to move string: " + other);
422  }
423 };
424 
426 
428 {
429  // check whether type traits work as expected
430  static_assert(Helper::IsStringType<std::string, std::string>::value);
431  static_assert(!Helper::IsStringType<std::string, std::wstring>::value);
432  static_assert(Helper::IsStringType<std::wstring, std::wstring>::value);
433  static_assert(Helper::IsStringViewType<std::string, std::string_view>::value);
434  static_assert(!Helper::IsStringViewType<std::wstring, std::string_view>::value);
435  static_assert(Helper::IsStringViewType<std::wstring, std::wstring_view>::value);
436  static_assert(Helper::IsConvertibleToConstStringRef<std::string, ConvertibleToString>::value);
437 #ifdef CPP_UTILITIES_USE_STANDARD_FILESYSTEM
438  static_assert(!Helper::IsConvertibleToConstStringRef<std::filesystem::path::string_type, std::filesystem::path>::value,
439  "conversion via native() preferred");
440 #endif
441  static_assert(
442  !Helper::IsConvertibleToConstStringRef<std::string, std::string>::value, "yes, in this context this should not be considered convertible");
443  static_assert(!Helper::IsConvertibleToConstStringRef<std::wstring, ConvertibleToString>::value);
444 #ifdef CPP_UTILITIES_USE_STANDARD_FILESYSTEM
445  static_assert(Helper::IsConvertibleToConstStringRefViaNative<std::filesystem::path::string_type, std::filesystem::path>::value);
446 #endif
447  static_assert(!Helper::IsConvertibleToConstStringRefViaNative<std::string, std::string>::value);
448 
449  // conversion of string-tuple to string (the actual string builder)
450  const tuple<const char *, string, int, const char *> tuple("string1", "string2", 1234, "string3");
451  CPPUNIT_ASSERT_EQUAL("string1string21234string3"s, tupleToString(tuple));
452  CPPUNIT_ASSERT_EQUAL("foobarfoo2bar2"s, tupleToString("foo"s % "bar" % "foo2"s % "bar2"));
453  CPPUNIT_ASSERT_EQUAL("v2.3.0"s, argsToString("v2.", 3, '.', 0));
454  CPPUNIT_ASSERT_EQUAL("v2.3.0"s, argsToString('v', make_tuple(2, '.', 3, '.', 0)));
455 #ifdef CPP_UTILITIES_USE_STANDARD_FILESYSTEM
456  if constexpr (std::is_same_v<std::filesystem::path::value_type, std::string::value_type>) {
457  CPPUNIT_ASSERT_EQUAL("path: foo"s, argsToString("path: ", std::filesystem::path("foo")));
458  }
459 #endif
460 
461  // construction of string-tuple and final conversion to string works
462  CPPUNIT_ASSERT_EQUAL_MESSAGE("result can be passed to any function taking a std::string"s, "123456789"s, "12" % string("34") % '5' % 67 + "89");
463  constexpr double velocityExample = 27.0;
464  CPPUNIT_ASSERT_EQUAL_MESSAGE("real-word example"s, "velocity: 27 km/h (7.5 m/s)"s,
465  "velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)");
466  CPPUNIT_ASSERT_EQUAL_MESSAGE(
467  "regular + operator still works (no problems with ambiguity)"s, "regular + still works"s, "regular"s + " + still works");
468  CPPUNIT_ASSERT_EQUAL_MESSAGE("using string_view", "foobar123"s, "foo"sv % "bar"sv + 123);
469 
470  // check that for the internal tuple construction no copies are made
471  StringThatDoesNotLikeToBeCopiedOrMoved str(" happen ");
472  const StringThatDoesNotLikeToBeCopiedOrMoved str2("for this");
473  CPPUNIT_ASSERT_EQUAL("no copy/move should happen for this!"s,
474  argsToString(StringThatDoesNotLikeToBeCopiedOrMoved("no copy/move should"), str, str2, StringThatDoesNotLikeToBeCopiedOrMoved("!")));
475 }
The ConversionTests class tests classes and functions provided by the files inside the conversion dir...
void testSwapOrderFunctions()
Tests swap order functions.
void testBinaryConversions()
Tests most important binary conversions.
void testStringEncodingConversions()
Tests string encoding conversions.
void testConversionException()
void testEndianness()
Tests whether macros for endianness are correct.
void testStringConversions()
Tests miscellaneous string conversions.
The ConversionException class is thrown by the various conversion functions of this library when a co...
#define LE_STR_FOR_ENDIANNESS(name)
Selects right string for little-endian checks.
void assertEqual(const char *message, const std::uint8_t *expectedValues, size_t expectedSize, const StringData &actualValues)
Internally used for string encoding tests to check results.
#define TEST_BE_CONVERSION(function)
#define BE_STR_FOR_ENDIANNESS(name)
Selects right string for big-endian checks.
#define TEST_LE_CONVERSION(function)
#define TEST_CUSTOM_CONVERSION(vice, versa, endianness, min, max)
CPPUNIT_TEST_SUITE_REGISTRATION(ConversionTests)
Contains all utilities provides by the c++utilities library.
CPP_UTILITIES_EXPORT StringData convertUtf8ToUtf16BE(const char *inputBuffer, std::size_t inputBufferSize)
Converts the specified UTF-8 string to UTF-16 (big-endian).
CPP_UTILITIES_EXPORT StringData convertString(const char *fromCharset, const char *toCharset, const char *inputBuffer, std::size_t inputBufferSize, float outputBufferSizeFactor=1.0f)
Converts the specified string from one character set to another.
StringType numberToString(IntegralType number, BaseType base=10)
Converts the given number to its equivalent string representation using the specified base.
CPP_UTILITIES_EXPORT StringData convertLatin1ToUtf8(const char *inputBuffer, std::size_t inputBufferSize)
Converts the specified Latin-1 string to UTF-8.
CPP_UTILITIES_EXPORT StringData convertUtf16LEToUtf8(const char *inputBuffer, std::size_t inputBufferSize)
Converts the specified UTF-16 (little-endian) string to UTF-8.
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...
Definition: testutils.h:232
CPP_UTILITIES_EXPORT std::pair< std::unique_ptr< std::uint8_t[]>, std::uint32_t > decodeBase64(const char *encodedStr, const std::uint32_t strSize)
Decodes the specified Base64 encoded string.
ReturnType joinStrings(const Container &strings, Detail::StringParamForContainer< Container > delimiter=Detail::StringParamForContainer< Container >(), bool omitEmpty=false, Detail::StringParamForContainer< Container > leftClosure=Detail::StringParamForContainer< Container >(), Detail::StringParamForContainer< Container > rightClosure=Detail::StringParamForContainer< Container >())
Joins the given strings using the specified delimiter.
constexpr CPP_UTILITIES_EXPORT std::uint16_t swapOrder(std::uint16_t value)
Swaps the byte order of the specified 16-bit unsigned integer.
bool startsWith(const StringType &str, const StringType &phrase)
Returns whether str starts with phrase.
CPP_UTILITIES_EXPORT void truncateString(std::string &str, char terminationChar='\0')
Truncates all characters after the first occurrence of the specified terminationChar and the terminat...
std::pair< std::unique_ptr< char[], StringDataDeleter >, std::size_t > StringData
Type used to return string encoding conversion result.
CPP_UTILITIES_EXPORT StringData convertUtf16BEToUtf8(const char *inputBuffer, std::size_t inputBufferSize)
Converts the specified UTF-16 (big-endian) string to UTF-8.
Container splitStringSimple(Detail::StringParamForContainer< Container > string, Detail::StringParamForContainer< Container > delimiter, int maxParts=-1)
Splits the given string (which might also be a string view) at the specified delimiter.
StringType argsToString(Args &&...args)
constexpr T max(T first, T second)
Returns the greatest of the given items.
Definition: math.h:100
StringType tupleToString(const std::tuple< Args... > &tuple)
Concatenates all strings hold by the specified tuple.
CPP_UTILITIES_EXPORT StringData convertUtf8ToLatin1(const char *inputBuffer, std::size_t inputBufferSize)
Converts the specified UTF-8 string to Latin-1.
bool endsWith(const StringType &str, const StringType &phrase)
Returns whether str ends with phrase.
constexpr CPP_UTILITIES_EXPORT std::uint32_t toNormalInt(std::uint32_t synchsafeInt)
Returns a normal 32-bit integer converted from a 32-bit synchsafe integer.
CPP_UTILITIES_EXPORT StringData convertUtf8ToUtf16LE(const char *inputBuffer, std::size_t inputBufferSize)
Converts the specified UTF-8 string to UTF-16 (little-endian).
CPP_UTILITIES_EXPORT std::string bitrateToString(double speedInKbitsPerSecond, bool useByteInsteadOfBits=false)
Converts the specified bitrate in kbit/s to its equivalent std::string representation.
constexpr T min(T first, T second)
Returns the smallest of the given items.
Definition: math.h:88
constexpr CPP_UTILITIES_EXPORT std::uint32_t toSynchsafeInt(std::uint32_t normalInt)
Returns a 32-bit synchsafe integer converted from a normal 32-bit integer.
CPP_UTILITIES_EXPORT std::string encodeBase64(const std::uint8_t *data, std::uint32_t dataSize)
Encodes the specified data to Base64.
CPP_UTILITIES_EXPORT std::string dataSizeToString(std::uint64_t sizeInByte, bool includeByte=false)
Converts the specified data size in byte to its equivalent std::string representation.
Container splitString(Detail::StringParamForContainer< Container > string, Detail::StringParamForContainer< Container > delimiter, EmptyPartsTreat emptyPartsRole=EmptyPartsTreat::Keep, int maxParts=-1)
Splits the given string at the specified delimiter.
constexpr int i