12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076 |
- /*
- * 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
-
- }
|