diff --git a/storm/String.hpp b/storm/String.hpp index 572db5a..83e8c2b 100644 --- a/storm/String.hpp +++ b/storm/String.hpp @@ -15,11 +15,11 @@ char* SStrChrR(char* string, char search); const char* SStrChrR(const char* string, char search); -int32_t SStrCmp(const char* string1, const char* string2, size_t maxchars); +int32_t SStrCmp(const char* string1, const char* string2, size_t maxchars = STORM_MAX_STR); -int32_t SStrCmpI(const char* string1, const char* string2, size_t maxchars); +int32_t SStrCmpI(const char* string1, const char* string2, size_t maxchars = STORM_MAX_STR); -size_t SStrCopy(char* dest, const char* source, size_t destsize); +size_t SStrCopy(char* dest, const char* source, size_t destsize = STORM_MAX_STR); char* SStrDupA(const char* string, const char* filename, uint32_t linenumber); diff --git a/test/String.cpp b/test/String.cpp index f51e47e..ce955bb 100644 --- a/test/String.cpp +++ b/test/String.cpp @@ -3,127 +3,153 @@ #include "test/Test.hpp" TEST_CASE("SStrChr", "[string]") { + auto string = "foobar"; + SECTION("finds first character when it exists at start of string") { - auto string = "foobar"; - auto search = 'f'; - auto result = SStrChr(string, search); + auto result = SStrChr(string, 'f'); REQUIRE(result == string); } SECTION("finds first character when it exists in middle of string") { - auto string = "foobar"; - auto search = 'b'; - auto result = SStrChr(string, search); + auto result = SStrChr(string, 'b'); REQUIRE(result == string + 3); } SECTION("finds first character when it exists at end of string") { - auto string = "foobar"; - auto search = 'r'; - auto result = SStrChr(string, search); + auto result = SStrChr(string, 'r'); REQUIRE(result == string + 5); } SECTION("returns nullptr when character does not exist in string") { - auto string = "foobar"; - auto search = 'z'; - auto result = SStrChr(string, search); + auto result = SStrChr(string, 'z'); REQUIRE(result == nullptr); } SECTION("returns nullptr when string is empty") { - auto string = ""; - auto search = 'z'; - auto result = SStrChr(string, search); + auto result = SStrChr("", 'z'); + REQUIRE(result == nullptr); + } + + SECTION("returns nullptr when character is 0") { + auto result = SStrChr(string, '\0'); REQUIRE(result == nullptr); } } TEST_CASE("SStrChrR", "[string]") { + auto string = "ffoobbaarr"; + SECTION("finds last character when it exists at start of string") { - auto string = "ffoobbaarr"; - auto search = 'f'; - auto result = SStrChrR(string, search); + auto result = SStrChrR(string, 'f'); REQUIRE(result == string + 1); } SECTION("finds last character when it exists in middle of string") { - auto string = "ffoobbaarr"; - auto search = 'b'; - auto result = SStrChrR(string, search); + auto result = SStrChrR(string, 'b'); REQUIRE(result == string + 5); } SECTION("finds last character when it exists at end of string") { - auto string = "ffoobbaarr"; - auto search = 'r'; - auto result = SStrChrR(string, search); + auto result = SStrChrR(string, 'r'); REQUIRE(result == string + 9); } SECTION("finds last character when it exists at start and end of string") { auto string = "ffoobbaarrff"; - auto search = 'f'; - auto result = SStrChrR(string, search); + auto result = SStrChrR(string, 'f'); REQUIRE(result == string + 11); } SECTION("returns nullptr when character does not exist in string") { - auto string = "ffoobbaarr"; - auto search = 'z'; - auto result = SStrChrR(string, search); + auto result = SStrChrR(string, 'z'); REQUIRE(result == nullptr); } SECTION("returns nullptr when string is empty") { - auto string = ""; - auto search = 'z'; - auto result = SStrChrR(string, search); + auto result = SStrChrR("", 'z'); + REQUIRE(result == nullptr); + } + + SECTION("returns nullptr when character is 0") { + auto result = SStrChrR(string, '\0'); REQUIRE(result == nullptr); } } TEST_CASE("SStrCmp", "[string]") { SECTION("compares two strings that exactly match correctly") { - auto compare = SStrCmp("foo", "foo", STORM_MAX_STR); + auto compare = SStrCmp("foo", "foo"); REQUIRE(compare == 0); } SECTION("compares two strings that partially match correctly") { - auto compare1 = SStrCmp("bar", "foobar", STORM_MAX_STR); - auto compare2 = SStrCmp("foobar", "bar", STORM_MAX_STR); + auto compare1 = SStrCmp("bar", "foobar"); + auto compare2 = SStrCmp("foobar", "bar"); REQUIRE(compare1 < 0); REQUIRE(compare2 > 0); } SECTION("compares two strings that do not match correctly") { - auto compare = SStrCmp("bar", "xyzzy", STORM_MAX_STR); + auto compare = SStrCmp("bar", "xyzzy"); REQUIRE(compare < 0); } + + SECTION("only compares up to maxchars") { + auto compare = SStrCmp("donkeykong", "donkeypinnochio", 6); + REQUIRE(compare == 0); + } + + SECTION("compare is case sensitive") { + auto compare = SStrCmp("dingdong", "dInGdOnG"); + REQUIRE(compare != 0); + } } TEST_CASE("SStrCmpI", "[string]") { SECTION("compares two strings that exactly match correctly") { - auto compare = SStrCmpI("foo", "foo", STORM_MAX_STR); + auto compare = SStrCmpI("foo", "foo"); REQUIRE(compare == 0); } SECTION("compares two strings that match with differing case correctly") { - auto compare = SStrCmpI("foo", "foO", STORM_MAX_STR); + auto compare = SStrCmpI("foo", "FoO"); REQUIRE(compare == 0); } + SECTION("compares two strings that partially match correctly") { + auto compare1 = SStrCmpI("bar", "foobar"); + auto compare2 = SStrCmpI("foobar", "bar"); + REQUIRE(compare1 < 0); + REQUIRE(compare2 > 0); + } + SECTION("compares two strings that do not match correctly") { - auto compare = SStrCmpI("bar", "xyzzy", STORM_MAX_STR); + auto compare = SStrCmpI("bar", "xyzzy"); REQUIRE(compare < 0); } + + SECTION("only compares up to maxchars") { + auto compare = SStrCmpI("donkeykong", "donkeypinnochio", 6); + REQUIRE(compare == 0); + } } TEST_CASE("SStrDupA", "[string]") { SECTION("duplicates string correctly") { auto string1 = "foo bar"; auto string2 = SStrDupA(string1, __FILE__, __LINE__); - auto compare = SStrCmp(string1, string2, STORM_MAX_STR); + auto compare = SStrCmp(string1, string2); + auto newPtr = string1 != string2; + SMemFree(string2); + + REQUIRE(compare == 0); + REQUIRE(newPtr == true); + } + + SECTION("duplicates empty string correctly") { + auto string1 = ""; + auto string2 = SStrDupA(string1, __FILE__, __LINE__); + auto compare = SStrCmp(string1, string2); auto newPtr = string1 != string2; SMemFree(string2); @@ -152,112 +178,144 @@ TEST_CASE("SStrHashHT", "[string]") { TEST_CASE("SStrLen", "[string]") { SECTION("calculates string length correctly") { - auto length = SStrLen("foo"); - REQUIRE(length == 3); + REQUIRE(SStrLen("foo") == 3); + } + + SECTION("calculates empty string length correctly") { + REQUIRE(SStrLen("") == 0); } } TEST_CASE("SStrLower", "[string]") { SECTION("rewrites uppercase string to lowercase correctly") { - auto upper = "FOOBAR"; - char* lower = static_cast(SMemAlloc(SStrLen(upper) + 1, __FILE__, __LINE__, 0x0)); - SStrCopy(lower, upper, STORM_MAX_STR); - SStrLower(lower); - auto compare = SStrCmp(lower, "foobar", SStrLen(lower)); - SMemFree(lower); + char string[] = "FOOBAR"; + SStrLower(string); - REQUIRE(!compare); + REQUIRE(!SStrCmp(string, "foobar")); } SECTION("rewrites lowercase string to lowercase correctly") { - auto lower1 = "foobar"; - char* lower2 = static_cast(SMemAlloc(SStrLen(lower1) + 1, __FILE__, __LINE__, 0x0)); - SStrCopy(lower2, lower1, STORM_MAX_STR); - SStrLower(lower2); - auto compare = SStrCmp(lower2, "foobar", SStrLen(lower2)); - SMemFree(lower2); + char string[] = "foobar"; + SStrLower(string); - REQUIRE(!compare); + REQUIRE(!SStrCmp(string, "foobar")); + } + + SECTION("does nothing on empty string") { + char string[] = ""; + SStrLower(string); + + REQUIRE(!SStrCmp(string, "")); } } TEST_CASE("SStrPack", "[string]") { SECTION("truncates dest correctly when first byte in source is null") { - char dest[10] = { 0 }; + char dest[10] = {}; auto source = "\0foobar"; - auto length = SStrPack(dest, source, 10); + auto length = SStrPack(dest, source, sizeof(dest)); + REQUIRE(length == 0); - REQUIRE(!SStrCmp(dest, "", SStrLen(""))); + REQUIRE(!SStrCmp(dest, "")); } SECTION("truncates dest correctly when middle byte in source is null") { - char dest[10] = { 0 }; + char dest[10] = {}; auto source = "foo\0bar"; - auto length = SStrPack(dest, source, 10); + auto length = SStrPack(dest, source, sizeof(dest)); + REQUIRE(length == 3); - REQUIRE(!SStrCmp(dest, "foo", SStrLen("foo"))); + REQUIRE(!SStrCmp(dest, "foo")); } SECTION("does not truncate dest when source has no early null byte") { - char dest[10] = { 0 }; + char dest[10] = {}; auto source = "foobar"; - auto length = SStrPack(dest, source, 10); + auto length = SStrPack(dest, source, sizeof(dest)); + REQUIRE(length == 6); - REQUIRE(!SStrCmp(dest, "foobar", SStrLen("foobar"))); + REQUIRE(!SStrCmp(dest, "foobar")); + } + + SECTION("appends to target string") { + char dest[10] = "who"; + auto length = SStrPack(dest, "dis", sizeof(dest)); + + REQUIRE(length == 6); + REQUIRE(!SStrCmp(dest, "whodis")); + } + + SECTION("truncates when dest size is not large enough") { + char dest[5] = "who"; + auto length = SStrPack(dest, "dis", sizeof(dest)); + + REQUIRE(length == 4); + REQUIRE(!SStrCmp(dest, "whod")); } } TEST_CASE("SStrPrintf", "[string]") { SECTION("fills dest with formatted string") { - char dest[100] = { 0 }; - auto format = "%s - %s"; - auto length = SStrPrintf(dest, 100, format, "foo", "bar"); + char dest[100] = {}; + auto length = SStrPrintf(dest, sizeof(dest), "%s - %s", "foo", "bar"); + REQUIRE(length == 9); - REQUIRE(!SStrCmp(dest, "foo - bar", SStrLen("foo - bar"))); + REQUIRE(!SStrCmp(dest, "foo - bar")); + } + + SECTION("fills dest with int") { + char dest[100] = {}; + auto length = SStrPrintf(dest, sizeof(dest), "%d", 69); + + REQUIRE(length == 2); + REQUIRE(!SStrCmp(dest, "69")); } SECTION("fills dest with empty string") { - char dest[100] = { 0 }; - auto format = ""; - auto length = SStrPrintf(dest, 100, format); + char dest[100] = {}; + auto length = SStrPrintf(dest, sizeof(dest), ""); + REQUIRE(length == 0); - REQUIRE(!SStrCmp(dest, "", SStrLen(""))); + REQUIRE(!SStrCmp(dest, "")); } + + SECTION("truncates when dest size is not large enough") { + char dest[4] = {}; + auto length = SStrPrintf(dest, sizeof(dest), "%s", "wowzers"); + + REQUIRE(length == 3); + REQUIRE(!SStrCmp(dest, "wow")); + } + } TEST_CASE("SStrStr", "[string]") { + auto string = "foobar"; + SECTION("finds substring when it exists at end of string") { - auto string = "foobar"; auto search = "bar"; auto substring = SStrStr(string, search); - REQUIRE(!SStrCmp(search, substring, SStrLen(search))); + REQUIRE(substring == string + 3); } SECTION("finds substring when it exists at start of string") { - auto string = "foobar"; auto search = "foo"; auto substring = SStrStr(string, search); - REQUIRE(!SStrCmp(search, substring, SStrLen(search))); + REQUIRE(substring == string); } SECTION("finds substring when search is empty") { - auto string = "foobar"; - auto search = ""; - auto substring = SStrStr(string, search); - REQUIRE(!SStrCmp(string, substring, SStrLen(string))); + auto substring = SStrStr(string, ""); + REQUIRE(substring == string); } SECTION("returns nullptr when search does not exist in string") { - auto string = "foobar"; - auto search = "xyzzy"; - auto substring = SStrStr(string, search); + auto substring = SStrStr(string, "xyzzy"); REQUIRE(substring == nullptr); } SECTION("returns nullptr when given empty string") { - auto string = ""; - auto search = "bar"; - auto substring = SStrStr(string, search); + auto substring = SStrStr("", "bar"); REQUIRE(substring == nullptr); } } @@ -265,36 +323,36 @@ TEST_CASE("SStrStr", "[string]") { TEST_CASE("SStrTokenize", "[string]") { SECTION("finds all tokens in comma-delimited string") { auto string = "foo,bar,baz"; - char buffer[100] = { 0 }; + char buffer[100] = {}; const char* tokens[] = { "foo", "bar", "baz" }; for (auto& token : tokens) { - SStrTokenize(&string, buffer, 1000, " ,", nullptr); - REQUIRE(!SStrCmp(buffer, token, STORM_MAX_STR)); + SStrTokenize(&string, buffer, sizeof(buffer), " ,", nullptr); + REQUIRE(!SStrCmp(buffer, token)); } } SECTION("finds all tokens in comma-and-whitespace-delimited string") { auto string = "foo , bar , baz"; - char buffer[100] = { 0 }; + char buffer[100] = {}; const char* tokens[] = { "foo", "bar", "baz" }; for (auto& token : tokens) { - SStrTokenize(&string, buffer, 1000, " ,", nullptr); - REQUIRE(!SStrCmp(buffer, token, STORM_MAX_STR)); + SStrTokenize(&string, buffer, sizeof(buffer), " ,", nullptr); + REQUIRE(!SStrCmp(buffer, token)); } } SECTION("finds no tokens empty string") { auto string = ""; - char buffer[100] = { 0 }; - SStrTokenize(&string, buffer, 1000, " ,", nullptr); - REQUIRE(!SStrCmp(buffer, "", STORM_MAX_STR)); + char buffer[100] = {}; + SStrTokenize(&string, buffer, sizeof(buffer), " ,", nullptr); + REQUIRE(!SStrCmp(buffer, "")); } SECTION("identifies quoted tokens") { auto string = "foo bar \"baz bazinga\" bodonkers \"donga dongs\""; - char buffer[100] = { 0 }; + char buffer[100] = {}; std::pair tokens[] = { std::make_pair("foo", 0), std::make_pair("bar", 0), @@ -305,7 +363,7 @@ TEST_CASE("SStrTokenize", "[string]") { for (auto& token : tokens) { int quoted = 0; - SStrTokenize(&string, buffer, 1000, " \"", "ed); + SStrTokenize(&string, buffer, sizeof(buffer), " \"", "ed); std::string result = buffer; REQUIRE(result == token.first); REQUIRE(quoted == token.second); @@ -314,7 +372,7 @@ TEST_CASE("SStrTokenize", "[string]") { SECTION("doesn't identify quoted tokens if excluded from whitespace") { auto string = "foo bar \"baz bazinga\" bodonkers \"donga dongs\""; - char buffer[100] = { 0 }; + char buffer[100] = {}; std::pair tokens[] = { std::make_pair("foo", 0), std::make_pair("bar", 0), @@ -327,7 +385,7 @@ TEST_CASE("SStrTokenize", "[string]") { for (auto& token : tokens) { int quoted = 0; - SStrTokenize(&string, buffer, 1000, " ", "ed); + SStrTokenize(&string, buffer, sizeof(buffer), " ", "ed); std::string result = buffer; REQUIRE(result == token.first); REQUIRE(quoted == token.second); @@ -337,130 +395,137 @@ TEST_CASE("SStrTokenize", "[string]") { TEST_CASE("SStrToFloat", "[string]") { SECTION("converts empty string to float") { - auto string = ""; - auto result = SStrToFloat(string); + auto result = SStrToFloat(""); REQUIRE(result == 0.0f); } SECTION("converts whitespace string to float") { - auto string = " "; - auto result = SStrToFloat(string); + auto result = SStrToFloat(" \t\r\n"); + REQUIRE(result == 0.0f); + } + + SECTION("converts random characters to float") { + auto result = SStrToFloat("abcd"); REQUIRE(result == 0.0f); } SECTION("converts string with positive int to float") { - auto string = "123"; - auto result = SStrToFloat(string); + auto result = SStrToFloat("123"); REQUIRE(result == 123.0f); } SECTION("converts string with negative int to float") { - auto string = "-123"; - auto result = SStrToFloat(string); + auto result = SStrToFloat("-123"); REQUIRE(result == -123.0f); } SECTION("converts string with positive float to float") { - auto string = "1.5"; - auto result = SStrToFloat(string); + auto result = SStrToFloat("1.5"); REQUIRE(result == 1.5f); } SECTION("converts string with negative float to float") { - auto string = "-1.5"; - auto result = SStrToFloat(string); + auto result = SStrToFloat("-1.5"); REQUIRE(result == -1.5f); } SECTION("converts string with float and positive exponent to float") { - auto string = "1.5e3"; - auto result = SStrToFloat(string); + auto result = SStrToFloat("1.5e3"); REQUIRE(result == 1500.0f); } + SECTION("converts string with float and positive full form exponent to float") { + auto result = SStrToFloat("1.5e+3"); + REQUIRE(result == 1500.0f); + } + + SECTION("converts string with capital exponent to float") { + auto result = SStrToFloat("1.5E+3"); + REQUIRE(result == 1500.0f); + } + + SECTION("converts string with random added letter to float") { + auto result = SStrToFloat("1.5g3"); + REQUIRE(result == 1.5f); + } + SECTION("converts string with float and negative exponent to float") { - auto string = "1500.0e-3"; - auto result = SStrToFloat(string); + auto result = SStrToFloat("1500.0e-3"); REQUIRE(result == 1.5f); } SECTION("converts string with zero to float") { - auto string = "0"; - auto result = SStrToFloat(string); + auto result = SStrToFloat("0"); REQUIRE(result == 0.0f); } SECTION("converts string with leading zero to float") { - auto string = "01"; - auto result = SStrToFloat(string); + auto result = SStrToFloat("01"); REQUIRE(result == 1.0f); } } TEST_CASE("SStrToInt", "[string]") { SECTION("converts empty string to int") { - auto string = ""; - auto result = SStrToInt(string); + auto result = SStrToInt(""); REQUIRE(result == 0); } SECTION("converts whitespace string to int") { - auto string = " "; - auto result = SStrToInt(string); + auto result = SStrToInt(" "); + REQUIRE(result == 0); + } + + SECTION("converts random characters to int") { + auto result = SStrToInt("abcd"); REQUIRE(result == 0); } SECTION("converts string with positive number to int") { - auto string = "123"; - auto result = SStrToInt(string); + auto result = SStrToInt("123"); REQUIRE(result == 123); } SECTION("converts string with negative number to int") { - auto string = "-123"; - auto result = SStrToInt(string); + auto result = SStrToInt("-123"); REQUIRE(result == -123); } SECTION("converts string with zero to int") { - auto string = "0"; - auto result = SStrToInt(string); + auto result = SStrToInt("0"); REQUIRE(result == 0); } SECTION("converts string with leading zero to int") { - auto string = "01"; - auto result = SStrToInt(string); + auto result = SStrToInt("01"); REQUIRE(result == 1); } SECTION("converts string with two whitespace-separated numbers to int") { - auto string = "123 456"; - auto result = SStrToInt(string); + auto result = SStrToInt("123 456"); REQUIRE(result == 123); } } TEST_CASE("SStrUpper", "[string]") { SECTION("rewrites lowercase string to uppercase correctly") { - auto lower = "foobar"; - auto upper = static_cast(SMemAlloc(SStrLen(lower) + 1, __FILE__, __LINE__, 0x0)); - SStrCopy(upper, lower, STORM_MAX_STR); - SStrUpper(upper); - auto compare = SStrCmp(upper, "FOOBAR", SStrLen(upper)); - SMemFree(upper); + char string[] = "foobar"; + SStrUpper(string); - REQUIRE(!compare); + REQUIRE(!SStrCmp(string, "FOOBAR")); } SECTION("rewrites uppercase string to uppercase correctly") { - auto upper1 = "FOOBAR"; - auto upper2 = static_cast(SMemAlloc(SStrLen(upper1) + 1, __FILE__, __LINE__, 0x0)); - SStrCopy(upper2, upper1, STORM_MAX_STR); - SStrUpper(upper2); - auto compare = SStrCmp(upper2, "FOOBAR", SStrLen(upper2)); - SMemFree(upper2); + char string[] = "FOOBAR"; + SStrUpper(string); - REQUIRE(!compare); + REQUIRE(!SStrCmp(string, "FOOBAR")); + } + + SECTION("does nothing on empty string") { + char string[] = ""; + SStrUpper(string); + + REQUIRE(!SStrCmp(string, "")); } }