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