1 #include "../conversion/binaryconversion.h"
2 #include "../conversion/stringbuilder.h"
3 #include "../conversion/stringconversion.h"
4 #include "../tests/testutils.h"
8 #include <cppunit/TestFixture.h>
9 #include <cppunit/extensions/HelperMacros.h>
12 #include <initializer_list>
16 #ifdef CPP_UTILITIES_USE_STANDARD_FILESYSTEM
22 using namespace CPPUNIT_NS;
26 static_assert(
toNormalInt(383) == 255,
"toNormalInt()");
27 static_assert(
swapOrder(
static_cast<std::uint16_t
>(0xABCD)) == 0xCDAB,
"swapOrder(uint16)");
28 static_assert(
swapOrder(
static_cast<std::uint32_t
>(0xABCDEF12)) == 0x12EFCDAB,
"swapOrder(uint32)");
29 static_assert(
swapOrder(
static_cast<std::uint64_t
>(0xABCDEF1234567890)) == 0x9078563412EFCDAB,
"swapOrder(uint64)");
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();
55 void testConversionException();
56 void testEndianness();
57 void testBinaryConversions();
58 void testSwapOrderFunctions();
59 void testStringEncodingConversions();
60 void testStringConversions();
61 void testStringBuilder();
64 template <
typename intType>
65 void testConversion(
const char *message,
function<
void(intType,
char *)> vice,
function<intType(
const char *)> verca, intType
min, intType
max);
68 random_device m_randomDevice;
69 mt19937 m_randomEngine;
76 , m_randomEngine(m_randomDevice())
93 } test = { 0x01020304 };
94 #if defined(CONVERSION_UTILITIES_BYTE_ORDER_BIG_ENDIAN)
96 CPPUNIT_ASSERT(CONVERSION_UTILITIES_IS_BYTE_ORDER_BIG_ENDIAN ==
true);
97 CPPUNIT_ASSERT(CONVERSION_UTILITIES_IS_BYTE_ORDER_LITTLE_ENDIAN ==
false);
99 CPPUNIT_ASSERT_MESSAGE(
"Byte order assumption (big-endian) is wrong", test.characters[0] == 0x01);
100 #elif defined(CONVERSION_UTILITIES_BYTE_ORDER_LITTLE_ENDIAN)
102 CPPUNIT_ASSERT(CONVERSION_UTILITIES_IS_BYTE_ORDER_BIG_ENDIAN ==
false);
103 CPPUNIT_ASSERT(CONVERSION_UTILITIES_IS_BYTE_ORDER_LITTLE_ENDIAN ==
true);
105 CPPUNIT_ASSERT_MESSAGE(
"Byte order assumption (little-endian) is wrong", test.characters[0] == 0x04);
107 CPPUNIT_FAIL(
"There is not valid byte order assumption");
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)
115 const intType random = uniform_int_distribution<intType>(
min,
max)(m_randomEngine);
117 msg << message <<
'(' << hex <<
'0' <<
'x' << random <<
')';
118 vice(random, m_buff);
119 CPPUNIT_ASSERT_MESSAGE(msg.str(), versa(m_buff) == random);
122 #define TEST_TYPE(endianness, function) decltype(endianness::function(m_buff))
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())
129 #define TEST_BE_CONVERSION(function) TEST_CONVERSION(function, BE)
131 #define TEST_LE_CONVERSION(function) TEST_CONVERSION(function, LE)
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)
146 for (
auto b = 1; b < 100; ++b) {
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);
177 void assertEqual(
const char *message,
const std::uint8_t *expectedValues,
size_t expectedSize,
const StringData &actualValues)
180 CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expectedSize, actualValues.second);
182 auto *end = expectedValues + expectedSize;
183 auto *
i =
reinterpret_cast<std::uint8_t *
>(actualValues.first.get());
184 for (; expectedValues != end; ++expectedValues, ++
i) {
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
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 };
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 };
250 CPPUNIT_ASSERT_EQUAL(
"0"s, numberToString<unsigned int>(0));
251 CPPUNIT_ASSERT_EQUAL(
"0"s, numberToString<signed int>(0));
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,
static_cast<string::value_type
>(base));
260 const auto asWideString = numberToString<std::uint64_t, wstring>(unsignedRandom, base);
261 CPPUNIT_ASSERT_EQUAL_MESSAGE(stringMsg, unsignedRandom, stringToNumber<std::uint64_t>(asString,
static_cast<string::value_type
>(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));
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,
static_cast<string::value_type
>(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));
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));
290 CPPUNIT_ASSERT_EQUAL(
"TEST"s, interpretIntegerAsString<std::uint32_t>(0x54455354));
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);
313 string findReplaceTest(
"findAndReplace()");
314 findAndReplace<string>(findReplaceTest,
"And",
"Or");
315 CPPUNIT_ASSERT_EQUAL(
"findOrReplace()"s, findReplaceTest);
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));
324 CPPUNIT_ASSERT(!
startsWith(
"test"s,
"tests"s));
325 CPPUNIT_ASSERT(!
startsWith(
"test"s,
"tests"));
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"));
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" }));
342 string truncateTest(
"foo bar ");
344 CPPUNIT_ASSERT_EQUAL(
"foo"s, truncateTest);
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);
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]);
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())));
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));
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));
387 operator std::string()
const;
398 CPPUNIT_FAIL(
"attempt to copy string: " + other);
401 : std::string(std::move(other))
403 CPPUNIT_FAIL(
"attempt to move string: " + other);
410 static_assert(Helper::IsStringType<std::string, std::string>::value);
411 static_assert(!Helper::IsStringType<std::string, std::wstring>::value);
412 static_assert(Helper::IsStringType<std::wstring, std::wstring>::value);
413 static_assert(Helper::IsStringViewType<std::string, std::string_view>::value);
414 static_assert(!Helper::IsStringViewType<std::wstring, std::string_view>::value);
415 static_assert(Helper::IsStringViewType<std::wstring, std::wstring_view>::value);
416 static_assert(Helper::IsConvertibleToConstStringRef<std::string, ConvertibleToString>::value);
417 #ifdef CPP_UTILITIES_USE_STANDARD_FILESYSTEM
418 static_assert(!Helper::IsConvertibleToConstStringRef<std::filesystem::path::string_type, std::filesystem::path>::value,
419 "conversion via native() preferred");
422 !Helper::IsConvertibleToConstStringRef<std::string, std::string>::value,
"yes, in this context this should not be considered convertible");
423 static_assert(!Helper::IsConvertibleToConstStringRef<std::wstring, ConvertibleToString>::value);
424 #ifdef CPP_UTILITIES_USE_STANDARD_FILESYSTEM
425 static_assert(Helper::IsConvertibleToConstStringRefViaNative<std::filesystem::path::string_type, std::filesystem::path>::value);
427 static_assert(!Helper::IsConvertibleToConstStringRefViaNative<std::string, std::string>::value);
430 const tuple<const char *, string, int, const char *> tuple(
"string1",
"string2", 1234,
"string3");
431 CPPUNIT_ASSERT_EQUAL(
"string1string21234string3"s,
tupleToString(tuple));
432 CPPUNIT_ASSERT_EQUAL(
"foobarfoo2bar2"s,
tupleToString(
"foo"s %
"bar" %
"foo2"s %
"bar2"));
433 CPPUNIT_ASSERT_EQUAL(
"v2.3.0"s,
argsToString(
"v2.", 3,
'.', 0));
434 CPPUNIT_ASSERT_EQUAL(
"v2.3.0"s,
argsToString(
'v', make_tuple(2,
'.', 3,
'.', 0)));
435 #ifdef CPP_UTILITIES_USE_STANDARD_FILESYSTEM
436 if constexpr (std::is_same_v<std::filesystem::path::value_type, std::string::value_type>) {
437 CPPUNIT_ASSERT_EQUAL(
"path: foo"s,
argsToString(
"path: ", std::filesystem::path(
"foo")));
442 CPPUNIT_ASSERT_EQUAL_MESSAGE(
"result can be passed to any function taking a std::string"s,
"123456789"s,
"12" %
string(
"34") %
'5' % 67 +
"89");
443 constexpr
double velocityExample = 27.0;
444 CPPUNIT_ASSERT_EQUAL_MESSAGE(
"real-word example"s,
"velocity: 27 km/h (7.5 m/s)"s,
446 CPPUNIT_ASSERT_EQUAL_MESSAGE(
447 "regular + operator still works (no problems with ambiguity)"s,
"regular + still works"s,
"regular"s +
" + still works");
448 CPPUNIT_ASSERT_EQUAL_MESSAGE(
"using string_view",
"foobar123"s,
"foo"sv %
"bar"sv + 123);
453 CPPUNIT_ASSERT_EQUAL(
"no copy/move should happen for this!"s,