#include "Testing/StringTesting.h" #include "String/Char.h" #include "Memory/Memory.h" #include "String/String.h" #include "Numeric/Numeric.h" #include "String/StringView.h" #include "Miscellaneous/AssertionMacros.h" NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) NAMESPACE_BEGIN(Testing) void TestString() { TestChar(); TestStringView(); TestTemplateString(); TestStringConversion(); } void TestChar() { { always_check(!CCharType<int>); always_check(CCharType<char>); always_check(CCharType<wchar>); always_check(CCharType<u8char>); always_check(CCharType<u16char>); always_check(CCharType<u32char>); always_check(CCharType<unicodechar>); } auto Test = []<typename T>(TInPlaceType<T>) { always_check(TChar<T>::IsASCII(LITERAL(T, '0'))); always_check(TChar<T>::IsASCII(LITERAL(T, 'A'))); always_check(TChar<T>::IsASCII(LITERAL(T, 'a'))); always_check(TChar<T>::IsASCII(LITERAL(T, 'A'))); always_check(TChar<T>::IsASCII(LITERAL(T, '0'))); always_check(TChar<T>::IsASCII(LITERAL(T, '\n'))); always_check(TChar<T>::IsASCII(LITERAL(T, '!'))); always_check(TChar<T>::IsASCII(LITERAL(T, '\t'))); always_check(TChar<T>::IsASCII(LITERAL(T, ' '))); always_check(TChar<T>::IsASCII(LITERAL(T, '#'))); always_check(TChar<T>::IsASCII(LITERAL(T, '['))); always_check(TChar<T>::IsAlnum(LITERAL(T, '0'))); always_check(TChar<T>::IsAlpha(LITERAL(T, 'A'))); always_check(TChar<T>::IsLower(LITERAL(T, 'a'))); always_check(TChar<T>::IsUpper(LITERAL(T, 'A'))); always_check(TChar<T>::IsDigit(LITERAL(T, '0'))); always_check(TChar<T>::IsCntrl(LITERAL(T, '\n'))); always_check(TChar<T>::IsGraph(LITERAL(T, '!'))); always_check(TChar<T>::IsSpace(LITERAL(T, '\t'))); always_check(TChar<T>::IsBlank(LITERAL(T, ' '))); always_check(TChar<T>::IsPrint(LITERAL(T, '#'))); always_check(TChar<T>::IsPunct(LITERAL(T, '['))); always_check(!TChar<T>::IsAlnum(LITERAL(T, '$'))); always_check(!TChar<T>::IsAlpha(LITERAL(T, '0'))); always_check(!TChar<T>::IsLower(LITERAL(T, 'A'))); always_check(!TChar<T>::IsUpper(LITERAL(T, 'a'))); always_check(!TChar<T>::IsDigit(LITERAL(T, 'I'))); always_check(!TChar<T>::IsCntrl(LITERAL(T, '_'))); always_check(!TChar<T>::IsGraph(LITERAL(T, ' '))); always_check(!TChar<T>::IsSpace(LITERAL(T, '='))); always_check(!TChar<T>::IsBlank(LITERAL(T, '+'))); always_check(!TChar<T>::IsPrint(LITERAL(T, '\n'))); always_check(!TChar<T>::IsPunct(LITERAL(T, 'H'))); always_check( TChar<T>::IsDigit(LITERAL(T, 'F'), 16)); always_check(!TChar<T>::IsDigit(LITERAL(T, 'G'), 16)); always_check(TChar<T>::ToLower(LITERAL(T, 'i')) == LITERAL(T, 'i')); always_check(TChar<T>::ToUpper(LITERAL(T, 'l')) == LITERAL(T, 'L')); always_check(0x0 == TChar<T>::ToDigit(LITERAL(T, '0'))); always_check(0xF == TChar<T>::ToDigit(LITERAL(T, 'f'))); always_check(0xF == TChar<T>::ToDigit(LITERAL(T, 'F'))); always_check(0x0 == TChar<T>::ToDigit(LITERAL(T, '0'), false)); always_check(0xF != TChar<T>::ToDigit(LITERAL(T, 'f'), false)); always_check(0xF == TChar<T>::ToDigit(LITERAL(T, 'F'), false)); always_check(0x0 == TChar<T>::ToDigit(LITERAL(T, '0'), true)); always_check(0xF == TChar<T>::ToDigit(LITERAL(T, 'f'), true)); always_check(0xF != TChar<T>::ToDigit(LITERAL(T, 'F'), true)); always_check(LITERAL(T, '0') == TChar<T>::FromDigit(0x0)); always_check(LITERAL(T, 'f') != TChar<T>::FromDigit(0xF)); always_check(LITERAL(T, 'F') == TChar<T>::FromDigit(0xF)); always_check(LITERAL(T, '0') == TChar<T>::FromDigit(0x0, false)); always_check(LITERAL(T, 'f') != TChar<T>::FromDigit(0xF, false)); always_check(LITERAL(T, 'F') == TChar<T>::FromDigit(0xF, false)); always_check(LITERAL(T, '0') == TChar<T>::FromDigit(0x0, true)); always_check(LITERAL(T, 'f') == TChar<T>::FromDigit(0xF, true)); always_check(LITERAL(T, 'F') != TChar<T>::FromDigit(0xF, true)); }; Test(InPlaceType<char>); Test(InPlaceType<wchar>); Test(InPlaceType<u8char>); Test(InPlaceType<u16char>); Test(InPlaceType<u32char>); Test(InPlaceType<unicodechar>); } void TestStringView() { auto Test = []<typename T>(TInPlaceType<T>) { { TStringView<T> Empty; always_check(Empty == LITERAL(T, "")); TStringView ViewI = LITERAL(T, "#Hello, World! Goodbye, World!#"); ViewI.RemovePrefix(1); ViewI.RemoveSuffix(1); T Buffer[64]; Memory::Memzero(Buffer); ViewI.Copy(Buffer); TStringView ViewII = Buffer; always_check(ViewI == LITERAL(T, "Hello, World! Goodbye, World!")); always_check(ViewII == LITERAL(T, "Hello, World! Goodbye, World!")); TStringView ViewA(ViewI.Begin(), 13); TStringView ViewB(ViewI.Begin(), ViewI.End()); TStringView ViewC(&Buffer[0], 13); TStringView ViewD(&Buffer[0]); always_check(ViewA == LITERAL(T, "Hello, World!")); always_check(ViewB == LITERAL(T, "Hello, World! Goodbye, World!")); always_check(ViewC == LITERAL(T, "Hello, World!")); always_check(ViewD == LITERAL(T, "Hello, World! Goodbye, World!")); } { TStringView View = LITERAL(T, "Hello, World! Goodbye, World!"); always_check( View.StartsWith(LITERAL(T, "Hello, World!"))); always_check(!View.StartsWith(LITERAL(T, "Goodbye, World!"))); always_check( View.StartsWith(LITERAL(T, 'H'))); always_check(!View.StartsWith(LITERAL(T, 'G'))); always_check(!View.EndsWith(LITERAL(T, "Hello, World!"))); always_check( View.EndsWith(LITERAL(T, "Goodbye, World!"))); always_check( View.EndsWith(LITERAL(T, '!'))); always_check(!View.EndsWith(LITERAL(T, '?'))); always_check( View.Contains(LITERAL(T, "Hello, World!"))); always_check( View.Contains(LITERAL(T, "Goodbye, World!"))); always_check( View.Contains(LITERAL(T, '!'))); always_check(!View.Contains(LITERAL(T, '?'))); } { TStringView View = LITERAL(T, "Hello, World! Goodbye, World!"); always_check(View.Find(LITERAL(T, "")) == 0); always_check(View.Find(LITERAL(T, "World")) == 7); always_check(View.Find(LITERAL(T, 'l')) == 2); always_check(View.RFind(LITERAL(T, "")) == 29); always_check(View.RFind(LITERAL(T, "World")) == 23); always_check(View.RFind(LITERAL(T, 'l')) == 26); always_check(View.Find(LITERAL(T, ""), 13) == 13); always_check(View.Find(LITERAL(T, "World"), 13) == 23); always_check(View.Find(LITERAL(T, 'l'), 13) == 26); always_check(View.RFind(LITERAL(T, ""), 13) == 13); always_check(View.RFind(LITERAL(T, "World"), 13) == 7); always_check(View.RFind(LITERAL(T, 'l'), 13) == 10); always_check(View.FindFirstOf(LITERAL(T, "eor")) == 1); always_check(View.FindFirstOf(LITERAL(T, 'l')) == 2); always_check(View.FindLastOf(LITERAL(T, "eor")) == 25); always_check(View.FindLastOf(LITERAL(T, 'l')) == 26); always_check(View.FindFirstNotOf(LITERAL(T, "Hello! Goodbye!")) == 5); always_check(View.FindFirstNotOf(LITERAL(T, '!')) == 0); always_check(View.FindLastNotOf(LITERAL(T, "Hello! Goodbye!")) == 25); always_check(View.FindLastNotOf(LITERAL(T, '!')) == 27); } { always_check(LITERAL_VIEW(T, " ABC ").TrimStart() == LITERAL(T, "ABC ")); always_check(LITERAL_VIEW(T, " ABC ").TrimEnd() == LITERAL(T, " ABC" )); always_check(LITERAL_VIEW(T, " ABC ").TrimStartAndEnd() == LITERAL(T, "ABC" )); always_check(LITERAL_VIEW(T, " A\0C ").TrimToNullTerminator() == LITERAL(T, " A")); } { always_check( LITERAL_VIEW(T, "012345678900").IsASCII()); always_check(!LITERAL_VIEW(T, "\u4E38\u8FA3").IsASCII()); always_check( LITERAL_VIEW(T, "012345678900").IsInteger()); always_check(!LITERAL_VIEW(T, "\u4E38\u8FA3").IsInteger()); always_check(!LITERAL_VIEW(T, "0123456789AB").IsInteger()); always_check( LITERAL_VIEW(T, "0123456789AB").IsInteger(16)); } }; Test(InPlaceType<char>); Test(InPlaceType<wchar>); Test(InPlaceType<u8char>); Test(InPlaceType<u16char>); Test(InPlaceType<u32char>); Test(InPlaceType<unicodechar>); } void TestTemplateString() { auto Test = []<typename T>(TInPlaceType<T>) { { TString<T> Empty; always_check(Empty.IsEmpty()); always_check(TStringView<T>(*Empty) == LITERAL(T, "")); TString<T> StrA(32, LITERAL(T, 'A')); TString StrB(LITERAL(T, "ABCDEFG"), 3); TString StrC(LITERAL(T, "ABCDEFG")); TString StrD(TStringView(LITERAL(T, "ABCDEFG"))); TString StrE({ LITERAL(T, 'A'), LITERAL(T, 'B'), LITERAL(T, 'C') }); always_check(TStringView<T>(*StrA) == LITERAL(T, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")); always_check(TStringView<T>(*StrB) == LITERAL(T, "ABC")); always_check(TStringView<T>(*StrC) == LITERAL(T, "ABCDEFG")); always_check(TStringView<T>(*StrD) == LITERAL(T, "ABCDEFG")); always_check(TStringView<T>(*StrE) == LITERAL(T, "ABC")); TString StrI(StrC); TString StrII(MoveTemp(StrC)); TString StrIII = Empty; TString StrIV = Empty; StrIII = StrD; StrIV = MoveTemp(StrD); always_check(TStringView(StrI ) == LITERAL(T, "ABCDEFG")); always_check(TStringView(StrII ) == LITERAL(T, "ABCDEFG")); always_check(TStringView(StrIII) == LITERAL(T, "ABCDEFG")); always_check(TStringView(StrIV ) == LITERAL(T, "ABCDEFG")); always_check(StrC == LITERAL(T, "")); always_check(StrD == LITERAL(T, "")); StrA.Reset(); always_check(StrA.IsEmpty()); always_check(StrA == LITERAL(T, "")); } { TString Str = LITERAL(T, "A"); always_check(!Str.IsEmpty()); always_check(Str.Num() == 1); always_check(Str == TString<T>(LITERAL(T, "A"))); always_check(Str == LITERAL(T, 'A') ); always_check(Str == LITERAL(T, 'A') ); always_check(TString<T>(LITERAL(T, "A")) == Str); always_check( LITERAL(T, 'A') == Str); always_check( LITERAL(T, "A") == Str); always_check(Str != TString<T>(LITERAL(T, "B"))); always_check(Str != LITERAL(T, 'B') ); always_check(Str != LITERAL(T, "B") ); always_check(TString<T>(LITERAL(T, "B")) != Str); always_check( LITERAL(T, 'B') != Str); always_check( LITERAL(T, "B") != Str); always_check(Str < TString<T>(LITERAL(T, "B"))); always_check(Str < LITERAL(T, 'B') ); always_check(Str < LITERAL(T, "B") ); always_check(TString<T>(LITERAL(T, "B")) > Str); always_check( LITERAL(T, 'B') > Str); always_check( LITERAL(T, "B") > Str); } { TString Str = LITERAL(T, "##"); Str.Insert(1, LITERAL(T, 'A')); always_check(Str == LITERAL(T, "#A#")); Str.Insert(2, LITERAL(T, "BCD")); always_check(Str == LITERAL(T, "#ABCD#")); Str.Insert(3, 3, LITERAL(T, '*')); always_check(Str == LITERAL(T, "#AB***CD#")); Str.Erase(4); always_check(Str == LITERAL(T, "#AB**CD#")); } { TString Str = LITERAL(T, "A"); Str.PushBack(LITERAL(T, 'B')); always_check(Str == LITERAL(T, "AB")); Str.PopBack(); always_check(Str == LITERAL(T, "A")); Str.Append(2, LITERAL(T, 'B')); always_check(Str == LITERAL(T, "ABB")); Str.Append(LITERAL(T, "CD")); always_check(Str == LITERAL(T, "ABBCD")); Str.Append({ LITERAL(T, 'E'), LITERAL(T, 'F') }); always_check(Str == LITERAL(T, "ABBCDEF")); Str = LITERAL(T, "A"); Str += LITERAL(T, 'B'); always_check(Str == LITERAL(T, "AB")); Str += LITERAL(T, "CD"); always_check(Str == LITERAL(T, "ABCD")); Str += { LITERAL(T, 'E'), LITERAL(T, 'F') }; always_check(Str == LITERAL(T, "ABCDEF")); } { TString StrA = LITERAL(T, "A"); TString StrB = LITERAL(T, "B"); always_check(StrA + StrB == LITERAL(T, "AB")); always_check(StrA + LITERAL(T, 'B') == LITERAL(T, "AB")); always_check(StrA + LITERAL(T, "BCD") == LITERAL(T, "ABCD")); always_check(LITERAL(T, 'B') + StrB == LITERAL(T, "BB")); always_check(LITERAL(T, "BCD") + StrB == LITERAL(T, "BCDB")); StrA = LITERAL(T, "A"); StrB = LITERAL(T, "B"); always_check(MoveTemp(StrA) + MoveTemp(StrB) == LITERAL(T, "AB")); StrA = LITERAL(T, "A"); StrB = LITERAL(T, "B"); always_check(MoveTemp(StrA) + LITERAL(T, 'B') == LITERAL(T, "AB")); StrA = LITERAL(T, "A"); StrB = LITERAL(T, "B"); always_check(MoveTemp(StrA) + LITERAL(T, "BCD") == LITERAL(T, "ABCD")); StrA = LITERAL(T, "A"); StrB = LITERAL(T, "B"); always_check(LITERAL(T, 'B') + MoveTemp(StrB) == LITERAL(T, "BB")); StrA = LITERAL(T, "A"); StrB = LITERAL(T, "B"); always_check(LITERAL(T, "BCD") + MoveTemp(StrB) == LITERAL(T, "BCDB")); } { TString Str = LITERAL(T, "Hello, World! Goodbye, World!"); always_check( Str.StartsWith(LITERAL(T, "Hello, World!"))); always_check(!Str.StartsWith(LITERAL(T, "Goodbye, World!"))); always_check( Str.StartsWith(LITERAL(T, 'H'))); always_check(!Str.StartsWith(LITERAL(T, 'G'))); always_check(!Str.EndsWith(LITERAL(T, "Hello, World!"))); always_check( Str.EndsWith(LITERAL(T, "Goodbye, World!"))); always_check( Str.EndsWith(LITERAL(T, '!'))); always_check(!Str.EndsWith(LITERAL(T, '?'))); always_check( Str.Contains(LITERAL(T, "Hello, World!"))); always_check( Str.Contains(LITERAL(T, "Goodbye, World!"))); always_check( Str.Contains(LITERAL(T, '!'))); always_check(!Str.Contains(LITERAL(T, '?'))); } { TString Str = LITERAL(T, "#AB**CD#"); always_check(Str.Replace(3, 2, 3, LITERAL(T, '^')) == LITERAL(T, "#AB^^^CD#")); always_check(Str.Replace(3, 3, LITERAL(T, "123")) == LITERAL(T, "#AB123CD#")); always_check(Str.Substr(3, 3) == LITERAL(T, "123")); always_check(Str.Substr(3) == LITERAL(T, "123CD#")); } { TString Str = LITERAL(T, "Hello, World! Goodbye, World!"); always_check(Str.Find(LITERAL(T, "")) == 0); always_check(Str.Find(LITERAL(T, "World")) == 7); always_check(Str.Find(LITERAL(T, 'l')) == 2); always_check(Str.RFind(LITERAL(T, "")) == 29); always_check(Str.RFind(LITERAL(T, "World")) == 23); always_check(Str.RFind(LITERAL(T, 'l')) == 26); always_check(Str.Find(LITERAL(T, ""), 13) == 13); always_check(Str.Find(LITERAL(T, "World"), 13) == 23); always_check(Str.Find(LITERAL(T, 'l'), 13) == 26); always_check(Str.RFind(LITERAL(T, ""), 13) == 13); always_check(Str.RFind(LITERAL(T, "World"), 13) == 7); always_check(Str.RFind(LITERAL(T, 'l'), 13) == 10); always_check(Str.FindFirstOf(LITERAL(T, "eor")) == 1); always_check(Str.FindFirstOf(LITERAL(T, 'l')) == 2); always_check(Str.FindLastOf(LITERAL(T, "eor")) == 25); always_check(Str.FindLastOf(LITERAL(T, 'l')) == 26); always_check(Str.FindFirstNotOf(LITERAL(T, "Hello! Goodbye!")) == 5); always_check(Str.FindFirstNotOf(LITERAL(T, '!')) == 0); always_check(Str.FindLastNotOf(LITERAL(T, "Hello! Goodbye!")) == 25); always_check(Str.FindLastNotOf(LITERAL(T, '!')) == 27); } { always_check(TString(LITERAL(T, " ABC ")).TrimStart() == LITERAL(T, "ABC ")); always_check(TString(LITERAL(T, " ABC ")).TrimEnd() == LITERAL(T, " ABC" )); always_check(TString(LITERAL(T, " ABC ")).TrimStartAndEnd() == LITERAL(T, "ABC" )); always_check(TString(LITERAL(T, " A\0C ")).TrimToNullTerminator() == LITERAL(T, " A")); } { always_check(TString(LITERAL(T, "\u4E38\u8FA3")).ToString() == TEXT("\u4E38\u8FA3")); always_check(TString(LITERAL(T, "\u4E38\u8FA3")).ToWString() == WTEXT("\u4E38\u8FA3")); always_check(TString(LITERAL(T, "\u4E38\u8FA3")).ToU8String() == U8TEXT("\u4E38\u8FA3")); always_check(TString(LITERAL(T, "\u4E38\u8FA3")).ToU16String() == U16TEXT("\u4E38\u8FA3")); always_check(TString(LITERAL(T, "\u4E38\u8FA3")).ToU32String() == U32TEXT("\u4E38\u8FA3")); always_check(TString(LITERAL(T, "\u4E38\u8FA3")).ToUnicodeString() == UNICODETEXT("\u4E38\u8FA3")); } }; Test(InPlaceType<char>); Test(InPlaceType<wchar>); Test(InPlaceType<u8char>); Test(InPlaceType<u16char>); Test(InPlaceType<u32char>); Test(InPlaceType<unicodechar>); } void TestStringConversion() { auto Test = []<typename T>(TInPlaceType<T>) { always_check(TString<T>::Format(LITERAL(T, "#{}#"), true ) == LITERAL(T, "#True#" )); always_check(TString<T>::Format(LITERAL(T, "#{}#"), false) == LITERAL(T, "#False#")); always_check(TString<T>::Format(LITERAL(T, "#{}#"), +0) == LITERAL(T, "#0#")); always_check(TString<T>::Format(LITERAL(T, "#{}#"), 0) == LITERAL(T, "#0#")); always_check(TString<T>::Format(LITERAL(T, "#{}#"), -0) == LITERAL(T, "#0#")); always_check(TString<T>::Format(LITERAL(T, "#{}#"), 42) == LITERAL(T, "#42#")); always_check(TString<T>::Format(LITERAL(T, "#{}#"), +0.0) == LITERAL(T, "#0.000000#")); always_check(TString<T>::Format(LITERAL(T, "#{}#"), 0.0) == LITERAL(T, "#0.000000#")); always_check(TString<T>::Format(LITERAL(T, "#{}#"), -0.0) == LITERAL(T, "#-0.000000#")); always_check(TString<T>::Format(LITERAL(T, "#{}#"), 3.14) == LITERAL(T, "#3.140000#")); always_check(TString<T>::Format(LITERAL(T, "#{}#"), +TNumericLimits<float>::Infinity()) == LITERAL(T, "#Infinity#")); always_check(TString<T>::Format(LITERAL(T, "#{}#"), -TNumericLimits<float>::Infinity()) == LITERAL(T, "#-Infinity#")); always_check(TString<T>::Format(LITERAL(T, "#{}#"), +TNumericLimits<float>::QuietNaN()) == LITERAL(T, "#NaN#")); always_check(TString<T>::Format(LITERAL(T, "#{}#"), -TNumericLimits<float>::QuietNaN()) == LITERAL(T, "#-NaN#")); auto CheckParseArithmetic = []<typename U>(TStringView<T> View, U Result) { U Object; if constexpr (CSameAs<U, bool>) always_check(View.Parse(LITERAL(T, "{0:}"), Object) == 1); else if constexpr (CIntegral<U>) always_check(View.Parse(LITERAL(T, "{0:+#I}"), Object) == 1); else if constexpr (CFloatingPoint<U>) always_check(View.Parse(LITERAL(T, "{0:+#G}"), Object) == 1); if constexpr (CFloatingPoint<U>) { always_check(Math::IsInfinity(Result) == Math::IsInfinity(Object)); always_check(Math::IsNaN(Result) == Math::IsNaN(Object)); always_check(Math::IsNegative(Result) == Math::IsNegative(Object)); if (Math::IsInfinity(Result) || Math::IsNaN(Result)) return; always_check(Math::IsNearlyEqual(Object, Result, 1e-4)); } else always_check(Object == Result); }; CheckParseArithmetic(LITERAL(T, "true" ), true ); CheckParseArithmetic(LITERAL(T, "false"), false); auto CheckParseInt = [&]<typename U>(TInPlaceType<U>) { CheckParseArithmetic(LITERAL(T, "+0"), static_cast<U>(+0.0)); CheckParseArithmetic(LITERAL(T, " 0"), static_cast<U>( 0.0)); CheckParseArithmetic(LITERAL(T, "-0"), static_cast<U>(-0.0)); CheckParseArithmetic(LITERAL(T, "+42"), static_cast<U>( +42)); CheckParseArithmetic(LITERAL(T, "+052"), static_cast<U>( +052)); CheckParseArithmetic(LITERAL(T, "+0x2A"), static_cast<U>( +0x2A)); CheckParseArithmetic(LITERAL(T, "+0b101010"), static_cast<U>(+0b101010)); CheckParseArithmetic(LITERAL(T, "42"), static_cast<U>( 42)); CheckParseArithmetic(LITERAL(T, "052"), static_cast<U>( 052)); CheckParseArithmetic(LITERAL(T, "0x2A"), static_cast<U>( 0x2A)); CheckParseArithmetic(LITERAL(T, "0b101010"), static_cast<U>(0b101010)); CheckParseArithmetic(LITERAL(T, "-42"), static_cast<U>( -42)); CheckParseArithmetic(LITERAL(T, "-052"), static_cast<U>( -052)); CheckParseArithmetic(LITERAL(T, "-0x2A"), static_cast<U>( -0x2A)); CheckParseArithmetic(LITERAL(T, "-0b101010"), static_cast<U>(-0b101010)); }; CheckParseInt(InPlaceType<int8>); CheckParseInt(InPlaceType<int16>); CheckParseInt(InPlaceType<int32>); CheckParseInt(InPlaceType<int64>); auto CheckParseFloat = [&]<typename U>(TInPlaceType<U>) { CheckParseArithmetic(LITERAL(T, "+3.14"), static_cast<U>( +3.14)); CheckParseArithmetic(LITERAL(T, "+3.14e2"), static_cast<U>( +3.14e2)); CheckParseArithmetic(LITERAL(T, "+3.14e-2"), static_cast<U>( +3.14e-2)); CheckParseArithmetic(LITERAL(T, "+0x1.91eb86p1"), static_cast<U>(+0x1.91eb86p1)); CheckParseArithmetic(LITERAL(T, "3.14"), static_cast<U>( 3.14)); CheckParseArithmetic(LITERAL(T, "3.14e2"), static_cast<U>( 3.14e2)); CheckParseArithmetic(LITERAL(T, "3.14e-2"), static_cast<U>( 3.14e-2)); CheckParseArithmetic(LITERAL(T, "0x1.91eb86p1"), static_cast<U>(0x1.91eb86p1)); CheckParseArithmetic(LITERAL(T, "-3.14"), static_cast<U>( -3.14)); CheckParseArithmetic(LITERAL(T, "-3.14e2"), static_cast<U>( -3.14e2)); CheckParseArithmetic(LITERAL(T, "-3.14e-2"), static_cast<U>( -3.14e-2)); CheckParseArithmetic(LITERAL(T, "-0x1.91eb86p1"), static_cast<U>(-0x1.91eb86p1)); CheckParseArithmetic(LITERAL(T, "+Infinity"), +TNumericLimits<U>::Infinity()); CheckParseArithmetic(LITERAL(T, " Infinity"), +TNumericLimits<U>::Infinity()); CheckParseArithmetic(LITERAL(T, "-Infinity"), -TNumericLimits<U>::Infinity()); CheckParseArithmetic(LITERAL(T, "+NaN"), +TNumericLimits<U>::QuietNaN()); CheckParseArithmetic(LITERAL(T, " NaN"), +TNumericLimits<U>::QuietNaN()); CheckParseArithmetic(LITERAL(T, "-NaN"), -TNumericLimits<U>::QuietNaN()); }; CheckParseFloat(InPlaceType<float>); CheckParseFloat(InPlaceType<double>); { always_check(TString<T>::FromBool(true ) == LITERAL(T, "True" )); always_check(TString<T>::FromBool(false) == LITERAL(T, "False")); } { always_check(TString<T>::FromInt(42) == LITERAL(T, "42" )); always_check(TString<T>::FromInt(255, 16) == LITERAL(T, "FF" )); always_check(TString<T>::FromInt(-42) == LITERAL(T, "-42" )); always_check(TString<T>::FromInt(0) == LITERAL(T, "0" )); always_check(TString<T>::FromInt(1234567890) == LITERAL(T, "1234567890")); always_check(TString<T>::FromInt(255, 2) == LITERAL(T, "11111111" )); always_check(TString<T>::FromInt(255, 8) == LITERAL(T, "377" )); always_check(TString<T>::FromInt(255, 36) == LITERAL(T, "73" )); } { always_check(TString<T>::FromFloat(3.14f) == LITERAL(T, "3.14" )); always_check(TString<T>::FromFloat(0.0f) == LITERAL(T, "0" )); always_check(TString<T>::FromFloat(-3.14f) == LITERAL(T, "-3.14" )); always_check(TString<T>::FromFloat(3.14f, true, false) == LITERAL(T, "3.14" )); always_check(TString<T>::FromFloat(3.14f, false, true) == LITERAL(T, "3.14e+00")); always_check(TString<T>::FromFloat(3.14f, false, false, 2) == LITERAL(T, "1.92p+1" )); always_check(TString<T>::FromFloat(1.0f / 3.0f, true, false, 5) == LITERAL(T, "0.33333" )); } { always_check( LITERAL_VIEW(T, "True" ).ToBool()); always_check(!LITERAL_VIEW(T, "False" ).ToBool()); always_check( LITERAL_VIEW(T, "1" ).ToBool()); always_check(!LITERAL_VIEW(T, "0" ).ToBool()); always_check(!LITERAL_VIEW(T, "random").ToBool()); } { always_check(LITERAL_VIEW(T, "42" ).ToInt() == 42 ); always_check(LITERAL_VIEW(T, "FF" ).ToInt(16) == 255); always_check(LITERAL_VIEW(T, "-42" ).ToInt() == -42); always_check(LITERAL_VIEW(T, "0" ).ToInt() == 0 ); always_check(LITERAL_VIEW(T, "Invalid").ToInt() == 0 ); always_check(LITERAL_VIEW(T, "999999999999999999999999999999").ToInt() == 0); always_check(LITERAL_VIEW(T, "-999999999999999999999999999999").ToInt() == 0); } { always_check(LITERAL_VIEW(T, "3.14" ).ToFloat() == 3.14f); always_check(LITERAL_VIEW(T, "3.14e+00").ToFloat() == 3.14f); always_check(LITERAL_VIEW(T, "-3.14" ).ToFloat() == -3.14f); always_check(LITERAL_VIEW(T, "0.0" ).ToFloat() == 0.0f); always_check(Math::IsNaN(LITERAL_VIEW(T, "1e+308").ToFloat())); always_check(Math::IsNaN(LITERAL_VIEW(T, "-1e+308").ToFloat())); always_check(Math::IsNaN(LITERAL_VIEW(T, "1e-308").ToFloat())); always_check(Math::IsNaN(LITERAL_VIEW(T, "-1e-308").ToFloat())); } }; Test(InPlaceType<char>); Test(InPlaceType<wchar>); Test(InPlaceType<u8char>); Test(InPlaceType<u16char>); Test(InPlaceType<u32char>); Test(InPlaceType<unicodechar>); } NAMESPACE_END(Testing) NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) NAMESPACE_REDCRAFT_END