fix StrSplit
This commit is contained in:
parent
f1f1f4b240
commit
00f8125757
131
'
Normal file
131
'
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
#include "sled/strings/utils.h"
|
||||||
|
#include <sstream>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
namespace sled {
|
||||||
|
|
||||||
|
char
|
||||||
|
ToLower(char c)
|
||||||
|
{
|
||||||
|
return ::tolower(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
char
|
||||||
|
ToUpper(char c)
|
||||||
|
{
|
||||||
|
return ::toupper(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
ToLower(const std::string &str)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
for (auto &ch : str) { ss << ToLower(ch); }
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
ToUpper(const std::string &str)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
for (auto &ch : str) { ss << ToUpper(ch); }
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
StrJoin(const std::vector<std::string> &strings, const std::string &delim, bool skip_empty)
|
||||||
|
{
|
||||||
|
if (strings.empty()) { return ""; }
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
size_t i = 0;
|
||||||
|
while (skip_empty && i < strings.size() && strings[i].empty()) { ++i; }
|
||||||
|
if (i < strings.size()) { ss << strings[i++]; }
|
||||||
|
for (; i < strings.size(); ++i) {
|
||||||
|
if (skip_empty && strings[i].empty()) { continue; }
|
||||||
|
ss << delim << strings[i];
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string>
|
||||||
|
StrSplit(const std::string &str, const std::string &delim, bool skip_empty)
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
if (str.empty()) { return result; }
|
||||||
|
|
||||||
|
size_t start = 0;
|
||||||
|
size_t next_pos = str.find_first_of(delim, start);
|
||||||
|
while (next_pos != std::string::npos) {
|
||||||
|
if ((!skip_empty && next_pos == start) || next_pos > start) {
|
||||||
|
result.emplace_back(str.begin() + start, str.begin() + next_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skip_empty) {
|
||||||
|
start = next_pos + 1;
|
||||||
|
next_pos = str.find_first_of(delim, start);
|
||||||
|
} else {
|
||||||
|
start = str.find_first_not_of(delim, next_pos);
|
||||||
|
if (start == std::string::npos) {
|
||||||
|
// all remaining characters are delimiters
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next_pos = str.find_first_of(delim, start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start < str.size()) { result.emplace_back(str.substr(start)); }
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
Trim(const std::string &str, const std::string &chars)
|
||||||
|
{
|
||||||
|
return TrimLeft(TrimRight(str, chars), chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
TrimLeft(const std::string &str, const std::string &chars)
|
||||||
|
{
|
||||||
|
size_t start = str.find_first_not_of(chars);
|
||||||
|
return start == std::string::npos ? "" : str.substr(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
TrimRight(const std::string &str, const std::string &chars)
|
||||||
|
{
|
||||||
|
size_t end = str.find_last_not_of(chars);
|
||||||
|
return end == std::string::npos ? "" : str.substr(0, end + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
EndsWith(const std::string &str, const std::string &suffix)
|
||||||
|
{
|
||||||
|
return str.size() >= suffix.size() && str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
StartsWith(const std::string &str, const std::string &prefix)
|
||||||
|
{
|
||||||
|
return str.size() >= prefix.size() && str.compare(0, prefix.size(), prefix) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
EndsWithIgnoreCase(const std::string &str, const std::string &suffix)
|
||||||
|
{
|
||||||
|
return EndsWith(ToLower(str), ToLower(suffix));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
StartsWithIgnoreCase(const std::string &str, const std::string &prefix)
|
||||||
|
{
|
||||||
|
return StartsWith(ToLower(str), ToLower(prefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
EqualsIgnoreCase(const std::string &lhs, const std::string &rhs)
|
||||||
|
{
|
||||||
|
return ToLower(lhs) == ToLower(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace sled
|
@ -45,6 +45,7 @@ target_include_directories(sled PUBLIC src/ 3party/eigen 3party/inja
|
|||||||
target_sources(
|
target_sources(
|
||||||
sled
|
sled
|
||||||
PRIVATE src/sled/async/async.cc
|
PRIVATE src/sled/async/async.cc
|
||||||
|
src/sled/debugging/symbolize.cc
|
||||||
src/sled/filesystem/path.cc
|
src/sled/filesystem/path.cc
|
||||||
src/sled/log/log.cc
|
src/sled/log/log.cc
|
||||||
src/sled/network/async_resolver.cc
|
src/sled/network/async_resolver.cc
|
||||||
@ -112,6 +113,32 @@ if(SLED_BUILD_BENCHMARK)
|
|||||||
benchmark::benchmark_main)
|
benchmark::benchmark_main)
|
||||||
endif(SLED_BUILD_BENCHMARK)
|
endif(SLED_BUILD_BENCHMARK)
|
||||||
|
|
||||||
|
function(sled_add_test)
|
||||||
|
set(prefix SLED_TEST)
|
||||||
|
# set(options INC_DIRS LIBS)
|
||||||
|
set(one_value_keywords NAME)
|
||||||
|
set(multi_value_keywords SRCS INC_DIRS LIBS)
|
||||||
|
cmake_parse_arguments("${prefix}" "${options}" "${one_value_keywords}"
|
||||||
|
"${multi_value_keywords}" ${ARGN})
|
||||||
|
|
||||||
|
message(WARNING "SLED_TEST_NAME: ${SLED_TEST_NAME}")
|
||||||
|
message(WARNING "SLED_TEST_SRCS: ${SLED_TEST_SRCS}")
|
||||||
|
message(WARNING "SLED_TEST_LIBS: ${SLED_TEST_LIBS}")
|
||||||
|
add_executable(${SLED_TEST_NAME} ${SLED_TEST_SRCS})
|
||||||
|
|
||||||
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
|
set(EXTRA_FLAGS -Wthread-safety -g -fsanitize=address
|
||||||
|
-fno-omit-frame-pointer -fno-optimize-sibling-calls)
|
||||||
|
target_compile_options(${SLED_TEST_NAME} PRIVATE ${EXTRA_FLAGS})
|
||||||
|
|
||||||
|
target_link_options(${SLED_TEST_NAME} PRIVATE ${EXTRA_FLAGS})
|
||||||
|
endif()
|
||||||
|
target_include_directories(${SLED_TEST_NAME} PRIVATE ${SLED_TEST_INC_DIRS})
|
||||||
|
target_link_libraries(${SLED_TEST_NAME} PRIVATE ${SLED_TEST_LIBS}
|
||||||
|
GTest::gtest)
|
||||||
|
add_test(NAME ${SLED_TEST_NAME} COMMAND ${SLED_TEST_NAME})
|
||||||
|
endfunction()
|
||||||
|
|
||||||
if(SLED_BUILD_TESTS)
|
if(SLED_BUILD_TESTS)
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
@ -119,17 +146,16 @@ if(SLED_BUILD_TESTS)
|
|||||||
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
|
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
|
||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(googletest)
|
FetchContent_MakeAvailable(googletest)
|
||||||
add_executable(
|
|
||||||
sled_tests
|
sled_add_test(
|
||||||
# src/sled/exec/just_test.cc
|
NAME
|
||||||
|
sled_base_test
|
||||||
|
SRCS
|
||||||
src/sled/async/async_test.cc
|
src/sled/async/async_test.cc
|
||||||
src/sled/any_test.cc
|
src/sled/any_test.cc
|
||||||
src/sled/filesystem/path_test.cc
|
src/sled/filesystem/path_test.cc
|
||||||
# src/sled/futures/promise_test.cc
|
|
||||||
src/sled/futures/detail/just_test.cc
|
src/sled/futures/detail/just_test.cc
|
||||||
src/sled/log/fmt_test.cc
|
src/sled/log/fmt_test.cc
|
||||||
# src/sled/profiling/profiling_test.cc
|
|
||||||
src/sled/strings/base64_test.cc
|
|
||||||
src/sled/synchronization/sequence_checker_test.cc
|
src/sled/synchronization/sequence_checker_test.cc
|
||||||
src/sled/cleanup_test.cc
|
src/sled/cleanup_test.cc
|
||||||
src/sled/status_test.cc
|
src/sled/status_test.cc
|
||||||
@ -137,16 +163,23 @@ if(SLED_BUILD_TESTS)
|
|||||||
src/sled/system/fiber/fiber_test.cc
|
src/sled/system/fiber/fiber_test.cc
|
||||||
src/sled/system/thread_pool_test.cc
|
src/sled/system/thread_pool_test.cc
|
||||||
src/sled/rx_test.cc
|
src/sled/rx_test.cc
|
||||||
src/sled/uri_test.cc)
|
src/sled/uri_test.cc
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
LIBS
|
||||||
set(EXTRA_FLAGS -Wthread-safety -g -fsanitize=address
|
sled
|
||||||
-fno-omit-frame-pointer -fno-optimize-sibling-calls)
|
GTest::gtest_main)
|
||||||
target_compile_options(sled_tests PRIVATE ${EXTRA_FLAGS})
|
|
||||||
|
|
||||||
target_link_options(sled_tests PRIVATE ${EXTRA_FLAGS})
|
sled_add_test(
|
||||||
endif()
|
NAME
|
||||||
target_link_libraries(sled_tests PRIVATE sled GTest::gtest GTest::gtest_main)
|
sled_strings_test
|
||||||
add_test(NAME sled_tests COMMAND sled_tests)
|
SRCS
|
||||||
|
src/sled/strings/utils_test.cc
|
||||||
|
src/sled/strings/base64_test.cc
|
||||||
|
LIBS
|
||||||
|
sled
|
||||||
|
GTest::gtest_main)
|
||||||
|
|
||||||
|
sled_add_test(NAME sled_symbolize_test SRCS
|
||||||
|
src/sled/debugging/symbolize_test.cc LIBS sled)
|
||||||
endif(SLED_BUILD_TESTS)
|
endif(SLED_BUILD_TESTS)
|
||||||
|
|
||||||
if(SLED_BUILD_FUZZ)
|
if(SLED_BUILD_FUZZ)
|
||||||
|
25
src/sled/debugging/symbolize.cc
Normal file
25
src/sled/debugging/symbolize.cc
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include "sled/debugging/symbolize.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
void
|
||||||
|
InitializeSymbolizer(const char *argv0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Symbolize(const void *pc, char *out, int out_size)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
void
|
||||||
|
InitializeSymbolizer(const char *argv0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Symbolize(const void *pc, char *out, int out_size)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#include "sled/debugging/symbolize_elf.inc"
|
||||||
|
#endif
|
10
src/sled/debugging/symbolize.h
Normal file
10
src/sled/debugging/symbolize.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef SLED_DEBUGGING_SYMBOLIZE_H
|
||||||
|
#define SLED_DEBUGGING_SYMBOLIZE_H
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace sled {
|
||||||
|
void InitializeSymbolizer(const char *argv0);
|
||||||
|
bool Symbolize(const void *pc, char *out, int out_size);
|
||||||
|
bool ReadAddrMap();
|
||||||
|
}// namespace sled
|
||||||
|
#endif// SLED_DEBUGGING_SYMBOLIZE_H
|
140
src/sled/debugging/symbolize_elf.inc
Normal file
140
src/sled/debugging/symbolize_elf.inc
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
#include <array>
|
||||||
|
#include <cxxabi.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <link.h>
|
||||||
|
#include <sled/log/log.h>
|
||||||
|
#include <sled/strings/utils.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace sled {
|
||||||
|
|
||||||
|
static constexpr char kTag[] = "symbolizer";
|
||||||
|
static char *g_exe = nullptr;
|
||||||
|
|
||||||
|
static const uint64_t
|
||||||
|
GetHex(const char *start, const char *end)
|
||||||
|
{
|
||||||
|
uint64_t hex = 0;
|
||||||
|
for (const char *p = start; p < end; ++p) {
|
||||||
|
int ch = *p;
|
||||||
|
if (ch >= '0' && ch <= '9') {
|
||||||
|
hex = hex * 16 + (ch - '0');
|
||||||
|
} else if (ch >= 'a' && ch <= 'f') {
|
||||||
|
hex = hex * 16 + (ch - 'a' + 10);
|
||||||
|
} else if (ch >= 'A' && ch <= 'F') {
|
||||||
|
hex = hex * 16 + (ch - 'A' + 10);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint64_t
|
||||||
|
GetHex(const std::string &str)
|
||||||
|
{
|
||||||
|
return GetHex(str.c_str(), str.c_str() + str.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ObjFile {
|
||||||
|
ObjFile() : filename(nullptr), start_addr(nullptr), end_addr(nullptr), offset(0), fd(-1), elf_type(-1)
|
||||||
|
{
|
||||||
|
memset(&elf_header, 0, sizeof(elf_header));
|
||||||
|
memset(phdrs.data(), 0, sizeof(ElfW(Phdr)) * phdrs.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
char *filename;
|
||||||
|
const void *start_addr;
|
||||||
|
const void *end_addr;
|
||||||
|
uint64_t offset;
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
int elf_type;
|
||||||
|
ElfW(Ehdr) elf_header;
|
||||||
|
|
||||||
|
std::array<ElfW(Phdr), 16> phdrs;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string
|
||||||
|
ReadFullFile(int fd)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
char buf[4096];
|
||||||
|
ssize_t n;
|
||||||
|
while ((n = read(fd, buf, sizeof(buf))) > 0) { ss.write(buf, n); }
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ReadAddrMap()
|
||||||
|
{
|
||||||
|
char maps_path[80];
|
||||||
|
snprintf(maps_path, sizeof(maps_path), "/proc/self/task/%d/maps", getpid());
|
||||||
|
int maps_fd;
|
||||||
|
do {
|
||||||
|
maps_fd = open(maps_path, O_RDONLY);
|
||||||
|
} while (maps_fd < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
if (maps_fd < 0) {
|
||||||
|
LOGE(kTag, "open {} failed, {}", maps_path, strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string full_file = ReadFullFile(maps_fd);
|
||||||
|
auto lines = sled::StrSplit(full_file, "\n");
|
||||||
|
|
||||||
|
// maps start_addr-end_addr permission offset dev inode pathname
|
||||||
|
for (const auto &line : lines) {
|
||||||
|
auto fields = sled::StrSplit(line, " \n\t", true);
|
||||||
|
if (fields.size() < 6) { continue; }
|
||||||
|
auto addrs = sled::StrSplit(fields[0], "-", false);
|
||||||
|
|
||||||
|
uint64_t start_addr = GetHex(addrs[0]);
|
||||||
|
uint64_t end_addr = GetHex(addrs[1]);
|
||||||
|
uint64_t offset = GetHex(fields[2]);
|
||||||
|
LOGD(kTag, "addr: {}-{} {} {} {}", start_addr, end_addr, offset, fields[1], fields[5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Symbolizer {};
|
||||||
|
|
||||||
|
void
|
||||||
|
InitializeSymbolizer(const char *argv0)
|
||||||
|
{
|
||||||
|
if (g_exe) {
|
||||||
|
free(g_exe);
|
||||||
|
g_exe = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argv0 && argv0[0] != '\0') { g_exe = strdup(argv0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Symbolize(const void *pc, char *out, int out_size)
|
||||||
|
{
|
||||||
|
Dl_info info;
|
||||||
|
if (!dladdr(pc, &info)) { return false; }
|
||||||
|
if (info.dli_fname && out_size > 0) {
|
||||||
|
strncpy(out, info.dli_fname, out_size);
|
||||||
|
|
||||||
|
const auto end_pos = static_cast<size_t>(out_size) - 1;
|
||||||
|
if (out[end_pos] != '\0') {
|
||||||
|
// add ...
|
||||||
|
out[end_pos] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}// namespace sled
|
43
src/sled/debugging/symbolize_test.cc
Normal file
43
src/sled/debugging/symbolize_test.cc
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <sled/debugging/symbolize.h>
|
||||||
|
#include <sled/make_unique.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
TestFunc1()
|
||||||
|
{}
|
||||||
|
|
||||||
|
static char try_symbolize_buffer[4096];
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
TrySymbolizeWithLimit(void *pc, int limit)
|
||||||
|
{
|
||||||
|
// ASSERT_LE(limit, 4096);
|
||||||
|
auto heap_buffer = sled::MakeUnique<char[]>(4096);
|
||||||
|
bool found = sled::Symbolize(pc, heap_buffer.get(), sizeof(try_symbolize_buffer));
|
||||||
|
strncpy(try_symbolize_buffer, heap_buffer.get(), sizeof(try_symbolize_buffer) - 1);
|
||||||
|
try_symbolize_buffer[sizeof(try_symbolize_buffer) - 1] = '\0';
|
||||||
|
|
||||||
|
return try_symbolize_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
TrySymbolize(void *pc)
|
||||||
|
{
|
||||||
|
return TrySymbolizeWithLimit(pc, 4096);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(Symbolize, base)
|
||||||
|
// {
|
||||||
|
// char buf[1024];
|
||||||
|
// EXPECT_EQ("TestFunc1", TrySymbolize((void *) &TestFunc1));
|
||||||
|
// }
|
||||||
|
|
||||||
|
TEST(Symbolize, ReadAddrMap) { sled::ReadAddrMap(); }
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
sled::InitializeSymbolizer(argv[0]);
|
||||||
|
testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
@ -54,15 +54,31 @@ StrSplit(const std::string &str, const std::string &delim, bool skip_empty)
|
|||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
if (str.empty()) { return result; }
|
if (str.empty()) { return result; }
|
||||||
|
|
||||||
size_t start = 0;
|
size_t start = 0;
|
||||||
size_t next_pos = str.find_first_of(delim, start);
|
size_t next_pos = str.find_first_of(delim, start);
|
||||||
while (next_pos != std::string::npos) {
|
while (next_pos != std::string::npos) {
|
||||||
if (!skip_empty || next_pos > start) { result.emplace_back(str.substr(start, next_pos - start)); }
|
if ((!skip_empty && next_pos == start) || next_pos > start) {
|
||||||
start = next_pos + 1;
|
result.emplace_back(str.begin() + start, str.begin() + next_pos);
|
||||||
next_pos = str.find_first_of(delim, start);
|
}
|
||||||
|
|
||||||
|
if (!skip_empty) {
|
||||||
|
start = next_pos + 1;
|
||||||
|
next_pos = str.find_first_of(delim, start);
|
||||||
|
} else {
|
||||||
|
start = str.find_first_not_of(delim, next_pos);
|
||||||
|
if (start == std::string::npos) {
|
||||||
|
// all remaining characters are delimiters
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next_pos = str.find_first_of(delim, start);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start < str.size()) { result.emplace_back(str.substr(start)); }
|
if (start < str.size()) {
|
||||||
|
result.emplace_back(str.substr(start));
|
||||||
|
} else if (!skip_empty && !str.empty() && delim.find(str.back()) != std::string::npos) {
|
||||||
|
result.emplace_back("");
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
99
src/sled/strings/utils_test.cc
Normal file
99
src/sled/strings/utils_test.cc
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <sled/strings/utils.h>
|
||||||
|
|
||||||
|
TEST(ToLower, Char)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(sled::ToLower('A'), 'a');
|
||||||
|
EXPECT_EQ(sled::ToLower('Z'), 'z');
|
||||||
|
EXPECT_EQ(sled::ToLower('a'), 'a');
|
||||||
|
EXPECT_EQ(sled::ToLower('z'), 'z');
|
||||||
|
EXPECT_EQ(sled::ToLower(' '), ' ');
|
||||||
|
EXPECT_EQ(sled::ToLower('\0'), '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ToUpper, Char)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(sled::ToUpper('A'), 'A');
|
||||||
|
EXPECT_EQ(sled::ToUpper('Z'), 'Z');
|
||||||
|
EXPECT_EQ(sled::ToUpper('a'), 'A');
|
||||||
|
EXPECT_EQ(sled::ToUpper('z'), 'Z');
|
||||||
|
EXPECT_EQ(sled::ToUpper(' '), ' ');
|
||||||
|
EXPECT_EQ(sled::ToUpper('\0'), '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ToLower, String)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(sled::ToLower("Hello World"), "hello world");
|
||||||
|
EXPECT_EQ(sled::ToLower("HELLO WORLD"), "hello world");
|
||||||
|
EXPECT_EQ(sled::ToLower("hello world"), "hello world");
|
||||||
|
EXPECT_EQ(sled::ToLower(" "), " ");
|
||||||
|
EXPECT_EQ(sled::ToLower(""), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ToUpper, String)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(sled::ToUpper("Hello World"), "HELLO WORLD");
|
||||||
|
EXPECT_EQ(sled::ToUpper("HELLO WORLD"), "HELLO WORLD");
|
||||||
|
EXPECT_EQ(sled::ToUpper("hello world"), "HELLO WORLD");
|
||||||
|
EXPECT_EQ(sled::ToUpper(" "), " ");
|
||||||
|
EXPECT_EQ(sled::ToUpper(""), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StrJoin, Empty)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(sled::StrJoin({}, ","), "");
|
||||||
|
EXPECT_EQ(sled::StrJoin({}, ",", true), "");
|
||||||
|
EXPECT_EQ(sled::StrJoin({}, ",", false), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StrJoin, Delim)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(sled::StrJoin({"a", "b", "c"}, ","), "a,b,c");
|
||||||
|
EXPECT_EQ(sled::StrJoin({"a", "b", "c"}, ",", true), "a,b,c");
|
||||||
|
EXPECT_EQ(sled::StrJoin({"a", "b", "c"}, ",", false), "a,b,c");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StrJoin, DelimSkipEmpty)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(sled::StrJoin({"a", "", "c"}, ","), "a,,c");
|
||||||
|
EXPECT_EQ(sled::StrJoin({"a", "", "c"}, ",", true), "a,c");
|
||||||
|
EXPECT_EQ(sled::StrJoin({"a", "", "c"}, ",", false), "a,,c");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StrSplit, Empty)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(sled::StrSplit("", ","), std::vector<std::string>());
|
||||||
|
EXPECT_EQ(sled::StrSplit("", ",", true), std::vector<std::string>());
|
||||||
|
EXPECT_EQ(sled::StrSplit("", ",", false), std::vector<std::string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StrSplit, Delim)
|
||||||
|
{
|
||||||
|
// single delim
|
||||||
|
EXPECT_EQ(sled::StrSplit("a,b,c", ","), std::vector<std::string>({"a", "b", "c"}));
|
||||||
|
EXPECT_EQ(sled::StrSplit("a,b,c", ",", true), std::vector<std::string>({"a", "b", "c"}));
|
||||||
|
EXPECT_EQ(sled::StrSplit("a,b,c", ",", false), std::vector<std::string>({"a", "b", "c"}));
|
||||||
|
EXPECT_EQ(sled::StrSplit("a,b,c,", ","), std::vector<std::string>({"a", "b", "c", ""}));
|
||||||
|
EXPECT_EQ(sled::StrSplit("a,b,c,", ",", true), std::vector<std::string>({"a", "b", "c"}));
|
||||||
|
EXPECT_EQ(sled::StrSplit("a,b,c,", ",", false), std::vector<std::string>({"a", "b", "c", ""}));
|
||||||
|
EXPECT_EQ(sled::StrSplit(",a,b,c", ","), std::vector<std::string>({"", "a", "b", "c"}));
|
||||||
|
EXPECT_EQ(sled::StrSplit(",a,b,c", ",", true), std::vector<std::string>({"a", "b", "c"}));
|
||||||
|
EXPECT_EQ(sled::StrSplit(",a,b,c", ",", false), std::vector<std::string>({"", "a", "b", "c"}));
|
||||||
|
|
||||||
|
// multi delim
|
||||||
|
EXPECT_EQ(sled::StrSplit(",,a,b,c", ",", true), std::vector<std::string>({"a", "b", "c"}));
|
||||||
|
EXPECT_EQ(sled::StrSplit(",,a,b,c", ",", false), std::vector<std::string>({"", "", "a", "b", "c"}));
|
||||||
|
EXPECT_EQ(sled::StrSplit("a,b,c,,", ",", true), std::vector<std::string>({"a", "b", "c"}));
|
||||||
|
EXPECT_EQ(sled::StrSplit("a,b,c,,", ",", false), std::vector<std::string>({"a", "b", "c", "", ""}));
|
||||||
|
EXPECT_EQ(sled::StrSplit("a,,b,c", ",", true), std::vector<std::string>({"a", "b", "c"}));
|
||||||
|
EXPECT_EQ(sled::StrSplit("a,,b,c", ",", false), std::vector<std::string>({"a", "", "b", "c"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StrSplit, MultiDelim)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(sled::StrSplit("a,b;c", ",;", true), std::vector<std::string>({"a", "b", "c"}));
|
||||||
|
EXPECT_EQ(sled::StrSplit("a,b;c", ",;", false), std::vector<std::string>({"a", "b", "c"}));
|
||||||
|
EXPECT_EQ(sled::StrSplit("a,b;c,", ",;", true), std::vector<std::string>({"a", "b", "c"}));
|
||||||
|
EXPECT_EQ(sled::StrSplit("a,b;c,", ",;", false), std::vector<std::string>({"a", "b", "c", ""}));
|
||||||
|
EXPECT_EQ(sled::StrSplit("a,b;c,", ";,", true), std::vector<std::string>({"a", "b", "c"}));
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user