C++ Utilities  5.11.0
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  CPPUNIT_ASSERT_EQUAL_MESSAGE("empty string", vector<string>({ string() }), splitString<vector<string>>(string(), ","));
305  CPPUNIT_ASSERT_EQUAL_MESSAGE(
306  "empty string (simple)", vector<string_view>({ string_view() }), splitStringSimple<vector<string_view>>(string_view(), ","));
307  vector<string> splitTestExpected({ "1", "2,3" });
308  vector<string> splitTestActual = splitString<vector<string>>("1,2,3"s, ","s, EmptyPartsTreat::Keep, 2);
309  CPPUNIT_ASSERT_EQUAL(splitTestExpected, splitTestActual);
310  splitTestActual = splitStringSimple<vector<string>>("1,2,3"s, ","s, 2);
311  CPPUNIT_ASSERT_EQUAL(splitTestExpected, splitTestActual);
312  splitTestExpected = { "12", "34", "56", "" };
313  splitTestActual = splitString<vector<string>>("12,34,56,"s, ","s);
314  CPPUNIT_ASSERT_EQUAL(splitTestExpected, splitTestActual);
315  splitTestActual = splitStringSimple<vector<string>>("12,34,56,"s, ","s);
316  CPPUNIT_ASSERT_EQUAL(splitTestExpected, splitTestActual);
317  splitTestExpected = { "1", "2,3", "4,,5" };
318  splitTestActual = splitString<vector<string>>("1,2,,3,4,,5"s, ","s, EmptyPartsTreat::Merge, 3);
319  CPPUNIT_ASSERT_EQUAL(splitTestExpected, splitTestActual);
320  string splitJoinTest = joinStrings(splitString<vector<string>>(",a,,ab,ABC,s"s, ","s, EmptyPartsTreat::Keep), " "s, false, "("s, ")"s);
321  CPPUNIT_ASSERT_EQUAL("() (a) () (ab) (ABC) (s)"s, splitJoinTest);
322  splitJoinTest = joinStrings(splitString<vector<string>>(",a,,ab,ABC,s"s, ","s, EmptyPartsTreat::Keep), " "s, true, "("s, ")"s);
323  CPPUNIT_ASSERT_EQUAL("(a) (ab) (ABC) (s)"s, splitJoinTest);
324  splitJoinTest = joinStrings(splitStringSimple<vector<string>>(",a,,ab,ABC,s"s, ","s), " "s, true, "("s, ")"s);
325  CPPUNIT_ASSERT_EQUAL("(a) (ab) (ABC) (s)"s, splitJoinTest);
326  splitJoinTest = joinStrings(splitString<vector<string>>(",a,,ab,ABC,s"s, ","s, EmptyPartsTreat::Omit), " "s, false, "("s, ")"s);
327  CPPUNIT_ASSERT_EQUAL("(a) (ab) (ABC) (s)"s, splitJoinTest);
328  splitJoinTest = joinStrings(splitString<vector<string>>(",a,,ab,ABC,s"s, ","s, EmptyPartsTreat::Merge), " "s, false, "("s, ")"s);
329  CPPUNIT_ASSERT_EQUAL("(a,ab) (ABC) (s)"s, splitJoinTest);
330 
331  // findAndReplace()
332  string findReplaceTest("findAndReplace()");
333  findAndReplace<string>(findReplaceTest, "And", "Or");
334  CPPUNIT_ASSERT_EQUAL("findOrReplace()"s, findReplaceTest);
335 
336  // startsWith()
337  CPPUNIT_ASSERT(!startsWith(findReplaceTest, "findAnd"));
338  CPPUNIT_ASSERT(startsWith(findReplaceTest, "findOr"));
339  CPPUNIT_ASSERT(!startsWith(findReplaceTest, "findAnd"s));
340  CPPUNIT_ASSERT(startsWith(findReplaceTest, "findOr"s));
341  CPPUNIT_ASSERT(startsWith("test"s, "test"s));
342  CPPUNIT_ASSERT(startsWith("test"s, "test"));
343  CPPUNIT_ASSERT(!startsWith("test"s, "tests"s));
344  CPPUNIT_ASSERT(!startsWith("test"s, "tests"));
345 
346  // endsWith()
347  CPPUNIT_ASSERT(!endsWith(findReplaceTest, "AndReplace()"));
348  CPPUNIT_ASSERT(endsWith(findReplaceTest, "OrReplace()"));
349  CPPUNIT_ASSERT(!endsWith(findReplaceTest, "AndReplace()"s));
350  CPPUNIT_ASSERT(endsWith(findReplaceTest, "OrReplace()"s));
351  CPPUNIT_ASSERT(endsWith("test"s, "test"s));
352  CPPUNIT_ASSERT(endsWith("test"s, "test"));
353  CPPUNIT_ASSERT(!endsWith("test"s, " test"s));
354  CPPUNIT_ASSERT(!endsWith("test"s, " test"));
355 
356  // containsSubstrings()
357  CPPUNIT_ASSERT(containsSubstrings<string>("this string contains foo and bar", { "foo", "bar" }));
358  CPPUNIT_ASSERT(!containsSubstrings<string>("this string contains foo and bar", { "bar", "foo" }));
359 
360  // truncateString()
361  string truncateTest("foo bar ");
362  truncateString(truncateTest, ' ');
363  CPPUNIT_ASSERT_EQUAL("foo"s, truncateTest);
364 
365  // encodeBase64() / decodeBase64() with random data
366  uniform_int_distribution<std::uint8_t> randomDistChar;
367  std::uint8_t originalBase64Data[4047];
368  for (std::uint8_t &c : originalBase64Data) {
369  c = randomDistChar(m_randomEngine);
370  }
371  auto encodedBase64Data = encodeBase64(originalBase64Data, sizeof(originalBase64Data));
372  auto decodedBase64Data = decodeBase64(encodedBase64Data.data(), static_cast<std::uint32_t>(encodedBase64Data.size()));
373  CPPUNIT_ASSERT(decodedBase64Data.second == sizeof(originalBase64Data));
374  for (unsigned int i = 0; i < sizeof(originalBase64Data); ++i) {
375  CPPUNIT_ASSERT(decodedBase64Data.first[i] == originalBase64Data[i]);
376  }
377  // test padding
378  encodedBase64Data = encodeBase64(originalBase64Data, sizeof(originalBase64Data) - 1);
379  CPPUNIT_ASSERT_EQUAL('=', encodedBase64Data.at(encodedBase64Data.size() - 1));
380  CPPUNIT_ASSERT_NO_THROW(decodeBase64(encodedBase64Data.data(), static_cast<std::uint32_t>(encodedBase64Data.size())));
381  encodedBase64Data = encodeBase64(originalBase64Data, sizeof(originalBase64Data) - 2);
382  CPPUNIT_ASSERT_EQUAL('=', encodedBase64Data.at(encodedBase64Data.size() - 1));
383  CPPUNIT_ASSERT_EQUAL('=', encodedBase64Data.at(encodedBase64Data.size() - 2));
384  CPPUNIT_ASSERT_NO_THROW(decodeBase64(encodedBase64Data.data(), static_cast<std::uint32_t>(encodedBase64Data.size())));
385  // test check for invalid size
386  CPPUNIT_ASSERT_THROW(decodeBase64(encodedBase64Data.data(), 3), ConversionException);
387 
388  // dataSizeToString(), bitrateToString()
389  CPPUNIT_ASSERT_EQUAL("512 bytes"s, dataSizeToString(512ull));
390  CPPUNIT_ASSERT_EQUAL("2.50 KiB"s, dataSizeToString((2048ull + 512ull)));
391  CPPUNIT_ASSERT_EQUAL("2.50 KiB (2560 byte)"s, dataSizeToString((2048ull + 512ull), true));
392  CPPUNIT_ASSERT_EQUAL("2.50 MiB"s, dataSizeToString((2048ull + 512ull) * 1024ull));
393  CPPUNIT_ASSERT_EQUAL("2.50 GiB"s, dataSizeToString((2048ull + 512ull) * 1024ull * 1024ull));
394  CPPUNIT_ASSERT_EQUAL("2.50 TiB"s, dataSizeToString((2048ull + 512ull) * 1024ull * 1024ull * 1024ull));
395  CPPUNIT_ASSERT_EQUAL("128 bit/s"s, bitrateToString(0.128, false));
396  CPPUNIT_ASSERT_EQUAL("128 kbit/s"s, bitrateToString(128.0, false));
397  CPPUNIT_ASSERT_EQUAL("128 Mbit/s"s, bitrateToString(128.0 * 1e3, false));
398  CPPUNIT_ASSERT_EQUAL("128 Gbit/s"s, bitrateToString(128.0 * 1e6, false));
399  CPPUNIT_ASSERT_EQUAL("16 byte/s"s, bitrateToString(0.128, true));
400  CPPUNIT_ASSERT_EQUAL("16 KiB/s"s, bitrateToString(128.0, true));
401  CPPUNIT_ASSERT_EQUAL("16 MiB/s"s, bitrateToString(128.0 * 1e3, true));
402  CPPUNIT_ASSERT_EQUAL("16 GiB/s"s, bitrateToString(128.0 * 1e6, true));
403 }
404 
406 
407 struct ConvertibleToString {
408  operator std::string() const;
409 };
410 
411 struct StringThatDoesNotLikeToBeCopiedOrMoved : public std::string {
412  explicit StringThatDoesNotLikeToBeCopiedOrMoved(const char *value)
413  : std::string(value)
414  {
415  }
416  [[noreturn]] StringThatDoesNotLikeToBeCopiedOrMoved(const StringThatDoesNotLikeToBeCopiedOrMoved &other)
417  : std::string(other)
418  {
419  CPPUNIT_FAIL("attempt to copy string: " + other);
420  }
421  [[noreturn]] StringThatDoesNotLikeToBeCopiedOrMoved(StringThatDoesNotLikeToBeCopiedOrMoved &&other)
422  : std::string(std::move(other))
423  {
424  CPPUNIT_FAIL("attempt to move string: " + other);
425  }
426 };
427 
429 
431 {
432  // check whether type traits work as expected
433  static_assert(Helper::IsStringType<std::string, std::string>::value);
434  static_assert(!Helper::IsStringType<std::string, std::wstring>::value);
435  static_assert(Helper::IsStringType<std::wstring, std::wstring>::value);
436  static_assert(Helper::IsStringViewType<std::string, std::string_view>::value);
437  static_assert(!Helper::IsStringViewType<std::wstring, std::string_view>::value);
438  static_assert(Helper::IsStringViewType<std::wstring, std::wstring_view>::value);
439  static_assert(Helper::IsConvertibleToConstStringRef<std::string, ConvertibleToString>::value);
440 #ifdef CPP_UTILITIES_USE_STANDARD_FILESYSTEM
441  static_assert(!Helper::IsConvertibleToConstStringRef<std::filesystem::path::string_type, std::filesystem::path>::value,
442  "conversion via native() preferred");
443 #endif
444  static_assert(
445  !Helper::IsConvertibleToConstStringRef<std::string, std::string>::value, "yes, in this context this should not be considered convertible");
446  static_assert(!Helper::IsConvertibleToConstStringRef<std::wstring, ConvertibleToString>::value);
447 #ifdef CPP_UTILITIES_USE_STANDARD_FILESYSTEM
448  static_assert(Helper::IsConvertibleToConstStringRefViaNative<std::filesystem::path::string_type, std::filesystem::path>::value);
449 #endif
450  static_assert(!Helper::IsConvertibleToConstStringRefViaNative<std::string, std::string>::value);
451 
452  // conversion of string-tuple to string (the actual string builder)
453  const tuple<const char *, string, int, const char *> tuple("string1", "string2", 1234, "string3");
454  CPPUNIT_ASSERT_EQUAL("string1string21234string3"s, tupleToString(tuple));
455  CPPUNIT_ASSERT_EQUAL("foobarfoo2bar2"s, tupleToString("foo"s % "bar" % "foo2"s % "bar2"));
456  CPPUNIT_ASSERT_EQUAL("v2.3.0"s, argsToString("v2.", 3, '.', 0));
457  CPPUNIT_ASSERT_EQUAL("v2.3.0"s, argsToString('v', make_tuple(2, '.', 3, '.', 0)));
458 #ifdef CPP_UTILITIES_USE_STANDARD_FILESYSTEM
459  if constexpr (std::is_same_v<std::filesystem::path::value_type, std::string::value_type>) {
460  CPPUNIT_ASSERT_EQUAL("path: foo"s, argsToString("path: ", std::filesystem::path("foo")));
461  }
462 #endif
463 
464  // construction of string-tuple and final conversion to string works
465  CPPUNIT_ASSERT_EQUAL_MESSAGE("result can be passed to any function taking a std::string"s, "123456789"s, "12" % string("34") % '5' % 67 + "89");
466  constexpr double velocityExample = 27.0;
467  CPPUNIT_ASSERT_EQUAL_MESSAGE("real-word example"s, "velocity: 27 km/h (7.5 m/s)"s,
468  "velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)");
469  CPPUNIT_ASSERT_EQUAL_MESSAGE(
470  "regular + operator still works (no problems with ambiguity)"s, "regular + still works"s, "regular"s + " + still works");
471  CPPUNIT_ASSERT_EQUAL_MESSAGE("using string_view", "foobar123"s, "foo"sv % "bar"sv + 123);
472 
473  // check that for the internal tuple construction no copies are made
474  StringThatDoesNotLikeToBeCopiedOrMoved str(" happen ");
475  const StringThatDoesNotLikeToBeCopiedOrMoved str2("for this");
476  CPPUNIT_ASSERT_EQUAL("no copy/move should happen for this!"s,
477  argsToString(StringThatDoesNotLikeToBeCopiedOrMoved("no copy/move should"), str, str2, StringThatDoesNotLikeToBeCopiedOrMoved("!")));
478 }
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