mirror of https://github.com/OpenTTD/OpenTTD
Codechange: introduce StrEqualsIgnoreCase/StrCompareIgnoreCase to replace strcasecmp
parent
36a0818bc5
commit
86786a7af6
|
@ -123,7 +123,7 @@ AIInfo *AIScannerInfo::FindInfo(const char *nameParam, int versionParam, bool fo
|
|||
* version which allows loading the requested version */
|
||||
for (const auto &item : this->info_list) {
|
||||
AIInfo *i = static_cast<AIInfo *>(item.second);
|
||||
if (strcasecmp(ai_name, i->GetName()) == 0 && i->CanLoadFromVersion(versionParam) && (version == -1 || i->GetVersion() > version)) {
|
||||
if (StrEqualsIgnoreCase(ai_name, i->GetName()) && i->CanLoadFromVersion(versionParam) && (version == -1 || i->GetVersion() > version)) {
|
||||
version = item.second->GetVersion();
|
||||
info = i;
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ public:
|
|||
Blitters::iterator it = GetBlitters().begin();
|
||||
for (; it != GetBlitters().end(); it++) {
|
||||
BlitterFactory *b = (*it).second;
|
||||
if (strcasecmp(bname, b->name.c_str()) == 0) {
|
||||
if (StrEqualsIgnoreCase(bname, b->name)) {
|
||||
return b->IsUsable() ? b : nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1868,7 +1868,7 @@ static ContentType StringToContentType(const char *str)
|
|||
{
|
||||
static const char * const inv_lookup[] = { "", "base", "newgrf", "ai", "ailib", "scenario", "heightmap" };
|
||||
for (uint i = 1 /* there is no type 0 */; i < lengthof(inv_lookup); i++) {
|
||||
if (strcasecmp(str, inv_lookup[i]) == 0) return (ContentType)i;
|
||||
if (StrEqualsIgnoreCase(str, inv_lookup[i])) return (ContentType)i;
|
||||
}
|
||||
return CONTENT_TYPE_END;
|
||||
}
|
||||
|
@ -1926,17 +1926,17 @@ DEF_CONSOLE_CMD(ConContent)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (strcasecmp(argv[1], "update") == 0) {
|
||||
if (StrEqualsIgnoreCase(argv[1], "update")) {
|
||||
_network_content_client.RequestContentList((argc > 2) ? StringToContentType(argv[2]) : CONTENT_TYPE_END);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcasecmp(argv[1], "upgrade") == 0) {
|
||||
if (StrEqualsIgnoreCase(argv[1], "upgrade")) {
|
||||
_network_content_client.SelectUpgrade();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcasecmp(argv[1], "select") == 0) {
|
||||
if (StrEqualsIgnoreCase(argv[1], "select")) {
|
||||
if (argc <= 2) {
|
||||
/* List selected content */
|
||||
IConsolePrint(CC_WHITE, "id, type, state, name");
|
||||
|
@ -1944,7 +1944,7 @@ DEF_CONSOLE_CMD(ConContent)
|
|||
if ((*iter)->state != ContentInfo::SELECTED && (*iter)->state != ContentInfo::AUTOSELECTED) continue;
|
||||
OutputContentState(*iter);
|
||||
}
|
||||
} else if (strcasecmp(argv[2], "all") == 0) {
|
||||
} else if (StrEqualsIgnoreCase(argv[2], "all")) {
|
||||
/* The intention of this function was that you could download
|
||||
* everything after a filter was applied; but this never really
|
||||
* took off. Instead, a select few people used this functionality
|
||||
|
@ -1958,12 +1958,12 @@ DEF_CONSOLE_CMD(ConContent)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (strcasecmp(argv[1], "unselect") == 0) {
|
||||
if (StrEqualsIgnoreCase(argv[1], "unselect")) {
|
||||
if (argc <= 2) {
|
||||
IConsolePrint(CC_ERROR, "You must enter the id.");
|
||||
return false;
|
||||
}
|
||||
if (strcasecmp(argv[2], "all") == 0) {
|
||||
if (StrEqualsIgnoreCase(argv[2], "all")) {
|
||||
_network_content_client.UnselectAll();
|
||||
} else {
|
||||
_network_content_client.Unselect((ContentID)atoi(argv[2]));
|
||||
|
@ -1971,7 +1971,7 @@ DEF_CONSOLE_CMD(ConContent)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (strcasecmp(argv[1], "state") == 0) {
|
||||
if (StrEqualsIgnoreCase(argv[1], "state")) {
|
||||
IConsolePrint(CC_WHITE, "id, type, state, name");
|
||||
for (ConstContentIterator iter = _network_content_client.Begin(); iter != _network_content_client.End(); iter++) {
|
||||
if (argc > 2 && strcasestr((*iter)->name.c_str(), argv[2]) == nullptr) continue;
|
||||
|
@ -1980,7 +1980,7 @@ DEF_CONSOLE_CMD(ConContent)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (strcasecmp(argv[1], "download") == 0) {
|
||||
if (StrEqualsIgnoreCase(argv[1], "download")) {
|
||||
uint files;
|
||||
uint bytes;
|
||||
_network_content_client.DownloadSelectedContent(files, bytes);
|
||||
|
@ -2007,7 +2007,7 @@ DEF_CONSOLE_CMD(ConFont)
|
|||
|
||||
FontSize argfs;
|
||||
for (argfs = FS_BEGIN; argfs < FS_END; argfs++) {
|
||||
if (argc > 1 && strcasecmp(argv[1], FontSizeToName(argfs)) == 0) break;
|
||||
if (argc > 1 && StrEqualsIgnoreCase(argv[1], FontSizeToName(argfs))) break;
|
||||
}
|
||||
|
||||
/* First argument must be a FontSize. */
|
||||
|
@ -2021,7 +2021,7 @@ DEF_CONSOLE_CMD(ConFont)
|
|||
|
||||
byte arg_index = 2;
|
||||
/* We may encounter "aa" or "noaa" but it must be the last argument. */
|
||||
if (strcasecmp(argv[arg_index], "aa") == 0 || strcasecmp(argv[arg_index], "noaa") == 0) {
|
||||
if (StrEqualsIgnoreCase(argv[arg_index], "aa") || StrEqualsIgnoreCase(argv[arg_index], "noaa")) {
|
||||
aa = strncasecmp(argv[arg_index++], "no", 2) != 0;
|
||||
if (argc > arg_index) return false;
|
||||
} else {
|
||||
|
@ -2043,7 +2043,7 @@ DEF_CONSOLE_CMD(ConFont)
|
|||
|
||||
if (argc > arg_index) {
|
||||
/* Last argument must be "aa" or "noaa". */
|
||||
if (strcasecmp(argv[arg_index], "aa") != 0 && strcasecmp(argv[arg_index], "noaa") != 0) return false;
|
||||
if (!StrEqualsIgnoreCase(argv[arg_index], "aa") && !StrEqualsIgnoreCase(argv[arg_index], "noaa")) return false;
|
||||
aa = strncasecmp(argv[arg_index++], "no", 2) != 0;
|
||||
if (argc > arg_index) return false;
|
||||
}
|
||||
|
@ -2171,7 +2171,7 @@ DEF_CONSOLE_CMD(ConListDirs)
|
|||
|
||||
std::set<std::string> seen_dirs;
|
||||
for (const SubdirNameMap &sdn : subdir_name_map) {
|
||||
if (strcasecmp(argv[1], sdn.name) != 0) continue;
|
||||
if (!StrEqualsIgnoreCase(argv[1], sdn.name)) continue;
|
||||
bool found = false;
|
||||
for (Searchpath sp : _valid_searchpaths) {
|
||||
/* Get the directory */
|
||||
|
@ -2256,7 +2256,7 @@ DEF_CONSOLE_CMD(ConNewGRFProfile)
|
|||
/* "unselect" sub-command */
|
||||
if (strncasecmp(argv[1], "uns", 3) == 0 && argc >= 3) {
|
||||
for (size_t argnum = 2; argnum < argc; ++argnum) {
|
||||
if (strcasecmp(argv[argnum], "all") == 0) {
|
||||
if (StrEqualsIgnoreCase(argv[argnum], "all")) {
|
||||
_newgrf_profilers.clear();
|
||||
break;
|
||||
}
|
||||
|
@ -2501,17 +2501,17 @@ DEF_CONSOLE_CMD(ConDumpInfo)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (strcasecmp(argv[1], "roadtypes") == 0) {
|
||||
if (StrEqualsIgnoreCase(argv[1], "roadtypes")) {
|
||||
ConDumpRoadTypes();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcasecmp(argv[1], "railtypes") == 0) {
|
||||
if (StrEqualsIgnoreCase(argv[1], "railtypes")) {
|
||||
ConDumpRailTypes();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcasecmp(argv[1], "cargotypes") == 0) {
|
||||
if (StrEqualsIgnoreCase(argv[1], "cargotypes")) {
|
||||
ConDumpCargoTypes();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -160,7 +160,7 @@ bool DriverFactoryBase::SelectDriverImpl(const std::string &name, Driver::Type t
|
|||
if (d->type != type) continue;
|
||||
|
||||
/* Check driver name */
|
||||
if (strcasecmp(dname.c_str(), d->name) != 0) continue;
|
||||
if (!StrEqualsIgnoreCase(dname, d->name)) continue;
|
||||
|
||||
/* Found our driver, let's try it */
|
||||
Driver *newd = d->CreateInstance();
|
||||
|
|
|
@ -1142,7 +1142,7 @@ static bool MatchesExtension(const char *extension, const char *filename)
|
|||
if (extension == nullptr) return true;
|
||||
|
||||
const char *ext = strrchr(filename, extension[0]);
|
||||
return ext != nullptr && strcasecmp(ext, extension) == 0;
|
||||
return ext != nullptr && StrEqualsIgnoreCase(ext, extension);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
18
src/fios.cpp
18
src/fios.cpp
|
@ -216,7 +216,7 @@ static std::string FiosMakeFilename(const std::string *path, const char *name, c
|
|||
|
||||
/* Don't append the extension if it is already there */
|
||||
const char *period = strrchr(name, '.');
|
||||
if (period != nullptr && strcasecmp(period, ext) == 0) ext = "";
|
||||
if (period != nullptr && StrEqualsIgnoreCase(period, ext)) ext = "";
|
||||
|
||||
return buf + PATHSEP + name + ext;
|
||||
}
|
||||
|
@ -473,14 +473,14 @@ FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &f
|
|||
/* Don't crash if we supply no extension */
|
||||
if (ext == nullptr) return FIOS_TYPE_INVALID;
|
||||
|
||||
if (strcasecmp(ext, ".sav") == 0) {
|
||||
if (StrEqualsIgnoreCase(ext, ".sav")) {
|
||||
GetFileTitle(file, title, last, SAVE_DIR);
|
||||
return FIOS_TYPE_FILE;
|
||||
}
|
||||
|
||||
if (fop == SLO_LOAD) {
|
||||
if (strcasecmp(ext, ".ss1") == 0 || strcasecmp(ext, ".sv1") == 0 ||
|
||||
strcasecmp(ext, ".sv2") == 0) {
|
||||
if (StrEqualsIgnoreCase(ext, ".ss1") || StrEqualsIgnoreCase(ext, ".sv1") ||
|
||||
StrEqualsIgnoreCase(ext, ".sv2")) {
|
||||
if (title != nullptr) GetOldSaveGameName(file, title, last);
|
||||
return FIOS_TYPE_OLDFILE;
|
||||
}
|
||||
|
@ -523,13 +523,13 @@ static FiosType FiosGetScenarioListCallback(SaveLoadOperation fop, const std::st
|
|||
* .SCN OpenTTD style scenario file
|
||||
* .SV0 Transport Tycoon Deluxe (Patch) scenario
|
||||
* .SS0 Transport Tycoon Deluxe preset scenario */
|
||||
if (strcasecmp(ext, ".scn") == 0) {
|
||||
if (StrEqualsIgnoreCase(ext, ".scn")) {
|
||||
GetFileTitle(file, title, last, SCENARIO_DIR);
|
||||
return FIOS_TYPE_SCENARIO;
|
||||
}
|
||||
|
||||
if (fop == SLO_LOAD) {
|
||||
if (strcasecmp(ext, ".sv0") == 0 || strcasecmp(ext, ".ss0") == 0 ) {
|
||||
if (StrEqualsIgnoreCase(ext, ".sv0") || StrEqualsIgnoreCase(ext, ".ss0")) {
|
||||
GetOldSaveGameName(file, title, last);
|
||||
return FIOS_TYPE_OLD_SCENARIO;
|
||||
}
|
||||
|
@ -568,10 +568,10 @@ static FiosType FiosGetHeightmapListCallback(SaveLoadOperation fop, const std::s
|
|||
FiosType type = FIOS_TYPE_INVALID;
|
||||
|
||||
#ifdef WITH_PNG
|
||||
if (strcasecmp(ext, ".png") == 0) type = FIOS_TYPE_PNG;
|
||||
if (StrEqualsIgnoreCase(ext, ".png")) type = FIOS_TYPE_PNG;
|
||||
#endif /* WITH_PNG */
|
||||
|
||||
if (strcasecmp(ext, ".bmp") == 0) type = FIOS_TYPE_BMP;
|
||||
if (StrEqualsIgnoreCase(ext, ".bmp")) type = FIOS_TYPE_BMP;
|
||||
|
||||
if (type == FIOS_TYPE_INVALID) return FIOS_TYPE_INVALID;
|
||||
|
||||
|
@ -760,7 +760,7 @@ FiosNumberedSaveName::FiosNumberedSaveName(const std::string &prefix) : prefix(p
|
|||
|
||||
/* Callback for FiosFileScanner. */
|
||||
static fios_getlist_callback_proc *proc = [](SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last) {
|
||||
if (strcasecmp(ext, ".sav") == 0 && StrStartsWith(file, _prefix)) return FIOS_TYPE_FILE;
|
||||
if (StrEqualsIgnoreCase(ext, ".sav") && StrStartsWith(file, _prefix)) return FIOS_TYPE_FILE;
|
||||
return FIOS_TYPE_INVALID;
|
||||
};
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ GameInfo *GameScannerInfo::FindInfo(const char *nameParam, int versionParam, boo
|
|||
* version which allows loading the requested version */
|
||||
for (const auto &item : this->info_list) {
|
||||
GameInfo *i = static_cast<GameInfo *>(item.second);
|
||||
if (strcasecmp(game_name, i->GetName()) == 0 && i->CanLoadFromVersion(versionParam) && (version == -1 || i->GetVersion() > version)) {
|
||||
if (StrEqualsIgnoreCase(game_name, i->GetName()) && i->CanLoadFromVersion(versionParam) && (version == -1 || i->GetVersion() > version)) {
|
||||
version = item.second->GetVersion();
|
||||
info = i;
|
||||
}
|
||||
|
|
|
@ -630,7 +630,7 @@ bool GRFFileScanner::AddFile(const std::string &filename, size_t basepath_length
|
|||
/* Because there can be multiple grfs with the same name, make sure we checked all grfs with the same name,
|
||||
* before inserting the entry. So insert a new grf at the end of all grfs with the same name, instead of
|
||||
* just after the first with the same name. Avoids doubles in the list. */
|
||||
if (strcasecmp(c->GetName(), d->GetName()) <= 0) {
|
||||
if (StrCompareIgnoreCase(c->GetName(), d->GetName()) <= 0) {
|
||||
stop = true;
|
||||
} else if (stop) {
|
||||
break;
|
||||
|
|
|
@ -70,12 +70,12 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
|
|||
FcPatternGetString(fs->fonts[i], FC_STYLE, 0, &style) == FcResultMatch) {
|
||||
|
||||
/* The correct style? */
|
||||
if (font_style != nullptr && strcasecmp(font_style, (char *)style) != 0) continue;
|
||||
if (font_style != nullptr && !StrEqualsIgnoreCase(font_style, (char *)style)) continue;
|
||||
|
||||
/* Font config takes the best shot, which, if the family name is spelled
|
||||
* wrongly a 'random' font, so check whether the family name is the
|
||||
* same as the supplied name */
|
||||
if (strcasecmp(font_family, (char *)family) == 0) {
|
||||
if (StrEqualsIgnoreCase(font_family, (char *)family)) {
|
||||
err = FT_New_Face(_library, (char *)file, 0, face);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ void ScriptScanner::RegisterScript(ScriptInfo *info)
|
|||
/* This script was already registered */
|
||||
#ifdef _WIN32
|
||||
/* Windows doesn't care about the case */
|
||||
if (strcasecmp(this->info_list[script_name]->GetMainScript(), info->GetMainScript()) == 0) {
|
||||
if (StrEqualsIgnoreCase(this->info_list[script_name]->GetMainScript(), info->GetMainScript()) == 0) {
|
||||
#else
|
||||
if (strcmp(this->info_list[script_name]->GetMainScript(), info->GetMainScript()) == 0) {
|
||||
#endif
|
||||
|
@ -231,7 +231,7 @@ static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, S
|
|||
|
||||
/* Check the extension. */
|
||||
const char *ext = strrchr(tar.first.c_str(), '.');
|
||||
if (ext == nullptr || strcasecmp(ext, ".nut") != 0) continue;
|
||||
if (ext == nullptr || !StrEqualsIgnoreCase(ext, ".nut")) continue;
|
||||
|
||||
checksum.AddFile(tar.first, 0, tar_filename);
|
||||
}
|
||||
|
|
|
@ -368,6 +368,59 @@ bool StrEndsWith(const std::string_view str, const std::string_view suffix)
|
|||
return str.compare(str.size() - suffix_len, suffix_len, suffix, 0, suffix_len) == 0;
|
||||
}
|
||||
|
||||
/** Case insensitive implementation of the standard character type traits. */
|
||||
struct CaseInsensitiveCharTraits : public std::char_traits<char> {
|
||||
static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
|
||||
static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); }
|
||||
static bool lt(char c1, char c2) { return toupper(c1) < toupper(c2); }
|
||||
|
||||
static int compare(const char *s1, const char *s2, size_t n)
|
||||
{
|
||||
while (n-- != 0) {
|
||||
if (toupper(*s1) < toupper(*s2)) return -1;
|
||||
if (toupper(*s1) > toupper(*s2)) return 1;
|
||||
++s1; ++s2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *find(const char *s, int n, char a)
|
||||
{
|
||||
while (n-- > 0 && toupper(*s) != toupper(a)) {
|
||||
++s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
/** Case insensitive string view. */
|
||||
typedef std::basic_string_view<char, CaseInsensitiveCharTraits> CaseInsensitiveStringView;
|
||||
|
||||
/**
|
||||
* Compares two string( view)s, while ignoring the case of the characters.
|
||||
* @param str1 The first string.
|
||||
* @param str2 The second string.
|
||||
* @return Less than zero if str1 < str2, zero if str1 == str2, greater than
|
||||
* zero if str1 > str2. All ignoring the case of the characters.
|
||||
*/
|
||||
int StrCompareIgnoreCase(const std::string_view str1, const std::string_view str2)
|
||||
{
|
||||
CaseInsensitiveStringView ci_str1{ str1.data(), str1.size() };
|
||||
CaseInsensitiveStringView ci_str2{ str2.data(), str2.size() };
|
||||
return ci_str1.compare(ci_str2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two string( view)s for equality, while ignoring the case of the characters.
|
||||
* @param str1 The first string.
|
||||
* @param str2 The second string.
|
||||
* @return True iff both strings are equal, barring the case of the characters.
|
||||
*/
|
||||
bool StrEqualsIgnoreCase(const std::string_view str1, const std::string_view str2)
|
||||
{
|
||||
if (str1.size() != str2.size()) return false;
|
||||
return StrCompareIgnoreCase(str1, str2) == 0;
|
||||
}
|
||||
|
||||
/** Scans the string for colour codes and strips them */
|
||||
void str_strip_colours(char *str)
|
||||
|
@ -728,7 +781,7 @@ int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front)
|
|||
#endif
|
||||
|
||||
/* Do a normal comparison if ICU is missing or if we cannot create a collator. */
|
||||
return strcasecmp(s1, s2);
|
||||
return StrCompareIgnoreCase(s1, s2);
|
||||
}
|
||||
|
||||
#ifdef WITH_UNISCRIBE
|
||||
|
|
|
@ -54,6 +54,9 @@ void StrTrimInPlace(std::string &str);
|
|||
bool StrStartsWith(const std::string_view str, const std::string_view prefix);
|
||||
bool StrEndsWith(const std::string_view str, const std::string_view suffix);
|
||||
|
||||
[[nodiscard]] int StrCompareIgnoreCase(const std::string_view str1, const std::string_view str2);
|
||||
[[nodiscard]] bool StrEqualsIgnoreCase(const std::string_view str1, const std::string_view str2);
|
||||
|
||||
/**
|
||||
* Check if a string buffer is empty.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
add_test_files(
|
||||
landscape_partial_pixel_z.cpp
|
||||
math_func.cpp
|
||||
string_func.cpp
|
||||
test_main.cpp
|
||||
)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file math_func_test.cpp Test functionality from core/math_func. */
|
||||
/** @file math_func.cpp Test functionality from core/math_func. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file string_func.cpp Test functionality from string_func. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
|
||||
#include "../3rdparty/catch2/catch.hpp"
|
||||
|
||||
#include "../string_func.h"
|
||||
|
||||
TEST_CASE("StrCompareIgnoreCase - std::string")
|
||||
{
|
||||
/* Same string, with different cases. */
|
||||
CHECK(StrCompareIgnoreCase(std::string{""}, std::string{""}) == 0);
|
||||
CHECK(StrCompareIgnoreCase(std::string{"a"}, std::string{"a"}) == 0);
|
||||
CHECK(StrCompareIgnoreCase(std::string{"a"}, std::string{"A"}) == 0);
|
||||
CHECK(StrCompareIgnoreCase(std::string{"A"}, std::string{"a"}) == 0);
|
||||
CHECK(StrCompareIgnoreCase(std::string{"A"}, std::string{"A"}) == 0);
|
||||
|
||||
/* Not the same string. */
|
||||
CHECK(StrCompareIgnoreCase(std::string{""}, std::string{"b"}) < 0);
|
||||
CHECK(StrCompareIgnoreCase(std::string{"a"}, std::string{""}) > 0);
|
||||
|
||||
CHECK(StrCompareIgnoreCase(std::string{"a"}, std::string{"b"}) < 0);
|
||||
CHECK(StrCompareIgnoreCase(std::string{"b"}, std::string{"a"}) > 0);
|
||||
CHECK(StrCompareIgnoreCase(std::string{"a"}, std::string{"B"}) < 0);
|
||||
CHECK(StrCompareIgnoreCase(std::string{"b"}, std::string{"A"}) > 0);
|
||||
CHECK(StrCompareIgnoreCase(std::string{"A"}, std::string{"b"}) < 0);
|
||||
CHECK(StrCompareIgnoreCase(std::string{"B"}, std::string{"a"}) > 0);
|
||||
|
||||
CHECK(StrCompareIgnoreCase(std::string{"a"}, std::string{"aa"}) < 0);
|
||||
CHECK(StrCompareIgnoreCase(std::string{"aa"}, std::string{"a"}) > 0);
|
||||
}
|
||||
|
||||
TEST_CASE("StrCompareIgnoreCase - char pointer")
|
||||
{
|
||||
/* Same string, with different cases. */
|
||||
CHECK(StrCompareIgnoreCase("", "") == 0);
|
||||
CHECK(StrCompareIgnoreCase("a", "a") == 0);
|
||||
CHECK(StrCompareIgnoreCase("a", "A") == 0);
|
||||
CHECK(StrCompareIgnoreCase("A", "a") == 0);
|
||||
CHECK(StrCompareIgnoreCase("A", "A") == 0);
|
||||
|
||||
/* Not the same string. */
|
||||
CHECK(StrCompareIgnoreCase("", "b") < 0);
|
||||
CHECK(StrCompareIgnoreCase("a", "") > 0);
|
||||
|
||||
CHECK(StrCompareIgnoreCase("a", "b") < 0);
|
||||
CHECK(StrCompareIgnoreCase("b", "a") > 0);
|
||||
CHECK(StrCompareIgnoreCase("a", "B") < 0);
|
||||
CHECK(StrCompareIgnoreCase("b", "A") > 0);
|
||||
CHECK(StrCompareIgnoreCase("A", "b") < 0);
|
||||
CHECK(StrCompareIgnoreCase("B", "a") > 0);
|
||||
|
||||
CHECK(StrCompareIgnoreCase("a", "aa") < 0);
|
||||
CHECK(StrCompareIgnoreCase("aa", "a") > 0);
|
||||
}
|
||||
|
||||
TEST_CASE("StrCompareIgnoreCase - std::string_view")
|
||||
{
|
||||
/*
|
||||
* With std::string_view the only way to access the data is via .data(),
|
||||
* which does not guarantee the termination that would be required by
|
||||
* things such as stricmp/strcasecmp. So, just passing .data() into stricmp
|
||||
* or strcasecmp would fail if it does not account for the length of the
|
||||
* view. Thus, contrary to the string/char* tests, this uses the same base
|
||||
* string but gets different sections to trigger these corner cases.
|
||||
*/
|
||||
std::string_view base{"aaAbB"};
|
||||
|
||||
/* Same string, with different cases. */
|
||||
CHECK(StrCompareIgnoreCase(base.substr(0, 0), base.substr(1, 0)) == 0); // Different positions
|
||||
CHECK(StrCompareIgnoreCase(base.substr(0, 1), base.substr(1, 1)) == 0); // Different positions
|
||||
CHECK(StrCompareIgnoreCase(base.substr(0, 1), base.substr(2, 1)) == 0);
|
||||
CHECK(StrCompareIgnoreCase(base.substr(2, 1), base.substr(1, 1)) == 0);
|
||||
CHECK(StrCompareIgnoreCase(base.substr(2, 1), base.substr(2, 1)) == 0);
|
||||
|
||||
/* Not the same string. */
|
||||
CHECK(StrCompareIgnoreCase(base.substr(3, 0), base.substr(3, 1)) < 0); // Same position, different lengths
|
||||
CHECK(StrCompareIgnoreCase(base.substr(0, 1), base.substr(0, 0)) > 0); // Same position, different lengths
|
||||
|
||||
CHECK(StrCompareIgnoreCase(base.substr(0, 1), base.substr(3, 1)) < 0);
|
||||
CHECK(StrCompareIgnoreCase(base.substr(3, 1), base.substr(0, 1)) > 0);
|
||||
CHECK(StrCompareIgnoreCase(base.substr(0, 1), base.substr(4, 1)) < 0);
|
||||
CHECK(StrCompareIgnoreCase(base.substr(3, 1), base.substr(2, 1)) > 0);
|
||||
CHECK(StrCompareIgnoreCase(base.substr(2, 1), base.substr(3, 1)) < 0);
|
||||
CHECK(StrCompareIgnoreCase(base.substr(4, 1), base.substr(0, 1)) > 0);
|
||||
|
||||
CHECK(StrCompareIgnoreCase(base.substr(0, 1), base.substr(0, 2)) < 0); // Same position, different lengths
|
||||
CHECK(StrCompareIgnoreCase(base.substr(0, 2), base.substr(0, 1)) > 0); // Same position, different lengths
|
||||
}
|
||||
|
||||
TEST_CASE("StrEqualsIgnoreCase - std::string")
|
||||
{
|
||||
/* Same string, with different cases. */
|
||||
CHECK(StrEqualsIgnoreCase(std::string{""}, std::string{""}));
|
||||
CHECK(StrEqualsIgnoreCase(std::string{"a"}, std::string{"a"}));
|
||||
CHECK(StrEqualsIgnoreCase(std::string{"a"}, std::string{"A"}));
|
||||
CHECK(StrEqualsIgnoreCase(std::string{"A"}, std::string{"a"}));
|
||||
CHECK(StrEqualsIgnoreCase(std::string{"A"}, std::string{"A"}));
|
||||
|
||||
/* Not the same string. */
|
||||
CHECK(!StrEqualsIgnoreCase(std::string{""}, std::string{"b"}));
|
||||
CHECK(!StrEqualsIgnoreCase(std::string{"a"}, std::string{""}));
|
||||
CHECK(!StrEqualsIgnoreCase(std::string{"a"}, std::string{"b"}));
|
||||
CHECK(!StrEqualsIgnoreCase(std::string{"b"}, std::string{"a"}));
|
||||
CHECK(!StrEqualsIgnoreCase(std::string{"a"}, std::string{"aa"}));
|
||||
CHECK(!StrEqualsIgnoreCase(std::string{"aa"}, std::string{"a"}));
|
||||
}
|
||||
|
||||
TEST_CASE("StrEqualsIgnoreCase - char pointer")
|
||||
{
|
||||
/* Same string, with different cases. */
|
||||
CHECK(StrEqualsIgnoreCase("", ""));
|
||||
CHECK(StrEqualsIgnoreCase("a", "a"));
|
||||
CHECK(StrEqualsIgnoreCase("a", "A"));
|
||||
CHECK(StrEqualsIgnoreCase("A", "a"));
|
||||
CHECK(StrEqualsIgnoreCase("A", "A"));
|
||||
|
||||
/* Not the same string. */
|
||||
CHECK(!StrEqualsIgnoreCase("", "b"));
|
||||
CHECK(!StrEqualsIgnoreCase("a", ""));
|
||||
CHECK(!StrEqualsIgnoreCase("a", "b"));
|
||||
CHECK(!StrEqualsIgnoreCase("b", "a"));
|
||||
CHECK(!StrEqualsIgnoreCase("a", "aa"));
|
||||
CHECK(!StrEqualsIgnoreCase("aa", "a"));
|
||||
}
|
||||
|
||||
TEST_CASE("StrEqualsIgnoreCase - std::string_view")
|
||||
{
|
||||
/*
|
||||
* With std::string_view the only way to access the data is via .data(),
|
||||
* which does not guarantee the termination that would be required by
|
||||
* things such as stricmp/strcasecmp. So, just passing .data() into stricmp
|
||||
* or strcasecmp would fail if it does not account for the length of the
|
||||
* view. Thus, contrary to the string/char* tests, this uses the same base
|
||||
* string but gets different sections to trigger these corner cases.
|
||||
*/
|
||||
std::string_view base{"aaAb"};
|
||||
|
||||
/* Same string, with different cases. */
|
||||
CHECK(StrEqualsIgnoreCase(base.substr(0, 0), base.substr(1, 0))); // Different positions
|
||||
CHECK(StrEqualsIgnoreCase(base.substr(0, 1), base.substr(1, 1))); // Different positions
|
||||
CHECK(StrEqualsIgnoreCase(base.substr(0, 1), base.substr(2, 1)));
|
||||
CHECK(StrEqualsIgnoreCase(base.substr(2, 1), base.substr(1, 1)));
|
||||
CHECK(StrEqualsIgnoreCase(base.substr(2, 1), base.substr(2, 1)));
|
||||
|
||||
/* Not the same string. */
|
||||
CHECK(!StrEqualsIgnoreCase(base.substr(3, 0), base.substr(3, 1))); // Same position, different lengths
|
||||
CHECK(!StrEqualsIgnoreCase(base.substr(0, 1), base.substr(0, 0)));
|
||||
CHECK(!StrEqualsIgnoreCase(base.substr(0, 1), base.substr(3, 1)));
|
||||
CHECK(!StrEqualsIgnoreCase(base.substr(3, 1), base.substr(0, 1)));
|
||||
CHECK(!StrEqualsIgnoreCase(base.substr(0, 1), base.substr(0, 2))); // Same position, different lengths
|
||||
CHECK(!StrEqualsIgnoreCase(base.substr(0, 2), base.substr(0, 1))); // Same position, different lengths
|
||||
}
|
Loading…
Reference in New Issue