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