1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <gtest/gtest-param-test.h>
- #include <AzCore/UnitTest/TestTypes.h>
- #include <AzCore/StringFunc/StringFunc.h>
- #include <string.h>
- namespace AZ
- {
- using namespace UnitTest;
- using StringFuncTest = LeakDetectionFixture;
- TEST_F(StringFuncTest, Equal_CaseSensitive_OnNonNullTerminatedStringView_Success)
- {
- constexpr AZStd::string_view testString1 = "Hello World IceCream";
- constexpr AZStd::string_view testString2 = "IceCream World Hello";
- constexpr bool caseSensitive = true;
- EXPECT_TRUE(AZ::StringFunc::Equal(testString1.substr(6,5), testString2.substr(9,5), caseSensitive));
- }
- TEST_F(StringFuncTest, Equal_CaseInsensitive_OnNonNullTerminatedStringView_Success)
- {
- constexpr AZStd::string_view testString1 = "Hello World IceCream";
- constexpr AZStd::string_view testString2 = "IceCream woRLd Hello";
- constexpr bool caseSensitive = false;
- EXPECT_TRUE(AZ::StringFunc::Equal(testString1.substr(6, 5), testString2.substr(9, 5), caseSensitive));
- }
- TEST_F(StringFuncTest, Equal_CaseSensitive_OnNonNullTerminatedStringView_WithDifferentCases_Fails)
- {
- constexpr AZStd::string_view testString1 = "Hello World IceCream";
- constexpr AZStd::string_view testString2 = "IceCream woRLd Hello";
- constexpr bool caseSensitive = true;
- EXPECT_FALSE(AZ::StringFunc::Equal(testString1.substr(6, 5), testString2.substr(9, 5), caseSensitive));
- }
- TEST_F(StringFuncTest, Equal_OnNonNullTerminatedStringView_WithDifferentSize_Fails)
- {
- constexpr AZStd::string_view testString1 = "Hello World IceCream";
- constexpr AZStd::string_view testString2 = "IceCream World Hello";
- EXPECT_FALSE(AZ::StringFunc::Equal(testString1.substr(6, 6), testString2.substr(9, 5)));
- }
- // Strip out any trailing path separators
- TEST_F(StringFuncTest, Strip_ValidInputExtraEndingPathSeparators_Success)
- {
- AZStd::string samplePath = "F:\\w s 1\\dev\\/";
- AZStd::string expectedResult = "F:\\w s 1\\dev";
- const char* stripCharacters = AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING AZ_WRONG_FILESYSTEM_SEPARATOR_STRING;
- AZ::StringFunc::Strip(samplePath, stripCharacters, false, false, true);
- ASSERT_TRUE(samplePath == expectedResult);
- }
-
- TEST_F(StringFuncTest, Strip_AllEmptyResult1_Success)
- {
- AZStd::string input = "aa";
- const char stripToken = 'a';
- AZ::StringFunc::Strip(input, stripToken);
- ASSERT_TRUE(input.empty());
- }
- TEST_F(StringFuncTest, Strip_AllEmptyResult2_Success)
- {
- AZStd::string input = "aaaa";
- const char stripToken = 'a';
- AZ::StringFunc::Strip(input, stripToken);
- ASSERT_TRUE(input.empty());
- }
- TEST_F(StringFuncTest, Strip_BeginEndCaseSensitiveEmptyResult1_Success)
- {
- AZStd::string input = "aa";
- const char stripToken = 'a';
- AZ::StringFunc::Strip(input, stripToken, true, true, true);
- ASSERT_TRUE(input.empty());
- }
- TEST_F(StringFuncTest, Strip_BeginEndCaseSensitiveEmptyResult2_Success)
- {
- AZStd::string input = "aaaa";
- AZStd::string expectedResult = "aa";
- const char stripToken = 'a';
- AZ::StringFunc::Strip(input, stripToken, true, true, true);
- ASSERT_EQ(input, expectedResult);
- }
- TEST_F(StringFuncTest, Strip_BeginEndCaseInsensitiveEmptyResult1_Success)
- {
- AZStd::string input = "aa";
- const char stripToken = 'a';
- AZ::StringFunc::Strip(input, stripToken, false, true, true);
- ASSERT_TRUE(input.empty());
- }
- TEST_F(StringFuncTest, Strip_BeginEndCaseInsensitiveEmptyResult2_Success)
- {
- AZStd::string input = "aaaa";
- AZStd::string expectedResult = "aa";
- const char stripToken = 'a';
- AZ::StringFunc::Strip(input, stripToken, false, true, true);
- ASSERT_EQ(input, expectedResult);
- }
- TEST_F(StringFuncTest, Join_PathsWithNoOverlappingDirectoriesDisabled_Success)
- {
- AZStd::string path1 = "1/2/3/4";
- AZStd::string path2 = "5/6";
- AZStd::string expectedResult = "1/2/3/4/5/6";
- AZStd::string joinResult;
- AZ::StringFunc::Path::Normalize(path1);
- AZ::StringFunc::Path::Normalize(path2);
- AZ::StringFunc::Path::Normalize(expectedResult);
- AZ::StringFunc::Path::Join(path1.c_str(), path2.c_str(), joinResult);
- ASSERT_EQ(joinResult, expectedResult);
- }
- TEST_F(StringFuncTest, Join_PathsWithOverlappingDirectoriesDisabled_Success)
- {
- AZStd::string path1 = "1/2/3/4";
- AZStd::string path2 = "3/4/5/6";
- AZStd::string expectedResult = "1/2/3/4/3/4/5/6";
- AZStd::string joinResult;
- AZ::StringFunc::Path::Normalize(path1);
- AZ::StringFunc::Path::Normalize(path2);
- AZ::StringFunc::Path::Normalize(expectedResult);
- AZ::StringFunc::Path::Join(path1.c_str(), path2.c_str(), joinResult);
- ASSERT_EQ(joinResult, expectedResult);
- }
- TEST_F(StringFuncTest, Join_PathsWithNoOverlappingDirectories_Success)
- {
- AZStd::string path1 = "1/2/3/4";
- AZStd::string path2 = "5/6";
- AZStd::string expectedResult = "1/2/3/4/5/6";
- AZStd::string joinResult;
- AZ::StringFunc::Path::Normalize(path1);
- AZ::StringFunc::Path::Normalize(path2);
- AZ::StringFunc::Path::Normalize(expectedResult);
- AZ::StringFunc::Path::Join(path1.c_str(), path2.c_str(), joinResult);
- ASSERT_EQ(joinResult, expectedResult);
- }
- TEST_F(StringFuncTest, Join_PathsWithOverlappingDirectories_Success)
- {
- AZStd::string path1 = "1/2/3/4";
- AZStd::string path2 = "3/4/5/6";
- AZStd::string expectedResult = "1/2/3/4/3/4/5/6";
- AZStd::string joinResult;
- AZ::StringFunc::Path::Normalize(path1);
- AZ::StringFunc::Path::Normalize(path2);
- AZ::StringFunc::Path::Normalize(expectedResult);
- AZ::StringFunc::Path::Join(path1.c_str(), path2.c_str(), joinResult);
- ASSERT_EQ(joinResult, expectedResult);
- }
- TEST_F(StringFuncTest, Join_PathsWithSecondNameOverlappingDirectory_Success)
- {
- AZStd::string path1 = "1/2/3/4";
- AZStd::string path2 = "3";
- AZStd::string expectedResult = "1/2/3/4/3";
- AZStd::string joinResult;
- AZ::StringFunc::Path::Normalize(path1);
- AZ::StringFunc::Path::Normalize(path2);
- AZ::StringFunc::Path::Normalize(expectedResult);
- AZ::StringFunc::Path::Join(path1.c_str(), path2.c_str(), joinResult);
- ASSERT_EQ(joinResult, expectedResult);
- }
- TEST_F(StringFuncTest, Join_NonPathJoin_CanJoinRange)
- {
- AZStd::string result;
- AZ::StringFunc::Join(result, AZStd::initializer_list<const char*>{ "1", "2", "3", "4", "3" }, '/');
- EXPECT_EQ("1/2/3/4/3", result);
- result.clear();
- // Try joining with a string literal instead of a char literal
- AZ::StringFunc::Join(result, AZStd::initializer_list<const char*>{ "1", "2", "3", "4", "3" }, "/");
- EXPECT_EQ("1/2/3/4/3", result);
- }
- TEST_F(StringFuncTest, Tokenize_SingleDelimeter_Empty)
- {
- AZStd::string input = "";
- AZStd::vector<AZStd::string> tokens;
- AZ::StringFunc::Tokenize(input.c_str(), tokens, ' ');
- ASSERT_EQ(tokens.size(), 0);
- }
- TEST_F(StringFuncTest, Tokenize_SingleDelimeter)
- {
- AZStd::string input = "a b,c";
- AZStd::vector<AZStd::string> tokens;
- AZ::StringFunc::Tokenize(input.c_str(), tokens, ' ');
- ASSERT_EQ(tokens.size(), 2);
- ASSERT_TRUE(tokens[0] == "a");
- ASSERT_TRUE(tokens[1] == "b,c");
- }
- TEST_F(StringFuncTest, Tokenize_MultiDelimeter_Empty)
- {
- AZStd::string input = "";
- AZStd::vector<AZStd::string> tokens;
- AZ::StringFunc::Tokenize(input.c_str(), tokens, " ,");
- ASSERT_EQ(tokens.size(), 0);
- }
- TEST_F(StringFuncTest, Tokenize_MultiDelimeters)
- {
- AZStd::string input = " -a +b +c -d-e";
- AZStd::vector<AZStd::string> tokens;
- AZ::StringFunc::Tokenize(input.c_str(), tokens, "-+");
- ASSERT_EQ(tokens.size(), 5);
- ASSERT_TRUE(tokens[0] == "a ");
- ASSERT_TRUE(tokens[1] == "b ");
- ASSERT_TRUE(tokens[2] == "c ");
- ASSERT_TRUE(tokens[3] == "d");
- ASSERT_TRUE(tokens[4] == "e");
- }
- TEST_F(StringFuncTest, Tokenize_SubstringDelimeters_Empty)
- {
- AZStd::string input = "";
- AZStd::vector<AZStd::string> tokens;
- AZStd::vector<AZStd::string_view> delimeters = {" -", " +"};
- AZ::StringFunc::Tokenize(input.c_str(), tokens, delimeters);
- ASSERT_EQ(tokens.size(), 0);
- }
- TEST_F(StringFuncTest, Tokenize_SubstringDelimeters)
- {
- AZStd::string input = " -a +b +c -d-e";
- AZStd::vector<AZStd::string> tokens;
- AZStd::vector<AZStd::string_view> delimeters = { " -", " +" };
- AZ::StringFunc::Tokenize(input.c_str(), tokens, delimeters);
- ASSERT_EQ(tokens.size(), 4);
- ASSERT_TRUE(tokens[0] == "a");
- ASSERT_TRUE(tokens[1] == "b");
- ASSERT_TRUE(tokens[2] == "c");
- ASSERT_TRUE(tokens[3] == "d-e"); // Test for something like a guid, which contain typical separator characters
- }
- TEST_F(StringFuncTest, TokenizeVisitor_EmptyString_DoesNotInvokeVisitor)
- {
- int visitedCount{};
- auto visitor = [&visitedCount](AZStd::string_view)
- {
- ++visitedCount;
- };
- AZ::StringFunc::TokenizeVisitor("", visitor, " ");
- EXPECT_EQ(0, visitedCount);
- }
- TEST_F(StringFuncTest, TokenizeVisitor_NonDelimitedString_InvokeVisitorOnce)
- {
- int visitedCount{};
- auto visitor = [&visitedCount](AZStd::string_view)
- {
- ++visitedCount;
- };
- AZ::StringFunc::TokenizeVisitor("Hello", visitor, " ");
- EXPECT_EQ(1, visitedCount);
- }
- TEST_F(StringFuncTest, TokenizeVisitor_DelimitedString_InvokeVisitorMultipleTimes)
- {
- int visitedCount{};
- auto visitor = [&visitedCount](AZStd::string_view)
- {
- ++visitedCount;
- };
- AZ::StringFunc::TokenizeVisitor("Hello World", visitor, " ");
- EXPECT_EQ(2, visitedCount);
- visitedCount = {};
- AZ::StringFunc::TokenizeVisitor("Hello World Again", visitor, " ");
- EXPECT_EQ(3, visitedCount);
- }
- TEST_F(StringFuncTest, TokenizeVisitor_EmptyStringOption_InvokeVisitorWithEmptyString)
- {
- int visitedCount{};
- bool emptyStringFound{};
- auto visitor = [&visitedCount, &emptyStringFound](AZStd::string_view token)
- {
- ++visitedCount;
- if (token.empty())
- {
- emptyStringFound = true;
- }
- };
- AZ::StringFunc::TokenizeVisitor("Hello,,World", visitor, ",", true);
- EXPECT_EQ(3, visitedCount);
- EXPECT_TRUE(emptyStringFound);
- visitedCount = {};
- emptyStringFound = {};
- AZ::StringFunc::TokenizeVisitor(",Hello,World", visitor, ",", true);
- EXPECT_EQ(3, visitedCount);
- EXPECT_TRUE(emptyStringFound);
- }
- TEST_F(StringFuncTest, TokenizeVisitor_WhiteSpaceOption_InvokeVisitorWithWhiteSpaceAroundTokenString)
- {
- int visitedCount{};
- bool trailingWhitespaceTokenFound{};
- bool leadingWhitespaceTokenFound{};
- auto visitor = [&visitedCount, &trailingWhitespaceTokenFound, &leadingWhitespaceTokenFound](AZStd::string_view token)
- {
- ++visitedCount;
- if (token.starts_with(' '))
- {
- leadingWhitespaceTokenFound = true;
- }
- if (token.ends_with(' '))
- {
- trailingWhitespaceTokenFound = true;
- }
- };
- AZ::StringFunc::TokenizeVisitor("Hello , World", visitor, ",", false, true);
- EXPECT_EQ(2, visitedCount);
- EXPECT_TRUE(trailingWhitespaceTokenFound);
- EXPECT_TRUE(leadingWhitespaceTokenFound);
- visitedCount = {};
- trailingWhitespaceTokenFound = {};
- leadingWhitespaceTokenFound = {};
- AZ::StringFunc::TokenizeVisitor("Hello, World", visitor, ",", false, true);
- EXPECT_EQ(2, visitedCount);
- EXPECT_FALSE(trailingWhitespaceTokenFound);
- EXPECT_TRUE(leadingWhitespaceTokenFound);
- visitedCount = {};
- trailingWhitespaceTokenFound = {};
- leadingWhitespaceTokenFound = {};
- AZ::StringFunc::TokenizeVisitor("Hello ,World", visitor, ",", false, true);
- EXPECT_EQ(2, visitedCount);
- EXPECT_TRUE(trailingWhitespaceTokenFound);
- EXPECT_FALSE(leadingWhitespaceTokenFound);
- }
- TEST_F(StringFuncTest, TokenizeVisitor_DocExampleAboveFunctionDeclaration_Succeeds)
- {
- constexpr AZStd::array visitTokens = { "Hello", "World", "", "More", "", "", "Tokens" };
- size_t visitIndex{};
- AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the
- // capture. Newer versions issue unused warning
- auto visitor = [&visitIndex, &visitTokens](AZStd::string_view token)
- AZ_POP_DISABLE_WARNING
- {
- if (visitIndex > visitTokens.size())
- {
- ADD_FAILURE() << "More tokens have been visited than are expected:" << visitTokens.size();
- return;
- }
- if (token != visitTokens[visitIndex])
- {
- AZStd::fixed_string<64> result{ token };
- ADD_FAILURE() << "Visited token \"" << result.c_str() << "\" does not match token \"" << visitTokens[visitIndex] << "\" at index (" << visitIndex << ") in the visitTokens array";
- }
- ++visitIndex;
- };
- AZ::StringFunc::TokenizeVisitor("Hello World More Tokens", visitor, " ", true, true);
- AZStd::vector<AZStd::string> resultTokens;
- AZ::StringFunc::Tokenize("Hello World More Tokens", resultTokens, ' ', true, true);
- ASSERT_EQ(visitTokens.size(), resultTokens.size());
- EXPECT_TRUE(AZStd::equal(resultTokens.begin(), resultTokens.end(), visitTokens.begin()));
- }
- TEST_F(StringFuncTest, TokenizeVisitorReverse_DocExampleAboveFunctionDeclaration_Succeeds)
- {
- constexpr AZStd::array visitTokens = { "Hello", "World", "", "More", "", "", "Tokens" };
- size_t visitIndex = visitTokens.size() - 1;
- AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the
- // capture. Newer versions issue unused warning
- auto visitor = [&visitIndex, &visitTokens](AZStd::string_view token)
- AZ_POP_DISABLE_WARNING
- {
- if (visitIndex > visitTokens.size())
- {
- ADD_FAILURE() << "More tokens have been visited than are expected:" << visitTokens.size();
- return;
- }
- if (token != visitTokens[visitIndex])
- {
- AZStd::fixed_string<64> result{ token };
- ADD_FAILURE() << "Visited token \"" << result.c_str() << "\" does not match token \"" << visitTokens[visitIndex] << "\" at index (" << visitIndex << ") in the visitTokens array";
- }
- --visitIndex;
- };
- AZ::StringFunc::TokenizeVisitorReverse("Hello World More Tokens", visitor, " ", true, true);
- AZStd::vector<AZStd::string> resultTokens;
- // Visitor functor which replaces the regular Tokenize behavior of inserting a new token into a vector of strings
- auto addToVectorVisitor = [&resultTokens](AZStd::string_view token)
- {
- resultTokens.push_back(token);
- };
- AZ::StringFunc::TokenizeVisitorReverse("Hello World More Tokens", addToVectorVisitor, ' ', true, true);
- ASSERT_EQ(visitTokens.size(), resultTokens.size());
- EXPECT_TRUE(AZStd::equal(resultTokens.begin(), resultTokens.end(), visitTokens.rbegin()));
- }
- TEST_F(StringFuncTest, TokenizeNext_WithEmptyString_ReturnsInvalid)
- {
- AZStd::string_view input{ "" };
- AZStd::optional<AZStd::string_view> token = AZ::StringFunc::TokenizeNext(input, ",");
- EXPECT_FALSE(token);
- }
- TEST_F(StringFuncTest, TokenizeNext_WithNonEmptyString_ReturnsValid)
- {
- AZStd::string_view input{ " " };
- AZStd::optional<AZStd::string_view> token = AZ::StringFunc::TokenizeNext(input, ",");
- EXPECT_TRUE(token);
- EXPECT_EQ(" ", *token);
- }
- TEST_F(StringFuncTest, TokenizeNext_DocExample1AboveFunctionDeclaration_Succeeds)
- {
- AZStd::string_view input = "Hello World";
- AZStd::optional<AZStd::string_view> output;
- output = StringFunc::TokenizeNext(input, " ");
- EXPECT_EQ("World", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("Hello", output);
- output = StringFunc::TokenizeNext(input, " ");
- EXPECT_EQ("", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("World", output);
- output = StringFunc::TokenizeNext(input, " ");
- EXPECT_EQ("", input);
- EXPECT_FALSE(output);
- }
- TEST_F(StringFuncTest, TokenizeNext_DocExample2AboveFunctionDeclaration_Succeeds)
- {
- AZStd::string_view input = "Hello World More Tokens";
- AZStd::optional<AZStd::string_view> output;
- output = StringFunc::TokenizeNext(input, ' ');
- EXPECT_EQ("World More Tokens", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("Hello", output);
- output = StringFunc::TokenizeNext(input, ' ');
- EXPECT_EQ(" More Tokens", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("World", output);
- output = StringFunc::TokenizeNext(input, ' ');
- EXPECT_EQ("More Tokens", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("", output);
- output = StringFunc::TokenizeNext(input, ' ');
- EXPECT_EQ(" Tokens", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("More", output);
- output = StringFunc::TokenizeNext(input, ' ');
- EXPECT_EQ(" Tokens", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("", output);
- output = StringFunc::TokenizeNext(input, ' ');
- EXPECT_EQ("Tokens", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("", output);
- output = StringFunc::TokenizeNext(input, ' ');
- EXPECT_EQ("", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("Tokens", output);
- output = StringFunc::TokenizeNext(input, ' ');
- EXPECT_EQ("", input);
- EXPECT_FALSE(output);
- }
- TEST_F(StringFuncTest, TokenizeLast_DocExample1AboveFunctionDeclaration_Succeeds)
- {
- AZStd::string_view input = "Hello World";
- AZStd::optional<AZStd::string_view> output;
- output = StringFunc::TokenizeLast(input, " ");
- EXPECT_EQ("Hello", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("World", output);
- output = StringFunc::TokenizeLast(input, " ");
- EXPECT_EQ("", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("Hello", output);
- output = StringFunc::TokenizeLast(input, " ");
- EXPECT_EQ("", input);
- EXPECT_FALSE(output);
- }
- TEST_F(StringFuncTest, TokenizeLast_DocExample2AboveFunctionDeclaration_Succeeds)
- {
- AZStd::string_view input = "Hello World More Tokens";
- AZStd::optional<AZStd::string_view> output;
- output = StringFunc::TokenizeLast(input, ' ');
- EXPECT_EQ("Hello World More ", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("Tokens", output);
- output = StringFunc::TokenizeLast(input, ' ');
- EXPECT_EQ("Hello World More ", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("", output);
- output = StringFunc::TokenizeLast(input, ' ');
- EXPECT_EQ("Hello World More", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("", output);
- output = StringFunc::TokenizeLast(input, ' ');
- EXPECT_EQ("Hello World ", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("More", output);
- output = StringFunc::TokenizeLast(input, ' ');
- EXPECT_EQ("Hello World", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("", output);
- output = StringFunc::TokenizeLast(input, ' ');
- EXPECT_EQ("Hello", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("World", output);
- output = StringFunc::TokenizeLast(input, ' ');
- EXPECT_EQ("", input);
- EXPECT_TRUE(output);
- EXPECT_EQ("Hello", output);
- output = StringFunc::TokenizeLast(input, ' ');
- EXPECT_EQ("", input);
- EXPECT_FALSE(output);
- }
- TEST_F(StringFuncTest, GroupDigits_BasicFunctionality)
- {
- // Test a bunch of numbers and other inputs
- const AZStd::pair<AZStd::string, AZStd::string> inputsAndExpectedOutputs[] =
- {
- { "0", "0" },
- { "10", "10" },
- { "100", "100" },
- { "1000", "1,000" },
- { "10000", "10,000" },
- { "100000", "100,000" },
- { "1000000", "1,000,000" },
- { "0.0", "0.0"},
- { "10.0", "10.0"},
- { "100.0", "100.0" },
- { "1000.0", "1,000.0" },
- { "10000.0", "10,000.0" },
- { "100000.0", "100,000.0" },
- { "1000000.0", "1,000,000.0" },
- { "-0.0", "-0.0" },
- { "-10.0", "-10.0" },
- { "-100.0", "-100.0" },
- { "-1000.0", "-1,000.0" },
- { "-10000.0", "-10,000.0" },
- { "-100000.0", "-100,000.0" },
- { "-1000000.0", "-1,000,000.0" },
- { "foo", "foo" },
- { "foo123.0", "foo123.0" },
- { "foo1234.0", "foo1,234.0" }
- };
- static const size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE];
- for (const auto& inputAndExpectedOutput : inputsAndExpectedOutputs)
- {
- azstrncpy(buffer, BUFFER_SIZE, inputAndExpectedOutput.first.c_str(), inputAndExpectedOutput.first.length() + 1);
- auto endPos = StringFunc::NumberFormatting::GroupDigits(buffer, BUFFER_SIZE);
- EXPECT_STREQ(buffer, inputAndExpectedOutput.second.c_str());
- EXPECT_EQ(inputAndExpectedOutput.second.length(), endPos);
- }
- // Test valid inputs
- AZ_TEST_START_ASSERTTEST;
- StringFunc::NumberFormatting::GroupDigits(nullptr, 0); // Should assert twice, for null pointer and 0 being <= decimalPosHint
- StringFunc::NumberFormatting::GroupDigits(buffer, BUFFER_SIZE, 0, ',', '.', 0, 0); // Should assert for having a non-positive grouping size
- AZ_TEST_STOP_ASSERTTEST(3);
- // Test buffer overruns
- static const size_t SMALL_BUFFER_SIZE = 8;
- char smallBuffer[SMALL_BUFFER_SIZE];
- char prevSmallBuffer[SMALL_BUFFER_SIZE];
- for (const auto& inputAndExpectedOutput : inputsAndExpectedOutputs)
- {
- azstrncpy(smallBuffer, SMALL_BUFFER_SIZE, inputAndExpectedOutput.first.c_str(), AZStd::min(inputAndExpectedOutput.first.length() + 1, SMALL_BUFFER_SIZE - 1));
- smallBuffer[SMALL_BUFFER_SIZE - 1] = 0; // Force null-termination
- memcpy(prevSmallBuffer, smallBuffer, SMALL_BUFFER_SIZE);
- auto endPos = StringFunc::NumberFormatting::GroupDigits(smallBuffer, SMALL_BUFFER_SIZE);
- if (inputAndExpectedOutput.second.length() >= SMALL_BUFFER_SIZE)
- {
- EXPECT_STREQ(smallBuffer, prevSmallBuffer); // No change if buffer overruns
- }
- else
- {
- EXPECT_STREQ(smallBuffer, inputAndExpectedOutput.second.c_str());
- EXPECT_EQ(inputAndExpectedOutput.second.length(), endPos);
- }
- }
- }
- TEST_F(StringFuncTest, GroupDigits_DifferentSettings)
- {
- struct TestSettings
- {
- AZStd::string m_input;
- AZStd::string m_output;
- size_t m_decimalPosHint;
- char m_digitSeparator;
- char m_decimalSeparator;
- int m_groupingSize;
- int m_firstGroupingSize;
- };
- const TestSettings testSettings[] =
- {
- { "123456789.0123", "123,456,789.0123", 9, ',', '.', 3, 0 }, // Correct decimal position hint
- { "123456789.0123", "123,456,789.0123", 8, ',', '.', 3, 0 }, // Incorrect decimal position hint
- { "123456789,0123", "123.456.789,0123", 0, '.', ',', 3, 0 }, // Swap glyphs used for decimal and grouping
- { "123456789.0123", "1,23,45,67,89.0123", 8, ',', '.', 2, 0 }, // Different grouping size
- { "123456789.0123", "12,34,56,789.0123", 8, ',', '.', 2, 3 }, // Customized grouping size for first group
- };
- static const size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE];
- for (const auto& settings : testSettings)
- {
- azstrncpy(buffer, BUFFER_SIZE, settings.m_input.c_str(), settings.m_input.length() + 1);
- auto endPos = StringFunc::NumberFormatting::GroupDigits(buffer, BUFFER_SIZE, settings.m_decimalPosHint, settings.m_digitSeparator,
- settings.m_decimalSeparator, settings.m_groupingSize, settings.m_firstGroupingSize);
- EXPECT_STREQ(buffer, settings.m_output.c_str());
- EXPECT_EQ(settings.m_output.length(), endPos);
- }
- }
- TEST_F(StringFuncTest, CalculateBranchToken_ValidInput_Success)
- {
- AZStd::string samplePath = "F:\\w s 1\\dev";
- AZStd::string expectedToken = "0x68E564C5";
- AZStd::string resultToken;
- AZ::StringFunc::AssetPath::CalculateBranchToken(samplePath, resultToken);
- ASSERT_TRUE(resultToken == expectedToken);
- }
- TEST_F(StringFuncTest, CalculateBranchToken_ValidInputExtra_Success)
- {
- AZStd::string samplePath = "F:\\w s 1\\dev\\";
- AZStd::string expectedToken = "0x68E564C5";
- AZStd::string resultToken;
- AZ::StringFunc::AssetPath::CalculateBranchToken(samplePath, resultToken);
- ASSERT_TRUE(resultToken == expectedToken);
- }
- TEST_F(StringFuncTest, HasDrive_EmptyInput_NoDriveFound)
- {
- EXPECT_FALSE(AZ::StringFunc::Path::HasDrive(""));
- }
- TEST_F(StringFuncTest, HasDrive_InputContainsDrive_DriveFound)
- {
- #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- AZStd::string input;
- input = "F:\\test\\to\\get\\drive\\";
- EXPECT_TRUE(AZ::StringFunc::Path::HasDrive(input.c_str()));
- #endif
- }
- TEST_F(StringFuncTest, HasDrive_InputDoesNotContainDrive_NoDriveFound)
- {
- AZStd::string input;
- #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- input = "test\\with\\no\\drive\\";
- #else
- input = "test/with/no/drive/";
- #endif
- EXPECT_FALSE(AZ::StringFunc::Path::HasDrive(input.c_str()));
- }
- TEST_F(StringFuncTest, HasDrive_CheckAllFileSystemFormats_InputContainsDrive_DriveFound)
- {
- AZStd::string input1 = "F:\\test\\to\\get\\drive\\";
- AZStd::string input2 = "/test/to/get/drive/";
- #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- EXPECT_TRUE(AZ::StringFunc::Path::HasDrive(input1.c_str(), true));
- #endif
- EXPECT_TRUE(AZ::StringFunc::Path::HasDrive(input2.c_str(), true));
- }
- TEST_F(StringFuncTest, HasDrive_CheckAllFileSystemFormats_InputDoesNotContainDrive_NoDriveFound)
- {
- AZStd::string input1 = "test\\with\\no\\drive\\";
- AZStd::string input2 = "test/with/no/drive/";
- EXPECT_FALSE(AZ::StringFunc::Path::HasDrive(input1.c_str(), true));
- EXPECT_FALSE(AZ::StringFunc::Path::HasDrive(input2.c_str(), true));
- }
- TEST_F(StringFuncTest, GetDrive_UseSameStringForInOut_Success)
- {
- #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- AZStd::string input = "F:\\test\\to\\get\\drive\\";
- AZStd::string expectedDriveResult = "F:";
- bool result = AZ::StringFunc::Path::GetDrive(input.c_str(), input);
- ASSERT_TRUE(result);
- ASSERT_EQ(input, expectedDriveResult);
- #endif
- }
- TEST_F(StringFuncTest, IsValid_LongPathComponent_Success)
- {
- #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- AZStd::string longFilename = "F:\\folder\\1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890.txt";
- AZStd::string longFolder = "F:\\1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\\filename.ext";
- bool result = AZ::StringFunc::Path::IsValid(longFilename.c_str(), true, true);
- EXPECT_TRUE(result);
- result = AZ::StringFunc::Path::IsValid(longFolder.c_str(), true, true);
- EXPECT_TRUE(result);
- #else
- AZStd::string longFilename = "/folder/1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890.txt";
- AZStd::string longFolder = "/1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890/filename.ext";
- bool result = AZ::StringFunc::Path::IsValid(longFilename.c_str(), false, true);
- EXPECT_TRUE(result);
- result = AZ::StringFunc::Path::IsValid(longFolder.c_str(), false, true);
- EXPECT_TRUE(result);
- #endif // AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- }
- //! Strip
- TEST_F(StringFuncTest, Strip_InternalCharactersAll_Success)
- {
- AZStd::string input = "Hello World";
- AZStd::string expectedResult = "Heo Word";
- const char stripToken = 'l';
- AZ::StringFunc::Strip(input, stripToken);
- ASSERT_EQ(input, expectedResult);
- }
- TEST_F(StringFuncTest, Strip_InternalCharactersBeginning_NoChange)
- {
- AZStd::string input = "Hello World";
- AZStd::string expectedResult = "Hello World";
- const char stripToken = 'l';
- AZ::StringFunc::Strip(input, stripToken, false, true);
- ASSERT_EQ(input, expectedResult);
- }
- TEST_F(StringFuncTest, Strip_InternalCharactersEnd_NoChange)
- {
- AZStd::string input = "Hello World";
- AZStd::string expectedResult = "Hello World";
- const char stripToken = 'l';
- AZ::StringFunc::Strip(input, stripToken, false, false, true);
- ASSERT_EQ(input, expectedResult);
- }
- TEST_F(StringFuncTest, Strip_InternalCharacterBeginningEnd_NoChange)
- {
- AZStd::string input = "Hello World";
- AZStd::string expectedResult = "Hello World";
- const char stripToken = 'l';
- AZ::StringFunc::Strip(input, stripToken, false, true, true);
- ASSERT_EQ(input, expectedResult);
- }
- TEST_F(StringFuncTest, Strip_InternalCharactersBeginningEndInsensitive_NoChange)
- {
- AZStd::string input = "HeLlo HeLlo HELlO";
- AZStd::string expectedResult = "HeLlo HeLlo HELlO";
- const char stripToken = 'l';
- AZ::StringFunc::Strip(input, stripToken, true, true, true);
- ASSERT_EQ(input, expectedResult);
- }
- TEST_F(StringFuncTest, Strip_InternalCharactersBeginningEndString_Success)
- {
- AZStd::string input = "HeLlo HeLlo HELlO";
- AZStd::string expectedResult = " HeLlo ";
- const char* stripToken = "hello";
- AZ::StringFunc::Strip(input, stripToken, false, true, true);
- ASSERT_EQ(input, expectedResult);
- }
- TEST_F(StringFuncTest, Strip_Beginning_Success)
- {
- AZStd::string input = "AbrAcadabra";
- AZStd::string expectedResult = "brAcadabra";
- const char stripToken = 'a';
- AZ::StringFunc::Strip(input, stripToken, false, true);
- ASSERT_EQ(input, expectedResult);
- }
- TEST_F(StringFuncTest, Strip_End_Success)
- {
- AZStd::string input = "AbrAcadabra";
- AZStd::string expectedResult = "AbrAcadabr";
- const char stripToken = 'a';
- AZ::StringFunc::Strip(input, stripToken, false, false, true);
- ASSERT_EQ(input, expectedResult);
- }
- TEST_F(StringFuncTest, Strip_BeginningEnd_Success)
- {
- AZStd::string input = "AbrAcadabra";
- AZStd::string expectedResult = "brAcadabr";
- const char stripToken = 'a';
- AZ::StringFunc::Strip(input, stripToken, false, true, true);
- ASSERT_EQ(input, expectedResult);
- }
- TEST_F(StringFuncTest, Strip_BeginningEndCaseSensitive_EndOnly)
- {
- AZStd::string input = "AbrAcadabra";
- AZStd::string expectedResult = "AbrAcadabr";
- const char stripToken = 'a';
- AZ::StringFunc::Strip(input, stripToken, true, true, true);
- ASSERT_EQ(input, expectedResult);
- }
- using StringFuncPathTest = LeakDetectionFixture;
- TEST_F(StringFuncPathTest, GetParentDir_InvokedOnAbsoluteDirectory_ReturnsSameDirectory)
- {
- #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- const char* input = R"str(C:\path\to\some\resource\)str";
- const char* expectedResult = R"str(C:\path\to\some)str";
- #else
- const char* input = R"str(/path/to/some/resource/)str";
- const char* expectedResult = R"str(/path/to/some)str";
- #endif
- AZStd::optional<AZStd::string> result = AZ::StringFunc::Path::GetParentDir(input);
- EXPECT_TRUE(result.has_value());
- EXPECT_STREQ(expectedResult, result->c_str());
- }
- TEST_F(StringFuncPathTest, GetParentDir_InvokedOnRelativeDirectory_ReturnsSameDirectory)
- {
- #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- const char* input = R"str(some\resource\)str";
- const char* expectedResult = R"str(some)str";
- #else
- const char* input = R"str(some/resource/)str";
- const char* expectedResult = R"str(some)str";
- #endif
- AZStd::optional<AZStd::string> result = AZ::StringFunc::Path::GetParentDir(input);
- EXPECT_TRUE(result.has_value());
- EXPECT_STREQ(expectedResult, result->c_str());
- }
- TEST_F(StringFuncPathTest, GetParentDir_InvokedOnRelativePathWithoutTrailingSlash_ReturnsParentDirectory)
- {
- #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- const char* input = R"str(some\resource.exe)str";
- const char* expectedResult = R"str(some)str";
- #else
- const char* input = R"str(some/resource.exe)str";
- const char* expectedResult = R"str(some)str";
- #endif
- AZStd::optional<AZStd::string> result = AZ::StringFunc::Path::GetParentDir(input);
- EXPECT_TRUE(result.has_value());
- EXPECT_STREQ(expectedResult, result->c_str());
- }
- TEST_F(StringFuncPathTest, GetParentDir_InvokedOnRoot_ReturnsRoot)
- {
- #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- const char* input = R"str(C:\)str";
- const char* expectedResult = R"str(C:\)str";
- #else
- const char* input = R"str(/)str";
- const char* expectedResult = R"str(/)str";
- #endif
- AZStd::optional<AZStd::string> result = AZ::StringFunc::Path::GetParentDir(input);
- EXPECT_TRUE(result.has_value());
- EXPECT_STREQ(expectedResult, result->c_str());
- }
- TEST_F(StringFuncPathTest, GetParentDir_InvokedOnEmptyPath_ReturnFalse)
- {
- const char* input = "";
- AZStd::optional<AZStd::string> result = AZ::StringFunc::Path::GetParentDir(input);
- EXPECT_FALSE(result.has_value());
- }
- TEST_F(StringFuncPathTest, GetParentDir_InvokedOnPathWithoutParent_ReturnsFalse)
- {
- const char* input = "Test.exe";
- AZStd::optional<AZStd::string> result = AZ::StringFunc::Path::GetParentDir(input);
- EXPECT_FALSE(result.has_value());
- }
- TEST_F(StringFuncPathTest, GetParentDir_InvokedOnWindowsDriveWithoutTrailingSlash_ReturnsTrue)
- {
- const char* input = R"str(C:)str";
- AZStd::optional<AZStd::string> result = AZ::StringFunc::Path::GetParentDir(input);
- #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- EXPECT_TRUE(result.has_value());
- #else
- EXPECT_FALSE(result.has_value());
- #endif
- }
- TEST_F(StringFuncPathTest, ReplaceExtension_WithoutDot)
- {
- AZStd::string s = "D:\\p4\\some.file";
- AZ::StringFunc::Path::ReplaceExtension(s, "xml");
- EXPECT_STREQ("D:\\p4\\some.xml", s.c_str());
- }
- TEST_F(StringFuncPathTest, ReplaceExtension_WithDot)
- {
- AZStd::string s = "D:\\p4\\some.file";
- AZ::StringFunc::Path::ReplaceExtension(s, ".xml");
- EXPECT_STREQ("D:\\p4\\some.xml", s.c_str());
- }
- TEST_F(StringFuncPathTest, ReplaceExtension_Empty)
- {
- AZStd::string s = "D:\\p4\\some.file";
- AZ::StringFunc::Path::ReplaceExtension(s, "");
- EXPECT_STREQ("D:\\p4\\some", s.c_str());
- }
- TEST_F(StringFuncPathTest, ReplaceExtension_Null)
- {
- AZStd::string s = "D:\\p4\\some.file";
- AZ::StringFunc::Path::ReplaceExtension(s, nullptr);
- EXPECT_STREQ("D:\\p4\\some", s.c_str());
- }
- class TestPathStringArgs
- {
- public:
- TestPathStringArgs(const char* input, const char* expected_output)
- : m_input(input),
- m_expected(expected_output)
- {}
- const char* m_input;
- const char* m_expected;
- };
- class StringPathFuncTest
- : public StringFuncTest,
- public ::testing::WithParamInterface<TestPathStringArgs>
- {
- public:
- StringPathFuncTest() = default;
- ~StringPathFuncTest() override = default;
- };
- TEST_P(StringPathFuncTest, TestNormalizePath)
- {
- const TestPathStringArgs& param = GetParam();
- AZStd::string input = AZStd::string(param.m_input);
- AZStd::string expected = AZStd::string(param.m_expected);
- bool result = AZ::StringFunc::Path::Normalize(input);
- EXPECT_TRUE(result);
- EXPECT_STREQ(input.c_str(), expected.c_str());
- }
- #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
- INSTANTIATE_TEST_SUITE_P(
- PathWithSingleDotSubFolders,
- StringPathFuncTest,
- ::testing::Values(
- TestPathStringArgs("F:\\test\\to\\get\\.\\drive\\", "F:\\test\\to\\get\\drive\\")
- ));
- INSTANTIATE_TEST_SUITE_P(
- PathWithDoubleDotSubFolders,
- StringPathFuncTest,
- ::testing::Values(
- TestPathStringArgs("C:\\One\\Two\\..\\Three\\", "C:\\One\\Three\\"),
- TestPathStringArgs("C:\\One\\..\\..\\Two\\", "C:\\Two\\"),
- TestPathStringArgs("C:\\One\\Two\\Three\\..\\", "C:\\One\\Two\\"),
- TestPathStringArgs("F:\\test\\to\\get\\..\\blue\\orchard\\..\\drive\\", "F:\\test\\to\\blue\\drive\\"),
- TestPathStringArgs("F:\\test\\to\\.\\.\\get\\..\\.\\.\\drive\\", "F:\\test\\to\\drive\\"),
- TestPathStringArgs("F:\\..\\test\\to\\.\\.\\get\\..\\.\\.\\drive\\", "F:\\test\\to\\drive\\"),
- TestPathStringArgs("F:\\..\\..\\..\\test\\to\\.\\.\\get\\..\\.\\.\\drive\\", "F:\\test\\to\\drive\\"),
- TestPathStringArgs("F:\\..\\..\\..\\test\\to\\.\\.\\get\\..\\.\\.\\drive\\..\\..\\..\\", "F:\\"),
- TestPathStringArgs("F:\\..\\", "F:\\")
- ));
- #else
- INSTANTIATE_TEST_SUITE_P(
- PathWithSingleDotSubFolders,
- StringPathFuncTest, ::testing::Values(
- TestPathStringArgs("/test/to/get/./drive/", "/test/to/get/drive/")
- ));
- INSTANTIATE_TEST_SUITE_P(
- PathWithDoubleDotSubFolders,
- StringPathFuncTest,
- ::testing::Values(
- TestPathStringArgs("/one/two/../three/", "/one/three/"),
- TestPathStringArgs("/one/../../two/", "/two/"),
- TestPathStringArgs("/one/two/three/../", "/one/two/"),
- TestPathStringArgs("/test/to/get/../blue/orchard/../drive/", "/test/to/blue/drive/"),
- TestPathStringArgs("/test/to/././get./././.drive/", "/test/to/get./.drive/"),
- TestPathStringArgs("/../../test/to/././get/../././drive/", "/test/to/drive/")
- ));
- #endif //AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
-
- }
|