C++ Utilities 5.27.0
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#ifndef CPP_UTILITIES_NO_ICONV
216 // define test string "ABCD" for the different encodings
217 const std::uint8_t simpleString[] = { 'A', 'B', 'C', 'D' };
218 const std::uint16_t simpleUtf16LEString[] = { 0x0041, 0x0042, 0x0043, 0x0044 };
219 const std::uint16_t simpleUtf16BEString[] = { 0x4100, 0x4200, 0x4300, 0x4400 };
220 // define test string "ABĂ–CD" for the different encodings
221 const std::uint8_t latin1String[] = { 'A', 'B', 0xD6, 'C', 'D' };
222 const std::uint8_t utf8String[] = { 'A', 'B', 0xC3, 0x96, 'C', 'D' };
223 const std::uint16_t utf16LEString[] = { 0x0041, 0x0042, 0x00D6, 0x0043, 0x0044 };
224 const std::uint16_t utf16BEString[] = { 0x4100, 0x4200, 0xD600, 0x4300, 0x4400 };
225 // test conversion to UTF-8
226 assertEqual("Latin-1 to UTF-8 (simple)", simpleString, 4, convertLatin1ToUtf8(reinterpret_cast<const char *>(simpleString), 4));
227 assertEqual("Latin-1 to UTF-8", utf8String, 6, convertLatin1ToUtf8(reinterpret_cast<const char *>(latin1String), 5));
229 "UTF-16LE to UTF-8 (simple)", simpleString, 4, convertUtf16LEToUtf8(reinterpret_cast<const char *>(LE_STR_FOR_ENDIANNESS(simpleUtf16)), 8));
230 assertEqual("UTF-16LE to UTF-8", utf8String, 6, convertUtf16LEToUtf8(reinterpret_cast<const char *>(LE_STR_FOR_ENDIANNESS(utf16)), 10));
232 "UTF-16BE to UTF-8 (simple)", simpleString, 4, convertUtf16BEToUtf8(reinterpret_cast<const char *>(BE_STR_FOR_ENDIANNESS(simpleUtf16)), 8));
233 assertEqual("UTF-16BE to UTF-8", utf8String, 6, convertUtf16BEToUtf8(reinterpret_cast<const char *>(BE_STR_FOR_ENDIANNESS(utf16)), 10));
234 // test conversion from UTF-8
235 assertEqual("UTF-8 to Latin-1 (simple)", simpleString, 4, convertUtf8ToLatin1(reinterpret_cast<const char *>(simpleString), 4));
236 assertEqual("UTF-8 to Latin-1", latin1String, 5, convertUtf8ToLatin1(reinterpret_cast<const char *>(utf8String), 6));
237 assertEqual("UTF-8 to UFT-16LE (simple)", reinterpret_cast<const std::uint8_t *>(LE_STR_FOR_ENDIANNESS(simpleUtf16)), 8,
238 convertUtf8ToUtf16LE(reinterpret_cast<const char *>(simpleString), 4));
239 assertEqual("UTF-8 to UFT-16LE", reinterpret_cast<const std::uint8_t *>(LE_STR_FOR_ENDIANNESS(utf16)), 10,
240 convertUtf8ToUtf16LE(reinterpret_cast<const char *>(utf8String), 6));
241 assertEqual("UTF-8 to UFT-16BE (simple)", reinterpret_cast<const std::uint8_t *>(BE_STR_FOR_ENDIANNESS(simpleUtf16)), 8,
242 convertUtf8ToUtf16BE(reinterpret_cast<const char *>(simpleString), 4));
243 assertEqual("UTF-8 to UFT-16BE", reinterpret_cast<const std::uint8_t *>(BE_STR_FOR_ENDIANNESS(utf16)), 10,
244 convertUtf8ToUtf16BE(reinterpret_cast<const char *>(utf8String), 6));
245 CPPUNIT_ASSERT_THROW(convertString("invalid charset", "UTF-8", "foo", 3, 1.0f), ConversionException);
246#endif
247}
248
253{
254 // stringToNumber() / numberToString() with zero and random numbers
255 CPPUNIT_ASSERT_EQUAL("0"s, numberToString<unsigned int>(0));
256 CPPUNIT_ASSERT_EQUAL("0"s, numberToString<signed int>(0));
257 uniform_int_distribution<std::int64_t> randomDistSigned(numeric_limits<std::int64_t>::min());
258 uniform_int_distribution<std::uint64_t> randomDistUnsigned(0);
259 const string stringMsg("string"), wideStringMsg("wide string"), bufferMsg("buffer");
260 for (std::uint8_t b = 1; b < 100; ++b) {
261 auto signedRandom = randomDistSigned(m_randomEngine);
262 auto unsignedRandom = randomDistUnsigned(m_randomEngine);
263 for (const auto base : initializer_list<std::uint8_t>{ 2, 8, 10, 16 }) {
264 const auto asString = numberToString<std::uint64_t, string>(unsignedRandom, base);
265 const auto asWideString = numberToString<std::uint64_t, wstring>(unsignedRandom, base);
266 CPPUNIT_ASSERT_EQUAL_MESSAGE(stringMsg, unsignedRandom, stringToNumber<std::uint64_t>(asString, base));
267 CPPUNIT_ASSERT_EQUAL_MESSAGE(wideStringMsg, unsignedRandom, stringToNumber<std::uint64_t>(asWideString, base));
268 CPPUNIT_ASSERT_EQUAL_MESSAGE(bufferMsg, unsignedRandom, bufferToNumber<std::uint64_t>(asString.data(), asString.size(), base));
269 }
270 for (const auto base : initializer_list<std::uint8_t>{ 10 }) {
271 const auto asString = numberToString<std::int64_t, string>(signedRandom, static_cast<string::value_type>(base));
272 const auto asWideString = numberToString<std::int64_t, wstring>(signedRandom, base);
273 CPPUNIT_ASSERT_EQUAL_MESSAGE(stringMsg, signedRandom, stringToNumber<std::int64_t>(asString, base));
274 CPPUNIT_ASSERT_EQUAL_MESSAGE(wideStringMsg, signedRandom, stringToNumber<std::int64_t>(asWideString, base));
275 CPPUNIT_ASSERT_EQUAL_MESSAGE(bufferMsg, signedRandom, bufferToNumber<std::int64_t>(asString.data(), asString.size(), base));
276 }
277 }
278
279 // stringToNumber() with spaces at the beginning, leading zeroes, different types and other corner cases
280 CPPUNIT_ASSERT_EQUAL(1, stringToNumber<std::int32_t>("01"));
281 CPPUNIT_ASSERT_EQUAL(1, stringToNumber<std::int32_t>(L"01"s));
282 CPPUNIT_ASSERT_EQUAL(1, stringToNumber<std::int32_t>(u"01"s));
283 CPPUNIT_ASSERT_EQUAL(-23, stringToNumber<std::int32_t>(" - 023"s));
284 CPPUNIT_ASSERT_EQUAL(-23, bufferToNumber<std::int32_t>(" - 023", 6));
285 CPPUNIT_ASSERT_EQUAL(1u, stringToNumber<std::uint32_t>("01"));
286 CPPUNIT_ASSERT_EQUAL(1u, stringToNumber<std::uint32_t>(L"01"s));
287 CPPUNIT_ASSERT_EQUAL(1u, stringToNumber<std::uint32_t>(u"01"s));
288 CPPUNIT_ASSERT_EQUAL(23u, stringToNumber<std::uint32_t>(" 023"s));
289 CPPUNIT_ASSERT_EQUAL(23u, bufferToNumber<std::uint32_t>(" 023", 5));
290 CPPUNIT_ASSERT_EQUAL(255u, stringToNumber<std::uint32_t>("fF", 16));
291 CPPUNIT_ASSERT_THROW_MESSAGE("character out of range", stringToNumber<std::uint32_t>("fF", 15), ConversionException);
292 CPPUNIT_ASSERT_THROW_MESSAGE("invalid character", stringToNumber<std::uint32_t>("(", 15), ConversionException);
293#ifdef __GNUC__ // overflow detection only supported on GCC and Clang
294 CPPUNIT_ASSERT_THROW_MESSAGE("overflow", stringToNumber<std::uint32_t>("100000000", 16), ConversionException);
295 CPPUNIT_ASSERT_THROW_MESSAGE("underflow", stringToNumber<std::int32_t>("-80000001", 16), ConversionException);
296 CPPUNIT_ASSERT_EQUAL_MESSAGE("positive limit", 0xFFFFFFFFu, stringToNumber<std::uint32_t>("FFFFFFFF", 16));
297 CPPUNIT_ASSERT_EQUAL_MESSAGE("negative limit", -2147483647, stringToNumber<std::int32_t>("-2147483647", 10));
298#endif
299
300 // stringToNumber() / numberToString() with floating point numbers
301 CPPUNIT_ASSERT_EQUAL(1.5f, stringToNumber<float>(numberToString(1.5f)));
302 CPPUNIT_ASSERT_EQUAL(1.5, stringToNumber<double>(numberToString(1.5)));
303 CPPUNIT_ASSERT_EQUAL(-10.25, stringToNumber<double>("-10.25"));
304
305 // interpretIntegerAsString()
306 CPPUNIT_ASSERT_EQUAL("TEST"s, interpretIntegerAsString<std::uint32_t>(0x54455354));
307
308 // splitString() / joinStrings()
309 CPPUNIT_ASSERT_EQUAL_MESSAGE("empty string", vector<string>({ string() }), splitString<vector<string>>(string(), ","));
310 CPPUNIT_ASSERT_EQUAL_MESSAGE(
311 "empty string (simple)", vector<string_view>({ string_view() }), splitStringSimple<vector<string_view>>(string_view(), ","));
312 vector<string> splitTestExpected({ "1", "2,3" });
313 vector<string> splitTestActual = splitString<vector<string>>("1,2,3"s, ","s, EmptyPartsTreat::Keep, 2);
314 CPPUNIT_ASSERT_EQUAL(splitTestExpected, splitTestActual);
315 splitTestActual = splitStringSimple<vector<string>>("1,2,3"s, ","s, 2);
316 CPPUNIT_ASSERT_EQUAL(splitTestExpected, splitTestActual);
317 splitTestExpected = { "12", "34", "56", "" };
318 splitTestActual = splitString<vector<string>>("12,34,56,"s, ","s);
319 CPPUNIT_ASSERT_EQUAL(splitTestExpected, splitTestActual);
320 splitTestActual = splitStringSimple<vector<string>>("12,34,56,"s, ","s);
321 CPPUNIT_ASSERT_EQUAL(splitTestExpected, splitTestActual);
322 splitTestExpected = { "1", "2,3", "4,,5" };
323 splitTestActual = splitString<vector<string>>("1,2,,3,4,,5"s, ","s, EmptyPartsTreat::Merge, 3);
324 CPPUNIT_ASSERT_EQUAL(splitTestExpected, splitTestActual);
325 string splitJoinTest = joinStrings(splitString<vector<string>>(",a,,ab,ABC,s"s, ","s, EmptyPartsTreat::Keep), " "s, false, "("s, ")"s);
326 CPPUNIT_ASSERT_EQUAL("() (a) () (ab) (ABC) (s)"s, splitJoinTest);
327 splitJoinTest = joinStrings(splitString<vector<string>>(",a,,ab,ABC,s"s, ","s, EmptyPartsTreat::Keep), " "s, true, "("s, ")"s);
328 CPPUNIT_ASSERT_EQUAL("(a) (ab) (ABC) (s)"s, splitJoinTest);
329 splitJoinTest = joinStrings(splitStringSimple<vector<string>>(",a,,ab,ABC,s"s, ","s), " "s, true, "("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::Omit), " "s, false, "("s, ")"s);
332 CPPUNIT_ASSERT_EQUAL("(a) (ab) (ABC) (s)"s, splitJoinTest);
333 splitJoinTest = joinStrings(splitString<vector<string>>(",a,,ab,ABC,s"s, ","s, EmptyPartsTreat::Merge), " "s, false, "("s, ")"s);
334 CPPUNIT_ASSERT_EQUAL("(a,ab) (ABC) (s)"s, splitJoinTest);
335
336 // findAndReplace()
337 string findReplaceTest("findAndReplace()");
338 findAndReplace<string>(findReplaceTest, "And", "Or");
339 CPPUNIT_ASSERT_EQUAL("findOrReplace()"s, findReplaceTest);
340
341 // startsWith()
342 CPPUNIT_ASSERT(!startsWith(findReplaceTest, "findAnd"));
343 CPPUNIT_ASSERT(startsWith(findReplaceTest, "findOr"));
344 CPPUNIT_ASSERT(!startsWith(findReplaceTest, "findAnd"s));
345 CPPUNIT_ASSERT(startsWith(findReplaceTest, "findOr"s));
346 CPPUNIT_ASSERT(startsWith("test"s, "test"s));
347 CPPUNIT_ASSERT(startsWith("test"s, "test"));
348 CPPUNIT_ASSERT(!startsWith("test"s, "tests"s));
349 CPPUNIT_ASSERT(!startsWith("test"s, "tests"));
350
351 // endsWith()
352 CPPUNIT_ASSERT(!endsWith(findReplaceTest, "AndReplace()"));
353 CPPUNIT_ASSERT(endsWith(findReplaceTest, "OrReplace()"));
354 CPPUNIT_ASSERT(!endsWith(findReplaceTest, "AndReplace()"s));
355 CPPUNIT_ASSERT(endsWith(findReplaceTest, "OrReplace()"s));
356 CPPUNIT_ASSERT(endsWith("test"s, "test"s));
357 CPPUNIT_ASSERT(endsWith("test"s, "test"));
358 CPPUNIT_ASSERT(!endsWith("test"s, " test"s));
359 CPPUNIT_ASSERT(!endsWith("test"s, " test"));
360
361 // containsSubstrings()
362 CPPUNIT_ASSERT(containsSubstrings<string>("this string contains foo and bar", { "foo", "bar" }));
363 CPPUNIT_ASSERT(!containsSubstrings<string>("this string contains foo and bar", { "bar", "foo" }));
364
365 // truncateString()
366 string truncateTest("foo bar ");
367 truncateString(truncateTest, ' ');
368 CPPUNIT_ASSERT_EQUAL("foo"s, truncateTest);
369
370 // encodeBase64() / decodeBase64() with random data
371 std::uniform_int_distribution<int> randomDistChar;
372 std::uint8_t originalBase64Data[4047];
373 for (std::uint8_t &c : originalBase64Data) {
374 c = static_cast<std::uint8_t>(randomDistChar(m_randomEngine) & 0xFF);
375 }
376 auto encodedBase64Data = encodeBase64(originalBase64Data, sizeof(originalBase64Data));
377 auto decodedBase64Data = decodeBase64(encodedBase64Data.data(), static_cast<std::uint32_t>(encodedBase64Data.size()));
378 CPPUNIT_ASSERT(decodedBase64Data.second == sizeof(originalBase64Data));
379 for (unsigned int i = 0; i < sizeof(originalBase64Data); ++i) {
380 CPPUNIT_ASSERT(decodedBase64Data.first[i] == originalBase64Data[i]);
381 }
382 // test padding
383 encodedBase64Data = encodeBase64(originalBase64Data, sizeof(originalBase64Data) - 1);
384 CPPUNIT_ASSERT_EQUAL('=', encodedBase64Data.at(encodedBase64Data.size() - 1));
385 CPPUNIT_ASSERT_NO_THROW(decodeBase64(encodedBase64Data.data(), static_cast<std::uint32_t>(encodedBase64Data.size())));
386 encodedBase64Data = encodeBase64(originalBase64Data, sizeof(originalBase64Data) - 2);
387 CPPUNIT_ASSERT_EQUAL('=', encodedBase64Data.at(encodedBase64Data.size() - 1));
388 CPPUNIT_ASSERT_EQUAL('=', encodedBase64Data.at(encodedBase64Data.size() - 2));
389 CPPUNIT_ASSERT_NO_THROW(decodeBase64(encodedBase64Data.data(), static_cast<std::uint32_t>(encodedBase64Data.size())));
390 // test check for invalid size
391 CPPUNIT_ASSERT_THROW(decodeBase64(encodedBase64Data.data(), 3), ConversionException);
392
393 // dataSizeToString(), bitrateToString()
394 CPPUNIT_ASSERT_EQUAL("512 bytes"s, dataSizeToString(512ull));
395 CPPUNIT_ASSERT_EQUAL("2.50 KiB"s, dataSizeToString((2048ull + 512ull)));
396 CPPUNIT_ASSERT_EQUAL("2.50 KiB (2560 byte)"s, dataSizeToString((2048ull + 512ull), true));
397 CPPUNIT_ASSERT_EQUAL("2.50 MiB"s, dataSizeToString((2048ull + 512ull) * 1024ull));
398 CPPUNIT_ASSERT_EQUAL("2.50 GiB"s, dataSizeToString((2048ull + 512ull) * 1024ull * 1024ull));
399 CPPUNIT_ASSERT_EQUAL("2.50 TiB"s, dataSizeToString((2048ull + 512ull) * 1024ull * 1024ull * 1024ull));
400 CPPUNIT_ASSERT_EQUAL("128 bit/s"s, bitrateToString(0.128, false));
401 CPPUNIT_ASSERT_EQUAL("128 kbit/s"s, bitrateToString(128.0, false));
402 CPPUNIT_ASSERT_EQUAL("128 Mbit/s"s, bitrateToString(128.0 * 1e3, false));
403 CPPUNIT_ASSERT_EQUAL("128 Gbit/s"s, bitrateToString(128.0 * 1e6, false));
404 CPPUNIT_ASSERT_EQUAL("16 byte/s"s, bitrateToString(0.128, true));
405 CPPUNIT_ASSERT_EQUAL("16 KiB/s"s, bitrateToString(128.0, true));
406 CPPUNIT_ASSERT_EQUAL("16 MiB/s"s, bitrateToString(128.0 * 1e3, true));
407 CPPUNIT_ASSERT_EQUAL("16 GiB/s"s, bitrateToString(128.0 * 1e6, true));
408}
409
411
412struct ConvertibleToString {
413 operator std::string() const;
414};
415
416struct StringThatDoesNotLikeToBeCopiedOrMoved : public std::string {
417 explicit StringThatDoesNotLikeToBeCopiedOrMoved(const char *value)
418 : std::string(value)
419 {
420 }
421 [[noreturn]] StringThatDoesNotLikeToBeCopiedOrMoved(const StringThatDoesNotLikeToBeCopiedOrMoved &other)
422 : std::string(other)
423 {
424 CPPUNIT_FAIL("attempt to copy string: " + other);
425 }
426 [[noreturn]] StringThatDoesNotLikeToBeCopiedOrMoved(StringThatDoesNotLikeToBeCopiedOrMoved &&other)
427 : std::string(std::move(other))
428 {
429 CPPUNIT_FAIL("attempt to move string: " + other);
430 }
431};
432
434
436{
437 // check whether type traits work as expected
438 static_assert(Helper::IsStringType<std::string, std::string>::value);
439 static_assert(!Helper::IsStringType<std::string, std::wstring>::value);
440 static_assert(Helper::IsStringType<std::wstring, std::wstring>::value);
441 static_assert(Helper::IsStringViewType<std::string, std::string_view>::value);
442 static_assert(!Helper::IsStringViewType<std::wstring, std::string_view>::value);
443 static_assert(Helper::IsStringViewType<std::wstring, std::wstring_view>::value);
444 static_assert(Helper::IsConvertibleToConstStringRef<std::string, ConvertibleToString>::value);
445#ifdef CPP_UTILITIES_USE_STANDARD_FILESYSTEM
446 static_assert(!Helper::IsConvertibleToConstStringRef<std::filesystem::path::string_type, std::filesystem::path>::value,
447 "conversion via native() preferred");
448#endif
449 static_assert(
450 !Helper::IsConvertibleToConstStringRef<std::string, std::string>::value, "yes, in this context this should not be considered convertible");
451 static_assert(!Helper::IsConvertibleToConstStringRef<std::wstring, ConvertibleToString>::value);
452#ifdef CPP_UTILITIES_USE_STANDARD_FILESYSTEM
453 static_assert(Helper::IsConvertibleToConstStringRefViaNative<std::filesystem::path::string_type, std::filesystem::path>::value);
454#endif
455 static_assert(!Helper::IsConvertibleToConstStringRefViaNative<std::string, std::string>::value);
456
457 // conversion of string-tuple to string (the actual string builder)
458 const tuple<const char *, string, int, const char *> tuple("string1", "string2", 1234, "string3");
459 CPPUNIT_ASSERT_EQUAL("string1string21234string3"s, tupleToString(tuple));
460 CPPUNIT_ASSERT_EQUAL("foobarfoo2bar2"s, tupleToString("foo"s % "bar" % "foo2"s % "bar2"));
461 CPPUNIT_ASSERT_EQUAL("v2.3.0"s, argsToString("v2.", 3, '.', 0));
462 CPPUNIT_ASSERT_EQUAL("v2.3.0"s, argsToString('v', make_tuple(2, '.', 3, '.', 0)));
463#ifdef CPP_UTILITIES_USE_STANDARD_FILESYSTEM
464 if constexpr (std::is_same_v<std::filesystem::path::value_type, std::string::value_type>) {
465 CPPUNIT_ASSERT_EQUAL("path: foo"s, argsToString("path: ", std::filesystem::path("foo")));
466 }
467#endif
468
469 // construction of string-tuple and final conversion to string works
470 CPPUNIT_ASSERT_EQUAL_MESSAGE("result can be passed to any function taking a std::string"s, "123456789"s, "12" % string("34") % '5' % 67 + "89");
471 constexpr double velocityExample = 27.0;
472 CPPUNIT_ASSERT_EQUAL_MESSAGE("real-word example"s, "velocity: 27 km/h (7.5 m/s)"s,
473 "velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)");
474 CPPUNIT_ASSERT_EQUAL_MESSAGE(
475 "regular + operator still works (no problems with ambiguity)"s, "regular + still works"s, "regular"s + " + still works");
476 CPPUNIT_ASSERT_EQUAL_MESSAGE("using string_view", "foobar123"s, "foo"sv % "bar"sv + 123);
477
478 // check that for the internal tuple construction no copies are made
479 StringThatDoesNotLikeToBeCopiedOrMoved str(" happen ");
480 const StringThatDoesNotLikeToBeCopiedOrMoved str2("for this");
481 CPPUNIT_ASSERT_EQUAL("no copy/move should happen for this!"s,
482 argsToString(StringThatDoesNotLikeToBeCopiedOrMoved("no copy/move should"), str, str2, StringThatDoesNotLikeToBeCopiedOrMoved("!")));
483}
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