C++ Utilities 5.14.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
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)");
30
34class ConversionTests : public TestFixture {
35 CPPUNIT_TEST_SUITE(ConversionTests);
36 CPPUNIT_TEST(testConversionException);
37 CPPUNIT_TEST(testEndianness);
38 CPPUNIT_TEST(testBinaryConversions);
39 CPPUNIT_TEST(testSwapOrderFunctions);
41 CPPUNIT_TEST(testStringConversions);
42 CPPUNIT_TEST(testStringBuilder);
43 CPPUNIT_TEST_SUITE_END();
44
45public:
47
48 void setUp()
49 {
50 }
51 void tearDown()
52 {
53 }
54
56 void testEndianness();
61 void testStringBuilder();
62
63private:
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
111template <typename intType>
112void 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
177void 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));
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));
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
407struct ConvertibleToString {
408 operator std::string() const;
409};
410
411struct 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...
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.
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 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.
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.
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:233
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.
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.
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