mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-01-31 11:23:21 +00:00
Codechange: replace strncasecmp with case ignoring variant of StrStarts/EndsWith
This commit is contained in:
parent
86786a7af6
commit
4dd5f994be
@ -2022,7 +2022,7 @@ DEF_CONSOLE_CMD(ConFont)
|
||||
byte arg_index = 2;
|
||||
/* We may encounter "aa" or "noaa" but it must be the last argument. */
|
||||
if (StrEqualsIgnoreCase(argv[arg_index], "aa") || StrEqualsIgnoreCase(argv[arg_index], "noaa")) {
|
||||
aa = strncasecmp(argv[arg_index++], "no", 2) != 0;
|
||||
aa = !StrStartsWithIgnoreCase(argv[arg_index++], "no");
|
||||
if (argc > arg_index) return false;
|
||||
} else {
|
||||
/* For <name> we want a string. */
|
||||
@ -2044,7 +2044,7 @@ DEF_CONSOLE_CMD(ConFont)
|
||||
if (argc > arg_index) {
|
||||
/* Last argument must be "aa" or "noaa". */
|
||||
if (!StrEqualsIgnoreCase(argv[arg_index], "aa") && !StrEqualsIgnoreCase(argv[arg_index], "noaa")) return false;
|
||||
aa = strncasecmp(argv[arg_index++], "no", 2) != 0;
|
||||
aa = !StrStartsWithIgnoreCase(argv[arg_index++], "no");
|
||||
if (argc > arg_index) return false;
|
||||
}
|
||||
|
||||
@ -2220,7 +2220,7 @@ DEF_CONSOLE_CMD(ConNewGRFProfile)
|
||||
const std::vector<GRFFile *> &files = GetAllGRFFiles();
|
||||
|
||||
/* "list" sub-command */
|
||||
if (argc == 1 || strncasecmp(argv[1], "lis", 3) == 0) {
|
||||
if (argc == 1 || StrStartsWithIgnoreCase(argv[1], "lis")) {
|
||||
IConsolePrint(CC_INFO, "Loaded GRF files:");
|
||||
int i = 1;
|
||||
for (GRFFile *grf : files) {
|
||||
@ -2236,7 +2236,7 @@ DEF_CONSOLE_CMD(ConNewGRFProfile)
|
||||
}
|
||||
|
||||
/* "select" sub-command */
|
||||
if (strncasecmp(argv[1], "sel", 3) == 0 && argc >= 3) {
|
||||
if (StrStartsWithIgnoreCase(argv[1], "sel") && argc >= 3) {
|
||||
for (size_t argnum = 2; argnum < argc; ++argnum) {
|
||||
int grfnum = atoi(argv[argnum]);
|
||||
if (grfnum < 1 || grfnum > (int)files.size()) { // safe cast, files.size() should not be larger than a few hundred in the most extreme cases
|
||||
@ -2254,7 +2254,7 @@ DEF_CONSOLE_CMD(ConNewGRFProfile)
|
||||
}
|
||||
|
||||
/* "unselect" sub-command */
|
||||
if (strncasecmp(argv[1], "uns", 3) == 0 && argc >= 3) {
|
||||
if (StrStartsWithIgnoreCase(argv[1], "uns") && argc >= 3) {
|
||||
for (size_t argnum = 2; argnum < argc; ++argnum) {
|
||||
if (StrEqualsIgnoreCase(argv[argnum], "all")) {
|
||||
_newgrf_profilers.clear();
|
||||
@ -2273,7 +2273,7 @@ DEF_CONSOLE_CMD(ConNewGRFProfile)
|
||||
}
|
||||
|
||||
/* "start" sub-command */
|
||||
if (strncasecmp(argv[1], "sta", 3) == 0) {
|
||||
if (StrStartsWithIgnoreCase(argv[1], "sta")) {
|
||||
std::string grfids;
|
||||
size_t started = 0;
|
||||
for (NewGRFProfiler &pr : _newgrf_profilers) {
|
||||
@ -2309,13 +2309,13 @@ DEF_CONSOLE_CMD(ConNewGRFProfile)
|
||||
}
|
||||
|
||||
/* "stop" sub-command */
|
||||
if (strncasecmp(argv[1], "sto", 3) == 0) {
|
||||
if (StrStartsWithIgnoreCase(argv[1], "sto")) {
|
||||
NewGRFProfiler::FinishAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* "abort" sub-command */
|
||||
if (strncasecmp(argv[1], "abo", 3) == 0) {
|
||||
if (StrStartsWithIgnoreCase(argv[1], "abo")) {
|
||||
for (NewGRFProfiler &pr : _newgrf_profilers) {
|
||||
pr.Abort();
|
||||
}
|
||||
|
@ -769,7 +769,7 @@ static bool ChangeWorkingDirectoryToExecutable(const char *exe)
|
||||
bool success = false;
|
||||
#ifdef WITH_COCOA
|
||||
char *app_bundle = strchr(tmp, '.');
|
||||
while (app_bundle != nullptr && strncasecmp(app_bundle, ".app", 4) != 0) app_bundle = strchr(&app_bundle[1], '.');
|
||||
while (app_bundle != nullptr && !StrStartsWithIgnoreCase(app_bundle, ".app")) app_bundle = strchr(&app_bundle[1], '.');
|
||||
|
||||
if (app_bundle != nullptr) *app_bundle = '\0';
|
||||
#endif /* WITH_COCOA */
|
||||
|
@ -386,7 +386,7 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c
|
||||
|
||||
/* found file must be directory, but not '.' or '..' */
|
||||
if (FiosIsValidFile(_fios_path->c_str(), dirent, &sb) && S_ISDIR(sb.st_mode) &&
|
||||
(!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) &&
|
||||
(!FiosIsHiddenFile(dirent) || StrStartsWithIgnoreCase(PERSONAL_DIR, d_name)) &&
|
||||
strcmp(d_name, ".") != 0 && strcmp(d_name, "..") != 0) {
|
||||
fios = &file_list.emplace_back();
|
||||
fios->type = FIOS_TYPE_DIR;
|
||||
|
@ -99,8 +99,9 @@ static uint16 ParseCode(const char *start, const char *end)
|
||||
assert(start <= end);
|
||||
while (start < end && *start == ' ') start++;
|
||||
while (end > start && *end == ' ') end--;
|
||||
std::string_view str{start, (size_t)(start - end)};
|
||||
for (uint i = 0; i < lengthof(_keycode_to_name); i++) {
|
||||
if (strlen(_keycode_to_name[i].name) == (size_t)(end - start) && strncasecmp(start, _keycode_to_name[i].name, end - start) == 0) {
|
||||
if (StrEqualsIgnoreCase(str, _keycode_to_name[i].name)) {
|
||||
return _keycode_to_name[i].keycode;
|
||||
}
|
||||
}
|
||||
|
@ -421,7 +421,7 @@ struct NetworkChatWindow : public Window {
|
||||
}
|
||||
|
||||
len = strlen(cur_name);
|
||||
if (tb_len < len && strncasecmp(cur_name, tb_buf, tb_len) == 0) {
|
||||
if (tb_len < len && StrStartsWith(cur_name, tb_buf)) {
|
||||
/* Save the data it was before completion */
|
||||
if (!second_scan) seprintf(_chat_tab_completion_buf, lastof(_chat_tab_completion_buf), "%s", tb->buf);
|
||||
_chat_tab_completion_active = true;
|
||||
|
@ -134,9 +134,9 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
|
||||
err = FT_New_Face(_library, font_path, index, face);
|
||||
if (err != FT_Err_Ok) break;
|
||||
|
||||
if (strncasecmp(font_name, (*face)->family_name, strlen((*face)->family_name)) == 0) break;
|
||||
if (StrStartsWithIgnoreCase(font_name, (*face)->family_name)) break;
|
||||
/* Try english name if font name failed */
|
||||
if (strncasecmp(font_name + strlen(font_name) + 1, (*face)->family_name, strlen((*face)->family_name)) == 0) break;
|
||||
if (StrStartsWithIgnoreCase(font_name + strlen(font_name) + 1, (*face)->family_name)) break;
|
||||
err = FT_Err_Cannot_Open_Resource;
|
||||
|
||||
} while ((FT_Long)++index != (*face)->num_faces);
|
||||
|
17
src/stdafx.h
17
src/stdafx.h
@ -37,10 +37,6 @@
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#if defined(__HAIKU__) || defined(__CYGWIN__)
|
||||
# include <strings.h> /* strncasecmp */
|
||||
#endif
|
||||
|
||||
/* It seems that we need to include stdint.h before anything else
|
||||
* We need INT64_MAX, which for most systems comes from stdint.h. However, MSVC
|
||||
* does not have stdint.h.
|
||||
@ -71,11 +67,6 @@
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#if defined(__OS2__)
|
||||
# include <types.h>
|
||||
# define strcasecmp stricmp
|
||||
#endif
|
||||
|
||||
/* Stuff for GCC */
|
||||
#if defined(__GNUC__) || (defined(__clang__) && !defined(_MSC_VER))
|
||||
# define NORETURN __attribute__ ((noreturn))
|
||||
@ -207,9 +198,6 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# define strcasecmp stricmp
|
||||
# define strncasecmp strnicmp
|
||||
|
||||
/* MSVC doesn't have these :( */
|
||||
# define S_ISDIR(mode) (mode & S_IFDIR)
|
||||
# define S_ISREG(mode) (mode & S_IFREG)
|
||||
@ -411,11 +399,6 @@ void NORETURN AssertFailedError(int line, const char *file, const char *expressi
|
||||
# define assert(expression) if (unlikely(!(expression))) AssertFailedError(__LINE__, __FILE__, #expression);
|
||||
#endif
|
||||
|
||||
#if defined(OPENBSD)
|
||||
/* OpenBSD uses strcasecmp(3) */
|
||||
# define _stricmp strcasecmp
|
||||
#endif
|
||||
|
||||
#if defined(MAX_PATH)
|
||||
/* It's already defined, no need to override */
|
||||
#elif defined(PATH_MAX) && PATH_MAX > 0
|
||||
|
@ -23,26 +23,27 @@
|
||||
#include <iomanip>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <errno.h> // required by vsnprintf implementation for MSVC
|
||||
# include <errno.h> // required by vsnprintf implementation for MSVC
|
||||
# define strncasecmp strnicmp
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "os/windows/win32.h"
|
||||
# include "os/windows/win32.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_UNISCRIBE
|
||||
#include "os/windows/string_uniscribe.h"
|
||||
# include "os/windows/string_uniscribe.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ICU_I18N
|
||||
/* Required by strnatcmp. */
|
||||
#include <unicode/ustring.h>
|
||||
#include "language.h"
|
||||
#include "gfx_func.h"
|
||||
# include <unicode/ustring.h>
|
||||
# include "language.h"
|
||||
# include "gfx_func.h"
|
||||
#endif /* WITH_ICU_I18N */
|
||||
|
||||
#if defined(WITH_COCOA)
|
||||
#include "os/macosx/string_osx.h"
|
||||
# include "os/macosx/string_osx.h"
|
||||
#endif
|
||||
|
||||
/* The function vsnprintf is used internally to perform the required formatting
|
||||
@ -355,6 +356,18 @@ bool StrStartsWith(const std::string_view str, const std::string_view prefix)
|
||||
return str.compare(0, prefix_len, prefix, 0, prefix_len) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given string starts with the given prefix, ignoring case.
|
||||
* @param str The string to look at.
|
||||
* @param prefix The prefix to look for.
|
||||
* @return True iff the begin of the string is the same as the prefix, ignoring case.
|
||||
*/
|
||||
bool StrStartsWithIgnoreCase(std::string_view str, const std::string_view prefix)
|
||||
{
|
||||
if (str.size() < prefix.size()) return false;
|
||||
return StrEqualsIgnoreCase(str.substr(0, prefix.size()), prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given string ends with the given suffix.
|
||||
* @param str The string to look at.
|
||||
@ -396,6 +409,18 @@ struct CaseInsensitiveCharTraits : public std::char_traits<char> {
|
||||
/** Case insensitive string view. */
|
||||
typedef std::basic_string_view<char, CaseInsensitiveCharTraits> CaseInsensitiveStringView;
|
||||
|
||||
/**
|
||||
* Check whether the given string ends with the given suffix, ignoring case.
|
||||
* @param str The string to look at.
|
||||
* @param suffix The suffix to look for.
|
||||
* @return True iff the end of the string is the same as the suffix, ignoring case.
|
||||
*/
|
||||
bool StrEndsWithIgnoreCase(std::string_view str, const std::string_view suffix)
|
||||
{
|
||||
if (str.size() < suffix.size()) return false;
|
||||
return StrEqualsIgnoreCase(str.substr(str.size() - suffix.size()), suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two string( view)s, while ignoring the case of the characters.
|
||||
* @param str1 The first string.
|
||||
|
@ -48,11 +48,13 @@ void str_strip_colours(char *str);
|
||||
bool strtolower(char *str);
|
||||
bool strtolower(std::string &str, std::string::size_type offs = 0);
|
||||
|
||||
bool StrValid(const char *str, const char *last) NOACCESS(2);
|
||||
[[nodiscard]] bool StrValid(const char *str, const char *last) NOACCESS(2);
|
||||
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]] bool StrStartsWith(const std::string_view str, const std::string_view prefix);
|
||||
[[nodiscard]] bool StrStartsWithIgnoreCase(std::string_view str, const std::string_view prefix);
|
||||
[[nodiscard]] bool StrEndsWith(const std::string_view str, const std::string_view suffix);
|
||||
[[nodiscard]] bool StrEndsWithIgnoreCase(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);
|
||||
|
@ -13,6 +13,8 @@
|
||||
|
||||
#include "../string_func.h"
|
||||
|
||||
/**** String compare/equals *****/
|
||||
|
||||
TEST_CASE("StrCompareIgnoreCase - std::string")
|
||||
{
|
||||
/* Same string, with different cases. */
|
||||
@ -158,3 +160,359 @@ TEST_CASE("StrEqualsIgnoreCase - std::string_view")
|
||||
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
|
||||
}
|
||||
|
||||
/**** String starts with *****/
|
||||
|
||||
TEST_CASE("StrStartsWith - std::string")
|
||||
{
|
||||
/* Everything starts with an empty prefix. */
|
||||
CHECK(StrStartsWith(std::string{""}, std::string{""}));
|
||||
CHECK(StrStartsWith(std::string{"a"}, std::string{""}));
|
||||
|
||||
/* Equal strings. */
|
||||
CHECK(StrStartsWith(std::string{"a"}, std::string{"a"}));
|
||||
CHECK(StrStartsWith(std::string{"A"}, std::string{"A"}));
|
||||
|
||||
/* Starts with same. */
|
||||
CHECK(StrStartsWith(std::string{"ab"}, std::string{"a"}));
|
||||
CHECK(StrStartsWith(std::string{"Ab"}, std::string{"A"}));
|
||||
|
||||
/* Different cases. */
|
||||
CHECK(!StrStartsWith(std::string{"a"}, std::string{"A"}));
|
||||
CHECK(!StrStartsWith(std::string{"A"}, std::string{"a"}));
|
||||
CHECK(!StrStartsWith(std::string{"ab"}, std::string{"A"}));
|
||||
CHECK(!StrStartsWith(std::string{"Ab"}, std::string{"a"}));
|
||||
|
||||
/* Does not start the same. */
|
||||
CHECK(!StrStartsWith(std::string{""}, std::string{"b"}));
|
||||
CHECK(!StrStartsWith(std::string{"a"}, std::string{"b"}));
|
||||
CHECK(!StrStartsWith(std::string{"b"}, std::string{"a"}));
|
||||
CHECK(!StrStartsWith(std::string{"a"}, std::string{"aa"}));
|
||||
}
|
||||
|
||||
TEST_CASE("StrStartsWith - char pointer")
|
||||
{
|
||||
CHECK(StrStartsWith("", ""));
|
||||
CHECK(StrStartsWith("a", ""));
|
||||
|
||||
/* Equal strings. */
|
||||
CHECK(StrStartsWith("a", "a"));
|
||||
CHECK(StrStartsWith("A", "A"));
|
||||
|
||||
/* Starts with same. */
|
||||
CHECK(StrStartsWith("ab", "a"));
|
||||
CHECK(StrStartsWith("Ab", "A"));
|
||||
|
||||
/* Different cases. */
|
||||
CHECK(!StrStartsWith("a", "A"));
|
||||
CHECK(!StrStartsWith("A", "a"));
|
||||
CHECK(!StrStartsWith("ab", "A"));
|
||||
CHECK(!StrStartsWith("Ab", "a"));
|
||||
|
||||
/* Does not start the same. */
|
||||
CHECK(!StrStartsWith("", "b"));
|
||||
CHECK(!StrStartsWith("a", "b"));
|
||||
CHECK(!StrStartsWith("b", "a"));
|
||||
CHECK(!StrStartsWith("a", "aa"));
|
||||
}
|
||||
|
||||
TEST_CASE("StrStartsWith - 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{"aabAb"};
|
||||
|
||||
/* Everything starts with an empty prefix. */
|
||||
CHECK(StrStartsWith(base.substr(0, 0), base.substr(1, 0))); // Different positions
|
||||
CHECK(StrStartsWith(base.substr(0, 1), base.substr(0, 0)));
|
||||
|
||||
/* Equals string. */
|
||||
CHECK(StrStartsWith(base.substr(0, 1), base.substr(1, 1))); // Different positions
|
||||
CHECK(StrStartsWith(base.substr(3, 1), base.substr(3, 1)));
|
||||
|
||||
/* Starts with same. */
|
||||
CHECK(StrStartsWith(base.substr(1, 2), base.substr(0, 1)));
|
||||
CHECK(StrStartsWith(base.substr(3, 2), base.substr(3, 1)));
|
||||
|
||||
/* Different cases. */
|
||||
CHECK(!StrStartsWith(base.substr(0, 1), base.substr(3, 1)));
|
||||
CHECK(!StrStartsWith(base.substr(3, 1), base.substr(0, 1)));
|
||||
CHECK(!StrStartsWith(base.substr(1, 2), base.substr(3, 1)));
|
||||
CHECK(!StrStartsWith(base.substr(3, 2), base.substr(0, 1)));
|
||||
|
||||
/* Does not start the same. */
|
||||
CHECK(!StrStartsWith(base.substr(2, 0), base.substr(2, 1)));
|
||||
CHECK(!StrStartsWith(base.substr(0, 1), base.substr(2, 1)));
|
||||
CHECK(!StrStartsWith(base.substr(2, 1), base.substr(0, 1)));
|
||||
CHECK(!StrStartsWith(base.substr(0, 1), base.substr(0, 2)));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("StrStartsWithIgnoreCase - std::string")
|
||||
{
|
||||
/* Everything starts with an empty prefix. */
|
||||
CHECK(StrStartsWithIgnoreCase(std::string{""}, std::string{""}));
|
||||
CHECK(StrStartsWithIgnoreCase(std::string{"a"}, std::string{""}));
|
||||
|
||||
/* Equals string, ignoring case. */
|
||||
CHECK(StrStartsWithIgnoreCase(std::string{"a"}, std::string{"a"}));
|
||||
CHECK(StrStartsWithIgnoreCase(std::string{"a"}, std::string{"A"}));
|
||||
CHECK(StrStartsWithIgnoreCase(std::string{"A"}, std::string{"a"}));
|
||||
CHECK(StrStartsWithIgnoreCase(std::string{"A"}, std::string{"A"}));
|
||||
|
||||
/* Starts with same, ignoring case. */
|
||||
CHECK(StrStartsWithIgnoreCase(std::string{"ab"}, std::string{"a"}));
|
||||
CHECK(StrStartsWithIgnoreCase(std::string{"ab"}, std::string{"A"}));
|
||||
CHECK(StrStartsWithIgnoreCase(std::string{"Ab"}, std::string{"a"}));
|
||||
CHECK(StrStartsWithIgnoreCase(std::string{"Ab"}, std::string{"A"}));
|
||||
|
||||
/* Does not start the same. */
|
||||
CHECK(!StrStartsWithIgnoreCase(std::string{""}, std::string{"b"}));
|
||||
CHECK(!StrStartsWithIgnoreCase(std::string{"a"}, std::string{"b"}));
|
||||
CHECK(!StrStartsWithIgnoreCase(std::string{"b"}, std::string{"a"}));
|
||||
CHECK(!StrStartsWithIgnoreCase(std::string{"a"}, std::string{"aa"}));
|
||||
}
|
||||
|
||||
TEST_CASE("StrStartsWithIgnoreCase - char pointer")
|
||||
{
|
||||
/* Everything starts with an empty prefix. */
|
||||
CHECK(StrStartsWithIgnoreCase("", ""));
|
||||
CHECK(StrStartsWithIgnoreCase("a", ""));
|
||||
|
||||
/* Equals string, ignoring case. */
|
||||
CHECK(StrStartsWithIgnoreCase("a", "a"));
|
||||
CHECK(StrStartsWithIgnoreCase("a", "A"));
|
||||
CHECK(StrStartsWithIgnoreCase("A", "a"));
|
||||
CHECK(StrStartsWithIgnoreCase("A", "A"));
|
||||
|
||||
/* Starts with same, ignoring case. */
|
||||
CHECK(StrStartsWithIgnoreCase("ab", "a"));
|
||||
CHECK(StrStartsWithIgnoreCase("ab", "A"));
|
||||
CHECK(StrStartsWithIgnoreCase("Ab", "a"));
|
||||
CHECK(StrStartsWithIgnoreCase("Ab", "A"));
|
||||
|
||||
/* Does not start the same. */
|
||||
CHECK(!StrStartsWithIgnoreCase("", "b"));
|
||||
CHECK(!StrStartsWithIgnoreCase("a", "b"));
|
||||
CHECK(!StrStartsWithIgnoreCase("b", "a"));
|
||||
CHECK(!StrStartsWithIgnoreCase("a", "aa"));
|
||||
}
|
||||
|
||||
TEST_CASE("StrStartsWithIgnoreCase - 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{"aabAb"};
|
||||
|
||||
/* Everything starts with an empty prefix. */
|
||||
CHECK(StrStartsWithIgnoreCase(base.substr(0, 0), base.substr(1, 0))); // Different positions
|
||||
CHECK(StrStartsWithIgnoreCase(base.substr(0, 1), base.substr(0, 0)));
|
||||
|
||||
/* Equals string, ignoring case. */
|
||||
CHECK(StrStartsWithIgnoreCase(base.substr(0, 1), base.substr(1, 1))); // Different positions
|
||||
CHECK(StrStartsWithIgnoreCase(base.substr(0, 1), base.substr(3, 1)));
|
||||
CHECK(StrStartsWithIgnoreCase(base.substr(3, 1), base.substr(0, 1)));
|
||||
CHECK(StrStartsWithIgnoreCase(base.substr(3, 1), base.substr(3, 1)));
|
||||
|
||||
/* Starts with same, ignoring case. */
|
||||
CHECK(StrStartsWithIgnoreCase(base.substr(1, 2), base.substr(0, 1)));
|
||||
CHECK(StrStartsWithIgnoreCase(base.substr(1, 2), base.substr(3, 1)));
|
||||
CHECK(StrStartsWithIgnoreCase(base.substr(3, 2), base.substr(0, 1)));
|
||||
CHECK(StrStartsWithIgnoreCase(base.substr(3, 2), base.substr(3, 1)));
|
||||
|
||||
/* Does not start the same. */
|
||||
CHECK(!StrStartsWithIgnoreCase(base.substr(2, 0), base.substr(2, 1)));
|
||||
CHECK(!StrStartsWithIgnoreCase(base.substr(0, 1), base.substr(2, 1)));
|
||||
CHECK(!StrStartsWithIgnoreCase(base.substr(2, 1), base.substr(0, 1)));
|
||||
CHECK(!StrStartsWithIgnoreCase(base.substr(0, 1), base.substr(0, 2)));
|
||||
}
|
||||
|
||||
/**** String ends with *****/
|
||||
|
||||
TEST_CASE("StrEndsWith - std::string")
|
||||
{
|
||||
/* Everything ends with an empty prefix. */
|
||||
CHECK(StrEndsWith(std::string{""}, std::string{""}));
|
||||
CHECK(StrEndsWith(std::string{"a"}, std::string{""}));
|
||||
|
||||
/* Equal strings. */
|
||||
CHECK(StrEndsWith(std::string{"a"}, std::string{"a"}));
|
||||
CHECK(StrEndsWith(std::string{"A"}, std::string{"A"}));
|
||||
|
||||
/* Ends with same. */
|
||||
CHECK(StrEndsWith(std::string{"ba"}, std::string{"a"}));
|
||||
CHECK(StrEndsWith(std::string{"bA"}, std::string{"A"}));
|
||||
|
||||
/* Different cases. */
|
||||
CHECK(!StrEndsWith(std::string{"a"}, std::string{"A"}));
|
||||
CHECK(!StrEndsWith(std::string{"A"}, std::string{"a"}));
|
||||
CHECK(!StrEndsWith(std::string{"ba"}, std::string{"A"}));
|
||||
CHECK(!StrEndsWith(std::string{"bA"}, std::string{"a"}));
|
||||
|
||||
/* Does not end the same. */
|
||||
CHECK(!StrEndsWith(std::string{""}, std::string{"b"}));
|
||||
CHECK(!StrEndsWith(std::string{"a"}, std::string{"b"}));
|
||||
CHECK(!StrEndsWith(std::string{"b"}, std::string{"a"}));
|
||||
CHECK(!StrEndsWith(std::string{"a"}, std::string{"aa"}));
|
||||
}
|
||||
|
||||
TEST_CASE("StrEndsWith - char pointer")
|
||||
{
|
||||
CHECK(StrEndsWith("", ""));
|
||||
CHECK(StrEndsWith("a", ""));
|
||||
|
||||
/* Equal strings. */
|
||||
CHECK(StrEndsWith("a", "a"));
|
||||
CHECK(StrEndsWith("A", "A"));
|
||||
|
||||
/* Ends with same. */
|
||||
CHECK(StrEndsWith("ba", "a"));
|
||||
CHECK(StrEndsWith("bA", "A"));
|
||||
|
||||
/* Different cases. */
|
||||
CHECK(!StrEndsWith("a", "A"));
|
||||
CHECK(!StrEndsWith("A", "a"));
|
||||
CHECK(!StrEndsWith("ba", "A"));
|
||||
CHECK(!StrEndsWith("bA", "a"));
|
||||
|
||||
/* Does not end the same. */
|
||||
CHECK(!StrEndsWith("", "b"));
|
||||
CHECK(!StrEndsWith("a", "b"));
|
||||
CHECK(!StrEndsWith("b", "a"));
|
||||
CHECK(!StrEndsWith("a", "aa"));
|
||||
}
|
||||
|
||||
TEST_CASE("StrEndsWith - 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{"aabAba"};
|
||||
|
||||
/* Everything ends with an empty prefix. */
|
||||
CHECK(StrEndsWith(base.substr(0, 0), base.substr(1, 0))); // Different positions
|
||||
CHECK(StrEndsWith(base.substr(0, 1), base.substr(0, 0)));
|
||||
|
||||
/* Equals string. */
|
||||
CHECK(StrEndsWith(base.substr(0, 1), base.substr(1, 1))); // Different positions
|
||||
CHECK(StrEndsWith(base.substr(3, 1), base.substr(3, 1)));
|
||||
|
||||
/* Ends with same. */
|
||||
CHECK(StrEndsWith(base.substr(4, 2), base.substr(0, 1)));
|
||||
CHECK(StrEndsWith(base.substr(2, 2), base.substr(3, 1)));
|
||||
|
||||
/* Different cases. */
|
||||
CHECK(!StrEndsWith(base.substr(0, 1), base.substr(3, 1)));
|
||||
CHECK(!StrEndsWith(base.substr(3, 1), base.substr(0, 1)));
|
||||
CHECK(!StrEndsWith(base.substr(4, 2), base.substr(3, 1)));
|
||||
CHECK(!StrEndsWith(base.substr(2, 2), base.substr(0, 1)));
|
||||
|
||||
/* Does not end the same. */
|
||||
CHECK(!StrEndsWith(base.substr(2, 0), base.substr(2, 1)));
|
||||
CHECK(!StrEndsWith(base.substr(0, 1), base.substr(2, 1)));
|
||||
CHECK(!StrEndsWith(base.substr(2, 1), base.substr(0, 1)));
|
||||
CHECK(!StrEndsWith(base.substr(0, 1), base.substr(0, 2)));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("StrEndsWithIgnoreCase - std::string")
|
||||
{
|
||||
/* Everything ends with an empty prefix. */
|
||||
CHECK(StrEndsWithIgnoreCase(std::string{""}, std::string{""}));
|
||||
CHECK(StrEndsWithIgnoreCase(std::string{"a"}, std::string{""}));
|
||||
|
||||
/* Equals string, ignoring case. */
|
||||
CHECK(StrEndsWithIgnoreCase(std::string{"a"}, std::string{"a"}));
|
||||
CHECK(StrEndsWithIgnoreCase(std::string{"a"}, std::string{"A"}));
|
||||
CHECK(StrEndsWithIgnoreCase(std::string{"A"}, std::string{"a"}));
|
||||
CHECK(StrEndsWithIgnoreCase(std::string{"A"}, std::string{"A"}));
|
||||
|
||||
/* Ends with same, ignoring case. */
|
||||
CHECK(StrEndsWithIgnoreCase(std::string{"ba"}, std::string{"a"}));
|
||||
CHECK(StrEndsWithIgnoreCase(std::string{"ba"}, std::string{"A"}));
|
||||
CHECK(StrEndsWithIgnoreCase(std::string{"bA"}, std::string{"a"}));
|
||||
CHECK(StrEndsWithIgnoreCase(std::string{"bA"}, std::string{"A"}));
|
||||
|
||||
/* Does not end the same. */
|
||||
CHECK(!StrEndsWithIgnoreCase(std::string{""}, std::string{"b"}));
|
||||
CHECK(!StrEndsWithIgnoreCase(std::string{"a"}, std::string{"b"}));
|
||||
CHECK(!StrEndsWithIgnoreCase(std::string{"b"}, std::string{"a"}));
|
||||
CHECK(!StrEndsWithIgnoreCase(std::string{"a"}, std::string{"aa"}));
|
||||
}
|
||||
|
||||
TEST_CASE("StrEndsWithIgnoreCase - char pointer")
|
||||
{
|
||||
/* Everything ends with an empty prefix. */
|
||||
CHECK(StrEndsWithIgnoreCase("", ""));
|
||||
CHECK(StrEndsWithIgnoreCase("a", ""));
|
||||
|
||||
/* Equals string, ignoring case. */
|
||||
CHECK(StrEndsWithIgnoreCase("a", "a"));
|
||||
CHECK(StrEndsWithIgnoreCase("a", "A"));
|
||||
CHECK(StrEndsWithIgnoreCase("A", "a"));
|
||||
CHECK(StrEndsWithIgnoreCase("A", "A"));
|
||||
|
||||
/* Ends with same, ignoring case. */
|
||||
CHECK(StrEndsWithIgnoreCase("ba", "a"));
|
||||
CHECK(StrEndsWithIgnoreCase("ba", "A"));
|
||||
CHECK(StrEndsWithIgnoreCase("bA", "a"));
|
||||
CHECK(StrEndsWithIgnoreCase("bA", "A"));
|
||||
|
||||
/* Does not end the same. */
|
||||
CHECK(!StrEndsWithIgnoreCase("", "b"));
|
||||
CHECK(!StrEndsWithIgnoreCase("a", "b"));
|
||||
CHECK(!StrEndsWithIgnoreCase("b", "a"));
|
||||
CHECK(!StrEndsWithIgnoreCase("a", "aa"));
|
||||
}
|
||||
|
||||
TEST_CASE("StrEndsWithIgnoreCase - 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{"aabAba"};
|
||||
|
||||
/* Everything ends with an empty prefix. */
|
||||
CHECK(StrEndsWithIgnoreCase(base.substr(0, 0), base.substr(1, 0))); // Different positions
|
||||
CHECK(StrEndsWithIgnoreCase(base.substr(0, 1), base.substr(0, 0)));
|
||||
|
||||
/* Equals string, ignoring case. */
|
||||
CHECK(StrEndsWithIgnoreCase(base.substr(0, 1), base.substr(1, 1))); // Different positions
|
||||
CHECK(StrEndsWithIgnoreCase(base.substr(0, 1), base.substr(3, 1)));
|
||||
CHECK(StrEndsWithIgnoreCase(base.substr(3, 1), base.substr(0, 1)));
|
||||
CHECK(StrEndsWithIgnoreCase(base.substr(3, 1), base.substr(3, 1)));
|
||||
|
||||
/* Ends with same, ignoring case. */
|
||||
CHECK(StrEndsWithIgnoreCase(base.substr(2, 2), base.substr(0, 1)));
|
||||
CHECK(StrEndsWithIgnoreCase(base.substr(2, 2), base.substr(3, 1)));
|
||||
CHECK(StrEndsWithIgnoreCase(base.substr(4, 2), base.substr(0, 1)));
|
||||
CHECK(StrEndsWithIgnoreCase(base.substr(4, 2), base.substr(3, 1)));
|
||||
|
||||
/* Does not end the same. */
|
||||
CHECK(!StrEndsWithIgnoreCase(base.substr(2, 0), base.substr(2, 1)));
|
||||
CHECK(!StrEndsWithIgnoreCase(base.substr(0, 1), base.substr(2, 1)));
|
||||
CHECK(!StrEndsWithIgnoreCase(base.substr(2, 1), base.substr(0, 1)));
|
||||
CHECK(!StrEndsWithIgnoreCase(base.substr(0, 1), base.substr(0, 2)));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user