diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index efe3335..78b9248 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,15 +47,6 @@ jobs: artifact_name: "Windows x64", cores: 2, } - - { - name: "Windows-MinGW/2019/Static/X64/Release", - os: windows-2019, - config: Release, - cmake_extra_args: "-G \"MinGW Makefiles\" -DCMAKE_C_COMPILER=C:/msys64/mingw64/bin/gcc.exe -DCMAKE_CXX_COMPILER=C:/msys64/mingw64/bin/g++.exe", - sudocmd: "", - artifact_name: "Windows x64", - cores: 2, - } - { name: "Ubuntu/20.04/Static/X64/Release", os: ubuntu-20.04, diff --git a/CMakeLists.txt b/CMakeLists.txt index ed1910f..6731b9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ set_compiler_booleans() # detect compiler option(SMALL_DEV_BUILD "Development build" ${MASTER_PROJECT}) option(SMALL_BUILD_EXAMPLES "Build examples" ${SMALL_DEV_BUILD}) option(SMALL_BUILD_TESTS "Build tests" ${SMALL_DEV_BUILD}) +option(SMALL_BUILD_TESTS_WITH_PCH "Build tests with precompiled headers" ${SMALL_DEV_BUILD}) option(SMALL_BUILD_INSTALLER "Build installer target" ${SMALL_DEV_BUILD}) option(SMALL_BUILD_PACKAGE "Build package" ${SMALL_DEV_BUILD}) diff --git a/README.md b/README.md index 9ddb480..7936034 100644 --- a/README.md +++ b/README.md @@ -120,11 +120,21 @@ Integration: === "Install" - Get the binary package from the [release section](https://github.com/alandefreitas/small/releases). These binaries refer to the latest release version of small. + !!! note + + Get the binary package from the [release section](https://github.com/alandefreitas/small/releases). + + These binaries refer to the latest release version of small. + + !!! hint + + If you need a more recent version of `small`, you can download the binary packages from the CI artifacts or build the library from the source files. === "Build from source" - Ensure your C++ compiler and CMake are up-to-date and then: + !!! note + + Ensure your C++ compiler and CMake are up-to-date and then: === "Ubuntu + GCC" @@ -175,7 +185,8 @@ Integration: ``` !!! hint "Parallel Build" - Replace `--parallel 2` with `--parallel ` + + Replace `--parallel 2` with `--parallel ` !!! note "Setting C++ Compiler" @@ -187,12 +198,16 @@ Integration: === "File amalgamation" - Because containers are header-only, you can directly copy the contents from the `source` directory into your project. + !!! note + + Because containers are header-only, you can directly copy the contents from the `source` directory into your project. + + !!! hint - In that case, you are responsible for setting the appropriate target include directories and any compile definitions you might require. + In that case, you are responsible for setting the appropriate target include directories and any compile definitions you might require. -Once the library is properly integrated, you can create containers from the namespace `small` like any other STL containers: +Once the library is properly integrated, you can create containers from the namespace `small` like any other STL container: ```cpp --8<-- "examples/main.cpp" @@ -205,15 +220,13 @@ All containers are optimized for the case when they're small but also efficient - Identification of relocatable types - Custom growth factors with better defaults - Communication with system memory allocators -- Explicit consideration of CPU cache sizes -- Explicit identification and consideration of L1 cache sizes -- Explicit identification and consideration of branch prediction +- Explicit consideration of CPU cache sizes and branch prediction Most applications have many small lists and sets of elements. These containers avoid spending a lot of time with large containers that contain just a few elements. Small containers usually try to use the stack before dynamically allocating memory and try to represent associative containers with stack arrays, unless these sets are very large. -Although many compilers support small string optimization (SSO) already, this library will ensure all strings support SOO, custom inline sizes, and unicode. +Although many compilers support small string optimization (SSO) already, this library will ensure all strings support SOO, custom inline sizes, relocation, and unicode. ## Vectors diff --git a/cmake/functions/project_flags.cmake b/cmake/functions/project_flags.cmake index 5133680..7891b75 100644 --- a/cmake/functions/project_flags.cmake +++ b/cmake/functions/project_flags.cmake @@ -72,7 +72,7 @@ macro(set_optimization_flags) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") else() # https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Og") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") endif() else() if (MSVC) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index bbaac0e..2b9e570 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -12,7 +12,6 @@ add_library(small small/detail/container/aligned_storage_vector.h small/detail/container/associative_vector.h small/detail/container/lookup_table_view.h - small/detail/container/max_size_map.h small/detail/container/span-lite.h small/detail/container/variant_vector.h small/detail/exception/scope_guard.h @@ -84,6 +83,6 @@ if (SMALL_BUILD_INSTALLER) install(EXPORT small-targets FILE small-targets.cmake NAMESPACE small:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Small + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/small ) endif() diff --git a/source/small/detail/algorithm/console_unicode_guard.h b/source/small/detail/algorithm/console_unicode_guard.h index 71b1dde..f07f6f5 100644 --- a/source/small/detail/algorithm/console_unicode_guard.h +++ b/source/small/detail/algorithm/console_unicode_guard.h @@ -12,6 +12,8 @@ /// - the terminal doesn't currently support unicode /// It might also need to temporarily change the console font if the input string includes large code points +#include + #if defined(_WIN32) && __has_include() #include #undef small @@ -24,7 +26,7 @@ namespace small { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif - console_unicode_guard(std::ostream &os, size_t size, size_t codepoints, bool above_10000 = true) { + inline console_unicode_guard(std::ostream &os, size_t size, size_t codepoints, bool above_10000 = true) { #if defined(_WIN32) && __has_include() const bool is_console = &os == reinterpret_cast(&std::cout) || &os == reinterpret_cast(&std::wcout); const bool requires_unicode = size != codepoints; @@ -66,8 +68,7 @@ namespace small { #pragma GCC diagnostic pop #endif - - ~console_unicode_guard() { + inline ~console_unicode_guard() { #if defined(_WIN32) && __has_include() if (requires_another_console_cp) { SetConsoleOutputCP(prev_console_output_cp); diff --git a/source/small/detail/algorithm/intcmp.h b/source/small/detail/algorithm/intcmp.h index ee96f0e..9fd79b9 100644 --- a/source/small/detail/algorithm/intcmp.h +++ b/source/small/detail/algorithm/intcmp.h @@ -108,7 +108,7 @@ namespace small { } } - long long int div_ceil(long long int numerator, long long int denominator) { + inline long long int div_ceil(long long int numerator, long long int denominator) { lldiv_t res = std::div(numerator, denominator); return res.rem ? (res.quot + 1) : res.quot; } diff --git a/source/small/detail/container/max_size_map.h b/source/small/detail/container/max_size_map.h deleted file mode 100644 index 4d82362..0000000 --- a/source/small/detail/container/max_size_map.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Created by Alan Freitas on 5/31/21. -// - -#ifndef SMALL_MAX_SIZE_MAP_H -#define SMALL_MAX_SIZE_MAP_H - -#include "aligned_storage_vector.h" -#include "associative_vector.h" - -namespace small {} - -#endif // SMALL_MAX_SIZE_MAP_H diff --git a/source/small/map.h b/source/small/map.h index 759b44c..834d608 100644 --- a/source/small/map.h +++ b/source/small/map.h @@ -6,7 +6,6 @@ #define SMALL_SMALL_MAP_H #include "detail/container/associative_vector.h" -#include "detail/container/max_size_map.h" #include "vector.h" /// \file A map container for small maps diff --git a/source/small/set.h b/source/small/set.h index 20ef557..5f604e8 100644 --- a/source/small/set.h +++ b/source/small/set.h @@ -6,7 +6,6 @@ #define SMALL_SMALL_SET_H #include "detail/container/associative_vector.h" -#include "detail/container/max_size_map.h" #include "vector.h" /// \file A set container for small sets diff --git a/source/small/string.h b/source/small/string.h index 3f4a204..82f9d47 100644 --- a/source/small/string.h +++ b/source/small/string.h @@ -3307,7 +3307,7 @@ namespace small { /// \throws std::invalid_argument if no conversion could be performed /// \throws std::out_of_range if the converted value would fall out of the range of the result type or if the /// underlying function (std::strtol or std::strtoll) sets errno to ERANGE. - int stoi(const small::string &str, std::size_t *pos = nullptr, int base = 10) { + inline int stoi(const small::string &str, std::size_t *pos = nullptr, int base = 10) { errno = 0; char *p_end; const long i = std::strtol(str.c_str(), &p_end, base); @@ -3330,7 +3330,7 @@ namespace small { /// \throws std::invalid_argument if no conversion could be performed /// \throws std::out_of_range if the converted value would fall out of the range of the result type or if the /// underlying function (std::strtol or std::strtoll) sets errno to ERANGE. - long stol(const small::string &str, std::size_t *pos = nullptr, int base = 10) { + inline long stol(const small::string &str, std::size_t *pos = nullptr, int base = 10) { errno = 0; char *p_end; const long i = std::strtol(str.c_str(), &p_end, base); @@ -3352,7 +3352,7 @@ namespace small { /// \throws std::invalid_argument if no conversion could be performed /// \throws std::out_of_range if the converted value would fall out of the range of the result type or if the /// underlying function (std::strtol or std::strtoll) sets errno to ERANGE. - long long stoll(const small::string &str, std::size_t *pos = nullptr, int base = 10) { + inline long long stoll(const small::string &str, std::size_t *pos = nullptr, int base = 10) { errno = 0; char *p_end; const long long i = std::strtoll(str.c_str(), &p_end, base); @@ -3374,7 +3374,7 @@ namespace small { /// \throws std::invalid_argument if no conversion could be performed /// \throws std::out_of_range if the converted value would fall out of the range of the result type or if the /// underlying function (std::strtoul or std::strtoull) sets errno to ERANGE. - unsigned long stoul(const small::string &str, std::size_t *pos = nullptr, int base = 10) { + inline unsigned long stoul(const small::string &str, std::size_t *pos = nullptr, int base = 10) { errno = 0; char *p_end; const unsigned long i = std::strtoul(str.c_str(), &p_end, base); @@ -3396,7 +3396,7 @@ namespace small { /// \throws std::invalid_argument if no conversion could be performed /// \throws std::out_of_range if the converted value would fall out of the range of the result type or if the /// underlying function (std::strtoul or std::strtoull) sets errno to ERANGE. - unsigned long long stoull(const small::string &str, std::size_t *pos = nullptr, int base = 10) { + inline unsigned long long stoull(const small::string &str, std::size_t *pos = nullptr, int base = 10) { errno = 0; char *p_end; const unsigned long long i = std::strtoull(str.c_str(), &p_end, base); @@ -3418,7 +3418,7 @@ namespace small { /// \throws std::invalid_argument if no conversion could be performed /// \throws std::out_of_range if the converted value would fall out of the range of the result type or if the /// underlying function (std::strtoul or std::strtoull) sets errno to ERANGE. - float stof(const small::string &str, std::size_t *pos = nullptr) { + inline float stof(const small::string &str, std::size_t *pos = nullptr) { errno = 0; char *p_end; const float i = std::strtof(str.c_str(), &p_end); @@ -3440,7 +3440,7 @@ namespace small { /// \throws std::invalid_argument if no conversion could be performed /// \throws std::out_of_range if the converted value would fall out of the range of the result type or if the /// underlying function (std::strtoul or std::strtoull) sets errno to ERANGE. - double stod(const small::string &str, std::size_t *pos = nullptr) { + inline double stod(const small::string &str, std::size_t *pos = nullptr) { errno = 0; char *p_end; const double i = std::strtod(str.c_str(), &p_end); @@ -3462,7 +3462,7 @@ namespace small { /// \throws std::invalid_argument if no conversion could be performed /// \throws std::out_of_range if the converted value would fall out of the range of the result type or if the /// underlying function (std::strtoul or std::strtoull) sets errno to ERANGE. - long double stold(const small::string &str, std::size_t *pos = nullptr) { + inline long double stold(const small::string &str, std::size_t *pos = nullptr) { errno = 0; char *p_end; const long double i = std::strtold(str.c_str(), &p_end); diff --git a/source/small/vector.h b/source/small/vector.h index d3b2fbd..5151605 100644 --- a/source/small/vector.h +++ b/source/small/vector.h @@ -151,7 +151,7 @@ namespace small { /// \brief True if we should just copy the inline storage static constexpr bool should_copy_inline = - std::is_trivially_destructible_v && sizeof(inline_storage_type) <= cache_line_size / 2; + std::is_trivially_copyable_v && sizeof(inline_storage_type) <= cache_line_size / 2; /// \brief True if we are using the std::allocator static constexpr bool using_std_allocator = std::is_same>::value; @@ -246,29 +246,38 @@ namespace small { /// \brief Copy assignment vector &operator=(const vector &rhs) { - if (this != &rhs) { - if constexpr (should_copy_inline) { - if (this->is_inline() && rhs.is_inline()) { - copy_inline_trivial(rhs); - return *this; - } - } else if (rhs.size() < capacity()) { - const size_t n = rhs.size(); - if constexpr (std::is_trivially_copy_assignable_v) { - std::memcpy((void *)begin().base(), (void *)rhs.begin().base(), n * sizeof(T)); - } else { - partially_uninitialized_copy(rhs.begin(), n, begin(), size()); - } - this->set_internal_size(n); - } else { - assign(rhs.begin(), rhs.end()); - } + if (this == &rhs) { + return *this; } + constexpr bool should_copy_alloc = std::allocator_traits::propagate_on_container_copy_assignment::value; if constexpr (should_copy_alloc) { enable_allocator_type::set_allocator(rhs.alloc_); } + + if constexpr (should_copy_inline) { + if (this->is_inline() && rhs.is_inline()) { + // cheap copy the inline buffer + copy_inline_trivial(rhs); + return *this; + } + } + + if (rhs.size() < capacity()) { + // rhs fits in lhs capacity + const size_t n = rhs.size(); + if constexpr (std::is_trivially_copy_assignable_v) { + std::memcpy((void *)begin().base(), (void *)rhs.begin().base(), n * sizeof(T)); + } else { + partially_uninitialized_copy(rhs.begin(), n, begin(), size()); + } + this->set_internal_size(n); + } else { + // rhs does not fit in lhs current capacity + assign(rhs.begin(), rhs.end()); + } + return *this; } diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 8ceb106..3d3f336 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -38,6 +38,11 @@ macro(add_small_test TEST_NAME) # Link with catch-main target_link_libraries(ut_${TEST_NAME} PUBLIC ${LINK_LIBS} catch_main) + # Definitions for PHC + if (SMALL_BUILD_TESTS_WITH_PCH) + target_compile_definitions(ut_${TEST_NAME} PRIVATE SMALL_BUILD_TESTS_WITH_PCH) + endif () + # Enable UTF-8 on windows target_msvc_compile_options(ut_${TEST_NAME} INTERFACE "/utf-8") @@ -50,7 +55,114 @@ macro(add_small_test TEST_NAME) endmacro() # Main tests -add_small_test(small_vector small::small) -add_small_test(small_string small::small) +add_small_test(ptr_wrapper small::small) +add_small_test(pod_small_vector small::small) +add_small_test(string_small_vector small::small) +add_small_test(custom_small_vector small::small) + +add_small_test(unicode_functions small::small) +add_small_test(small_string_make small::small) +add_small_test(small_string_access small::small) +add_small_test(small_string_modify small::small) +add_small_test(small_string_modify_algorithms small::small) +add_small_test(small_string_const_algorithms small::small) +add_small_test(small_string_non_member small::small) + add_small_test(small_map small::small) add_small_test(small_set small::small) + +if (SMALL_BUILD_TESTS_WITH_PCH) + foreach (vector_target ut_ptr_wrapper ut_pod_small_vector ut_string_small_vector ut_custom_small_vector) + target_precompile_headers(${vector_target} + PRIVATE + # C++ + + + + + + + + # C++ headers for vector + + + + + + + + + # External + + + # Small vector + + + + + + + + + + ) + endforeach () + + # Use small::string in custom element so that it becomes relocatable + target_precompile_headers(ut_custom_small_vector + PRIVATE + + ) + + foreach (string_target + ut_unicode_functions + ut_small_string_make + ut_small_string_access + ut_small_string_modify + ut_small_string_modify_algorithms + ut_small_string_const_algorithms + ut_small_string_non_member) + target_precompile_headers(${string_target} + PRIVATE + + + + + + + + + + + + + ) + endforeach() + + target_precompile_headers(ut_small_set + PRIVATE + + + + + + + + + + ) + + target_precompile_headers(ut_small_map + PRIVATE + + + + + + + + + + ) + +endif () \ No newline at end of file diff --git a/tests/unit_tests/custom_small_vector.cpp b/tests/unit_tests/custom_small_vector.cpp new file mode 100644 index 0000000..686d32a --- /dev/null +++ b/tests/unit_tests/custom_small_vector.cpp @@ -0,0 +1,533 @@ +#ifndef SMALL_BUILD_TESTS_WITH_PCH +// C++ +#include +#include +#include +#include +#include +#include + +// External +#include + +// Small +#include +#include +#endif + +// A relocatable custom type +struct custom_type { + enum class custom_enum { even, odd }; + custom_type() {} // NOLINT(modernize-use-equals-default,cppcoreguidelines-pro-type-member-init) + custom_type(const std::string &v) // NOLINT(google-explicit-constructor) + : type_(v.size() & 1 ? custom_enum::even : custom_enum::odd), name_(v), url_("https://" + v), + version_(v.size() < 4 ? std::optional(std::nullopt) : std::optional(static_cast(v.size()))), + tag_(v.substr(2)), system_(v.substr(0, 2)), raw_(v) {} + custom_type(const char *v) : custom_type(std::string(v)) {} // NOLINT(google-explicit-constructor) + custom_enum type_; + // use relocatable internal string + small::string name_; + small::string url_; + std::optional version_{std::nullopt}; + std::optional tag_{std::nullopt}; + std::optional system_{std::nullopt}; + std::optional raw_{std::nullopt}; +}; + +// Allow comparing with std::string to make tests easier +bool operator==(const custom_type &lhs, const custom_type &rhs) { return lhs.raw_ == rhs.raw_; } +bool operator!=(const custom_type &lhs, const custom_type &rhs) { return !(rhs == lhs); } + +bool operator==(const custom_type &lhs, const std::string &rhs) { return lhs.raw_ == rhs; } +bool operator!=(const custom_type &lhs, const std::string &rhs) { return !(lhs == rhs); } +bool operator==(const std::string &lhs, const custom_type &rhs) { return rhs.raw_ == lhs; } +bool operator!=(const std::string &lhs, const custom_type &rhs) { return !(lhs == rhs); } + +bool operator==(const custom_type &lhs, const char *rhs) { return lhs.raw_ == std::string(rhs); } +bool operator!=(const custom_type &lhs, const char *rhs) { return !(lhs == rhs); } +bool operator==(const char *lhs, const custom_type &rhs) { return rhs.raw_ == std::string(lhs); } +bool operator!=(const char *lhs, const custom_type &rhs) { return !(lhs == rhs); } + +bool operator<(const custom_type &lhs, const custom_type &rhs) { return lhs.raw_ < rhs.raw_; } +bool operator>(const custom_type &lhs, const custom_type &rhs) { return rhs < lhs; } +bool operator<=(const custom_type &lhs, const custom_type &rhs) { return !(rhs < lhs); } +bool operator>=(const custom_type &lhs, const custom_type &rhs) { return !(lhs < rhs); } + +bool operator<(const custom_type &lhs, const std::string &rhs) { return lhs.raw_ < rhs; } +bool operator>(const custom_type &lhs, const std::string &rhs) { return rhs < lhs; } +bool operator<=(const custom_type &lhs, const std::string &rhs) { return !(rhs < lhs); } +bool operator>=(const custom_type &lhs, const std::string &rhs) { return !(lhs < rhs); } + +namespace small { + // The custom type has no internal pointers, so we can relocate it faster + // Most types might be relocatable, but we have to conservatively assume they are not + template <> struct is_relocatable : std::true_type {}; + + // Vectors of custom type should have 10 inlined values by default for some reason, + // so we don't need to specify this default value for every small vector + template <> struct default_inline_storage : std::integral_constant {}; +} // namespace small + +TEST_CASE("Custom Vector") { + using namespace small; + + STATIC_REQUIRE(is_relocatable_v); + auto equal_il = [](const auto &sm_vector, std::initializer_list il) -> bool { + return std::equal(sm_vector.begin(), sm_vector.end(), il.begin(), il.end()); + }; + + SECTION("Constructor") { + SECTION("Asserts") { + REQUIRE(std::is_copy_constructible_v>); + REQUIRE(std::is_copy_assignable_v>); + REQUIRE(std::is_move_constructible_v>); + REQUIRE(std::is_move_assignable_v>); + + REQUIRE(std::is_copy_constructible_v, 5>>); + REQUIRE(std::is_copy_assignable_v, 5>>); + REQUIRE(std::is_move_constructible_v, 5>>); + REQUIRE(std::is_move_assignable_v, 5>>); + } + + SECTION("Default") { + vector a; + REQUIRE(a.empty()); + REQUIRE(equal_il(a, {})); + } + + SECTION("Allocator") { + std::allocator alloc; + vector> a(alloc); + REQUIRE(a.empty()); + REQUIRE(equal_il(a, {})); + REQUIRE(a.get_allocator() == alloc); + } + + SECTION("With size") { + std::allocator alloc; + vector b(3, alloc); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 3); + REQUIRE(b.get_allocator() == alloc); + } + + SECTION("From value") { + std::allocator alloc; + vector c(3, "one", alloc); + REQUIRE(c.size() == 3); + REQUIRE_FALSE(c.empty()); + REQUIRE(equal_il(c, {"one", "one", "one"})); + REQUIRE(c.get_allocator() == alloc); + } + + SECTION("From Iterators") { + std::allocator alloc; + std::vector dv = {"six", "five", "four"}; + vector d(dv.begin(), dv.end(), alloc); + REQUIRE(d.size() == 3); + REQUIRE_FALSE(d.empty()); + REQUIRE(equal_il(d, {"six", "five", "four"})); + REQUIRE(d.get_allocator() == alloc); + } + + SECTION("From initializer list") { + vector e = {"one", "two"}; + REQUIRE(e.size() == 2); + REQUIRE_FALSE(e.empty()); + REQUIRE(equal_il(e, {"one", "two"})); + } + + SECTION("From ranges") { + std::vector v = {"one", "two", "three"}; + vector e(v); + REQUIRE(e.size() == 3); + REQUIRE_FALSE(e.empty()); + REQUIRE(equal_il(e, {"one", "two", "three"})); + } + } + + SECTION("Assign") { + SECTION("From initializer list") { + vector a; + REQUIRE(a.empty()); + a = {"six", "five", "four"}; + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"six", "five", "four"})); + } + + SECTION("From another small vector") { + vector a; + REQUIRE(a.empty()); + a = {"six", "five", "four"}; + + vector b; + REQUIRE(b.empty()); + b = a; + REQUIRE(b.size() == 3); + REQUIRE_FALSE(b.empty()); + REQUIRE(a == b); + } + + SECTION("From iterators") { + vector a; + REQUIRE(a.empty()); + std::vector v = {"six", "five", "four"}; + a.assign(v.begin(), v.end()); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"six", "five", "four"})); + } + + SECTION("From size and value") { + vector a; + REQUIRE(a.empty()); + a.assign(3, "one"); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "one", "one"})); + } + + SECTION("From initializer list") { + vector a; + REQUIRE(a.empty()); + a.assign({"six", "five", "four"}); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"six", "five", "four"})); + } + + SECTION("Fill") { + vector a(3, "one"); + REQUIRE_FALSE(a.empty()); + a.fill("two"); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"two", "two", "two"})); + } + + SECTION("Swap") { + vector a(4, "one"); + vector b(3, "two"); + + std::initializer_list ar = {"one", "one", "one", "one"}; + std::initializer_list br = {"two", "two", "two"}; + + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 4); + REQUIRE(equal_il(a, ar)); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 3); + REQUIRE(equal_il(b, br)); + + a.swap(b); + + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 3); + REQUIRE(equal_il(a, br)); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 4); + REQUIRE(equal_il(b, ar)); + + std::swap(a, b); + + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 4); + REQUIRE(equal_il(a, ar)); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 3); + REQUIRE(equal_il(b, br)); + } + } + + SECTION("Iterators") { + vector a = {"one", "two", "three"}; + + REQUIRE(a.begin() == a.data()); + REQUIRE(a.end() == a.data() + a.size()); + REQUIRE_FALSE(a.end() == a.data() + a.capacity()); + REQUIRE(*a.begin() == "one"); + REQUIRE(*std::prev(a.end()) == "three"); + + REQUIRE(a.cbegin() == a.data()); + REQUIRE(a.cend() == a.data() + a.size()); + REQUIRE_FALSE(a.cend() == a.data() + a.capacity()); + REQUIRE(*a.cbegin() == "one"); + REQUIRE(*std::prev(a.cend()) == "three"); + + REQUIRE(*a.rbegin() == "three"); + REQUIRE(*std::prev(a.rend()) == "one"); + + REQUIRE(*a.crbegin() == "three"); + REQUIRE(*std::prev(a.crend()) == "one"); + } + + SECTION("Capacity") { + /* + * The inline capacity depends on the platform, but these values don't vary a lot + */ + vector a = {"one", "two", "three"}; + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.is_inline()); + REQUIRE(a.capacity() == 5); + + a.reserve(10); + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() >= 10); + + a.shrink_to_fit(); + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() == 5); + + a.resize(4); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() == 5); + + a.shrink_to_fit(); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() == 5); + } + + SECTION("Element access") { + vector a = {"one", "two", "three"}; + REQUIRE(a[0] == "one"); + REQUIRE(a[1] == "two"); + REQUIRE(a[2] == "three"); + REQUIRE(a.at(0) == "one"); + REQUIRE(a.at(1) == "two"); + REQUIRE(a.at(2) == "three"); + REQUIRE_THROWS(a.at(3) == "four"); + REQUIRE_THROWS(a.at(4) == "five"); + REQUIRE(a.front() == "one"); + REQUIRE(a.back() == "three"); + REQUIRE(*a.data() == "one"); + REQUIRE(*(a.data() + 1) == "two"); + REQUIRE(*(a.data() + 2) == "three"); + REQUIRE(*(a.data() + a.size() - 1) == "three"); + REQUIRE(*(a.data() + a.size() - 2) == "two"); + REQUIRE(*(a.data() + a.size() - 3) == "one"); + } + + SECTION("Modifiers") { + vector a = {"one", "two", "three"}; + a.push_back("four"); + REQUIRE(a.back() == "four"); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "three", "four"})); + + // NOLINTNEXTLINE(performance-move-const-arg) + a.push_back(std::move("five")); + REQUIRE(a.back() == "five"); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "three", "four", "five"})); + + a.pop_back(); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "three", "four"})); + + a.emplace_back("five"); + REQUIRE(a.back() == "five"); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "three", "four", "five"})); + + a.pop_back(); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "three", "four"})); + + auto it = a.emplace(a.begin() + 2, "ten"); + REQUIRE(it == a.begin() + 2); + auto& b = a.back(); + REQUIRE(b == "four"); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "ten", "three", "four"})); + + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "ten"})); + + it = a.insert(a.begin() + 1, "twenty"); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "twenty", "two", "ten"})); + + // NOLINTNEXTLINE(performance-move-const-arg) + it = a.insert(a.begin() + 2, std::move("thirty")); + REQUIRE(it == a.begin() + 2); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "twenty", "thirty", "two", "ten"})); + + a.pop_back(); + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "twenty"})); + + it = a.insert(a.begin() + 1, 2, "ten"); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "ten", "ten", "twenty"})); + + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "ten"})); + + std::initializer_list src = {"two", "four", "eight"}; + it = a.insert(a.begin() + 1, src.begin(), src.end()); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "four", "eight", "ten"})); + + a.pop_back(); + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two"})); + + it = a.insert(a.begin() + 1, {"two", "four", "eight"}); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "four", "eight", "two"})); + + it = a.erase(a.begin() + 1); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "four", "eight", "two"})); + + it = a.erase(a.begin() + 1, a.begin() + 3); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two"})); + + a.clear(); + // NOLINTNEXTLINE(readability-container-size-empty) + REQUIRE(a.size() == 0); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE(a.empty()); + REQUIRE(equal_il(a, {})); + + a.resize(2); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + + a.resize(4, "five"); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a[2] == "five"); + REQUIRE(a[3] == "five"); + } + + SECTION("Element access errors") { + vector a = {"one", "two", "three"}; + try { + a.at(4); + } catch (std::exception &e) { + REQUIRE(e.what() == std::string_view("at: cannot access element after vector::size()")); + } + } + + SECTION("Relational Operators") { + vector a = {"one", "two", "three"}; + vector b = {"two", "four", "five"}; + + REQUIRE_FALSE(a == b); + REQUIRE(a != b); + REQUIRE(a < b); + REQUIRE(a <= b); + REQUIRE_FALSE(a > b); + REQUIRE_FALSE(a >= b); + } + + SECTION("From raw vector") { + auto a = to_vector({"one", "two", "three"}); + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() > 3); + REQUIRE(a.capacity() == 5); + REQUIRE(a.capacity() == default_inline_storage_v); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "three"})); + + auto b = to_vector({"one", "two", "three"}); + REQUIRE(b.size() == 3); + REQUIRE(b.max_size() > 5); + REQUIRE(b.capacity() == 5); + REQUIRE_FALSE(b.empty()); + REQUIRE(equal_il(b, {"one", "two", "three"})); + + custom_type cr[] = {"one", "two", "three"}; + auto c = to_vector(cr); + REQUIRE(c.size() == 3); + REQUIRE(c.max_size() > 3); + REQUIRE(c.capacity() == 10); + REQUIRE(c.capacity() == default_inline_storage_v); + REQUIRE_FALSE(c.empty()); + REQUIRE(equal_il(b, {"one", "two", "three"})); + } +} diff --git a/tests/unit_tests/pod_small_vector.cpp b/tests/unit_tests/pod_small_vector.cpp new file mode 100644 index 0000000..436cffc --- /dev/null +++ b/tests/unit_tests/pod_small_vector.cpp @@ -0,0 +1,885 @@ +#ifndef SMALL_BUILD_TESTS_WITH_PCH +// C++ +#include +#include +#include +#include +#include +#include + +// External +#include + +// Small +#include +#endif + +TEST_CASE("POD Small Vector") { + using namespace small; + + STATIC_REQUIRE(is_relocatable_v); + auto equal_il = [](const auto &sm_vector, std::initializer_list il) -> bool { + return std::equal(sm_vector.begin(), sm_vector.end(), il.begin(), il.end()); + }; + + SECTION("Constructor") { + SECTION("Asserts") { + REQUIRE(std::is_copy_constructible_v>); + REQUIRE(std::is_copy_assignable_v>); + REQUIRE(std::is_move_constructible_v>); + REQUIRE(std::is_move_assignable_v>); + + REQUIRE(std::is_copy_constructible_v, 5>>); + REQUIRE(std::is_copy_assignable_v, 5>>); + REQUIRE(std::is_move_constructible_v, 5>>); + REQUIRE(std::is_move_assignable_v, 5>>); + } + + SECTION("Default") { + vector a; + REQUIRE(a.empty()); + REQUIRE(equal_il(a, {})); + } + + SECTION("Allocator") { + std::allocator alloc; + vector> a(alloc); + REQUIRE(a.empty()); + REQUIRE(equal_il(a, {})); + REQUIRE(a.get_allocator() == alloc); + } + + SECTION("With size") { + std::allocator alloc; + vector b(3, alloc); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 3); + REQUIRE(b.get_allocator() == alloc); + } + + SECTION("From value") { + std::allocator alloc; + vector c(3, 1, alloc); + REQUIRE(c.size() == 3); + REQUIRE_FALSE(c.empty()); + REQUIRE(equal_il(c, {1, 1, 1})); + REQUIRE(c.get_allocator() == alloc); + } + + SECTION("From Iterators") { + std::allocator alloc; + std::vector dv = {6, 5, 4}; + vector d(dv.begin(), dv.end(), alloc); + REQUIRE(d.size() == 3); + REQUIRE_FALSE(d.empty()); + REQUIRE(equal_il(d, {6, 5, 4})); + REQUIRE(d.get_allocator() == alloc); + } + + SECTION("From initializer list") { + vector e = {1, 2}; + REQUIRE(e.size() == 2); + REQUIRE_FALSE(e.empty()); + REQUIRE(equal_il(e, {1, 2})); + } + + SECTION("From ranges") { + std::vector v = {1, 2, 3}; + vector e(v); + REQUIRE(e.size() == 3); + REQUIRE_FALSE(e.empty()); + REQUIRE(equal_il(e, {1, 2, 3})); + } + } + + SECTION("Assign") { + SECTION("From initializer list") { + vector a; + REQUIRE(a.empty()); + a = {6, 5, 4}; + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {6, 5, 4})); + } + + SECTION("From another small vector") { + vector a; + REQUIRE(a.empty()); + a = {6, 5, 4}; + + vector b; + REQUIRE(b.empty()); + b = a; + REQUIRE(b.size() == 3); + REQUIRE_FALSE(b.empty()); + REQUIRE(a == b); + } + + SECTION("From iterators") { + vector a; + REQUIRE(a.empty()); + std::vector v = {6, 5, 4}; + a.assign(v.begin(), v.end()); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {6, 5, 4})); + } + + SECTION("From size and value") { + vector a; + REQUIRE(a.empty()); + a.assign(3, 1); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 1, 1})); + } + + SECTION("From initializer list") { + vector a; + REQUIRE(a.empty()); + a.assign({6, 5, 4}); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {6, 5, 4})); + } + + SECTION("Fill") { + vector a(3, 1); + REQUIRE_FALSE(a.empty()); + a.fill(2); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {2, 2, 2})); + } + + SECTION("Swap") { + vector a(4, 1); + vector b(3, 2); + + std::initializer_list ar = {1, 1, 1, 1}; + std::initializer_list br = {2, 2, 2}; + + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 4); + REQUIRE(equal_il(a, ar)); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 3); + REQUIRE(equal_il(b, br)); + + a.swap(b); + + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 3); + REQUIRE(equal_il(a, br)); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 4); + REQUIRE(equal_il(b, ar)); + + std::swap(a, b); + + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 4); + REQUIRE(equal_il(a, ar)); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 3); + REQUIRE(equal_il(b, br)); + } + } + + SECTION("Iterators") { + vector a = {1, 2, 3}; + + REQUIRE(a.begin() == a.data()); + REQUIRE(a.end() == a.data() + a.size()); + REQUIRE_FALSE(a.end() == a.data() + a.capacity()); + REQUIRE(*a.begin() == 1); + REQUIRE(*std::prev(a.end()) == 3); + + REQUIRE(a.cbegin() == a.data()); + REQUIRE(a.cend() == a.data() + a.size()); + REQUIRE_FALSE(a.cend() == a.data() + a.capacity()); + REQUIRE(*a.cbegin() == 1); + REQUIRE(*std::prev(a.cend()) == 3); + + REQUIRE(*a.rbegin() == 3); + REQUIRE(*std::prev(a.rend()) == 1); + + REQUIRE(*a.crbegin() == 3); + REQUIRE(*std::prev(a.crend()) == 1); + } + + SECTION("Capacity") { + vector a = {1, 2, 3}; + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() == 5); + + a.reserve(10); + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() >= 10); + + a.shrink_to_fit(); + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() == 5); + + a.resize(4); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() == 5); + + a.shrink_to_fit(); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() == 5); + } + + SECTION("Element access") { + vector a = {1, 2, 3}; + REQUIRE(a[0] == 1); + REQUIRE(a[1] == 2); + REQUIRE(a[2] == 3); + REQUIRE(a.at(0) == 1); + REQUIRE(a.at(1) == 2); + REQUIRE(a.at(2) == 3); + REQUIRE_THROWS(a.at(3) == 4); + REQUIRE_THROWS(a.at(4) == 5); + REQUIRE(a.front() == 1); + REQUIRE(a.back() == 3); + REQUIRE(*a.data() == 1); + REQUIRE(*(a.data() + 1) == 2); + REQUIRE(*(a.data() + 2) == 3); + REQUIRE(*(a.data() + a.size() - 1) == 3); + REQUIRE(*(a.data() + a.size() - 2) == 2); + REQUIRE(*(a.data() + a.size() - 3) == 1); + } + + SECTION("Modifiers") { + vector a = {1, 2, 3}; + a.push_back(4); + REQUIRE(a.back() == 4); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 2, 3, 4})); + + // NOLINTNEXTLINE(performance-move-const-arg) + a.push_back(std::move(5)); + REQUIRE(a.back() == 5); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 2, 3, 4, 5})); + + a.pop_back(); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 2, 3, 4})); + + a.emplace_back(5); + REQUIRE(a.back() == 5); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 2, 3, 4, 5})); + + a.pop_back(); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 2, 3, 4})); + + auto it = a.emplace(a.begin() + 2, 10); + REQUIRE(it == a.begin() + 2); + REQUIRE(a.back() == 4); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 2, 10, 3, 4})); + + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 2, 10})); + + it = a.insert(a.begin() + 1, 20); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 20, 2, 10})); + + // NOLINTNEXTLINE(performance-move-const-arg) + it = a.insert(a.begin() + 2, std::move(30)); + REQUIRE(it == a.begin() + 2); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 20, 30, 2, 10})); + + a.pop_back(); + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 20})); + + it = a.insert(a.begin() + 1, 2, 10); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 10, 10, 20})); + + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 10})); + + std::initializer_list src = {2, 4, 8}; + it = a.insert(a.begin() + 1, src.begin(), src.end()); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 2, 4, 8, 10})); + + a.pop_back(); + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 2})); + + it = a.insert(a.begin() + 1, {2, 4, 8}); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 2, 4, 8, 2})); + + it = a.erase(a.begin() + 1); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 4, 8, 2})); + + it = a.erase(a.begin() + 1, a.begin() + 3); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 2})); + + a.clear(); + // NOLINTNEXTLINE(readability-container-size-empty) + REQUIRE(a.size() == 0); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE(a.empty()); + REQUIRE(equal_il(a, {})); + + a.resize(2); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + + a.resize(4, 5); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a[2] == 5); + REQUIRE(a[3] == 5); + } + + SECTION("Element access errors") { + vector a = {1, 2, 3}; + try { + a.at(4); + } catch (std::exception &e) { + REQUIRE(e.what() == std::string_view("at: cannot access element after vector::size()")); + } + } + + SECTION("Relational Operators") { + vector a = {1, 2, 3}; + vector b = {2, 4, 5}; + + REQUIRE_FALSE(a == b); + REQUIRE(a != b); + REQUIRE(a < b); + REQUIRE(a <= b); + REQUIRE_FALSE(a > b); + REQUIRE_FALSE(a >= b); + } + + SECTION("From raw vector") { + auto a = to_vector({1, 2, 3}); + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() > 3); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 2, 3})); + + auto b = to_vector({1, 2, 3}); + REQUIRE(b.size() == 3); + REQUIRE(b.max_size() > 5); + REQUIRE(b.capacity() == 5); + REQUIRE_FALSE(b.empty()); + REQUIRE(equal_il(b, {1, 2, 3})); + + int cr[] = {1, 2, 3}; + auto c = to_vector(cr); + REQUIRE(c.size() == 3); + REQUIRE(c.max_size() > 3); + REQUIRE(c.is_inline()); + REQUIRE(c.capacity() == small::default_inline_storage_v); + REQUIRE(c.capacity() == 5); + REQUIRE_FALSE(c.empty()); + REQUIRE(equal_il(b, {1, 2, 3})); + } +} + +TEST_CASE("POD Max size vector") { + using namespace small; + + auto equal_il = [](const auto &sm_array, std::initializer_list il) -> bool { + return std::equal(sm_array.begin(), sm_array.end(), il.begin(), il.end()); + }; + + auto full = [](const auto &sm_array) -> bool { + return sm_array.is_inline() && sm_array.size() == sm_array.capacity(); + }; + + SECTION("Constructor") { + SECTION("Asserts") { + REQUIRE(std::is_copy_constructible_v>); + REQUIRE(std::is_copy_assignable_v>); + REQUIRE(std::is_move_constructible_v>); + REQUIRE(std::is_move_assignable_v>); + + REQUIRE(std::is_copy_constructible_v, 5>>); + REQUIRE(std::is_copy_assignable_v, 5>>); + REQUIRE(std::is_move_constructible_v, 5>>); + REQUIRE(std::is_move_assignable_v, 5>>); + } + + SECTION("Default") { + max_size_vector a; + REQUIRE(a.empty()); + REQUIRE(equal_il(a, {})); + } + + SECTION("With size") { + max_size_vector b(3); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 3); + } + + SECTION("From value") { + max_size_vector c(3, 1); + REQUIRE(c.size() == 3); + REQUIRE_FALSE(c.empty()); + REQUIRE(equal_il(c, {1, 1, 1})); + } + + SECTION("From Iterators") { + std::vector dv = {6, 5, 4}; + max_size_vector d(dv.begin(), dv.end()); + REQUIRE(d.size() == 3); + REQUIRE_FALSE(d.empty()); + REQUIRE(equal_il(d, {6, 5, 4})); + } + + SECTION("From initializer list") { + max_size_vector e = {1, 2}; + REQUIRE(e.size() == 2); + REQUIRE_FALSE(e.empty()); + REQUIRE(equal_il(e, {1, 2})); + } + } + + SECTION("Assign") { + SECTION("From initializer list") { + max_size_vector a; + REQUIRE(a.empty()); + a = {6, 5, 4}; + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {6, 5, 4})); + } + + SECTION("From another small array") { + max_size_vector a; + REQUIRE(a.empty()); + a = {6, 5, 4}; + + max_size_vector b; + REQUIRE(b.empty()); + b = a; + REQUIRE(b.size() == 3); + REQUIRE_FALSE(b.empty()); + REQUIRE(a == b); + } + + SECTION("From iterators") { + max_size_vector a; + REQUIRE(a.empty()); + std::vector v = {6, 5, 4}; + a.assign(v.begin(), v.end()); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {6, 5, 4})); + } + + SECTION("From size and value") { + max_size_vector a; + REQUIRE(a.empty()); + a.assign(3, 1); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {1, 1, 1})); + } + + SECTION("From initializer list") { + max_size_vector a; + REQUIRE(a.empty()); + a.assign({6, 5, 4}); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {6, 5, 4})); + } + + SECTION("Fill") { + max_size_vector a(3, 1); + REQUIRE_FALSE(a.empty()); + a.fill(2); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {2, 2, 2})); + } + + SECTION("Swap") { + max_size_vector a(4, 1); + max_size_vector b(3, 2); + + std::initializer_list ar = {1, 1, 1, 1}; + std::initializer_list br = {2, 2, 2}; + + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 4); + REQUIRE(equal_il(a, ar)); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 3); + REQUIRE(equal_il(b, br)); + + a.swap(b); + + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 3); + REQUIRE(equal_il(a, br)); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 4); + REQUIRE(equal_il(b, ar)); + + std::swap(a, b); + + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 4); + REQUIRE(equal_il(a, ar)); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 3); + REQUIRE(equal_il(b, br)); + } + } + + SECTION("Iterators") { + max_size_vector a = {1, 2, 3}; + + REQUIRE(a.begin() == a.data()); + REQUIRE(a.end() == a.data() + a.size()); + REQUIRE_FALSE(a.end() == a.data() + a.capacity()); + REQUIRE(*a.begin() == 1); + REQUIRE(*std::prev(a.end()) == 3); + + REQUIRE(a.cbegin() == a.data()); + REQUIRE(a.cend() == a.data() + a.size()); + REQUIRE_FALSE(a.cend() == a.data() + a.capacity()); + REQUIRE(*a.cbegin() == 1); + REQUIRE(*std::prev(a.cend()) == 3); + + REQUIRE(*a.rbegin() == 3); + REQUIRE(*std::prev(a.rend()) == 1); + + REQUIRE(*a.crbegin() == 3); + REQUIRE(*std::prev(a.crend()) == 1); + } + + SECTION("Capacity") { + max_size_vector a = {1, 2, 3}; + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(full(a)); + } + + SECTION("Element access") { + max_size_vector a = {1, 2, 3}; + REQUIRE(a[0] == 1); + REQUIRE(a[1] == 2); + REQUIRE(a[2] == 3); + REQUIRE(a.at(0) == 1); + REQUIRE(a.at(1) == 2); + REQUIRE(a.at(2) == 3); + REQUIRE_THROWS(a.at(3) == 4); + REQUIRE_THROWS(a.at(4) == 5); + REQUIRE(a.front() == 1); + REQUIRE(a.back() == 3); + REQUIRE(*a.data() == 1); + REQUIRE(*(a.data() + 1) == 2); + REQUIRE(*(a.data() + 2) == 3); + REQUIRE(*(a.data() + a.size() - 1) == 3); + REQUIRE(*(a.data() + a.size() - 2) == 2); + REQUIRE(*(a.data() + a.size() - 3) == 1); + } + + SECTION("Modifiers") { + max_size_vector a = {1, 2, 3}; + a.push_back(4); + REQUIRE(a.back() == 4); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE_FALSE(full(a)); + REQUIRE(equal_il(a, {1, 2, 3, 4})); + + // NOLINTNEXTLINE(performance-move-const-arg) + a.push_back(std::move(5)); + REQUIRE(a.back() == 5); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(full(a)); + REQUIRE(equal_il(a, {1, 2, 3, 4, 5})); + + a.pop_back(); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE_FALSE(full(a)); + REQUIRE(equal_il(a, {1, 2, 3, 4})); + + a.emplace_back(5); + REQUIRE(a.back() == 5); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(full(a)); + REQUIRE(equal_il(a, {1, 2, 3, 4, 5})); + + a.pop_back(); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE_FALSE(full(a)); + REQUIRE(equal_il(a, {1, 2, 3, 4})); + + auto it = a.emplace(a.begin() + 2, 10); + REQUIRE(it == a.begin() + 2); + REQUIRE(a.back() == 4); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(full(a)); + REQUIRE(equal_il(a, {1, 2, 10, 3, 4})); + + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE_FALSE(full(a)); + REQUIRE(equal_il(a, {1, 2, 10})); + + it = a.insert(a.begin() + 1, 20); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE_FALSE(full(a)); + REQUIRE(equal_il(a, {1, 20, 2, 10})); + + // NOLINTNEXTLINE(performance-move-const-arg) + it = a.insert(a.begin() + 2, std::move(30)); + REQUIRE(it == a.begin() + 2); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(full(a)); + REQUIRE(equal_il(a, {1, 20, 30, 2, 10})); + + a.pop_back(); + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE_FALSE(full(a)); + REQUIRE(equal_il(a, {1, 20})); + + it = a.insert(a.begin() + 1, 2, 10); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE_FALSE(full(a)); + REQUIRE(equal_il(a, {1, 10, 10, 20})); + + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE_FALSE(full(a)); + REQUIRE(equal_il(a, {1, 10})); + + std::initializer_list src = {2, 4, 8}; + it = a.insert(a.begin() + 1, src.begin(), src.end()); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(full(a)); + REQUIRE(equal_il(a, {1, 2, 4, 8, 10})); + + a.pop_back(); + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE_FALSE(full(a)); + REQUIRE(equal_il(a, {1, 2})); + + it = a.insert(a.begin() + 1, {2, 4, 8}); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(full(a)); + REQUIRE(equal_il(a, {1, 2, 4, 8, 2})); + + it = a.erase(a.begin() + 1); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE_FALSE(full(a)); + REQUIRE(equal_il(a, {1, 4, 8, 2})); + + it = a.erase(a.begin() + 1, a.begin() + 3); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE_FALSE(full(a)); + REQUIRE(equal_il(a, {1, 2})); + + a.clear(); + // NOLINTNEXTLINE(readability-container-size-empty) + REQUIRE(a.size() == 0); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE(a.empty()); + REQUIRE_FALSE(full(a)); + REQUIRE(equal_il(a, {})); + + a.resize(2); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE_FALSE(full(a)); + + a.resize(4, 5); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() == 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE_FALSE(full(a)); + REQUIRE(a[2] == 5); + REQUIRE(a[3] == 5); + } + + SECTION("Element access errors") { + max_size_vector a = {1, 2, 3}; + try { + a.at(4); + } catch (std::exception &e) { + REQUIRE(e.what() == std::string_view("at: cannot access element after vector::size()")); + } + } + + SECTION("Relational Operators") { + max_size_vector a = {1, 2, 3}; + max_size_vector b = {2, 4, 5}; + + REQUIRE_FALSE(a == b); + REQUIRE(a != b); + REQUIRE(a < b); + REQUIRE(a <= b); + REQUIRE_FALSE(a > b); + REQUIRE_FALSE(a >= b); + } +} \ No newline at end of file diff --git a/tests/unit_tests/ptr_wrapper.cpp b/tests/unit_tests/ptr_wrapper.cpp new file mode 100644 index 0000000..e88c13c --- /dev/null +++ b/tests/unit_tests/ptr_wrapper.cpp @@ -0,0 +1,84 @@ +#ifndef SMALL_BUILD_TESTS_WITH_PCH +// C++ +#include +#include +#include +#include +#include +#include + +// External +#include + +// Small +#include +#endif + +TEST_CASE("Pointer wrapper") { + using namespace small; + + SECTION("Constructor") { + SECTION("Empty") { [[maybe_unused]] pointer_wrapper p; } + + SECTION("From pointer") { + int a = 2; + pointer_wrapper p(&a); + REQUIRE(p.base() == &a); + } + + SECTION("From another pointer wrapper") { + int a = 2; + pointer_wrapper p1(&a); + REQUIRE(p1.base() == &a); + + pointer_wrapper p2(p1); + REQUIRE(p2.base() == &a); + } + } + + int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + pointer_wrapper begin(&a[0]); + pointer_wrapper end(&a[0] + 9); + + SECTION("Element access") { + REQUIRE(begin != end); + REQUIRE(*begin == 1); + REQUIRE(*std::prev(end) == 9); + REQUIRE(begin.base() == &a[0]); + REQUIRE(begin[0] == 1); + REQUIRE(begin[1] == 2); + REQUIRE(begin[2] == 3); + } + + SECTION("Modifiers") { + ++begin; + REQUIRE(*begin == 2); + begin++; + REQUIRE(*begin == 3); + --begin; + REQUIRE(*begin == 2); + begin--; + REQUIRE(*begin == 1); + auto it = begin + 1; + REQUIRE(*it == 2); + it = begin + 2; + REQUIRE(*it == 3); + begin += 2; + REQUIRE(*begin == 3); + it = begin - 1; + REQUIRE(*it == 2); + it = begin - 2; + REQUIRE(*it == 1); + begin -= 2; + REQUIRE(*begin == 1); + } + + SECTION("Algorithms") { + int b[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; + pointer_wrapper b_begin(&b[0]); + pointer_wrapper b_end(&b[0] + 9); + + std::copy(begin, end, b_begin); + REQUIRE(std::equal(begin, end, b_begin, b_end)); + } +} \ No newline at end of file diff --git a/tests/unit_tests/small_map.cpp b/tests/unit_tests/small_map.cpp index 977c61b..a4d6170 100644 --- a/tests/unit_tests/small_map.cpp +++ b/tests/unit_tests/small_map.cpp @@ -1,3 +1,4 @@ +#ifndef SMALL_BUILD_TESTS_WITH_PCH #include #include #include @@ -7,8 +8,7 @@ #include #include -#include -#include +#endif TEST_CASE("Small Map") { using namespace small; diff --git a/tests/unit_tests/small_set.cpp b/tests/unit_tests/small_set.cpp index ee65746..ecb61b8 100644 --- a/tests/unit_tests/small_set.cpp +++ b/tests/unit_tests/small_set.cpp @@ -1,3 +1,4 @@ +#ifndef SMALL_BUILD_TESTS_WITH_PCH #include #include #include @@ -7,6 +8,7 @@ #include #include +#endif TEST_CASE("Small Set") { using namespace small; diff --git a/tests/unit_tests/small_string.cpp b/tests/unit_tests/small_string.cpp deleted file mode 100644 index b8fbc3b..0000000 --- a/tests/unit_tests/small_string.cpp +++ /dev/null @@ -1,4308 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -// UTF8 string literals are really not safe in MSVC. -// u8"" doesn't work properly even with escape sequences. -// More recent versions might improve on that a little, but we will still -// need a more robust solution to support older versions in any case. -// Until then, it seems like the most robust solution is to initialize -// small::strings with U"...", even if that requires converting the -// codepoints. -constexpr bool is_windows() { -#if defined(_WIN32) - return true; -#else - return false; -#endif -} - - -TEST_CASE("String") { - using namespace small; - - auto equal_il = [](const auto &sm_string, std::initializer_list il) -> bool { - return std::equal(sm_string.begin(), sm_string.end(), il.begin(), il.end()); - }; - - SECTION("Asserts") { - STATIC_REQUIRE(std::is_copy_constructible_v); - STATIC_REQUIRE(std::is_copy_assignable_v); - STATIC_REQUIRE(std::is_move_constructible_v); - STATIC_REQUIRE(std::is_move_assignable_v); - STATIC_REQUIRE(is_utf8_v); - STATIC_REQUIRE(is_utf16_v); - STATIC_REQUIRE(is_utf32_v); - } - - SECTION("Unicode") { - SECTION("UTF8") { - utf8_char_type a = 'g'; - // utf8_char_type b = 'รก'; // <- can't fit in 8 bits - // utf8_char_type c = '๐Ÿ˜€'; - std::basic_string d = "g"; - std::basic_string e = "รก"; - std::basic_string f = "๐Ÿ˜€"; - SECTION("Check") { - // Check container sizes - REQUIRE(d.size() == 1); - REQUIRE(e.size() == 2); - REQUIRE(f.size() == 4); - - // Identify continuation bytes - REQUIRE_FALSE(is_utf8_continuation(d[0])); - REQUIRE_FALSE(is_utf8_continuation(e[0])); - REQUIRE(is_utf8_continuation(e[1])); - REQUIRE_FALSE(is_utf8_continuation(f[0])); - REQUIRE(is_utf8_continuation(f[1])); - REQUIRE(is_utf8_continuation(f[2])); - REQUIRE(is_utf8_continuation(f[3])); - - // Identify utf size from first char - REQUIRE(utf8_size(a) == 1); - REQUIRE(utf8_size(d[0]) == 1); - REQUIRE(utf8_size(e[0]) == 2); - REQUIRE(utf8_size(e[1]) == 1); - REQUIRE(utf8_size(f[0]) == 4); - REQUIRE(utf8_size(f[1]) == 1); - REQUIRE(utf8_size(f[2]) == 1); - REQUIRE(utf8_size(f[3]) == 1); - - // Identify continuation bytes (inferring input type) - REQUIRE_FALSE(is_utf_continuation(d[0])); - REQUIRE_FALSE(is_utf_continuation(e[0])); - REQUIRE(is_utf_continuation(e[1])); - REQUIRE_FALSE(is_utf_continuation(f[0])); - REQUIRE(is_utf_continuation(f[1])); - REQUIRE(is_utf_continuation(f[2])); - REQUIRE(is_utf_continuation(f[3])); - - // Identify utf size from first char (inferring input type) - REQUIRE(utf_size(a, 1) == 1); - REQUIRE(utf_size(d[0], 1) == 1); - REQUIRE(utf_size(e[0], 2) == 2); - REQUIRE(utf_size(e[1], 1) == 1); - REQUIRE(utf_size(f[0], 4) == 4); - REQUIRE(utf_size(f[1], 4) == 1); - REQUIRE(utf_size(f[2], 4) == 1); - REQUIRE(utf_size(f[3], 4) == 1); - } - SECTION("To UTF16") { - utf16_char_type buf[2]; - - REQUIRE(from_utf8_to_utf16(&a, 1, buf, 2) == 1); - utf32_char_type r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(from_utf8_to_utf16(d.begin(), d.size(), buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(from_utf8_to_utf16(e.begin(), e.size(), buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(from_utf8_to_utf16(f.begin(), f.size(), buf, 2) == 2); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - - // Inferring type from input - REQUIRE(to_utf16(&a, 1, buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf16(d.begin(), d.size(), buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf16(e.begin(), e.size(), buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf16(f.begin(), f.size(), buf, 2) == 2); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - - // Inferring type from input and output - REQUIRE(to_utf(&a, 1, buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf(d.begin(), d.size(), buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf(e.begin(), e.size(), buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf(f.begin(), f.size(), buf, 2) == 2); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - } - - SECTION("To UTF32") { - utf32_char_type r; - - r = from_utf8_to_utf32(&a, 1); - REQUIRE(r == U'g'); - - r = from_utf8_to_utf32(d.begin(), d.size()); - REQUIRE(r == U'g'); - - r = from_utf8_to_utf32(e.begin(), e.size()); - REQUIRE(r == U'รก'); - - r = from_utf8_to_utf32(f.begin(), f.size()); - REQUIRE(r == U'๐Ÿ˜€'); - - // Inferring type from input - REQUIRE(to_utf32(&a, 1, &r, 1) == 1); - REQUIRE(r == U'g'); - - REQUIRE(to_utf32(d.begin(), d.size(), &r, 1) == 1); - REQUIRE(r == U'g'); - - REQUIRE(to_utf32(e.begin(), e.size(), &r, 1) == 1); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf32(f.begin(), f.size(), &r, 1) == 1); - REQUIRE(r == U'๐Ÿ˜€'); - - // Inferring type from input and output - REQUIRE(to_utf(&a, 1, &r, 1) == 1); - REQUIRE(r == U'g'); - - REQUIRE(to_utf(d.begin(), d.size(), &r, 1) == 1); - REQUIRE(r == U'g'); - - REQUIRE(to_utf(e.begin(), e.size(), &r, 1) == 1); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf(f.begin(), f.size(), &r, 1) == 1); - REQUIRE(r == U'๐Ÿ˜€'); - } - } - SECTION("UTF16") { - utf16_char_type a = u'g'; - utf16_char_type b = u'รก'; - // utf16_char_type c = u'๐Ÿ˜€'; // <- can't fit in a char - std::basic_string d = u"g"; - std::basic_string e = u"รก"; - std::basic_string f = u"๐Ÿ˜€"; - - SECTION("Check") { - // Check container sizes - REQUIRE(d.size() == 1); - REQUIRE(e.size() == 1); - REQUIRE(f.size() == 2); - - // Identify surrogate code units - REQUIRE_FALSE(is_utf16_surrogate(a)); - REQUIRE_FALSE(is_utf16_surrogate(b)); - REQUIRE_FALSE(is_utf16_surrogate(d[0])); - REQUIRE_FALSE(is_utf16_surrogate(e[0])); - REQUIRE(is_utf16_surrogate(f[0])); - REQUIRE(is_utf16_surrogate(f[1])); - - // Identify high and low surrogate code units - REQUIRE_FALSE(is_utf16_high_surrogate(a)); - REQUIRE_FALSE(is_utf16_low_surrogate(a)); - REQUIRE_FALSE(is_utf16_high_surrogate(b)); - REQUIRE_FALSE(is_utf16_low_surrogate(b)); - REQUIRE_FALSE(is_utf16_high_surrogate(d[0])); - REQUIRE_FALSE(is_utf16_low_surrogate(d[0])); - REQUIRE_FALSE(is_utf16_high_surrogate(e[0])); - REQUIRE_FALSE(is_utf16_low_surrogate(e[0])); - REQUIRE(is_utf16_high_surrogate(f[0])); - REQUIRE_FALSE(is_utf16_low_surrogate(f[0])); - REQUIRE_FALSE(is_utf16_high_surrogate(f[1])); - REQUIRE(is_utf16_low_surrogate(f[1])); - - // Identify continuation code units (alias for low surrogates) - REQUIRE_FALSE(is_utf16_continuation(a)); - REQUIRE_FALSE(is_utf16_continuation(b)); - REQUIRE_FALSE(is_utf16_continuation(d[0])); - REQUIRE_FALSE(is_utf16_continuation(e[0])); - REQUIRE_FALSE(is_utf16_continuation(f[0])); - REQUIRE(is_utf16_continuation(f[1])); - - // Identify utf size from first char - REQUIRE(utf16_size(a) == 1); - REQUIRE(utf16_size(b) == 1); - REQUIRE(utf16_size(d[0]) == 1); - REQUIRE(utf16_size(e[0]) == 1); - REQUIRE(utf16_size(f[0]) == 2); - REQUIRE(utf16_size(f[1]) == 1); - - // Identify continuation code units identifying input type - REQUIRE_FALSE(is_utf_continuation(a)); - REQUIRE_FALSE(is_utf_continuation(b)); - REQUIRE_FALSE(is_utf_continuation(d[0])); - REQUIRE_FALSE(is_utf_continuation(e[0])); - REQUIRE_FALSE(is_utf_continuation(f[0])); - REQUIRE(is_utf_continuation(f[1])); - - // Identify utf size from first char identifying input type - REQUIRE(utf_size(a, 1) == 1); - REQUIRE(utf_size(b, 1) == 1); - REQUIRE(utf_size(d[0], 1) == 1); - REQUIRE(utf_size(e[0], 1) == 1); - REQUIRE(utf_size(f[0], 2) == 2); - REQUIRE(utf_size(f[1], 2) == 1); - } - SECTION("To UTF8") { - utf8_char_type buf[8]; - - REQUIRE(from_utf16_to_utf8(&a, 1, buf, 8) == 1); - utf32_char_type r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(from_utf16_to_utf8(&b, 1, buf, 8) == 2); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(from_utf16_to_utf8(d.begin(), d.size(), buf, 8) == 1); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(from_utf16_to_utf8(e.begin(), e.size(), buf, 8) == 2); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(from_utf16_to_utf8(f.begin(), f.size(), buf, 8) == 4); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - - // Inferring type from input - REQUIRE(to_utf8(&a, 1, buf, 8) == 1); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf8(&b, 1, buf, 8) == 2); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf8(d.begin(), d.size(), buf, 8) == 1); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf8(e.begin(), e.size(), buf, 8) == 2); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf8(f.begin(), f.size(), buf, 8) == 4); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - - // Inferring type from input and output - REQUIRE(to_utf(&a, 1, buf, 8) == 1); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf(d.begin(), d.size(), buf, 8) == 1); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf(e.begin(), e.size(), buf, 8) == 2); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf(f.begin(), f.size(), buf, 8) == 4); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - } - SECTION("To UTF32") { - REQUIRE(utf16_surrogates_to_utf32(f[0], f[1]) == U'๐Ÿ˜€'); - - utf32_char_type r; - - r = from_utf16_to_utf32(&a, 1); - REQUIRE(r == U'g'); - - r = from_utf16_to_utf32(&b, 1); - REQUIRE(r == U'รก'); - - r = from_utf16_to_utf32(d.begin(), d.size()); - REQUIRE(r == U'g'); - - r = from_utf16_to_utf32(e.begin(), e.size()); - REQUIRE(r == U'รก'); - - r = from_utf16_to_utf32(f.begin(), f.size()); - REQUIRE(r == U'๐Ÿ˜€'); - - // Inferring type from input - REQUIRE(to_utf32(&a, 1, &r, 1) == 1); - REQUIRE(r == U'g'); - - REQUIRE(to_utf32(&b, 1, &r, 1) == 1); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf32(d.begin(), d.size(), &r, 1) == 1); - REQUIRE(r == U'g'); - - REQUIRE(to_utf32(e.begin(), e.size(), &r, 1) == 1); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf32(f.begin(), f.size(), &r, 1) == 1); - REQUIRE(r == U'๐Ÿ˜€'); - - // Inferring type from input and output - REQUIRE(to_utf(&a, 1, &r, 1) == 1); - REQUIRE(r == U'g'); - - REQUIRE(to_utf(d.begin(), d.size(), &r, 1) == 1); - REQUIRE(r == U'g'); - - REQUIRE(to_utf(e.begin(), e.size(), &r, 1) == 1); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf(f.begin(), f.size(), &r, 1) == 1); - REQUIRE(r == U'๐Ÿ˜€'); - } - } - SECTION("UTF32") { - utf32_char_type a = U'g'; - utf32_char_type b = U'รก'; - utf32_char_type c = U'๐Ÿ˜€'; - std::basic_string d = U"g"; - std::basic_string e = U"รก"; - std::basic_string f = U"๐Ÿ˜€"; - SECTION("Check") { - // Check container sizes - REQUIRE(d.size() == 1); - REQUIRE(e.size() == 1); - REQUIRE(f.size() == 1); - - // Identify continuation code units (always false for utf32) - REQUIRE_FALSE(is_utf32_continuation(a)); - REQUIRE_FALSE(is_utf32_continuation(b)); - REQUIRE_FALSE(is_utf32_continuation(d[0])); - REQUIRE_FALSE(is_utf32_continuation(e[0])); - REQUIRE_FALSE(is_utf32_continuation(f[0])); - - // Identify utf size from first char (always 1 for utf32) - REQUIRE(utf32_size(a) == 1); - REQUIRE(utf32_size(b) == 1); - REQUIRE(utf32_size(c) == 1); - REQUIRE(utf32_size(d[0]) == 1); - REQUIRE(utf32_size(e[0]) == 1); - REQUIRE(utf32_size(f[0]) == 1); - - // Identify continuation code units identifying input type - REQUIRE_FALSE(is_utf_continuation(a)); - REQUIRE_FALSE(is_utf_continuation(b)); - REQUIRE_FALSE(is_utf_continuation(d[0])); - REQUIRE_FALSE(is_utf_continuation(e[0])); - REQUIRE_FALSE(is_utf_continuation(f[0])); - - // Identify utf size from first char identifying input type - REQUIRE(utf_size(a, 1) == 1); - REQUIRE(utf_size(b, 1) == 1); - REQUIRE(utf_size(c, 1) == 1); - REQUIRE(utf_size(d[0], 1) == 1); - REQUIRE(utf_size(e[0], 1) == 1); - REQUIRE(utf_size(f[0], 1) == 1); - } - SECTION("To UTF8") { - utf8_char_type buf[8]; - - REQUIRE(from_utf32_to_utf8(a, buf, 8) == 1); - utf32_char_type r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(from_utf32_to_utf8(b, buf, 8) == 2); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(from_utf32_to_utf8(c, buf, 8) == 4); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - - REQUIRE(from_utf32_to_utf8(d.front(), buf, 8) == 1); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(from_utf32_to_utf8(e.front(), buf, 8) == 2); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(from_utf32_to_utf8(f.front(), buf, 8) == 4); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - - // Inferring type from input - REQUIRE(to_utf8(&a, 1, buf, 8) == 1); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf8(&b, 1, buf, 8) == 2); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf8(&c, 1, buf, 8) == 4); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - - REQUIRE(to_utf8(d.begin(), d.size(), buf, 8) == 1); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf8(e.begin(), e.size(), buf, 8) == 2); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf8(f.begin(), f.size(), buf, 8) == 4); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - - // Inferring type from input and output - REQUIRE(to_utf(&a, 1, buf, 8) == 1); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf(&b, 1, buf, 8) == 2); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf(&c, 1, buf, 8) == 4); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - - REQUIRE(to_utf(d.begin(), d.size(), buf, 8) == 1); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf(e.begin(), e.size(), buf, 8) == 2); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf(f.begin(), f.size(), buf, 8) == 4); - r = from_utf8_to_utf32(buf, utf8_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - } - - SECTION("To UTF16") { - utf16_char_type buf[2]; - - REQUIRE(from_utf32_to_utf16(a, buf, 2) == 1); - utf32_char_type r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(from_utf32_to_utf16(b, buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(from_utf32_to_utf16(c, buf, 2) == 2); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - - REQUIRE(from_utf32_to_utf16(d.front(), buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(from_utf32_to_utf16(e.front(), buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(from_utf32_to_utf16(f.front(), buf, 2) == 2); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - - // Inferring type from input - REQUIRE(to_utf16(&a, 1, buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf16(&b, 1, buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf16(&c, 1, buf, 2) == 2); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - - REQUIRE(to_utf16(d.begin(), d.size(), buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf16(e.begin(), e.size(), buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf16(f.begin(), f.size(), buf, 2) == 2); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - - // Inferring type from input and output - REQUIRE(to_utf(&a, 1, buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf(&b, 1, buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf(&c, 1, buf, 2) == 2); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - - REQUIRE(to_utf(d.begin(), d.size(), buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'g'); - - REQUIRE(to_utf(e.begin(), e.size(), buf, 2) == 1); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'รก'); - - REQUIRE(to_utf(f.begin(), f.size(), buf, 2) == 2); - r = from_utf16_to_utf32(buf, utf16_size(buf[0])); - REQUIRE(r == U'๐Ÿ˜€'); - } - } - } - - SECTION("Constructor") { - SECTION("Default") { - string a; - REQUIRE(a.empty()); - REQUIRE(a.size() == 0); // NOLINT(readability-container-size-empty) - REQUIRE(a.size_codepoints() == 0); - REQUIRE(equal_il(a, {})); - } - - SECTION("Allocator") { - std::allocator alloc; - string a(alloc); - REQUIRE(a.empty()); - REQUIRE(equal_il(a, {})); - REQUIRE(a.get_allocator() == alloc); - } - - SECTION("From char value") { - SECTION("Zero values") { - std::allocator alloc; - string c(0, 'x', alloc); // NOLINT(bugprone-string-constructor) - REQUIRE(c.empty()); - REQUIRE(c.size() == 0); // NOLINT(readability-container-size-empty) - REQUIRE(c.size_codepoints() == 0); - REQUIRE(c == ""); // NOLINT(readability-container-size-empty) - REQUIRE(c == U""); // NOLINT(readability-container-size-empty) - REQUIRE(c.get_allocator() == alloc); - } - - SECTION("Constant values") { - std::allocator alloc; - string c(3, 'x', alloc); - REQUIRE_FALSE(c.empty()); - REQUIRE(c.size() == 3); - REQUIRE(c.size_codepoints() == 3); - REQUIRE(c == "xxx"); - REQUIRE(c == U"xxx"); - REQUIRE(c.get_allocator() == alloc); - } - - SECTION("From UTF16 value") { - std::allocator alloc; - string c(3, u'x', alloc); - REQUIRE_FALSE(c.empty()); - REQUIRE(c.size() == 3); - REQUIRE(c.size_codepoints() == 3); - REQUIRE(c == "xxx"); - REQUIRE(c == u"xxx"); - REQUIRE(c.get_allocator() == alloc); - } - - SECTION("From multibyte UTF16 value") { - // We don't provide full support/conversions for multi-code-unit UTF16 for now, - // but other uni-code-unit UTF16 strings should be fine. - // In any case, UTF8 and UTF32 should be able to represent anything. - // You can use UTF32 as an intermediary if you need a case that is not supported. - std::allocator alloc; - string c(3, u'รก', alloc); - REQUIRE_FALSE(c.empty()); - REQUIRE(c.size_codepoints() == 3); - REQUIRE(c.size() == 6); - REQUIRE(c == "รกรกรก"); - REQUIRE(c == u"รกรกรก"); - REQUIRE(c.get_allocator() == alloc); - } - - SECTION("From utf32 value") { - std::allocator alloc; - string c(3, U'x', alloc); - REQUIRE_FALSE(c.empty()); - REQUIRE(c.size() == 3); - REQUIRE(c.size_codepoints() == 3); - REQUIRE(c == "xxx"); - REQUIRE(c == U"xxx"); - REQUIRE(c.get_allocator() == alloc); - } - - SECTION("From multibyte utf32 value") { - std::allocator alloc; - string c(3, U'๐Ÿ˜€', alloc); - REQUIRE_FALSE(c.empty()); - REQUIRE(c.size_codepoints() == 3); - REQUIRE(c.size() == 12); - REQUIRE(c == "๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); - REQUIRE(c == U"๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); - REQUIRE(c.get_allocator() == alloc); - } - } - - SECTION("From char iterators") { - SECTION("Empty range") { - std::allocator alloc; - std::string dv; - string d(dv.begin(), dv.end(), alloc); - REQUIRE(d.empty()); - REQUIRE(d.size_codepoints() == 0); - REQUIRE(d.size() == 0); // NOLINT(readability-container-size-empty) - REQUIRE(d == ""); // NOLINT(readability-container-size-empty) - REQUIRE(d == U""); // NOLINT(readability-container-size-empty) - REQUIRE(d.get_allocator() == alloc); - } - SECTION("No unicode") { - std::allocator alloc; - std::string dv = "654"; - string d(dv.begin(), dv.end(), alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 3); - REQUIRE(d.size() == 3); - REQUIRE(d == "654"); - REQUIRE(d == U"654"); - REQUIRE(d.get_allocator() == alloc); - } - SECTION("Half unicode") { - std::allocator alloc; - std::string dv = "๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"; - REQUIRE(dv.size() == 15); - string d(dv.begin(), dv.end(), alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 15); - REQUIRE(d == "๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"); - REQUIRE(d == U"๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"); - REQUIRE(d.get_allocator() == alloc); - } - SECTION("Full unicode") { - std::allocator alloc; - std::string dv = "๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"; - string d(dv.begin(), dv.end(), alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 24); - REQUIRE(d == "๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); - REQUIRE(d == U"๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); - REQUIRE(d.get_allocator() == alloc); - } - } - - SECTION("From wide char iterators") { - SECTION("No unicode") { - std::allocator alloc; - std::u32string dv = U"654"; - string d(dv.begin(), dv.end(), alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 3); - REQUIRE(d.size() == 3); - REQUIRE(d == "654"); - REQUIRE(d == U"654"); - REQUIRE(d.get_allocator() == alloc); - } - SECTION("Half unicode") { - std::allocator alloc; - std::u32string dv = U"๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"; - string d(dv.begin(), dv.end(), alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 15); - REQUIRE(d == "๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"); - REQUIRE(d == U"๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"); - REQUIRE(d.get_allocator() == alloc); - } - SECTION("Full unicode") { - std::allocator alloc; - std::u32string dv = U"๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"; - string d(dv.begin(), dv.end(), alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 24); - REQUIRE(d == "๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); - REQUIRE(d == U"๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); - REQUIRE(d.get_allocator() == alloc); - } - } - - SECTION("From codepoint iterators") { - SECTION("No unicode") { - std::allocator alloc; - string dv = U"654"; - string d(dv.begin_codepoint(), dv.end_codepoint(), alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 3); - REQUIRE(d.size() == 3); - REQUIRE(d == "654"); - REQUIRE(d == U"654"); - REQUIRE(d.get_allocator() == alloc); - } - SECTION("Half unicode") { - std::allocator alloc; - string dv = U"๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"; - string d(dv.begin_codepoint(), dv.end_codepoint(), alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 15); - REQUIRE(d == "๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"); - REQUIRE(d == U"๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"); - REQUIRE(d.get_allocator() == alloc); - } - SECTION("Full unicode") { - std::allocator alloc; - string dv = U"๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"; - string d(dv.begin_codepoint(), dv.end_codepoint(), alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 24); - REQUIRE(d == "๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); - REQUIRE(d == U"๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); - REQUIRE(d.get_allocator() == alloc); - } - } - - SECTION("From substring") { - SECTION("From begin") { - std::allocator alloc; - string dv = "123456"; - string d(dv, 3, alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 3); - REQUIRE(d.size() == 3); - REQUIRE(d == "456"); - REQUIRE(d == U"456"); - REQUIRE(d.get_allocator() == alloc); - } - - SECTION("From range") { - std::allocator alloc; - string dv = "123456"; - string d(dv, 2, 2, alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 2); - REQUIRE(d.size() == 2); - REQUIRE(d == "34"); - REQUIRE(d == U"34"); - REQUIRE(d.get_allocator() == alloc); - } - - SECTION("From npos range") { - std::allocator alloc; - string dv = "123456"; - string d(dv, 2, string::npos, alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 4); - REQUIRE(d.size() == 4); - REQUIRE(d == "3456"); - REQUIRE(d == U"3456"); - REQUIRE(d.get_allocator() == alloc); - } - - SECTION("Literal string count") { - SECTION("Char") { - std::allocator alloc; - string d("123456", 2, alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 2); - REQUIRE(d.size() == 2); - REQUIRE(d == "12"); - REQUIRE(d == U"12"); - REQUIRE(d.get_allocator() == alloc); - } - - SECTION("Wide char") { - std::allocator alloc; - string d(U"123456", 2, alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 2); - REQUIRE(d.size() == 2); - REQUIRE(d == "12"); - REQUIRE(d == U"12"); - REQUIRE(d.get_allocator() == alloc); - } - } - } - - SECTION("From literal") { - SECTION("Char") { - std::allocator alloc; - string d("123456", alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 6); - REQUIRE(d == "123456"); - REQUIRE(d == U"123456"); - REQUIRE(d.get_allocator() == alloc); - } - SECTION("Wide char") { - std::allocator alloc; - string d(U"123456", alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 6); - REQUIRE(d == "123456"); - REQUIRE(d == U"123456"); - REQUIRE(d.get_allocator() == alloc); - } - } - - SECTION("From initializer list") { - SECTION("Char") { - std::allocator alloc; - string d({'1', '2', '3', '4', '5', '6'}, alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 6); - REQUIRE(d == "123456"); - REQUIRE(d == U"123456"); - REQUIRE(d.get_allocator() == alloc); - } - SECTION("Wide char") { - std::allocator alloc; - string d({U'1', U'2', U'3', U'4', U'5', U'6'}, alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 6); - REQUIRE(d == "123456"); - REQUIRE(d == U"123456"); - REQUIRE(d.get_allocator() == alloc); - } - } - - SECTION("From string view") { - SECTION("Char") { - std::allocator alloc; - string d(std::string_view("123456"), alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 6); - REQUIRE(d == "123456"); - REQUIRE(d == U"123456"); - REQUIRE(d.get_allocator() == alloc); - } - SECTION("Wide char") { - std::allocator alloc; - string d(std::u32string_view(U"123456"), alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 6); - REQUIRE(d == "123456"); - REQUIRE(d == U"123456"); - REQUIRE(d.get_allocator() == alloc); - } - } - - SECTION("From std string") { - SECTION("Char") { - std::allocator alloc; - string d(std::string("123456"), alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 6); - REQUIRE(d == "123456"); - REQUIRE(d == U"123456"); - REQUIRE(d.get_allocator() == alloc); - } - SECTION("Wide char") { - std::allocator alloc; - string d(std::u32string(U"123456"), alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 6); - REQUIRE(d == "123456"); - REQUIRE(d == U"123456"); - REQUIRE(d.get_allocator() == alloc); - } - } - - SECTION("Rule of five") { - SECTION("Copy") { - string dv = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; - string d(dv); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 15); - REQUIRE(d == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(dv.size_codepoints() == 6); - REQUIRE(dv.size() == 15); - REQUIRE(dv == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(dv == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(d == dv); - } - - SECTION("Copy and set alloc") { - std::allocator alloc; - string dv = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; - string d(dv, alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 15); - REQUIRE(d == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(dv.size_codepoints() == 6); - REQUIRE(dv.size() == 15); - REQUIRE(dv == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(dv == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(d == dv); - REQUIRE(d.get_allocator() == alloc); - } - - SECTION("Move") { - string dv = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; - string d(std::move(dv)); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 15); - REQUIRE(d == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(dv.size_codepoints() == 0); // NOLINT(readability-container-size-empty,bugprone-use-after-move) - REQUIRE(dv.size() == 0); // NOLINT(readability-container-size-empty,bugprone-use-after-move) - REQUIRE(dv == ""); // NOLINT(readability-container-size-empty,bugprone-use-after-move) - REQUIRE(dv == U""); // NOLINT(readability-container-size-empty,bugprone-use-after-move) - REQUIRE(dv.empty()); - // is null terminated - REQUIRE(dv[0] == '\0'); - } - - if constexpr (not is_windows()) { - SECTION("Move and set alloc") { - std::allocator alloc; - // There's no safe way to do that on MSVC :O - string dv = u8"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; - string d(std::move(dv), alloc); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 15); - REQUIRE(d == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(dv.size_codepoints() == 0); // NOLINT(bugprone-use-after-move) - REQUIRE(dv.size() == 0); // NOLINT(readability-container-size-empty) - REQUIRE(dv == ""); // NOLINT(readability-container-size-empty) - REQUIRE(dv == U""); // NOLINT(readability-container-size-empty) - REQUIRE(dv.empty()); - // is null terminated - REQUIRE(dv[0] == '\0'); - REQUIRE(d.get_allocator() == alloc); - } - } - } - } - - SECTION("Assignment Operator") { - if constexpr (not is_windows()) { - SECTION("String") { - string dv = u8"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; - string d; - d = dv; - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 15); - REQUIRE(d == u8"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(dv.size_codepoints() == 6); - REQUIRE(dv.size() == 15); - REQUIRE(dv == u8"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(dv == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(d == dv); - } - } - - SECTION("Move String") { - string dv = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; - string d; - d = std::move(dv); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 15); - REQUIRE(d == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(dv.size_codepoints() == 0); // NOLINT(bugprone-use-after-move) - REQUIRE(dv.size() == 0); // NOLINT(bugprone-use-after-move,readability-container-size-empty) - REQUIRE(dv == ""); // NOLINT(bugprone-use-after-move,readability-container-size-empty) - REQUIRE(dv == U""); // NOLINT(bugprone-use-after-move,readability-container-size-empty) - REQUIRE_FALSE(d == dv); - REQUIRE(dv.size() == 0); // NOLINT(bugprone-use-after-move,readability-container-size-empty) - REQUIRE(dv.front() == '\0'); - } - - SECTION("Literal") { - string d; - d = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 15); - REQUIRE(d == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - } - - SECTION("Wide Literal") { - string d; - d = U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 15); - REQUIRE(d == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); - } - - SECTION("Char") { - string d; - d = '1'; - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 1); - REQUIRE(d.size() == 1); - REQUIRE(d == "1"); - REQUIRE(d == U"1"); - } - - SECTION("Wide Char") { - string d; - d = U'1'; - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 1); - REQUIRE(d.size() == 1); - REQUIRE(d == "1"); - REQUIRE(d == U"1"); - } - - SECTION("Unicode Wide Char") { - string d; - d = U'๐Ÿ˜€'; - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 1); - REQUIRE(d.size() == 4); - REQUIRE(d == "๐Ÿ˜€"); - REQUIRE(d == U"๐Ÿ˜€"); - } - } - - SECTION("Assign") { - SECTION("Char") { - string d; - d.assign(3, '1'); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 3); - REQUIRE(d.size() == 3); - REQUIRE(d == "111"); - REQUIRE(d == U"111"); - } - - SECTION("Wide Char") { - string d; - d.assign(3, U'1'); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 3); - REQUIRE(d.size() == 3); - REQUIRE(d == "111"); - REQUIRE(d == U"111"); - } - - SECTION("Unicode Wide Char") { - string d; - d.assign(3, U'๐Ÿ˜€'); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 3); - REQUIRE(d.size() == 12); - REQUIRE(d == "๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); - REQUIRE(d == U"๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); - } - - SECTION("Substring") { - string dv = "123456"; - string d; - d.assign(dv, 2, 2); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 2); - REQUIRE(d.size() == 2); - REQUIRE(d == "34"); - REQUIRE(d == U"34"); - REQUIRE(dv.size_codepoints() == 6); - REQUIRE(dv.size() == 6); - REQUIRE(dv == "123456"); - REQUIRE(dv == U"123456"); - REQUIRE_FALSE(d == dv); - } - - SECTION("String") { - string dv = "123456"; - string d; - d.assign(dv); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 6); - REQUIRE(d == "123456"); - REQUIRE(d == U"123456"); - REQUIRE(dv.size_codepoints() == 6); - REQUIRE(dv.size() == 6); - REQUIRE(dv == "123456"); - REQUIRE(dv == U"123456"); - REQUIRE(d == dv); - } - - SECTION("String Move") { - string dv = "123456"; - string d; - d.assign(std::move(dv)); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 6); - REQUIRE(d == "123456"); - REQUIRE(d == U"123456"); - REQUIRE(dv.size_codepoints() == 0); // NOLINT(bugprone-use-after-move) - REQUIRE(dv.size() == 0); // NOLINT(bugprone-use-after-move,readability-container-size-empty) - REQUIRE(dv == ""); // NOLINT(bugprone-use-after-move,readability-container-size-empty) - REQUIRE(dv == U""); // NOLINT(bugprone-use-after-move,readability-container-size-empty) - REQUIRE(dv.front() == '\0'); - REQUIRE_FALSE(d == dv); - } - - SECTION("Literal") { - string d; - d.assign("123456", 3); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 3); - REQUIRE(d.size() == 3); - REQUIRE(d == "123"); - REQUIRE(d == U"123"); - } - - SECTION("Wide Literal") { - string d; - d.assign(U"123456", 3); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 3); - REQUIRE(d.size() == 3); - REQUIRE(d == "123"); - REQUIRE(d == U"123"); - } - - SECTION("Initializer list") { - string d; - d.assign({'1', '2', '3', '4', '5', '6'}); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 6); - REQUIRE(d == "123456"); - REQUIRE(d == U"123456"); - } - - SECTION("String view") { - string d; - d.assign(std::string_view("123456")); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 6); - REQUIRE(d == "123456"); - REQUIRE(d == U"123456"); - } - - SECTION("Wide string view") { - string d; - d.assign(std::u32string_view(U"123456")); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 6); - REQUIRE(d.size() == 6); - REQUIRE(d == "123456"); - REQUIRE(d == U"123456"); - } - - SECTION("Substring view") { - string d; - d.assign(std::string_view("123456"), 2, 2); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 2); - REQUIRE(d.size() == 2); - REQUIRE(d == "34"); - REQUIRE(d == U"34"); - } - - SECTION("Wide string view") { - string d; - d.assign(std::u32string_view(U"123456"), 2, 2); - REQUIRE_FALSE(d.empty()); - REQUIRE(d.size_codepoints() == 2); - REQUIRE(d.size() == 2); - REQUIRE(d == "34"); - REQUIRE(d == U"34"); - } - } - - SECTION("Element access") { - SECTION("At") { - string s = "123456"; - REQUIRE(s.at(0) == '1'); - REQUIRE(s.at(1) == '2'); - REQUIRE(s.at(2) == '3'); - REQUIRE(s.at(3) == '4'); - REQUIRE(s.at(4) == '5'); - REQUIRE(s.at(5) == '6'); - } - - using cp_index = string::codepoint_index; - - SECTION("At codepoint (through references)") { - SECTION("No unicode") { - string s = "123456"; - REQUIRE(s.at(cp_index(0)) == '1'); - REQUIRE(s.at(cp_index(1)) == '2'); - REQUIRE(s.at(cp_index(2)) == '3'); - REQUIRE(s.at(cp_index(3)) == '4'); - REQUIRE(s.at(cp_index(4)) == '5'); - REQUIRE(s.at(cp_index(5)) == '6'); - } - SECTION("Half unicode") { - string s = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; - REQUIRE(s.at(cp_index(0)) == '1'); - REQUIRE(s.at(cp_index(1)) == U'๐Ÿ˜€'); - REQUIRE(s.at(cp_index(2)) == '2'); - REQUIRE(s.at(cp_index(3)) == U'๐Ÿ˜€'); - REQUIRE(s.at(cp_index(4)) == '3'); - REQUIRE(s.at(cp_index(5)) == U'๐Ÿ˜€'); - REQUIRE(s.at(cp_index(0)) == "1"); - REQUIRE(s.at(cp_index(1)) == "๐Ÿ˜€"); - REQUIRE(s.at(cp_index(2)) == "2"); - REQUIRE(s.at(cp_index(3)) == "๐Ÿ˜€"); - REQUIRE(s.at(cp_index(4)) == "3"); - REQUIRE(s.at(cp_index(5)) == "๐Ÿ˜€"); - } - SECTION("Full unicode") { - string s = "๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"; - REQUIRE(s.at(cp_index(0)) == U'๐Ÿ™‚'); - REQUIRE(s.at(cp_index(1)) == U'๐Ÿ˜€'); - REQUIRE(s.at(cp_index(2)) == U'๐Ÿ™‚'); - REQUIRE(s.at(cp_index(3)) == U'๐Ÿ˜€'); - REQUIRE(s.at(cp_index(4)) == U'๐Ÿ™‚'); - REQUIRE(s.at(cp_index(5)) == U'๐Ÿ˜€'); - REQUIRE(s.at(cp_index(0)) == "๐Ÿ™‚"); - REQUIRE(s.at(cp_index(1)) == "๐Ÿ˜€"); - REQUIRE(s.at(cp_index(2)) == "๐Ÿ™‚"); - REQUIRE(s.at(cp_index(3)) == "๐Ÿ˜€"); - REQUIRE(s.at(cp_index(4)) == "๐Ÿ™‚"); - REQUIRE(s.at(cp_index(5)) == "๐Ÿ˜€"); - } - } - - SECTION("Subscript") { - string s = "123456"; - REQUIRE(s[0] == '1'); - REQUIRE(s[1] == '2'); - REQUIRE(s[2] == '3'); - REQUIRE(s[3] == '4'); - REQUIRE(s[4] == '5'); - REQUIRE(s[5] == '6'); - } - - SECTION("Subscript codepoint") { - string s = "123456"; - REQUIRE(s[cp_index(0)] == '1'); - REQUIRE(s[cp_index(1)] == '2'); - REQUIRE(s[cp_index(2)] == '3'); - REQUIRE(s[cp_index(3)] == '4'); - REQUIRE(s[cp_index(4)] == '5'); - REQUIRE(s[cp_index(5)] == '6'); - } - - SECTION("Subscript codepoint (direct values)") { - string s = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; - REQUIRE(s(cp_index(0)) == '1'); - REQUIRE(s(cp_index(1)) == U'๐Ÿ˜€'); - REQUIRE(s(cp_index(2)) == '2'); - REQUIRE(s(cp_index(3)) == U'๐Ÿ˜€'); - REQUIRE(s(cp_index(4)) == '3'); - REQUIRE(s(cp_index(5)) == U'๐Ÿ˜€'); - } - - SECTION("Subscript codepoint (through references)") { - string s = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; - REQUIRE(s[cp_index(0)] == '1'); - REQUIRE(s[cp_index(1)] == U'๐Ÿ˜€'); - REQUIRE(s[cp_index(2)] == '2'); - REQUIRE(s[cp_index(3)] == U'๐Ÿ˜€'); - REQUIRE(s[cp_index(4)] == '3'); - REQUIRE(s[cp_index(5)] == U'๐Ÿ˜€'); - } - - SECTION("Front/Back") { - string s = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€5"; - REQUIRE(s.front() == '1'); - REQUIRE(s.back() == '5'); - } - - SECTION("Front/Back Codepoints") { - string s = "๐Ÿ˜€1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€5๐Ÿ˜€"; - REQUIRE(s.front_codepoint() == U'๐Ÿ˜€'); - REQUIRE(s.back_codepoint() == U'๐Ÿ˜€'); - REQUIRE(s.front_codepoint() == "๐Ÿ˜€"); - REQUIRE(s.back_codepoint() == "๐Ÿ˜€"); - } - - SECTION("Data") { - string s = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€5"; - std::string_view sv(s.data(), s.size()); - REQUIRE(s == sv); - REQUIRE(s.data() == s.c_str()); - REQUIRE(s.operator std::string_view() == sv); - } - } - - SECTION("Iterators") { - SECTION("Byte Iterators") { - string a = "123"; - REQUIRE(a.begin() == a.data()); - REQUIRE(a.end() == a.data() + a.size()); - - REQUIRE(*a.begin() == '1'); - REQUIRE(*std::next(a.begin()) == '2'); - REQUIRE(*std::prev(a.end()) == '3'); - - REQUIRE(a.cbegin() == a.data()); - REQUIRE(a.cend() == a.data() + a.size()); - - REQUIRE(*a.cbegin() == '1'); - REQUIRE(*std::next(a.cbegin()) == '2'); - REQUIRE(*std::prev(a.cend()) == '3'); - - REQUIRE(*a.rbegin() == '3'); - REQUIRE(*std::next(a.rbegin()) == '2'); - REQUIRE(*std::prev(a.rend()) == '1'); - - REQUIRE(*a.crbegin() == '3'); - REQUIRE(*std::next(a.crbegin()) == '2'); - REQUIRE(*std::prev(a.crend()) == '1'); - } - - SECTION("Codepoint Iterators") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€"; - REQUIRE(static_cast(a.end_codepoint() - a.begin_codepoint()) == a.size_codepoints()); - - REQUIRE(*a.begin_codepoint() == U'๐Ÿ˜'); - REQUIRE(*std::next(a.begin_codepoint()) == U'๐Ÿ™‚'); - REQUIRE(*std::prev(a.end_codepoint()) == U'๐Ÿ˜€'); - - REQUIRE(*a.cbegin_codepoint() == a.front_codepoint()); - REQUIRE(*std::prev(a.cend_codepoint()) == a.back_codepoint()); - - REQUIRE(*a.cbegin_codepoint() == U'๐Ÿ˜'); - REQUIRE(*std::next(a.cbegin_codepoint()) == U'๐Ÿ™‚'); - REQUIRE(*std::prev(a.cend_codepoint()) == U'๐Ÿ˜€'); - - REQUIRE(*a.rbegin_codepoint() == U'๐Ÿ˜€'); - REQUIRE(*std::next(a.rbegin_codepoint()) == U'๐Ÿ™‚'); - REQUIRE(*std::prev(a.rend_codepoint()) == U'๐Ÿ˜'); - - REQUIRE(*a.crbegin_codepoint() == U'๐Ÿ˜€'); - REQUIRE(*std::next(a.crbegin_codepoint()) == U'๐Ÿ™‚'); - REQUIRE(*std::prev(a.crend_codepoint()) == U'๐Ÿ˜'); - } - } - - SECTION("Capacity") { - string a = U"1๐Ÿ˜€3"; - - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 6); - REQUIRE(a.size_codepoints() == 3); - REQUIRE(a.max_size() > 100000); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() >= 13); - REQUIRE(a.capacity() <= 15); - size_t old_cap = a.capacity(); - - a.reserve(10); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 6); - REQUIRE(a.size_codepoints() == 3); - REQUIRE(a.max_size() > 100000); - REQUIRE_FALSE(a.empty()); - size_t new_cap = a.capacity(); - REQUIRE(new_cap >= old_cap); - - a.reserve(20); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 6); - REQUIRE(a.size_codepoints() == 3); - REQUIRE(a.max_size() > 100000); - REQUIRE_FALSE(a.empty()); - new_cap = a.capacity(); - REQUIRE(new_cap > old_cap); - - a.shrink_to_fit(); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 6); - REQUIRE(a.size_codepoints() == 3); - REQUIRE(a.max_size() > 100000); - REQUIRE_FALSE(a.empty()); - new_cap = a.capacity(); - REQUIRE(new_cap >= 6); // larger than initial size but might not be inline anymore - - a = U"1๐Ÿ˜€3"; - a.shrink_to_fit(); - REQUIRE(a.size() == 6); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() >= a.size()); - REQUIRE_FALSE(is_malformed(a)); - } - - SECTION("Resize") { - SECTION("Code units") { - string a = "1๐Ÿ˜€3"; - REQUIRE_FALSE(is_malformed(a)); - a.resize(4); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() >= 13); - REQUIRE(a.capacity() <= 15); - REQUIRE(a.size_codepoints() == 1); - REQUIRE(is_malformed(a)); - - a = "1๐Ÿ˜€3"; - REQUIRE_FALSE(is_malformed(a)); - a.resize(20); - REQUIRE(a.size() == 20); - REQUIRE(a.max_size() > 20); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() > 20); - REQUIRE(a.size_codepoints() == 17); - REQUIRE_FALSE(is_malformed(a)); - - a = "1๐Ÿ˜€3"; - a.resize(14, 'x'); - REQUIRE(a.size() == 6 + 8); - REQUIRE(a.size_codepoints() == 3 + 8); - REQUIRE(a.max_size() > 14); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() > 14); - REQUIRE_FALSE(is_malformed(a)); - - a = "1๐Ÿ˜€3"; - a.resize(14, U'x'); - REQUIRE(a.size() == 6 + 8); - REQUIRE(a.size_codepoints() == 3 + 8); - REQUIRE(a.max_size() > 14); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() > 14); - REQUIRE_FALSE(is_malformed(a)); - - a = "1๐Ÿ˜€3"; // <- size 6 - a.resize(14, U'๐Ÿ˜€'); // <- size 6 + 8 = 14 (two extra codepoints) - REQUIRE(a.size_codepoints() == 5); - REQUIRE(a.size() == 14); - REQUIRE(a.max_size() > 40); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() > 14); - REQUIRE_FALSE(is_malformed(a)); - - a = "1๐Ÿ˜€3"; - a.shrink_to_fit(); - REQUIRE(a.size() == 6); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() > a.size()); - REQUIRE_FALSE(is_malformed(a)); - } - - SECTION("Code points") { - string a = "1๐Ÿ˜€3"; - REQUIRE_FALSE(is_malformed(a)); - a.resize(string::codepoint_index(4)); - REQUIRE(a.size() == 7); - REQUIRE(a.max_size() > 7); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() >= 13); - REQUIRE(a.capacity() <= 17); - REQUIRE(a.size_codepoints() == 4); - REQUIRE_FALSE(is_malformed(a)); - - a = "1๐Ÿ˜€3"; - REQUIRE_FALSE(is_malformed(a)); - a.resize(string::codepoint_index(20)); - REQUIRE(a.size() == 23); - REQUIRE(a.max_size() > 23); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() > 23); - REQUIRE(a.size_codepoints() == 20); - REQUIRE_FALSE(is_malformed(a)); - - a = "1๐Ÿ˜€3"; - a.resize(string::codepoint_index(14), 'x'); - REQUIRE(a.size() == 6 + 14 - 3); - REQUIRE(a.size_codepoints() == 3 + 11); - REQUIRE(a.max_size() > 14); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() > 14); - REQUIRE_FALSE(is_malformed(a)); - - a = "1๐Ÿ˜€3"; - a.resize(string::codepoint_index(14), U'x'); - REQUIRE(a.size() == 6 + 11); - REQUIRE(a.size_codepoints() == 3 + 11); - REQUIRE(a.max_size() > 17); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() > 17); - REQUIRE_FALSE(is_malformed(a)); - - a = "1๐Ÿ˜€3"; - a.resize(string::codepoint_index(14), U'๐Ÿ˜€'); - REQUIRE(a.size_codepoints() == 14); - REQUIRE(a.size() == 12 * 4 + 2); - REQUIRE(a.max_size() > 40); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() > 14); - REQUIRE_FALSE(is_malformed(a)); - } - } - - SECTION("Clear") { - string a = "1๐Ÿ˜€3"; - a.clear(); - REQUIRE(a.empty()); - REQUIRE(a.size() == 0); // NOLINT(readability-container-size-empty) - REQUIRE(a.size_codepoints() == 0); - REQUIRE(a.max_size() > 10); - REQUIRE(a.capacity() > a.size()); - REQUIRE_FALSE(is_malformed(a)); - } - - SECTION("Insert") { - SECTION("Char") { - SECTION("At index") { - SECTION("One element") { - string a = "124"; - a.insert(2, 1, '3'); - REQUIRE(a == "1234"); - } - SECTION("Multiple elements") { - string a = "abcz"; - a.insert(3, 3, '.'); - REQUIRE(a == "abc...z"); - } - SECTION("Unicode") { - string a = "abcz"; - a.insert(3, 3, U'๐Ÿ˜€'); - REQUIRE(a == "abc๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€z"); - } - } - - SECTION("At codepoint") { - SECTION("One element") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(string::codepoint_index(2), 1, '3'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); - } - SECTION("Multiple elements") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(string::codepoint_index(2), 3, '.'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚...๐Ÿ˜"); - } - SECTION("Unicode") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(string::codepoint_index(2), 3, U'๐Ÿ˜€'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); - } - } - - SECTION("At iterator") { - SECTION("One element") { - string a = "124"; - a.insert(a.begin() + 2, 1, '3'); - REQUIRE(a == "1234"); - } - SECTION("Multiple elements") { - string a = "abcz"; - a.insert(a.begin() + 3, 3, '.'); - REQUIRE(a == "abc...z"); - } - SECTION("Unicode") { - string a = "abcz"; - a.insert(a.begin() + 3, 3, U'๐Ÿ˜€'); - REQUIRE(a == "abc๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€z"); - } - } - - SECTION("At codepoint iterator") { - SECTION("One element") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(a.begin_codepoint() + string::codepoint_index(2), 1, '3'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); - } - SECTION("Multiple elements") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(a.begin_codepoint() + string::codepoint_index(2), 3, '.'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚...๐Ÿ˜"); - } - SECTION("Unicode") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(a.begin_codepoint() + string::codepoint_index(2), 3, U'๐Ÿ˜€'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("Literal string") { - SECTION("At index") { - SECTION("One element") { - string a = "124"; - a.insert(2, "3"); - REQUIRE(a == "1234"); - } - SECTION("Multiple elements") { - string a = "abcz"; - a.insert(3, "defgh"); - REQUIRE(a == "abcdefghz"); - } - SECTION("Unicode") { - string a = "abcz"; - a.insert(3, U"๐Ÿ™‚๐Ÿ˜€"); - REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€z"); - } - } - - SECTION("At codepoint") { - SECTION("One element") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(string::codepoint_index(2), "3"); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); - } - SECTION("Multiple elements") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(string::codepoint_index(2), "defgh"); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚defgh๐Ÿ˜"); - } - SECTION("Unicode") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(string::codepoint_index(2), U"๐Ÿ™‚๐Ÿ˜€"); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("Partial literal string") { - SECTION("At index") { - SECTION("One element") { - string a = "124"; - a.insert(2, "3456", 1); - REQUIRE(a == "1234"); - } - SECTION("Multiple elements") { - string a = "abcz"; - a.insert(3, "defghijklmn", 5); - REQUIRE(a == "abcdefghz"); - } - SECTION("Unicode") { - string a = "abcz"; - a.insert(3, U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€", 2); - REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€z"); - } - } - - SECTION("At codepoint") { - SECTION("One element") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(string::codepoint_index(2), "3456", 1); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); - } - SECTION("Multiple elements") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(string::codepoint_index(2), "defghijkl", 5); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚defgh๐Ÿ˜"); - } - SECTION("Unicode") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(string::codepoint_index(2), U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€", 2); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("Other string") { - SECTION("At index") { - SECTION("One element") { - string a = "124"; - string other("3"); - a.insert(2, other); - REQUIRE(a == "1234"); - } - SECTION("Multiple elements") { - string a = "abcz"; - string other("defgh"); - a.insert(3, other); - REQUIRE(a == "abcdefghz"); - } - SECTION("Unicode") { - string a = "abcz"; - string other(U"๐Ÿ™‚๐Ÿ˜€"); - a.insert(3, other); - REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€z"); - } - } - - SECTION("At codepoint") { - SECTION("One element") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - string other("3"); - a.insert(string::codepoint_index(2), other); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); - } - SECTION("Multiple elements") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - string other("defgh"); - a.insert(string::codepoint_index(2), other); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚defgh๐Ÿ˜"); - } - SECTION("Unicode") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - string other(U"๐Ÿ™‚๐Ÿ˜€"); - a.insert(string::codepoint_index(2), other); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("Other string suffix") { - SECTION("At index") { - SECTION("One element") { - string a = "124"; - string other("3456"); - a.insert(2, other, 1); - REQUIRE(a == "124564"); - } - SECTION("Multiple elements") { - string a = "abcz"; - string other("defghijklmn"); - a.insert(3, other, 5); - REQUIRE(a == "abcijklmnz"); - } - SECTION("Unicode") { - string a = "abcz"; - string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); - a.insert(3, other, 8); - REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€z"); - } - } - - SECTION("At codepoint") { - SECTION("One element") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - string other("3456"); - a.insert(string::codepoint_index(2), other, 1); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚456๐Ÿ˜"); - } - SECTION("Multiple elements") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - string other("defghijkl"); - a.insert(string::codepoint_index(2), other, 5); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚ijkl๐Ÿ˜"); - } - SECTION("Unicode") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); - a.insert(string::codepoint_index(2), other, 8); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("Other string codepoint suffix") { - SECTION("At index") { - SECTION("One element") { - string a = "124"; - string other("3456"); - a.insert(2, other, string::codepoint_index(1)); - REQUIRE(a == "124564"); - } - SECTION("Multiple elements") { - string a = "abcz"; - string other("defghijklmn"); - a.insert(3, other, string::codepoint_index(5)); - REQUIRE(a == "abcijklmnz"); - } - SECTION("Unicode") { - string a = "abcz"; - string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); - a.insert(3, other, string::codepoint_index(2)); - REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€z"); - } - } - - SECTION("At codepoint") { - SECTION("One element") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - string other("3456"); - a.insert(string::codepoint_index(2), other, string::codepoint_index(1)); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚456๐Ÿ˜"); - } - SECTION("Multiple elements") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - string other("defghijkl"); - a.insert(string::codepoint_index(2), other, string::codepoint_index(5)); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚ijkl๐Ÿ˜"); - } - SECTION("Unicode") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); - a.insert(string::codepoint_index(2), other, string::codepoint_index(2)); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("Other string substr") { - SECTION("At index") { - SECTION("One element") { - string a = "124"; - string other("3456"); - a.insert(2, other, 0, 1); - REQUIRE(a == "1234"); - } - SECTION("Multiple elements") { - string a = "abcz"; - string other("defghijklmn"); - a.insert(3, other, 1, 3); - REQUIRE(a == "abcefgz"); - } - SECTION("Unicode") { - string a = "abcz"; - string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); - a.insert(3, other, 4, 12); - REQUIRE(a == "abc๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€z"); - } - } - - SECTION("At codepoint") { - SECTION("One element") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - string other("3456"); - a.insert(string::codepoint_index(2), other, 1, 2); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚45๐Ÿ˜"); - } - SECTION("Multiple elements") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - string other("defghijkl"); - a.insert(string::codepoint_index(2), other, 5, 2); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚ij๐Ÿ˜"); - } - SECTION("Unicode") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); - a.insert(string::codepoint_index(2), other, 12, 8); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜"); - } - } - } - - SECTION("Other string codepoint substr") { - SECTION("At index") { - SECTION("One element") { - string a = "124"; - string other("3456"); - a.insert(2, other, string::codepoint_index(1), string::codepoint_index(2)); - REQUIRE(a == "12454"); - } - SECTION("Multiple elements") { - string a = "abcz"; - string other("defghijklmn"); - a.insert(3, other, string::codepoint_index(1), string::codepoint_index(3)); - REQUIRE(a == "abcefgz"); - } - SECTION("Unicode") { - string a = "abcz"; - string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); - a.insert(3, other, string::codepoint_index(2), string::codepoint_index(3)); - REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚z"); - } - } - - SECTION("At codepoint") { - SECTION("One element") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - string other("3456"); - a.insert(string::codepoint_index(2), other, string::codepoint_index(1), string::codepoint_index(2)); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚45๐Ÿ˜"); - } - SECTION("Multiple elements") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - string other("defghijkl"); - a.insert(string::codepoint_index(2), other, string::codepoint_index(5), string::codepoint_index(2)); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚ij๐Ÿ˜"); - } - SECTION("Unicode") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); - a.insert(string::codepoint_index(2), other, string::codepoint_index(3), string::codepoint_index(2)); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜"); - } - } - } - - SECTION("Single char") { - SECTION("At index") { - SECTION("Unibyte") { - string a = "abcz"; - a.insert(a.begin() + 3, 'd'); - REQUIRE(a == "abcdz"); - } - SECTION("Multibyte") { - string a = "abcz"; - a.insert(a.begin() + 3, U'๐Ÿ™‚'); - REQUIRE(a == "abc๐Ÿ™‚z"); - } - } - - SECTION("At codepoint") { - SECTION("Unibyte") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(a.begin_codepoint() + string::codepoint_index(2), '3'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); - } - SECTION("Multibyte") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(a.begin_codepoint() + string::codepoint_index(2), U'๐Ÿ˜€'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("Other container iterator") { - SECTION("At index") { - SECTION("One element") { - string a = "124"; - std::string other("3"); - a.insert(a.begin() + 2, other.begin(), other.end()); - REQUIRE(a == "1234"); - } - SECTION("Multiple elements") { - string a = "abcz"; - std::string other("defgh"); - a.insert(a.begin() + 3, other.begin(), other.end()); - REQUIRE(a == "abcdefghz"); - } - SECTION("Unicode") { - string a = "abcz"; - std::u32string other(U"๐Ÿ™‚๐Ÿ˜€"); - a.insert(a.begin() + 3, other.begin(), other.end()); - REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€z"); - } - } - - SECTION("At codepoint") { - SECTION("One element") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - std::string other("3"); - a.insert(a.begin_codepoint() + string::codepoint_index(2), other.begin(), other.end()); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); - } - SECTION("Multiple elements") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - std::string other("defgh"); - a.insert(a.begin_codepoint() + string::codepoint_index(2), other.begin(), other.end()); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚defgh๐Ÿ˜"); - } - SECTION("Unicode") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - std::u32string other(U"๐Ÿ™‚๐Ÿ˜€"); - a.insert(a.begin_codepoint() + string::codepoint_index(2), other.begin(), other.end()); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("Initializer list") { - SECTION("At index") { - SECTION("One element") { - string a = "124"; - a.insert(a.begin() + 2, {'3'}); - REQUIRE(a == "1234"); - } - SECTION("Multiple elements") { - string a = "abcz"; - a.insert(a.begin() + 3, {'d', 'e', 'f', 'g', 'h'}); - REQUIRE(a == "abcdefghz"); - } - SECTION("Unicode") { - string a = "abcz"; - a.insert(a.begin() + 3, {U'๐Ÿ™‚', U'๐Ÿ˜€'}); - REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€z"); - } - } - - SECTION("At codepoint") { - SECTION("One element") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(a.begin_codepoint() + string::codepoint_index(2), {'3'}); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); - } - SECTION("Multiple elements") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - a.insert(a.begin_codepoint() + string::codepoint_index(2), {'d', 'e', 'f', 'g', 'h'}); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚defgh๐Ÿ˜"); - } - SECTION("Unicode") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - std::u32string other(U"๐Ÿ™‚๐Ÿ˜€"); - a.insert(a.begin_codepoint() + string::codepoint_index(2), {U'๐Ÿ™‚', U'๐Ÿ˜€'}); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("String view") { - SECTION("At index") { - SECTION("One element") { - string a = "124"; - std::string_view other("3"); - a.insert(2, other); - REQUIRE(a == "1234"); - } - SECTION("Multiple elements") { - string a = "abcz"; - std::string_view other("defgh"); - a.insert(3, other); - REQUIRE(a == "abcdefghz"); - } - SECTION("Unicode") { - string a = "abcz"; - std::u32string_view other(U"๐Ÿ™‚๐Ÿ˜€"); - a.insert(3, other); - REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€z"); - } - } - - SECTION("At codepoint") { - SECTION("One element") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - std::string_view other("3"); - a.insert(string::codepoint_index(2), other); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); - } - SECTION("Multiple elements") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - std::string_view other("defgh"); - a.insert(string::codepoint_index(2), other); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚defgh๐Ÿ˜"); - } - SECTION("Unicode") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - std::u32string_view other(U"๐Ÿ™‚๐Ÿ˜€"); - a.insert(string::codepoint_index(2), other); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("String view substr") { - SECTION("At index") { - SECTION("One element") { - string a = "124"; - std::string_view other("3456"); - a.insert(2, other, 0, 1); - REQUIRE(a == "1234"); - } - SECTION("Multiple elements") { - string a = "abcz"; - std::string_view other("defghijklmn"); - a.insert(3, other, 1, 3); - REQUIRE(a == "abcefgz"); - } - SECTION("Unicode") { - string a = "abcz"; - std::u32string_view other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); - a.insert(3, other, 1, 3); - REQUIRE(a == "abc๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€z"); - } - } - - SECTION("At codepoint") { - SECTION("One element") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - std::string_view other("3456"); - a.insert(string::codepoint_index(2), other, 1, 2); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚45๐Ÿ˜"); - } - SECTION("Multiple elements") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - std::string_view other("defghijkl"); - a.insert(string::codepoint_index(2), other, 5, 2); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚ij๐Ÿ˜"); - } - SECTION("Unicode") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; - std::u32string_view other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); - a.insert(string::codepoint_index(2), other, 1, 3); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - } - } - - SECTION("Erase") { - SECTION("Index suffix") { - string a = "abcdefghij"; - a.erase(3); - REQUIRE(a == "abc"); - } - SECTION("Index substr") { - string a = "abcdefghij"; - a.erase(3, 2); - REQUIRE(a == "abcfghij"); - } - SECTION("Codepoint suffix") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.erase(string::codepoint_index(3)); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€"); - } - SECTION("Codepoint substr") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.erase(string::codepoint_index(3), string::codepoint_index(2)); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - SECTION("Single position") { - string a = "abcdefghij"; - a.erase(a.begin() + 3); - REQUIRE(a == "abcefghij"); - } - SECTION("Single codepoint") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.erase(a.begin_codepoint() + string::codepoint_index(3)); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); - } - SECTION("Index range") { - string a = "abcdefghij"; - a.erase(a.begin() + 3, a.begin() + 5); - REQUIRE(a == "abcfghij"); - } - SECTION("Codepoint range") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.erase(a.begin_codepoint() + string::codepoint_index(3), a.begin_codepoint() + string::codepoint_index(5)); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - - SECTION("Push back") { - SECTION("Single position") { - string a = "abcdefghij"; - a.push_back('k'); - REQUIRE(a == "abcdefghijk"); - } - SECTION("Single codepoint") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.push_back(U'๐Ÿ˜€'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€"); - } - } - - SECTION("Pop back") { - SECTION("Single position") { - string a = "abcdefghij"; - a.pop_back(); - REQUIRE(a == "abcdefghi"); - } - SECTION("Single codepoint") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.pop_back_codepoint(); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); - } - } - - SECTION("Push \"front\"") { - SECTION("Single position") { - string a = "abcdefghij"; - a.insert(a.begin(), 'k'); - REQUIRE(a == "kabcdefghij"); - } - SECTION("Single codepoint") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.insert(a.begin(), U'๐Ÿ˜€'); - REQUIRE(a == "๐Ÿ˜€๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - - SECTION("Pop \"front\"") { - SECTION("Single position") { - string a = "abcdefghij"; - a.erase(a.begin()); - REQUIRE(a == "bcdefghij"); - } - SECTION("Single codepoint") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.erase(a.begin_codepoint()); - REQUIRE(a == "๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - - SECTION("Append") { - SECTION("Chars") { - SECTION("Single position") { - string a = "abcdefghij"; - a.append(3, 'k'); - REQUIRE(a == "abcdefghijkkk"); - } - SECTION("Single codepoint") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.append(3, U'๐Ÿ˜€'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); - } - } - SECTION("Other string") { - SECTION("Complete") { - string a = "abcdefghij"; - string b = "klmnop"; - a.append(b); - REQUIRE(a == "abcdefghijklmnop"); - } - SECTION("Suffix") { - string a = "abcdefghij"; - string b = "klmnop"; - a.append(b, 2); - REQUIRE(a == "abcdefghijmnop"); - } - SECTION("Substr") { - string a = "abcdefghij"; - string b = "klmnop"; - a.append(b, 2, 3); - REQUIRE(a == "abcdefghijmno"); - } - SECTION("Codepoint Complete") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.append(b); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - SECTION("Codepoint Suffix") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.append(b, string::codepoint_index(2)); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - SECTION("Codepoint Substr") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.append(b, string::codepoint_index(2), string::codepoint_index(3)); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); - } - } - SECTION("String Literal") { - SECTION("Complete") { - string a = "abcdefghij"; - a.append("klmnop"); - REQUIRE(a == "abcdefghijklmnop"); - } - SECTION("Prefix") { - string a = "abcdefghij"; - a.append("klmnop", 2); - REQUIRE(a == "abcdefghijkl"); - } - SECTION("Codepoint Complete") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.append("๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - SECTION("Codepoint Prefix") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.append(U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜", 2); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚"); - } - } - - SECTION("Iterator ranges") { - SECTION("Complete") { - string a = "abcdefghij"; - std::string b = "klmnop"; - a.append(b.begin(), b.end()); - REQUIRE(a == "abcdefghijklmnop"); - } - SECTION("Prefix") { - string a = "abcdefghij"; - std::string b = "klmnop"; - a.append(b.begin(), b.begin() + 2); - REQUIRE(a == "abcdefghijkl"); - } - SECTION("Codepoint Complete") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - std::u32string b = U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.append(b.begin(), b.end()); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - SECTION("Codepoint Prefix") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - std::u32string b = U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.append(b.begin(), b.begin() + 2); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚"); - } - } - - SECTION("Initializer list") { - SECTION("Complete") { - string a = "abcdefghij"; - a.append({'k', 'l', 'm', 'n', 'o', 'p'}); - REQUIRE(a == "abcdefghijklmnop"); - } - SECTION("Codepoint Complete") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.append({U'๐Ÿ˜', U'๐Ÿ™‚', U'๐Ÿ˜€', U'๐Ÿ™‚', U'๐Ÿ˜€', U'๐Ÿ˜'}); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - - SECTION("Other string view") { - SECTION("Complete") { - string a = "abcdefghij"; - std::string_view b = "klmnop"; - a.append(b); - REQUIRE(a == "abcdefghijklmnop"); - } - SECTION("Suffix") { - string a = "abcdefghij"; - std::string_view b = "klmnop"; - a.append(b, 2); - REQUIRE(a == "abcdefghijmnop"); - } - SECTION("Substr") { - string a = "abcdefghij"; - std::string_view b = "klmnop"; - a.append(b, 2, 3); - REQUIRE(a == "abcdefghijmno"); - } - SECTION("Codepoint Complete") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - std::string_view b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.append(b); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - SECTION("Codepoint Suffix") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - std::u32string_view b = U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.append(b, 2); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - SECTION("Codepoint Substr") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - std::u32string_view b = U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.append(b, 2, 3); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); - } - } - } - - SECTION("Operator +=") { - SECTION("Other string") { - SECTION("Complete") { - string a = "abcdefghij"; - string b = "klmnop"; - a += b; - REQUIRE(a == "abcdefghijklmnop"); - } - SECTION("Codepoint Complete") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a += b; - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - SECTION("Chars") { - SECTION("Single position") { - string a = "abcdefghij"; - a += 'k'; - REQUIRE(a == "abcdefghijk"); - } - SECTION("Single codepoint") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a += U'๐Ÿ˜€'; - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€"); - } - } - SECTION("String Literal") { - SECTION("Complete") { - string a = "abcdefghij"; - a += "klmnop"; - REQUIRE(a == "abcdefghijklmnop"); - } - SECTION("Codepoint Complete") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a += "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - - SECTION("Initializer list") { - SECTION("Complete") { - string a = "abcdefghij"; - a += {'k', 'l', 'm', 'n', 'o', 'p'}; - REQUIRE(a == "abcdefghijklmnop"); - } - SECTION("Codepoint Complete") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a += {U'๐Ÿ˜', U'๐Ÿ™‚', U'๐Ÿ˜€', U'๐Ÿ™‚', U'๐Ÿ˜€', U'๐Ÿ˜'}; - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - - SECTION("Other string view") { - SECTION("Complete") { - string a = "abcdefghij"; - std::string_view b = "klmnop"; - a += b; - REQUIRE(a == "abcdefghijklmnop"); - } - SECTION("Codepoint Complete") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - std::string_view b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a += b; - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("Starts with") { - SECTION("String view") { - SECTION("UTF8 rhs") { - string a = "abcdefghij"; - SECTION("Starts not-empty") { - std::string_view b = "abcde"; - REQUIRE(a.starts_with(b)); - } - - SECTION("Might find but does not start with") { - std::string_view b = "bcdef"; - REQUIRE_FALSE(a.starts_with(b)); - } - - SECTION("Always start with empty") { - std::string_view b = ""; // NOLINT(readability-redundant-string-init) - REQUIRE(a.starts_with(b)); - } - - SECTION("Cannot start with if empty") { - a.clear(); - std::string_view b = "bcdef"; - REQUIRE_FALSE(a.starts_with(b)); - } - - SECTION("Always start if both empty") { - a.clear(); - std::string_view b = ""; // NOLINT(readability-redundant-string-init) - REQUIRE(a.starts_with(b)); - } - } - - if constexpr (not is_windows()) { - SECTION("UTF32 rhs") { - string a = u8"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - SECTION("Starts not-empty") { - std::u32string_view b = U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€"; - REQUIRE(a.starts_with(b)); - } - - SECTION("Might find but does not start with") { - std::u32string_view b = U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚"; - REQUIRE_FALSE(a.starts_with(b)); - } - - SECTION("Always start with empty") { - std::u32string_view b = U""; // NOLINT(readability-redundant-string-init) - REQUIRE(a.starts_with(b)); - } - - SECTION("Cannot start with if empty") { - a.clear(); - std::u32string_view b = U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€"; - REQUIRE_FALSE(a.starts_with(b)); - } - - SECTION("Always start if both empty") { - a.clear(); - std::u32string_view b = U""; // NOLINT(readability-redundant-string-init) - REQUIRE(a.starts_with(b)); - } - } - } - } - - SECTION("Char") { - SECTION("UTF8 rhs") { - string a = "abcdefghij"; - SECTION("Starts not-empty") { REQUIRE(a.starts_with('a')); } - - SECTION("Might find but does not start with") { REQUIRE_FALSE(a.starts_with('b')); } - - SECTION("Cannot start with if empty") { - a.clear(); - REQUIRE_FALSE(a.starts_with('a')); - } - } - SECTION("UTF32 rhs") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - SECTION("Starts not-empty") { REQUIRE(a.starts_with(U'๐Ÿ˜')); } - - SECTION("Might find but does not start with") { REQUIRE_FALSE(a.starts_with(U'๐Ÿ™‚')); } - - SECTION("Cannot start with if empty") { - a.clear(); - REQUIRE_FALSE(a.starts_with(U'๐Ÿ˜')); - } - } - } - - SECTION("String literal") { - SECTION("UTF8 rhs") { - string a = "abcdefghij"; - SECTION("Starts not-empty") { REQUIRE(a.starts_with("abcde")); } - - SECTION("Might find but does not start with") { REQUIRE_FALSE(a.starts_with("bcdef")); } - - SECTION("Always start with empty") { REQUIRE(a.starts_with("")); } - - SECTION("Cannot start with if empty") { - a.clear(); - REQUIRE_FALSE(a.starts_with("bcdef")); - } - - SECTION("Always start if both empty") { - a.clear(); - REQUIRE(a.starts_with("")); - } - } - SECTION("UTF32 rhs") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - SECTION("Starts not-empty") { REQUIRE(a.starts_with(U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€")); } - - SECTION("Might find but does not start with") { REQUIRE_FALSE(a.starts_with(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚")); } - - SECTION("Always start with empty") { REQUIRE(a.starts_with(U"")); } - - SECTION("Cannot start with if empty") { - a.clear(); - REQUIRE_FALSE(a.starts_with(U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€")); - } - - SECTION("Always start if both empty") { - a.clear(); - REQUIRE(a.starts_with(U"")); - } - } - } - } - - SECTION("Ends with") { - SECTION("String view") { - SECTION("UTF8 rhs") { - string a = "abcdefghij"; - SECTION("Ends not-empty") { - std::string_view b = "ghij"; - REQUIRE(a.ends_with(b)); - } - - SECTION("Might find but does not end with") { - std::string_view b = "bcdef"; - REQUIRE_FALSE(a.ends_with(b)); - } - - SECTION("Always end with empty") { - std::string_view b = ""; // NOLINT(readability-redundant-string-init) - REQUIRE(a.ends_with(b)); - } - - SECTION("Cannot end with if empty") { - a.clear(); - std::string_view b = "ghij"; - REQUIRE_FALSE(a.ends_with(b)); - } - - SECTION("Always end if both empty") { - a.clear(); - std::string_view b = ""; // NOLINT(readability-redundant-string-init) - REQUIRE(a.ends_with(b)); - } - } - SECTION("UTF32 rhs") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - SECTION("Ends not-empty") { - std::u32string_view b = U"๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - REQUIRE(a.ends_with(b)); - } - - SECTION("Might find but does not end with") { - std::u32string_view b = U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚"; - REQUIRE_FALSE(a.ends_with(b)); - } - - SECTION("Always end with empty") { - std::u32string_view b = U""; // NOLINT(readability-redundant-string-init) - REQUIRE(a.ends_with(b)); - } - - SECTION("Cannot end with if empty") { - a.clear(); - std::u32string_view b = U"๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - REQUIRE_FALSE(a.ends_with(b)); - } - - SECTION("Always end if both empty") { - a.clear(); - std::u32string_view b = U""; // NOLINT(readability-redundant-string-init) - REQUIRE(a.ends_with(b)); - } - } - } - - SECTION("Char") { - SECTION("UTF8 rhs") { - string a = "abcdefghij"; - SECTION("Ends not-empty") { REQUIRE(a.ends_with('j')); } - - SECTION("Might find but does not end with") { REQUIRE_FALSE(a.ends_with('b')); } - - SECTION("Cannot end with if empty") { - a.clear(); - REQUIRE_FALSE(a.ends_with('j')); - } - } - SECTION("UTF32 rhs") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - SECTION("Ends not-empty") { REQUIRE(a.ends_with(U'๐Ÿ˜')); } - - SECTION("Might find but does not end with") { REQUIRE_FALSE(a.ends_with(U'๐Ÿ™‚')); } - - SECTION("Cannot end with if empty") { - a.clear(); - REQUIRE_FALSE(a.ends_with(U'๐Ÿ˜')); - } - } - } - - SECTION("String literal") { - SECTION("UTF8 rhs") { - string a = "abcdefghij"; - SECTION("Ends not-empty") { REQUIRE(a.ends_with("ghij")); } - - SECTION("Might find but does not end with") { REQUIRE_FALSE(a.ends_with("bcdef")); } - - SECTION("Always end with empty") { REQUIRE(a.ends_with("")); } - - SECTION("Cannot end with if empty") { - a.clear(); - REQUIRE_FALSE(a.ends_with("bcdef")); - } - - SECTION("Always end if both empty") { - a.clear(); - REQUIRE(a.ends_with("")); - } - } - SECTION("UTF32 rhs") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - SECTION("Ends not-empty") { REQUIRE(a.ends_with(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ˜")); } - - SECTION("Might find but does not end with") { REQUIRE_FALSE(a.ends_with(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚")); } - - SECTION("Always end with empty") { REQUIRE(a.ends_with(U"")); } - - SECTION("Cannot end with if empty") { - a.clear(); - REQUIRE_FALSE(a.ends_with(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ˜")); - } - - SECTION("Always end if both empty") { - a.clear(); - REQUIRE(a.ends_with(U"")); - } - } - } - } - - SECTION("Contains") { - SECTION("String view") { - SECTION("UTF8 rhs") { - string a = "abcdefghij"; - SECTION("Contains start") { - std::string_view b = "abc"; - REQUIRE(a.contains(b)); - } - - SECTION("Contains middle") { - std::string_view b = "def"; - REQUIRE(a.contains(b)); - } - - SECTION("Contains end") { - std::string_view b = "hij"; - REQUIRE(a.contains(b)); - } - - SECTION("Does not contain") { - std::string_view b = "ijk"; - REQUIRE_FALSE(a.contains(b)); - } - - SECTION("Always contains empty") { - std::string_view b = ""; // NOLINT(readability-redundant-string-init) - REQUIRE(a.contains(b)); - } - - SECTION("Cannot contain if empty") { - a.clear(); - std::string_view b = "ghij"; - REQUIRE_FALSE(a.contains(b)); - } - - SECTION("Always contains if both empty") { - a.clear(); - std::string_view b = ""; // NOLINT(readability-redundant-string-init) - REQUIRE(a.contains(b)); - } - } - SECTION("UTF32 rhs") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - SECTION("Contains start") { - std::u32string_view b = U"๐Ÿ˜๐Ÿ™‚"; - REQUIRE(a.contains(b)); - } - - SECTION("Contains middle") { - std::u32string_view b = U"๐Ÿ˜€๐Ÿ™‚"; - REQUIRE(a.contains(b)); - } - - SECTION("Contains end") { - std::u32string_view b = U"๐Ÿ˜€๐Ÿ˜"; - REQUIRE(a.contains(b)); - } - - SECTION("Does not contain") { - std::u32string_view b = U"๐Ÿ˜๐Ÿ˜€"; - REQUIRE_FALSE(a.contains(b)); - } - - SECTION("Always contains empty") { - std::u32string_view b = U""; // NOLINT(readability-redundant-string-init) - REQUIRE(a.contains(b)); - } - - SECTION("Cannot contain if empty") { - a.clear(); - std::u32string_view b = U"๐Ÿ˜๐Ÿ™‚"; - REQUIRE_FALSE(a.contains(b)); - } - - SECTION("Always contains if both empty") { - a.clear(); - std::u32string_view b = U""; // NOLINT(readability-redundant-string-init) - REQUIRE(a.contains(b)); - } - } - } - - SECTION("Char") { - SECTION("UTF8 rhs") { - string a = "abcdefghij"; - SECTION("Start") { REQUIRE(a.contains('a')); } - - SECTION("Middle") { REQUIRE(a.contains('f')); } - - SECTION("End") { REQUIRE(a.contains('j')); } - - SECTION("Cannot contains if empty") { - a.clear(); - REQUIRE_FALSE(a.contains('j')); - } - } - SECTION("UTF32 rhs") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - SECTION("Start") { REQUIRE(a.contains(U'๐Ÿ˜')); } - - SECTION("Middle") { REQUIRE(a.contains(U'๐Ÿ™‚')); } - - SECTION("End") { REQUIRE(a.contains(U'๐Ÿ˜')); } - - SECTION("Cannot contains if empty") { - a.clear(); - REQUIRE_FALSE(a.contains(U'๐Ÿ˜')); - } - } - } - - SECTION("String view") { - SECTION("UTF8 rhs") { - string a = "abcdefghij"; - SECTION("Contains start") { REQUIRE(a.contains("abc")); } - - SECTION("Contains middle") { REQUIRE(a.contains("def")); } - - SECTION("Contains end") { REQUIRE(a.contains("hij")); } - - SECTION("Does not contain") { REQUIRE_FALSE(a.contains("ijk")); } - - SECTION("Always contains empty") { REQUIRE(a.contains("")); } - - SECTION("Cannot contain if empty") { - a.clear(); - REQUIRE_FALSE(a.contains("ghij")); - } - - SECTION("Always contains if both empty") { - a.clear(); - REQUIRE(a.contains("")); - } - } - SECTION("UTF32 rhs") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - SECTION("Contains start") { REQUIRE(a.contains(U"๐Ÿ˜๐Ÿ™‚")); } - - SECTION("Contains middle") { REQUIRE(a.contains(U"๐Ÿ˜€๐Ÿ™‚")); } - - SECTION("Contains end") { REQUIRE(a.contains(U"๐Ÿ˜€๐Ÿ˜")); } - - SECTION("Does not contain") { REQUIRE_FALSE(a.contains(U"๐Ÿ˜๐Ÿ˜€")); } - - SECTION("Always contains empty") { REQUIRE(a.contains(U"")); } - - SECTION("Cannot contain if empty") { - a.clear(); - REQUIRE_FALSE(a.contains(U"๐Ÿ˜๐Ÿ™‚")); - } - - SECTION("Always contains if both empty") { - a.clear(); - REQUIRE(a.contains(U"")); - } - } - } - } - - SECTION("Replace") { - SECTION("Other string") { - SECTION("Replace code units") { - string a = "abcdefghij"; - - SECTION("Replace start") { - string b = "xxx"; - a.replace(a.begin(), a.begin() + 3, b); - REQUIRE(a == "xxxdefghij"); - } - - SECTION("Replace middle") { - string b = "xxx"; - a.replace(a.begin() + 3, a.begin() + 6, b); - REQUIRE(a == "abcxxxghij"); - } - - SECTION("Replace end") { - string b = "xxx"; - a.replace(a.begin() + 7, a.begin() + 10, b); - REQUIRE(a == "abcdefgxxx"); - } - } - - SECTION("Replace code points") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - - SECTION("Replace start") { - string b = "xxx"; - a.replace(a.begin_codepoint(), a.begin_codepoint() + 3, b); - REQUIRE(a == "xxx๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace middle") { - string b = "xxx"; - a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, b); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xxx๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace end") { - string b = "xxx"; - a.replace(a.begin_codepoint() + 4, a.begin_codepoint() + 6, b); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚xxx"); - } - } - - SECTION("Replace code units with substr") { - string a = "abcdefghij"; - - SECTION("Replace with suffix") { - string b = "123"; - a.replace(3, 3, b, 1); - REQUIRE(a == "abc23ghij"); - } - - SECTION("Replace with substr") { - string b = "123"; - a.replace(3, 3, b, 1, 1); - REQUIRE(a == "abc2ghij"); - } - - SECTION("Replace with code point suffix") { - string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.replace(3, 3, b, string::codepoint_index(2)); - REQUIRE(a == "abc๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜ghij"); - } - - SECTION("Replace with code point substr") { - string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.replace(3, 3, b, string::codepoint_index(2), string::codepoint_index(2)); - REQUIRE(a == "abc๐Ÿ˜€๐Ÿ™‚ghij"); - } - } - - SECTION("Replace code points with substr") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - - SECTION("Replace with suffix") { - string b = "123"; - a.replace(string::codepoint_index(2), string::codepoint_index(2), b, 1); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚23๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace with substr") { - string b = "123"; - a.replace(string::codepoint_index(2), string::codepoint_index(2), b, 1, 1); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚2๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace with code point suffix") { - string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.replace(string::codepoint_index(2), string::codepoint_index(2), b, string::codepoint_index(2)); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace with code point substr") { - string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - a.replace(string::codepoint_index(2), string::codepoint_index(2), b, string::codepoint_index(2), - string::codepoint_index(2)); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("Iterators") { - SECTION("Code units iterator") { - string a = "abcdefghij"; - SECTION("Rhs is smaller") { - string b = "123"; - a.replace(a.begin() + 3, a.begin() + 5, b.begin() + 1, b.begin() + 2); - REQUIRE(a == "abc2fghij"); - } - - SECTION("Rhs is same size") { - string b = "123"; - a.replace(a.begin() + 3, a.begin() + 5, b.begin() + 1, b.begin() + 3); - REQUIRE(a == "abc23fghij"); - } - - SECTION("Rhs is larger") { - string b = "123"; - a.replace(a.begin() + 3, a.begin() + 5, b.begin() + 0, b.begin() + 3); - REQUIRE(a == "abc123fghij"); - } - } - - SECTION("Code point iterator") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - SECTION("Rhs is smaller") { - string b = "๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ"; - a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, b.begin_codepoint() + 1, - b.begin_codepoint() + 2); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™ƒ๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Rhs is same size") { - string b = "๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ"; - a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, b.begin_codepoint() + 1, - b.begin_codepoint() + 3); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Rhs is larger") { - string b = "๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ"; - a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, b.begin_codepoint() + 1, - b.begin_codepoint() + 4); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("String literal") { - SECTION("Replace code unit indexes") { - string a = "abcdefghij"; - - SECTION("Replace start") { - a.replace(0, 0 + 3, "xxx"); - REQUIRE(a == "xxxdefghij"); - } - - SECTION("Replace middle") { - a.replace(3, 3, "xxx"); - REQUIRE(a == "abcxxxghij"); - } - - SECTION("Replace end") { - a.replace(7, 3, "xxx"); - REQUIRE(a == "abcdefgxxx"); - } - } - - SECTION("Replace code unit indexes with substr") { - string a = "abcdefghij"; - - SECTION("Replace start") { - a.replace(0, 0 + 3, "xxx", 2); - REQUIRE(a == "xxdefghij"); - } - - SECTION("Replace middle") { - a.replace(3, 3, "xxx", 2); - REQUIRE(a == "abcxxghij"); - } - - SECTION("Replace end") { - a.replace(7, 3, "xxx", 2); - REQUIRE(a == "abcdefgxx"); - } - } - - SECTION("Replace code point indexes") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - - SECTION("Replace start") { - a.replace(string::codepoint_index(0), string::codepoint_index(3), U"๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ"); - REQUIRE(a == "๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace middle") { - a.replace(string::codepoint_index(2), string::codepoint_index(2), U"๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ"); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace end") { - a.replace(string::codepoint_index(4), string::codepoint_index(2), U"๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ"); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ"); - } - } - - SECTION("Replace code point indexes with substr") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - - SECTION("Replace start") { - a.replace(string::codepoint_index(0), string::codepoint_index(2), U"๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ", 2); - REQUIRE(a == "๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace middle") { - a.replace(string::codepoint_index(2), string::codepoint_index(2), U"๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ", 2); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace end") { - a.replace(string::codepoint_index(4), string::codepoint_index(2), U"๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ", 2); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ™ƒ๐Ÿ™ƒ"); - } - } - - SECTION("Replace code units iterators") { - string a = "abcdefghij"; - - SECTION("Replace start") { - a.replace(a.begin(), a.begin() + 3, "xxx"); - REQUIRE(a == "xxxdefghij"); - } - - SECTION("Replace middle") { - a.replace(a.begin() + 3, a.begin() + 6, "xxx"); - REQUIRE(a == "abcxxxghij"); - } - - SECTION("Replace end") { - a.replace(a.begin() + 7, a.begin() + 10, "xxx"); - REQUIRE(a == "abcdefgxxx"); - } - } - - SECTION("Replace code units iterators with substr") { - string a = "abcdefghij"; - - SECTION("Replace start") { - a.replace(a.begin(), a.begin() + 3, "xxx", 2); - REQUIRE(a == "xxdefghij"); - } - - SECTION("Replace middle") { - a.replace(a.begin() + 3, a.begin() + 6, "xxx", 2); - REQUIRE(a == "abcxxghij"); - } - - SECTION("Replace end") { - a.replace(a.begin() + 7, a.begin() + 10, "xxx", 2); - REQUIRE(a == "abcdefgxx"); - } - } - - SECTION("Replace code points") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - - SECTION("Replace start") { - a.replace(a.begin_codepoint(), a.begin_codepoint() + 3, "xxx"); - REQUIRE(a == "xxx๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace middle") { - a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, "xxx"); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xxx๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace end") { - a.replace(a.begin_codepoint() + 4, a.begin_codepoint() + 6, "xxx"); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚xxx"); - } - } - - SECTION("Replace code points with substr") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - - SECTION("Replace start") { - a.replace(a.begin_codepoint(), a.begin_codepoint() + 3, "xxx", 2); - REQUIRE(a == "xx๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace middle") { - a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, "xxx", 2); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xx๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace end") { - a.replace(a.begin_codepoint() + 4, a.begin_codepoint() + 6, "xxx", 2); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚xx"); - } - } - - SECTION("Replace code units with substr") { - string a = "abcdefghij"; - - SECTION("Replace with suffix") { - a.replace(3, 3, "123", 1); - REQUIRE(a == "abc1ghij"); - } - - SECTION("Replace with substr") { - a.replace(3, 3, "123", 1, 1); - REQUIRE(a == "abc2ghij"); - } - - SECTION("Replace with code point suffix") { - a.replace(3, 3, "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜", 8); - REQUIRE(a == "abc๐Ÿ˜๐Ÿ™‚ghij"); - } - - SECTION("Replace with code point substr") { - a.replace(3, 3, "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜", 8, 8); - REQUIRE(a == "abc๐Ÿ˜€๐Ÿ™‚ghij"); - } - } - - SECTION("Replace code points with substr") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - - SECTION("Replace with suffix") { - a.replace(string::codepoint_index(2), string::codepoint_index(2), "123", 1); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚1๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace with substr") { - a.replace(string::codepoint_index(2), string::codepoint_index(2), "123", 1, 1); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚2๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace with code point suffix") { - a.replace(string::codepoint_index(2), string::codepoint_index(2), "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜", 8); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace with code point substr") { - a.replace(string::codepoint_index(2), string::codepoint_index(2), "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜", 8, 8); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("Char") { - SECTION("Replace code unit indexes") { - string a = "abcdefghij"; - - SECTION("Smaller") { - a.replace(3, 2, 1, 'x'); - REQUIRE(a == "abcxfghij"); - } - - SECTION("Same size") { - a.replace(3, 2, 2, 'x'); - REQUIRE(a == "abcxxfghij"); - } - - SECTION("Larger") { - a.replace(3, 2, 3, 'x'); - REQUIRE(a == "abcxxxfghij"); - } - - SECTION("Wide char") { - a.replace(3, 2, 1, U'๐Ÿ˜€'); - REQUIRE(a == "abc๐Ÿ˜€fghij"); - } - - SECTION("Wide char twice") { - a.replace(3, 2, 2, U'๐Ÿ˜€'); - REQUIRE(a == "abc๐Ÿ˜€๐Ÿ˜€fghij"); - } - - SECTION("Wide char 3x") { - a.replace(3, 2, 3, U'๐Ÿ˜€'); - REQUIRE(a == "abc๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€fghij"); - } - } - - SECTION("Replace code point indexes") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - - SECTION("Smaller") { - a.replace(string::codepoint_index(2), string::codepoint_index(2), 1, 'x'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚x๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Same size") { - a.replace(string::codepoint_index(2), string::codepoint_index(2), 2, 'x'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xx๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Larger") { - a.replace(string::codepoint_index(2), string::codepoint_index(2), 3, 'x'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xxx๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Wide char") { - a.replace(string::codepoint_index(2), string::codepoint_index(2), 1, U'๐Ÿ˜€'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Wide char twice") { - a.replace(string::codepoint_index(2), string::codepoint_index(2), 2, U'๐Ÿ˜€'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Wide char 3x") { - a.replace(string::codepoint_index(2), string::codepoint_index(2), 3, U'๐Ÿ˜€'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); - } - } - - SECTION("Replace code unit iterators") { - string a = "abcdefghij"; - - SECTION("Smaller") { - a.replace(a.begin() + 3, a.begin() + 3 + 2, 1, 'x'); - REQUIRE(a == "abcxfghij"); - } - - SECTION("Same size") { - a.replace(a.begin() + 3, a.begin() + 3 + 2, 2, 'x'); - REQUIRE(a == "abcxxfghij"); - } - - SECTION("Larger") { - a.replace(a.begin() + 3, a.begin() + 3 + 2, 3, 'x'); - REQUIRE(a == "abcxxxfghij"); - } - - SECTION("Wide char") { - a.replace(a.begin() + 3, a.begin() + 3 + 2, 1, U'๐Ÿ˜€'); - REQUIRE(a == "abc๐Ÿ˜€fghij"); - } - - SECTION("Wide char twice") { - a.replace(a.begin() + 3, a.begin() + 3 + 2, 2, U'๐Ÿ˜€'); - REQUIRE(a == "abc๐Ÿ˜€๐Ÿ˜€fghij"); - } - - SECTION("Wide char 3x") { - a.replace(a.begin() + 3, a.begin() + 3 + 2, 3, U'๐Ÿ˜€'); - REQUIRE(a == "abc๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€fghij"); - } - } - - SECTION("Replace code point iterators") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - - SECTION("Smaller") { - a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 2 + 2, 1, 'x'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚x๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Same size") { - a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 2 + 2, 2, 'x'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xx๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Larger") { - a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 2 + 2, 3, 'x'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xxx๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Wide char") { - a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 2 + 2, 1, U'๐Ÿ˜€'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Wide char twice") { - a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 2 + 2, 2, U'๐Ÿ˜€'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Wide char 3x") { - a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 2 + 2, 3, U'๐Ÿ˜€'); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("Initializer list") { - SECTION("Replace code unit iterators") { - string a = "abcdefghij"; - - SECTION("Replace start") { - a.replace(a.begin(), a.begin() + 3, {'x', 'x', 'x'}); - REQUIRE(a == "xxxdefghij"); - } - - SECTION("Replace middle") { - a.replace(a.begin() + 3, a.begin() + 6, {'x', 'x', 'x'}); - REQUIRE(a == "abcxxxghij"); - } - - SECTION("Replace end") { - a.replace(a.begin() + 7, a.begin() + 10, {'x', 'x', 'x'}); - REQUIRE(a == "abcdefgxxx"); - } - } - - SECTION("Replace code point iterators") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - - SECTION("Replace start") { - a.replace(a.begin_codepoint(), a.begin_codepoint() + 3, {'x', 'x', 'x'}); - REQUIRE(a == "xxx๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace middle") { - a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, {'x', 'x', 'x'}); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xxx๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace end") { - a.replace(a.begin_codepoint() + 4, a.begin_codepoint() + 6, {'x', 'x', 'x'}); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚xxx"); - } - } - } - - SECTION("String view") { - SECTION("Replace code unit indexes") { - string a = "abcdefghij"; - - SECTION("Replace start") { - std::string_view b = "xxx"; - a.replace(0, 3, b); - REQUIRE(a == "xxxdefghij"); - } - - SECTION("Replace middle") { - std::string_view b = "xxx"; - a.replace(3, 3, b); - REQUIRE(a == "abcxxxghij"); - } - - SECTION("Replace end") { - std::string_view b = "xxx"; - a.replace(7, 3, b); - REQUIRE(a == "abcdefgxxx"); - } - } - - SECTION("Replace code point indexes") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - - SECTION("Replace start") { - std::string_view b = "xxx"; - a.replace(string::codepoint_index(0), string::codepoint_index(3), b); - REQUIRE(a == "xxx๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace middle") { - std::string_view b = "xxx"; - a.replace(string::codepoint_index(2), string::codepoint_index(2), b); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xxx๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace end") { - std::string_view b = "xxx"; - a.replace(string::codepoint_index(4), string::codepoint_index(2), b); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚xxx"); - } - } - - SECTION("Replace code unit iterators") { - string a = "abcdefghij"; - - SECTION("Replace start") { - std::string_view b = "xxx"; - a.replace(a.begin(), a.begin() + 3, b); - REQUIRE(a == "xxxdefghij"); - } - - SECTION("Replace middle") { - std::string_view b = "xxx"; - a.replace(a.begin() + 3, a.begin() + 6, b); - REQUIRE(a == "abcxxxghij"); - } - - SECTION("Replace end") { - std::string_view b = "xxx"; - a.replace(a.begin() + 7, a.begin() + 10, b); - REQUIRE(a == "abcdefgxxx"); - } - } - - SECTION("Replace code point iterators") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - - SECTION("Replace start") { - std::string_view b = "xxx"; - a.replace(a.begin_codepoint(), a.begin_codepoint() + 3, b); - REQUIRE(a == "xxx๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace middle") { - std::string_view b = "xxx"; - a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, b); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xxx๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace end") { - std::string_view b = "xxx"; - a.replace(a.begin_codepoint() + 4, a.begin_codepoint() + 6, b); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚xxx"); - } - } - - SECTION("Replace code unit indexes with substr") { - string a = "abcdefghij"; - - SECTION("Replace start") { - std::string_view b = "xxx"; - a.replace(0, 3, b, 1); - REQUIRE(a == "xxdefghij"); - } - - SECTION("Replace middle") { - std::string_view b = "xxx"; - a.replace(3, 3, b, 1); - REQUIRE(a == "abcxxghij"); - } - - SECTION("Replace end") { - std::string_view b = "xxx"; - a.replace(7, 3, b, 1); - REQUIRE(a == "abcdefgxx"); - } - } - - SECTION("Replace code point indexes with substr") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - - SECTION("Replace start") { - std::string_view b = "xxx"; - a.replace(string::codepoint_index(0), string::codepoint_index(3), b, 1); - REQUIRE(a == "xx๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace middle") { - std::string_view b = "xxx"; - a.replace(string::codepoint_index(2), string::codepoint_index(2), b, 1); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xx๐Ÿ˜€๐Ÿ˜"); - } - - SECTION("Replace end") { - std::string_view b = "xxx"; - a.replace(string::codepoint_index(4), string::codepoint_index(2), b, 1); - REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚xx"); - } - } - } - } - - SECTION("Substr") { - SECTION("Code unit") { - string a = "abcdefghij"; - - SECTION("Start") { - string b = a.substr(0, 3); - REQUIRE(b == "abc"); - } - - SECTION("Middle") { - string b = a.substr(3, 3); - REQUIRE(b == "def"); - } - - SECTION("End") { - string b = a.substr(6, 4); - REQUIRE(b == "ghij"); - } - } - - SECTION("Code point") { - string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; - SECTION("Start") { - string b = a.substr(string::codepoint_index(0), string::codepoint_index(2)); - REQUIRE(b == "๐Ÿ˜๐Ÿ™‚"); - } - - SECTION("Middle") { - string b = a.substr(string::codepoint_index(2), string::codepoint_index(2)); - REQUIRE(b == "๐Ÿ˜€๐Ÿ™‚"); - } - - SECTION("End") { - string b = a.substr(string::codepoint_index(4), string::codepoint_index(2)); - REQUIRE(b == "๐Ÿ˜€๐Ÿ˜"); - } - } - } - - SECTION("Copy") { - SECTION("To UTF8") { - SECTION("Copy count") { - string a("abcdefghij"); - char b[7]{}; - a.copy(b, sizeof b); - REQUIRE(std::string_view(b, 7) == "abcdefg"); - } - - SECTION("From pos") { - string a("abcdefghij"); - char b[7]{}; - a.copy(b, sizeof b, 3); - REQUIRE(std::string_view(b, 7) == "defghij"); - } - } - - SECTION("To UTF32") { - SECTION("Copy count") { - string a("๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - utf32_char_type b[7]{}; - a.copy(b, string::codepoint_index(7)); - REQUIRE(std::u32string_view(b, 7) == U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜"); - } - - SECTION("From pos") { - string a("๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); - utf32_char_type b[7]{}; - a.copy(b, string::codepoint_index(7), string::codepoint_index(3)); - REQUIRE(std::u32string_view(b, 7) == U"๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚"); - } - } - } - - SECTION("Swap") { - string a = "abc"; - string b = "def"; - SECTION("Member") { - a.swap(b); - REQUIRE(b == "abc"); - REQUIRE(a == "def"); - } - - SECTION("Non-member") { - swap(a, b); - REQUIRE(b == "abc"); - REQUIRE(a == "def"); - } - - SECTION("Std swap") { - std::swap(a, b); - REQUIRE(b == "abc"); - REQUIRE(a == "def"); - } - } - - SECTION("Search") { - SECTION("Codeunit / Codepoint convert") { - string a = "๐Ÿ˜a๐Ÿ˜€b๐Ÿ˜€c๐Ÿ˜d๐Ÿ˜€e๐Ÿ˜€f"; - auto cu_it = a.find_codeunit(string::codepoint_index(5)); - REQUIRE(*cu_it == 'c'); - auto cp_it = a.find_codepoint(10); - REQUIRE(*cp_it == U'๐Ÿ˜€'); - } - - SECTION("Find first substring") { - SECTION("Same encoding") { - string a = "abcdefghij"; - - SECTION("Other string") { - string b = "def"; - REQUIRE(a.find(b) == 3); - REQUIRE(a.find(b, 3) == 3); - REQUIRE(a.find(b, 4) == string::npos); - } - - SECTION("Literal string") { - REQUIRE(a.find("def") == 3); - REQUIRE(a.find("def", 3) == 3); - REQUIRE(a.find("def", 4) == string::npos); - } - - SECTION("Literal substring") { - REQUIRE(a.find("defzxc", 0, 3) == 3); - REQUIRE(a.find("defzxc", 3, 3) == 3); - REQUIRE(a.find("defzxc", 4, 3) == string::npos); - } - - SECTION("Char") { - REQUIRE(a.find('d', 0) == 3); - REQUIRE(a.find('d', 3) == 3); - REQUIRE(a.find('d', 4) == string::npos); - } - - SECTION("String view") { - REQUIRE(a.find(std::string_view("def"), 0) == 3); - REQUIRE(a.find(std::string_view("def"), 3) == 3); - REQUIRE(a.find(std::string_view("def"), 4) == string::npos); - } - } - - SECTION("Different encoding") { - string a = "๐Ÿ˜a๐Ÿ˜€b๐Ÿ˜€c๐Ÿ˜d๐Ÿ˜€e๐Ÿ˜€f"; - - SECTION("Other string") { - string b = "๐Ÿ˜€c๐Ÿ˜"; - REQUIRE(a.find(b) == 10); - REQUIRE(a.find(b, 10) == 10); - REQUIRE(a.find(b, 14) == string::npos); - } - - SECTION("Literal string") { - REQUIRE(a.find(U"๐Ÿ˜€c๐Ÿ˜") == 10); - REQUIRE(a.find(U"๐Ÿ˜€c๐Ÿ˜", 10) == 10); - REQUIRE(a.find(U"๐Ÿ˜€c๐Ÿ˜", 14) == string::npos); - } - - SECTION("Literal substring") { - REQUIRE(a.find(U"๐Ÿ˜€c๐Ÿ˜zxc", 0, 3) == 10); - REQUIRE(a.find(U"๐Ÿ˜€c๐Ÿ˜zxc", 10, 3) == 10); - REQUIRE(a.find(U"๐Ÿ˜€c๐Ÿ˜zxc", 14, 3) == string::npos); - } - - SECTION("Char") { - REQUIRE(a.find(U'๐Ÿ˜€', 0) == 5); - REQUIRE(a.find(U'๐Ÿ˜€', 10) == 10); - REQUIRE(a.find(U'๐Ÿ˜', 19) == string::npos); // <- idx 19 / value d / cp_idx 7 - } - - SECTION("String view") { - REQUIRE(a.find(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 0) == 10); - REQUIRE(a.find(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 10) == 10); - REQUIRE(a.find(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 14) == string::npos); - } - } - } - - SECTION("Find last substring") { - SECTION("Same encoding") { - string a = "abcdefghij"; - - SECTION("Other string") { - string b = "def"; - REQUIRE(a.rfind(b) == 3); - REQUIRE(a.rfind(b, 3) == 3); - REQUIRE(a.rfind(b, 4) == 3); - REQUIRE(a.rfind(b, 2) == string::npos); - } - - SECTION("Literal string") { - REQUIRE(a.rfind("def") == 3); - REQUIRE(a.rfind("def", 3) == 3); - REQUIRE(a.rfind("def", 4) == 3); - REQUIRE(a.rfind("def", 2) == string::npos); - } - - SECTION("Literal substring") { - REQUIRE(a.rfind("defzxc", 0, 3) == string::npos); - REQUIRE(a.rfind("defzxc", 3, 3) == 3); - REQUIRE(a.rfind("defzxc", 4, 3) == 3); - REQUIRE(a.rfind("defzxc", 2, 3) == string::npos); - } - - SECTION("Char") { - REQUIRE(a.rfind('d', 0) == string::npos); - REQUIRE(a.rfind('d', 3) == 3); - REQUIRE(a.rfind('d', 4) == 3); - REQUIRE(a.rfind('d', 2) == string::npos); - } - - SECTION("String view") { - REQUIRE(a.rfind(std::string_view("def"), 0) == string::npos); - REQUIRE(a.rfind(std::string_view("def"), 3) == 3); - REQUIRE(a.rfind(std::string_view("def"), 4) == 3); - REQUIRE(a.rfind(std::string_view("def"), 2) == string::npos); - } - } - - SECTION("Different encoding") { - string a = "๐Ÿ˜a๐Ÿ˜€b๐Ÿ˜€c๐Ÿ˜d๐Ÿ˜€e๐Ÿ˜€f"; - - SECTION("Other string") { - string b = "๐Ÿ˜€c๐Ÿ˜"; - REQUIRE(a.rfind(b) == 10); - REQUIRE(a.rfind(b, 10) == 10); - REQUIRE(a.rfind(b, 9) == string::npos); - } - - SECTION("Literal string") { - REQUIRE(a.rfind(U"๐Ÿ˜€c๐Ÿ˜") == 10); - REQUIRE(a.rfind(U"๐Ÿ˜€c๐Ÿ˜", 10) == 10); - REQUIRE(a.rfind(U"๐Ÿ˜€c๐Ÿ˜", 9) == string::npos); - } - - SECTION("Literal substring") { - REQUIRE(a.rfind(U"๐Ÿ˜€c๐Ÿ˜zxc", 14, 3) == 10); - REQUIRE(a.rfind(U"๐Ÿ˜€c๐Ÿ˜zxc", 10, 3) == 10); - REQUIRE(a.rfind(U"๐Ÿ˜€c๐Ÿ˜zxc", 9, 3) == string::npos); - } - - SECTION("Char") { - REQUIRE(a.rfind(U'๐Ÿ˜€', 19) == 10); - REQUIRE(a.rfind(U'๐Ÿ˜€', 10) == 10); - REQUIRE(a.rfind(U'๐Ÿ˜€', 9) == 5); - REQUIRE(a.rfind(U'๐Ÿ˜€', 0) == string::npos); - } - - SECTION("String view") { - REQUIRE(a.rfind(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 14) == 10); - REQUIRE(a.rfind(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 10) == 10); - REQUIRE(a.rfind(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 0) == string::npos); - } - } - } - - SECTION("Find first of chars") { - SECTION("Same encoding") { - string a = "abcdefghij"; - - SECTION("Other string") { - string b = "fed"; - REQUIRE(a.find_first_of(b) == 3); - REQUIRE(a.find_first_of(b, 3) == 3); - REQUIRE(a.find_first_of(b, 6) == string::npos); - } - - SECTION("Literal string") { - REQUIRE(a.find_first_of("fed") == 3); - REQUIRE(a.find_first_of("fed", 3) == 3); - REQUIRE(a.find_first_of("fed", 6) == string::npos); - } - - SECTION("Literal substring") { - REQUIRE(a.find_first_of("fedzxc", 0, 3) == 3); - REQUIRE(a.find_first_of("fedzxc", 3, 3) == 3); - REQUIRE(a.find_first_of("fedzxc", 6, 3) == string::npos); - } - - SECTION("Char") { - REQUIRE(a.find_first_of('e', 0) == 4); - REQUIRE(a.find_first_of('e', 3) == 4); - REQUIRE(a.find_first_of('e', 6) == string::npos); - } - - SECTION("String view") { - REQUIRE(a.find_first_of(std::string_view("fed"), 0) == 3); - REQUIRE(a.find_first_of(std::string_view("fed"), 3) == 3); - REQUIRE(a.find_first_of(std::string_view("fed"), 6) == string::npos); - } - } - - SECTION("Different encoding") { - string a = "๐Ÿ˜a๐Ÿ˜€b๐Ÿ˜€c๐Ÿ˜d๐Ÿ˜€e๐Ÿ˜€f"; - - SECTION("Other string") { - std::u32string b = U"๐Ÿ˜€c๐Ÿ˜"; - REQUIRE(a.find_first_of(b) == 0); - REQUIRE(a.find_first_of(b, 10) == 10); - REQUIRE(a.find_first_of(b, 26) == string::npos); - } - - SECTION("Literal string") { - REQUIRE(a.find_first_of(U"๐Ÿ˜€c๐Ÿ˜") == 0); - REQUIRE(a.find_first_of(U"๐Ÿ˜€c๐Ÿ˜", 10) == 10); - REQUIRE(a.find_first_of(U"๐Ÿ˜€c๐Ÿ˜", 26) == string::npos); - } - - SECTION("Literal substring") { - REQUIRE(a.find_first_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 0, 3) == 0); - REQUIRE(a.find_first_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 10, 3) == 10); - REQUIRE(a.find_first_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 26, 3) == string::npos); - } - - SECTION("Char") { - REQUIRE(a.find_first_of(U'๐Ÿ˜€', 0) == 5); - REQUIRE(a.find_first_of(U'๐Ÿ˜€', 10) == 10); - REQUIRE(a.find_first_of(U'๐Ÿ˜', 26) == string::npos); - } - - SECTION("String view") { - REQUIRE(a.find_first_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 0) == 0); - REQUIRE(a.find_first_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 10) == 10); - REQUIRE(a.find_first_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 26) == string::npos); - } - } - } - - SECTION("Find first not of chars") { - SECTION("Same encoding") { - string a = "abcdefghij"; - - SECTION("Other string") { - string b = "fed"; - REQUIRE(a.find_first_not_of(b) == 0); - REQUIRE(a.find_first_not_of(b, 3) == 6); - REQUIRE(a.find_first_not_of(b, 11) == string::npos); - } - - SECTION("Literal string") { - REQUIRE(a.find_first_not_of("fed") == 0); - REQUIRE(a.find_first_not_of("fed", 3) == 6); - REQUIRE(a.find_first_not_of("fed", 11) == string::npos); - } - - SECTION("Literal substring") { - REQUIRE(a.find_first_not_of("fedzxc", 0, 3) == 0); - REQUIRE(a.find_first_not_of("fedzxc", 3, 3) == 6); - REQUIRE(a.find_first_not_of("fedzxc", 11, 3) == string::npos); - } - - SECTION("Char") { - REQUIRE(a.find_first_not_of('e', 0) == 0); - REQUIRE(a.find_first_not_of('e', 3) == 3); - REQUIRE(a.find_first_not_of('e', 4) == 5); - REQUIRE(a.find_first_not_of('e', 11) == string::npos); - } - - SECTION("String view") { - REQUIRE(a.find_first_not_of(std::string_view("fed"), 0) == 0); - REQUIRE(a.find_first_not_of(std::string_view("fed"), 3) == 6); - REQUIRE(a.find_first_not_of(std::string_view("fed"), 11) == string::npos); - } - } - - SECTION("Different encoding") { - string a = "๐Ÿ˜a๐Ÿ˜€b๐Ÿ˜€c๐Ÿ˜d๐Ÿ˜€e๐Ÿ˜€f"; - - SECTION("Other string") { - std::u32string b = U"๐Ÿ˜€c๐Ÿ˜"; - REQUIRE(a.find_first_not_of(b) == 4); - REQUIRE(a.find_first_not_of(b, 10) == 19); - REQUIRE(a.find_first_not_of(b, 31) == string::npos); - } - - SECTION("Literal string") { - REQUIRE(a.find_first_not_of(U"๐Ÿ˜€c๐Ÿ˜") == 4); - REQUIRE(a.find_first_not_of(U"๐Ÿ˜€c๐Ÿ˜", 10) == 19); - REQUIRE(a.find_first_not_of(U"๐Ÿ˜€c๐Ÿ˜", 31) == string::npos); - } - - SECTION("Literal substring") { - REQUIRE(a.find_first_not_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 0, 3) == 4); - REQUIRE(a.find_first_not_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 10, 3) == 19); - REQUIRE(a.find_first_not_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 31, 3) == string::npos); - } - - SECTION("Char") { - REQUIRE(a.find_first_not_of(U'๐Ÿ˜€', 0) == 0); - REQUIRE(a.find_first_not_of(U'๐Ÿ˜€', 10) == 14); - REQUIRE(a.find_first_not_of(U'๐Ÿ˜', 31) == string::npos); - } - - SECTION("String view") { - REQUIRE(a.find_first_not_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 0) == 4); - REQUIRE(a.find_first_not_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 10) == 19); - REQUIRE(a.find_first_not_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 31) == string::npos); - } - } - } - - SECTION("Find last of chars") { - SECTION("Same encoding") { - string a = "abcdefghij"; - - SECTION("Other string") { - string b = "fed"; - REQUIRE(a.find_last_of(b) == 5); - REQUIRE(a.find_last_of(b, 3) == 3); - REQUIRE(a.find_last_of(b, 2) == string::npos); - } - - SECTION("Literal string") { - REQUIRE(a.find_last_of("fed") == 5); - REQUIRE(a.find_last_of("fed", 3) == 3); - REQUIRE(a.find_last_of("fed", 2) == string::npos); - } - - SECTION("Literal substring") { - REQUIRE(a.find_last_of("fedzxc", 6, 3) == 5); - REQUIRE(a.find_last_of("fedzxc", 3, 3) == 3); - REQUIRE(a.find_last_of("fedzxc", 2, 3) == string::npos); - } - - SECTION("Char") { - REQUIRE(a.find_last_of('e', 6) == 4); - REQUIRE(a.find_last_of('e', 4) == 4); - REQUIRE(a.find_last_of('e', 3) == string::npos); - } - - SECTION("String view") { - REQUIRE(a.find_last_of(std::string_view("fed"), 6) == 5); - REQUIRE(a.find_last_of(std::string_view("fed"), 3) == 3); - REQUIRE(a.find_last_of(std::string_view("fed"), 2) == string::npos); - } - } - - SECTION("Different encoding") { - string a = "๐Ÿ˜a๐Ÿ˜€b๐Ÿ˜€c๐Ÿ˜d๐Ÿ˜€e๐Ÿ˜€f"; - - SECTION("Other string") { - std::u32string b = U"๐Ÿ˜€c๐Ÿ˜"; - REQUIRE(a.find_last_of(b) == 25); - REQUIRE(a.find_last_of(b, 10) == 10); - REQUIRE(a.find_last_of(b, 0) == 0); - } - - SECTION("Literal string") { - REQUIRE(a.find_last_of(U"๐Ÿ˜€c๐Ÿ˜") == 25); - REQUIRE(a.find_last_of(U"๐Ÿ˜€c๐Ÿ˜", 10) == 10); - REQUIRE(a.find_last_of(U"๐Ÿ˜€c๐Ÿ˜", 0) == 0); - } - - SECTION("Literal substring") { - REQUIRE(a.find_last_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 0, 3) == 0); - REQUIRE(a.find_last_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 10, 3) == 10); - REQUIRE(a.find_last_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 26, 3) == 25); - } - - SECTION("Char") { - REQUIRE(a.find_last_of(U'๐Ÿ˜€', 0) == string::npos); - REQUIRE(a.find_last_of(U'๐Ÿ˜€', 10) == 10); - REQUIRE(a.find_last_of(U'๐Ÿ˜', 26) == 15); - } - - SECTION("String view") { - REQUIRE(a.find_last_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 26) == 25); - REQUIRE(a.find_last_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 10) == 10); - REQUIRE(a.find_last_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 0) == 0); - } - } - } - - SECTION("Find last not of chars") { - SECTION("Same encoding") { - string a = "abcdefghij"; - - SECTION("Other string") { - string b = "fed"; - REQUIRE(a.find_last_not_of(b) == 9); - REQUIRE(a.find_last_not_of(b, 3) == 2); - REQUIRE(a.find_last_not_of(b, 11) == 9); - } - - SECTION("Literal string") { - REQUIRE(a.find_last_not_of("fed") == 9); - REQUIRE(a.find_last_not_of("fed", 3) == 2); - REQUIRE(a.find_last_not_of("fed", 11) == 9); - } - - SECTION("Literal substring") { - REQUIRE(a.find_last_not_of("fedzxc", 0, 3) == 0); - REQUIRE(a.find_last_not_of("fedzxc", 3, 3) == 2); - REQUIRE(a.find_last_not_of("fedzxc", 11, 3) == 9); - } - - SECTION("Char") { - REQUIRE(a.find_last_not_of('e', 0) == 0); - REQUIRE(a.find_last_not_of('e', 3) == 3); - REQUIRE(a.find_last_not_of('e', 4) == 3); - REQUIRE(a.find_last_not_of('e', 11) == 9); - } - - SECTION("String view") { - REQUIRE(a.find_last_not_of(std::string_view("fed"), 0) == 0); - REQUIRE(a.find_last_not_of(std::string_view("fed"), 3) == 2); - REQUIRE(a.find_last_not_of(std::string_view("fed"), 11) == 9); - } - } - - SECTION("Different encoding") { - string a = "๐Ÿ˜a๐Ÿ˜€b๐Ÿ˜€c๐Ÿ˜d๐Ÿ˜€e๐Ÿ˜€f"; - - SECTION("Other string") { - std::u32string b = U"๐Ÿ˜€c๐Ÿ˜"; - REQUIRE(a.find_last_not_of(b) == 29); - REQUIRE(a.find_last_not_of(b, 10) == 9); - REQUIRE(a.find_last_not_of(b, 31) == 29); - } - - SECTION("Literal string") { - REQUIRE(a.find_last_not_of(U"๐Ÿ˜€c๐Ÿ˜") == 29); - REQUIRE(a.find_last_not_of(U"๐Ÿ˜€c๐Ÿ˜", 10) == 9); - REQUIRE(a.find_last_not_of(U"๐Ÿ˜€c๐Ÿ˜", 31) == 29); - } - - SECTION("Literal substring") { - REQUIRE(a.find_last_not_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 0, 3) == string::npos); - REQUIRE(a.find_last_not_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 10, 3) == 9); - REQUIRE(a.find_last_not_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 31, 3) == 29); - } - - SECTION("Char") { - REQUIRE(a.find_last_not_of(U'๐Ÿ˜€', 0) == 0); - REQUIRE(a.find_last_not_of(U'๐Ÿ˜€', 10) == 9); - REQUIRE(a.find_last_not_of(U'๐Ÿ˜', 31) == 29); - } - - SECTION("String view") { - REQUIRE(a.find_last_not_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 0) == string::npos); - REQUIRE(a.find_last_not_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 10) == 9); - REQUIRE(a.find_last_not_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 31) == 29); - } - } - } - } - - SECTION("Non-member") { - SECTION("Concatenate strings") { - SECTION("const string & + const string &") { - string lhs = "abc"; - string rhs = "def"; - string c = lhs + rhs; - REQUIRE(c == "abcdef"); - } - SECTION("const string & + const char *") { - string lhs = "abc"; - string c = lhs + "def"; - REQUIRE(c == "abcdef"); - } - SECTION("const string & + char ") { - string lhs = "abc"; - char rhs = 'd'; - string c = lhs + rhs; - REQUIRE(c == "abcd"); - } - SECTION("const char * + const string &") { - string rhs = "def"; - string c = "abc" + rhs; - REQUIRE(c == "abcdef"); - } - SECTION("char + const string &") { - char lhs = 'a'; - string rhs = "def"; - string c = lhs + rhs; - REQUIRE(c == "adef"); - } - SECTION("string && + string &&") { - string lhs = "abc"; - string rhs = "def"; - string c = std::move(lhs) + std::move(rhs); - REQUIRE(c == "abcdef"); - } - SECTION("string && + const string &") { - string lhs = "abc"; - string rhs = "def"; - string c = std::move(lhs) + rhs; - REQUIRE(c == "abcdef"); - } - SECTION("string && + const char *") { - string lhs = "abc"; - string c = std::move(lhs) + "def"; - REQUIRE(c == "abcdef"); - } - SECTION("string && + char ") { - string lhs = "abc"; - char rhs = 'd'; - string c = std::move(lhs) + rhs; - REQUIRE(c == "abcd"); - } - SECTION("const string & + string &&") { - string lhs = "abc"; - string rhs = "def"; - string c = lhs + std::move(rhs); - REQUIRE(c == "abcdef"); - } - SECTION("const char * + string &&") { - string rhs = "def"; - string c = "abc" + std::move(rhs); - REQUIRE(c == "abcdef"); - } - SECTION("char + string &&") { - char lhs = 'a'; - string rhs = "def"; - string c = lhs + std::move(rhs); - REQUIRE(c == "adef"); - } - } - - SECTION("Erase") { - string cnt(10, ' '); - std::iota(cnt.begin(), cnt.end(), '0'); - - SECTION("Values") { - erase(cnt, '3'); - REQUIRE(cnt == "012456789"); - } - - SECTION("Condition") { - size_t n_erased = erase_if(cnt, [](char x) { return (x - '0') % 2 == 0; }); - REQUIRE(cnt == "13579"); - REQUIRE(n_erased == 5); - } - } - - SECTION("Streams") { - small::string a = "123456"; - - SECTION("Output") { - std::stringstream ss; - ss << a; - REQUIRE(ss.str() == "123456"); - } - - SECTION("Input") { - std::stringstream ss; - ss << "123"; - ss >> a; - REQUIRE(a == "123"); - } - - SECTION("Getline") { - std::stringstream ss; - ss << "123 456\n789\n"; - getline(ss, a); - REQUIRE(a == "123 456"); - } - } - - SECTION("String to number") { - SECTION("Integer") { - small::string i = "123"; - std::unique_ptr size = std::make_unique(0); - SECTION("stoi") { - int n = stoi(i, size.get(), 10); - REQUIRE(n == 123); - REQUIRE(*size == 3); - } - SECTION("stol") { - long n = stol(i, size.get(), 10); - REQUIRE(n == 123); - REQUIRE(*size == 3); - } - SECTION("stoll") { - long long n = stoll(i, size.get(), 10); - REQUIRE(n == 123); - REQUIRE(*size == 3); - } - SECTION("stoul") { - unsigned long n = stoul(i, size.get(), 10); - REQUIRE(n == 123); - REQUIRE(*size == 3); - } - SECTION("stoull") { - unsigned long long n = stoull(i, size.get(), 10); - REQUIRE(n == 123); - REQUIRE(*size == 3); - } - } - - SECTION("Floating") { - small::string d = "123.456"; - std::unique_ptr size = std::make_unique(0); - SECTION("stof") { - float n = stof(d, size.get()); - REQUIRE(n >= 123.455); - REQUIRE(n <= 123.457); - REQUIRE(*size == 7); - } - SECTION("stod") { - double n = stod(d, size.get()); - REQUIRE(n >= 123.455); - REQUIRE(n <= 123.457); - REQUIRE(*size == 7); - } - SECTION("stold") { - long double n = stold(d, size.get()); - REQUIRE(n >= 123.455); - REQUIRE(n <= 123.457); - REQUIRE(*size == 7); - } - } - } - - SECTION("Number to string") { - REQUIRE(small::to_string(static_cast(123)) == "123"); - REQUIRE(small::to_string(static_cast(123)) == "123"); - REQUIRE(small::to_string(static_cast(123)) == "123"); - REQUIRE(small::to_string(static_cast(123)) == "123"); - REQUIRE(small::to_string(static_cast(123)) == "123"); - REQUIRE(small::to_string(static_cast(123)) == "123"); - REQUIRE(small::to_string(static_cast(123)) == "123"); - REQUIRE(small::to_string(static_cast(123)) == "123"); - REQUIRE(small::to_string(static_cast(123)) == "123"); - } - - SECTION("Hash") { - SECTION("Isolated") { - std::hash hasher; - string a = "abc"; - REQUIRE_FALSE(hasher(a) == 0); - } - - SECTION("Hash table") { - std::unordered_set s; - s.insert("abc"); - s.insert("def"); - s.insert("ghi"); - REQUIRE(s.size() == 3); - } - } - - SECTION("Relocatable in inline vector") { - small::vector v(5); - v.emplace_back("new str"); - v.emplace(v.begin() + 3, "middle str"); - REQUIRE(v.size() == 7); - } - } -} \ No newline at end of file diff --git a/tests/unit_tests/small_string_access.cpp b/tests/unit_tests/small_string_access.cpp new file mode 100644 index 0000000..6ad67f1 --- /dev/null +++ b/tests/unit_tests/small_string_access.cpp @@ -0,0 +1,250 @@ +#ifndef SMALL_BUILD_TESTS_WITH_PCH +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#endif + +// UTF8 string literals are really not safe in MSVC. +// u8"" doesn't work properly even with escape sequences. +// More recent versions might improve on that a little, but we will still +// need a more robust solution to support older versions in any case. +// Until then, it seems like the most robust solution is to initialize +// small::strings with U"...", even if that requires converting the +// codepoints. +constexpr bool is_windows() { +#if defined(_WIN32) + return true; +#else + return false; +#endif +} + +TEST_CASE("String") { + using namespace small; + + SECTION("Element access") { + SECTION("At") { + string s = "123456"; + REQUIRE(s.at(0) == '1'); + REQUIRE(s.at(1) == '2'); + REQUIRE(s.at(2) == '3'); + REQUIRE(s.at(3) == '4'); + REQUIRE(s.at(4) == '5'); + REQUIRE(s.at(5) == '6'); + } + + using cp_index = string::codepoint_index; + + SECTION("At codepoint (through references)") { + SECTION("No unicode") { + string s = "123456"; + REQUIRE(s.at(cp_index(0)) == '1'); + REQUIRE(s.at(cp_index(1)) == '2'); + REQUIRE(s.at(cp_index(2)) == '3'); + REQUIRE(s.at(cp_index(3)) == '4'); + REQUIRE(s.at(cp_index(4)) == '5'); + REQUIRE(s.at(cp_index(5)) == '6'); + } + SECTION("Half unicode") { + string s = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; + REQUIRE(s.at(cp_index(0)) == '1'); + REQUIRE(s.at(cp_index(1)) == U'๐Ÿ˜€'); + REQUIRE(s.at(cp_index(2)) == '2'); + REQUIRE(s.at(cp_index(3)) == U'๐Ÿ˜€'); + REQUIRE(s.at(cp_index(4)) == '3'); + REQUIRE(s.at(cp_index(5)) == U'๐Ÿ˜€'); + REQUIRE(s.at(cp_index(0)) == "1"); + REQUIRE(s.at(cp_index(1)) == "๐Ÿ˜€"); + REQUIRE(s.at(cp_index(2)) == "2"); + REQUIRE(s.at(cp_index(3)) == "๐Ÿ˜€"); + REQUIRE(s.at(cp_index(4)) == "3"); + REQUIRE(s.at(cp_index(5)) == "๐Ÿ˜€"); + } + SECTION("Full unicode") { + string s = "๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"; + REQUIRE(s.at(cp_index(0)) == U'๐Ÿ™‚'); + REQUIRE(s.at(cp_index(1)) == U'๐Ÿ˜€'); + REQUIRE(s.at(cp_index(2)) == U'๐Ÿ™‚'); + REQUIRE(s.at(cp_index(3)) == U'๐Ÿ˜€'); + REQUIRE(s.at(cp_index(4)) == U'๐Ÿ™‚'); + REQUIRE(s.at(cp_index(5)) == U'๐Ÿ˜€'); + REQUIRE(s.at(cp_index(0)) == "๐Ÿ™‚"); + REQUIRE(s.at(cp_index(1)) == "๐Ÿ˜€"); + REQUIRE(s.at(cp_index(2)) == "๐Ÿ™‚"); + REQUIRE(s.at(cp_index(3)) == "๐Ÿ˜€"); + REQUIRE(s.at(cp_index(4)) == "๐Ÿ™‚"); + REQUIRE(s.at(cp_index(5)) == "๐Ÿ˜€"); + } + } + + SECTION("Subscript") { + string s = "123456"; + REQUIRE(s[0] == '1'); + REQUIRE(s[1] == '2'); + REQUIRE(s[2] == '3'); + REQUIRE(s[3] == '4'); + REQUIRE(s[4] == '5'); + REQUIRE(s[5] == '6'); + } + + SECTION("Subscript codepoint") { + string s = "123456"; + REQUIRE(s[cp_index(0)] == '1'); + REQUIRE(s[cp_index(1)] == '2'); + REQUIRE(s[cp_index(2)] == '3'); + REQUIRE(s[cp_index(3)] == '4'); + REQUIRE(s[cp_index(4)] == '5'); + REQUIRE(s[cp_index(5)] == '6'); + } + + SECTION("Subscript codepoint (direct values)") { + string s = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; + REQUIRE(s(cp_index(0)) == '1'); + REQUIRE(s(cp_index(1)) == U'๐Ÿ˜€'); + REQUIRE(s(cp_index(2)) == '2'); + REQUIRE(s(cp_index(3)) == U'๐Ÿ˜€'); + REQUIRE(s(cp_index(4)) == '3'); + REQUIRE(s(cp_index(5)) == U'๐Ÿ˜€'); + } + + SECTION("Subscript codepoint (through references)") { + string s = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; + REQUIRE(s[cp_index(0)] == '1'); + REQUIRE(s[cp_index(1)] == U'๐Ÿ˜€'); + REQUIRE(s[cp_index(2)] == '2'); + REQUIRE(s[cp_index(3)] == U'๐Ÿ˜€'); + REQUIRE(s[cp_index(4)] == '3'); + REQUIRE(s[cp_index(5)] == U'๐Ÿ˜€'); + } + + SECTION("Front/Back") { + string s = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€5"; + REQUIRE(s.front() == '1'); + REQUIRE(s.back() == '5'); + } + + SECTION("Front/Back Codepoints") { + string s = "๐Ÿ˜€1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€5๐Ÿ˜€"; + REQUIRE(s.front_codepoint() == U'๐Ÿ˜€'); + REQUIRE(s.back_codepoint() == U'๐Ÿ˜€'); + REQUIRE(s.front_codepoint() == "๐Ÿ˜€"); + REQUIRE(s.back_codepoint() == "๐Ÿ˜€"); + } + + SECTION("Data") { + string s = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€5"; + std::string_view sv(s.data(), s.size()); + REQUIRE(s == sv); + REQUIRE(s.data() == s.c_str()); + REQUIRE(s.operator std::string_view() == sv); + } + } + + SECTION("Iterators") { + SECTION("Byte Iterators") { + string a = "123"; + REQUIRE(a.begin() == a.data()); + REQUIRE(a.end() == a.data() + a.size()); + + REQUIRE(*a.begin() == '1'); + REQUIRE(*std::next(a.begin()) == '2'); + REQUIRE(*std::prev(a.end()) == '3'); + + REQUIRE(a.cbegin() == a.data()); + REQUIRE(a.cend() == a.data() + a.size()); + + REQUIRE(*a.cbegin() == '1'); + REQUIRE(*std::next(a.cbegin()) == '2'); + REQUIRE(*std::prev(a.cend()) == '3'); + + REQUIRE(*a.rbegin() == '3'); + REQUIRE(*std::next(a.rbegin()) == '2'); + REQUIRE(*std::prev(a.rend()) == '1'); + + REQUIRE(*a.crbegin() == '3'); + REQUIRE(*std::next(a.crbegin()) == '2'); + REQUIRE(*std::prev(a.crend()) == '1'); + } + + SECTION("Codepoint Iterators") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€"; + REQUIRE(static_cast(a.end_codepoint() - a.begin_codepoint()) == a.size_codepoints()); + + REQUIRE(*a.begin_codepoint() == U'๐Ÿ˜'); + REQUIRE(*std::next(a.begin_codepoint()) == U'๐Ÿ™‚'); + REQUIRE(*std::prev(a.end_codepoint()) == U'๐Ÿ˜€'); + + REQUIRE(*a.cbegin_codepoint() == a.front_codepoint()); + REQUIRE(*std::prev(a.cend_codepoint()) == a.back_codepoint()); + + REQUIRE(*a.cbegin_codepoint() == U'๐Ÿ˜'); + REQUIRE(*std::next(a.cbegin_codepoint()) == U'๐Ÿ™‚'); + REQUIRE(*std::prev(a.cend_codepoint()) == U'๐Ÿ˜€'); + + REQUIRE(*a.rbegin_codepoint() == U'๐Ÿ˜€'); + REQUIRE(*std::next(a.rbegin_codepoint()) == U'๐Ÿ™‚'); + REQUIRE(*std::prev(a.rend_codepoint()) == U'๐Ÿ˜'); + + REQUIRE(*a.crbegin_codepoint() == U'๐Ÿ˜€'); + REQUIRE(*std::next(a.crbegin_codepoint()) == U'๐Ÿ™‚'); + REQUIRE(*std::prev(a.crend_codepoint()) == U'๐Ÿ˜'); + } + } + + SECTION("Capacity") { + string a = U"1๐Ÿ˜€3"; + + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 6); + REQUIRE(a.size_codepoints() == 3); + REQUIRE(a.max_size() > 100000); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() >= 13); + REQUIRE(a.capacity() <= 15); + size_t old_cap = a.capacity(); + + a.reserve(10); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 6); + REQUIRE(a.size_codepoints() == 3); + REQUIRE(a.max_size() > 100000); + REQUIRE_FALSE(a.empty()); + size_t new_cap = a.capacity(); + REQUIRE(new_cap >= old_cap); + + a.reserve(20); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 6); + REQUIRE(a.size_codepoints() == 3); + REQUIRE(a.max_size() > 100000); + REQUIRE_FALSE(a.empty()); + new_cap = a.capacity(); + REQUIRE(new_cap > old_cap); + + a.shrink_to_fit(); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 6); + REQUIRE(a.size_codepoints() == 3); + REQUIRE(a.max_size() > 100000); + REQUIRE_FALSE(a.empty()); + new_cap = a.capacity(); + REQUIRE(new_cap >= 6); // larger than initial size but might not be inline anymore + + a = U"1๐Ÿ˜€3"; + a.shrink_to_fit(); + REQUIRE(a.size() == 6); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() >= a.size()); + REQUIRE_FALSE(is_malformed(a)); + } +} \ No newline at end of file diff --git a/tests/unit_tests/small_string_const_algorithms.cpp b/tests/unit_tests/small_string_const_algorithms.cpp new file mode 100644 index 0000000..af2e46c --- /dev/null +++ b/tests/unit_tests/small_string_const_algorithms.cpp @@ -0,0 +1,578 @@ +#ifndef SMALL_BUILD_TESTS_WITH_PCH +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#endif + +// UTF8 string literals are really not safe in MSVC. +// u8"" doesn't work properly even with escape sequences. +// More recent versions might improve on that a little, but we will still +// need a more robust solution to support older versions in any case. +// Until then, it seems like the most robust solution is to initialize +// small::strings with U"...", even if that requires converting the +// codepoints. +constexpr bool is_windows() { +#if defined(_WIN32) + return true; +#else + return false; +#endif +} + +TEST_CASE("String Const Algorithms") { + using namespace small; + + SECTION("Substr") { + SECTION("Code unit") { + string a = "abcdefghij"; + + SECTION("Start") { + string b = a.substr(0, 3); + REQUIRE(b == "abc"); + } + + SECTION("Middle") { + string b = a.substr(3, 3); + REQUIRE(b == "def"); + } + + SECTION("End") { + string b = a.substr(6, 4); + REQUIRE(b == "ghij"); + } + } + + SECTION("Code point") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + SECTION("Start") { + string b = a.substr(string::codepoint_index(0), string::codepoint_index(2)); + REQUIRE(b == "๐Ÿ˜๐Ÿ™‚"); + } + + SECTION("Middle") { + string b = a.substr(string::codepoint_index(2), string::codepoint_index(2)); + REQUIRE(b == "๐Ÿ˜€๐Ÿ™‚"); + } + + SECTION("End") { + string b = a.substr(string::codepoint_index(4), string::codepoint_index(2)); + REQUIRE(b == "๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("Copy") { + SECTION("To UTF8") { + SECTION("Copy count") { + string a("abcdefghij"); + char b[7]{}; + a.copy(b, sizeof b); + REQUIRE(std::string_view(b, 7) == "abcdefg"); + } + + SECTION("From pos") { + string a("abcdefghij"); + char b[7]{}; + a.copy(b, sizeof b, 3); + REQUIRE(std::string_view(b, 7) == "defghij"); + } + } + + SECTION("To UTF32") { + SECTION("Copy count") { + string a("๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + utf32_char_type b[7]{}; + a.copy(b, string::codepoint_index(7)); + REQUIRE(std::u32string_view(b, 7) == U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜"); + } + + SECTION("From pos") { + string a("๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + utf32_char_type b[7]{}; + a.copy(b, string::codepoint_index(7), string::codepoint_index(3)); + REQUIRE(std::u32string_view(b, 7) == U"๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚"); + } + } + } + + SECTION("Swap") { + string a = "abc"; + string b = "def"; + SECTION("Member") { + a.swap(b); + REQUIRE(b == "abc"); + REQUIRE(a == "def"); + } + + SECTION("Non-member") { + swap(a, b); + REQUIRE(b == "abc"); + REQUIRE(a == "def"); + } + + SECTION("Std swap") { + std::swap(a, b); + REQUIRE(b == "abc"); + REQUIRE(a == "def"); + } + } + + SECTION("Search") { + SECTION("Codeunit / Codepoint convert") { + string a = "๐Ÿ˜a๐Ÿ˜€b๐Ÿ˜€c๐Ÿ˜d๐Ÿ˜€e๐Ÿ˜€f"; + auto cu_it = a.find_codeunit(string::codepoint_index(5)); + REQUIRE(*cu_it == 'c'); + auto cp_it = a.find_codepoint(10); + REQUIRE(*cp_it == U'๐Ÿ˜€'); + } + + SECTION("Find first substring") { + SECTION("Same encoding") { + string a = "abcdefghij"; + + SECTION("Other string") { + string b = "def"; + REQUIRE(a.find(b) == 3); + REQUIRE(a.find(b, 3) == 3); + REQUIRE(a.find(b, 4) == string::npos); + } + + SECTION("Literal string") { + REQUIRE(a.find("def") == 3); + REQUIRE(a.find("def", 3) == 3); + REQUIRE(a.find("def", 4) == string::npos); + } + + SECTION("Literal substring") { + REQUIRE(a.find("defzxc", 0, 3) == 3); + REQUIRE(a.find("defzxc", 3, 3) == 3); + REQUIRE(a.find("defzxc", 4, 3) == string::npos); + } + + SECTION("Char") { + REQUIRE(a.find('d', 0) == 3); + REQUIRE(a.find('d', 3) == 3); + REQUIRE(a.find('d', 4) == string::npos); + } + + SECTION("String view") { + REQUIRE(a.find(std::string_view("def"), 0) == 3); + REQUIRE(a.find(std::string_view("def"), 3) == 3); + REQUIRE(a.find(std::string_view("def"), 4) == string::npos); + } + } + + SECTION("Different encoding") { + string a = "๐Ÿ˜a๐Ÿ˜€b๐Ÿ˜€c๐Ÿ˜d๐Ÿ˜€e๐Ÿ˜€f"; + + SECTION("Other string") { + string b = "๐Ÿ˜€c๐Ÿ˜"; + REQUIRE(a.find(b) == 10); + REQUIRE(a.find(b, 10) == 10); + REQUIRE(a.find(b, 14) == string::npos); + } + + SECTION("Literal string") { + REQUIRE(a.find(U"๐Ÿ˜€c๐Ÿ˜") == 10); + REQUIRE(a.find(U"๐Ÿ˜€c๐Ÿ˜", 10) == 10); + REQUIRE(a.find(U"๐Ÿ˜€c๐Ÿ˜", 14) == string::npos); + } + + SECTION("Literal substring") { + REQUIRE(a.find(U"๐Ÿ˜€c๐Ÿ˜zxc", 0, 3) == 10); + REQUIRE(a.find(U"๐Ÿ˜€c๐Ÿ˜zxc", 10, 3) == 10); + REQUIRE(a.find(U"๐Ÿ˜€c๐Ÿ˜zxc", 14, 3) == string::npos); + } + + SECTION("Char") { + REQUIRE(a.find(U'๐Ÿ˜€', 0) == 5); + REQUIRE(a.find(U'๐Ÿ˜€', 10) == 10); + REQUIRE(a.find(U'๐Ÿ˜', 19) == string::npos); // <- idx 19 / value d / cp_idx 7 + } + + SECTION("String view") { + REQUIRE(a.find(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 0) == 10); + REQUIRE(a.find(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 10) == 10); + REQUIRE(a.find(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 14) == string::npos); + } + } + } + + SECTION("Find last substring") { + SECTION("Same encoding") { + string a = "abcdefghij"; + + SECTION("Other string") { + string b = "def"; + REQUIRE(a.rfind(b) == 3); + REQUIRE(a.rfind(b, 3) == 3); + REQUIRE(a.rfind(b, 4) == 3); + REQUIRE(a.rfind(b, 2) == string::npos); + } + + SECTION("Literal string") { + REQUIRE(a.rfind("def") == 3); + REQUIRE(a.rfind("def", 3) == 3); + REQUIRE(a.rfind("def", 4) == 3); + REQUIRE(a.rfind("def", 2) == string::npos); + } + + SECTION("Literal substring") { + REQUIRE(a.rfind("defzxc", 0, 3) == string::npos); + REQUIRE(a.rfind("defzxc", 3, 3) == 3); + REQUIRE(a.rfind("defzxc", 4, 3) == 3); + REQUIRE(a.rfind("defzxc", 2, 3) == string::npos); + } + + SECTION("Char") { + REQUIRE(a.rfind('d', 0) == string::npos); + REQUIRE(a.rfind('d', 3) == 3); + REQUIRE(a.rfind('d', 4) == 3); + REQUIRE(a.rfind('d', 2) == string::npos); + } + + SECTION("String view") { + REQUIRE(a.rfind(std::string_view("def"), 0) == string::npos); + REQUIRE(a.rfind(std::string_view("def"), 3) == 3); + REQUIRE(a.rfind(std::string_view("def"), 4) == 3); + REQUIRE(a.rfind(std::string_view("def"), 2) == string::npos); + } + } + + SECTION("Different encoding") { + string a = "๐Ÿ˜a๐Ÿ˜€b๐Ÿ˜€c๐Ÿ˜d๐Ÿ˜€e๐Ÿ˜€f"; + + SECTION("Other string") { + string b = "๐Ÿ˜€c๐Ÿ˜"; + REQUIRE(a.rfind(b) == 10); + REQUIRE(a.rfind(b, 10) == 10); + REQUIRE(a.rfind(b, 9) == string::npos); + } + + SECTION("Literal string") { + REQUIRE(a.rfind(U"๐Ÿ˜€c๐Ÿ˜") == 10); + REQUIRE(a.rfind(U"๐Ÿ˜€c๐Ÿ˜", 10) == 10); + REQUIRE(a.rfind(U"๐Ÿ˜€c๐Ÿ˜", 9) == string::npos); + } + + SECTION("Literal substring") { + REQUIRE(a.rfind(U"๐Ÿ˜€c๐Ÿ˜zxc", 14, 3) == 10); + REQUIRE(a.rfind(U"๐Ÿ˜€c๐Ÿ˜zxc", 10, 3) == 10); + REQUIRE(a.rfind(U"๐Ÿ˜€c๐Ÿ˜zxc", 9, 3) == string::npos); + } + + SECTION("Char") { + REQUIRE(a.rfind(U'๐Ÿ˜€', 19) == 10); + REQUIRE(a.rfind(U'๐Ÿ˜€', 10) == 10); + REQUIRE(a.rfind(U'๐Ÿ˜€', 9) == 5); + REQUIRE(a.rfind(U'๐Ÿ˜€', 0) == string::npos); + } + + SECTION("String view") { + REQUIRE(a.rfind(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 14) == 10); + REQUIRE(a.rfind(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 10) == 10); + REQUIRE(a.rfind(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 0) == string::npos); + } + } + } + + SECTION("Find first of chars") { + SECTION("Same encoding") { + string a = "abcdefghij"; + + SECTION("Other string") { + string b = "fed"; + REQUIRE(a.find_first_of(b) == 3); + REQUIRE(a.find_first_of(b, 3) == 3); + REQUIRE(a.find_first_of(b, 6) == string::npos); + } + + SECTION("Literal string") { + REQUIRE(a.find_first_of("fed") == 3); + REQUIRE(a.find_first_of("fed", 3) == 3); + REQUIRE(a.find_first_of("fed", 6) == string::npos); + } + + SECTION("Literal substring") { + REQUIRE(a.find_first_of("fedzxc", 0, 3) == 3); + REQUIRE(a.find_first_of("fedzxc", 3, 3) == 3); + REQUIRE(a.find_first_of("fedzxc", 6, 3) == string::npos); + } + + SECTION("Char") { + REQUIRE(a.find_first_of('e', 0) == 4); + REQUIRE(a.find_first_of('e', 3) == 4); + REQUIRE(a.find_first_of('e', 6) == string::npos); + } + + SECTION("String view") { + REQUIRE(a.find_first_of(std::string_view("fed"), 0) == 3); + REQUIRE(a.find_first_of(std::string_view("fed"), 3) == 3); + REQUIRE(a.find_first_of(std::string_view("fed"), 6) == string::npos); + } + } + + SECTION("Different encoding") { + string a = "๐Ÿ˜a๐Ÿ˜€b๐Ÿ˜€c๐Ÿ˜d๐Ÿ˜€e๐Ÿ˜€f"; + + SECTION("Other string") { + std::u32string b = U"๐Ÿ˜€c๐Ÿ˜"; + REQUIRE(a.find_first_of(b) == 0); + REQUIRE(a.find_first_of(b, 10) == 10); + REQUIRE(a.find_first_of(b, 26) == string::npos); + } + + SECTION("Literal string") { + REQUIRE(a.find_first_of(U"๐Ÿ˜€c๐Ÿ˜") == 0); + REQUIRE(a.find_first_of(U"๐Ÿ˜€c๐Ÿ˜", 10) == 10); + REQUIRE(a.find_first_of(U"๐Ÿ˜€c๐Ÿ˜", 26) == string::npos); + } + + SECTION("Literal substring") { + REQUIRE(a.find_first_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 0, 3) == 0); + REQUIRE(a.find_first_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 10, 3) == 10); + REQUIRE(a.find_first_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 26, 3) == string::npos); + } + + SECTION("Char") { + REQUIRE(a.find_first_of(U'๐Ÿ˜€', 0) == 5); + REQUIRE(a.find_first_of(U'๐Ÿ˜€', 10) == 10); + REQUIRE(a.find_first_of(U'๐Ÿ˜', 26) == string::npos); + } + + SECTION("String view") { + REQUIRE(a.find_first_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 0) == 0); + REQUIRE(a.find_first_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 10) == 10); + REQUIRE(a.find_first_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 26) == string::npos); + } + } + } + + SECTION("Find first not of chars") { + SECTION("Same encoding") { + string a = "abcdefghij"; + + SECTION("Other string") { + string b = "fed"; + REQUIRE(a.find_first_not_of(b) == 0); + REQUIRE(a.find_first_not_of(b, 3) == 6); + REQUIRE(a.find_first_not_of(b, 11) == string::npos); + } + + SECTION("Literal string") { + REQUIRE(a.find_first_not_of("fed") == 0); + REQUIRE(a.find_first_not_of("fed", 3) == 6); + REQUIRE(a.find_first_not_of("fed", 11) == string::npos); + } + + SECTION("Literal substring") { + REQUIRE(a.find_first_not_of("fedzxc", 0, 3) == 0); + REQUIRE(a.find_first_not_of("fedzxc", 3, 3) == 6); + REQUIRE(a.find_first_not_of("fedzxc", 11, 3) == string::npos); + } + + SECTION("Char") { + REQUIRE(a.find_first_not_of('e', 0) == 0); + REQUIRE(a.find_first_not_of('e', 3) == 3); + REQUIRE(a.find_first_not_of('e', 4) == 5); + REQUIRE(a.find_first_not_of('e', 11) == string::npos); + } + + SECTION("String view") { + REQUIRE(a.find_first_not_of(std::string_view("fed"), 0) == 0); + REQUIRE(a.find_first_not_of(std::string_view("fed"), 3) == 6); + REQUIRE(a.find_first_not_of(std::string_view("fed"), 11) == string::npos); + } + } + + SECTION("Different encoding") { + string a = "๐Ÿ˜a๐Ÿ˜€b๐Ÿ˜€c๐Ÿ˜d๐Ÿ˜€e๐Ÿ˜€f"; + + SECTION("Other string") { + std::u32string b = U"๐Ÿ˜€c๐Ÿ˜"; + REQUIRE(a.find_first_not_of(b) == 4); + REQUIRE(a.find_first_not_of(b, 10) == 19); + REQUIRE(a.find_first_not_of(b, 31) == string::npos); + } + + SECTION("Literal string") { + REQUIRE(a.find_first_not_of(U"๐Ÿ˜€c๐Ÿ˜") == 4); + REQUIRE(a.find_first_not_of(U"๐Ÿ˜€c๐Ÿ˜", 10) == 19); + REQUIRE(a.find_first_not_of(U"๐Ÿ˜€c๐Ÿ˜", 31) == string::npos); + } + + SECTION("Literal substring") { + REQUIRE(a.find_first_not_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 0, 3) == 4); + REQUIRE(a.find_first_not_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 10, 3) == 19); + REQUIRE(a.find_first_not_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 31, 3) == string::npos); + } + + SECTION("Char") { + REQUIRE(a.find_first_not_of(U'๐Ÿ˜€', 0) == 0); + REQUIRE(a.find_first_not_of(U'๐Ÿ˜€', 10) == 14); + REQUIRE(a.find_first_not_of(U'๐Ÿ˜', 31) == string::npos); + } + + SECTION("String view") { + REQUIRE(a.find_first_not_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 0) == 4); + REQUIRE(a.find_first_not_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 10) == 19); + REQUIRE(a.find_first_not_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 31) == string::npos); + } + } + } + + SECTION("Find last of chars") { + SECTION("Same encoding") { + string a = "abcdefghij"; + + SECTION("Other string") { + string b = "fed"; + REQUIRE(a.find_last_of(b) == 5); + REQUIRE(a.find_last_of(b, 3) == 3); + REQUIRE(a.find_last_of(b, 2) == string::npos); + } + + SECTION("Literal string") { + REQUIRE(a.find_last_of("fed") == 5); + REQUIRE(a.find_last_of("fed", 3) == 3); + REQUIRE(a.find_last_of("fed", 2) == string::npos); + } + + SECTION("Literal substring") { + REQUIRE(a.find_last_of("fedzxc", 6, 3) == 5); + REQUIRE(a.find_last_of("fedzxc", 3, 3) == 3); + REQUIRE(a.find_last_of("fedzxc", 2, 3) == string::npos); + } + + SECTION("Char") { + REQUIRE(a.find_last_of('e', 6) == 4); + REQUIRE(a.find_last_of('e', 4) == 4); + REQUIRE(a.find_last_of('e', 3) == string::npos); + } + + SECTION("String view") { + REQUIRE(a.find_last_of(std::string_view("fed"), 6) == 5); + REQUIRE(a.find_last_of(std::string_view("fed"), 3) == 3); + REQUIRE(a.find_last_of(std::string_view("fed"), 2) == string::npos); + } + } + + SECTION("Different encoding") { + string a = "๐Ÿ˜a๐Ÿ˜€b๐Ÿ˜€c๐Ÿ˜d๐Ÿ˜€e๐Ÿ˜€f"; + + SECTION("Other string") { + std::u32string b = U"๐Ÿ˜€c๐Ÿ˜"; + REQUIRE(a.find_last_of(b) == 25); + REQUIRE(a.find_last_of(b, 10) == 10); + REQUIRE(a.find_last_of(b, 0) == 0); + } + + SECTION("Literal string") { + REQUIRE(a.find_last_of(U"๐Ÿ˜€c๐Ÿ˜") == 25); + REQUIRE(a.find_last_of(U"๐Ÿ˜€c๐Ÿ˜", 10) == 10); + REQUIRE(a.find_last_of(U"๐Ÿ˜€c๐Ÿ˜", 0) == 0); + } + + SECTION("Literal substring") { + REQUIRE(a.find_last_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 0, 3) == 0); + REQUIRE(a.find_last_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 10, 3) == 10); + REQUIRE(a.find_last_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 26, 3) == 25); + } + + SECTION("Char") { + REQUIRE(a.find_last_of(U'๐Ÿ˜€', 0) == string::npos); + REQUIRE(a.find_last_of(U'๐Ÿ˜€', 10) == 10); + REQUIRE(a.find_last_of(U'๐Ÿ˜', 26) == 15); + } + + SECTION("String view") { + REQUIRE(a.find_last_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 26) == 25); + REQUIRE(a.find_last_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 10) == 10); + REQUIRE(a.find_last_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 0) == 0); + } + } + } + + SECTION("Find last not of chars") { + SECTION("Same encoding") { + string a = "abcdefghij"; + + SECTION("Other string") { + string b = "fed"; + REQUIRE(a.find_last_not_of(b) == 9); + REQUIRE(a.find_last_not_of(b, 3) == 2); + REQUIRE(a.find_last_not_of(b, 11) == 9); + } + + SECTION("Literal string") { + REQUIRE(a.find_last_not_of("fed") == 9); + REQUIRE(a.find_last_not_of("fed", 3) == 2); + REQUIRE(a.find_last_not_of("fed", 11) == 9); + } + + SECTION("Literal substring") { + REQUIRE(a.find_last_not_of("fedzxc", 0, 3) == 0); + REQUIRE(a.find_last_not_of("fedzxc", 3, 3) == 2); + REQUIRE(a.find_last_not_of("fedzxc", 11, 3) == 9); + } + + SECTION("Char") { + REQUIRE(a.find_last_not_of('e', 0) == 0); + REQUIRE(a.find_last_not_of('e', 3) == 3); + REQUIRE(a.find_last_not_of('e', 4) == 3); + REQUIRE(a.find_last_not_of('e', 11) == 9); + } + + SECTION("String view") { + REQUIRE(a.find_last_not_of(std::string_view("fed"), 0) == 0); + REQUIRE(a.find_last_not_of(std::string_view("fed"), 3) == 2); + REQUIRE(a.find_last_not_of(std::string_view("fed"), 11) == 9); + } + } + + SECTION("Different encoding") { + string a = "๐Ÿ˜a๐Ÿ˜€b๐Ÿ˜€c๐Ÿ˜d๐Ÿ˜€e๐Ÿ˜€f"; + + SECTION("Other string") { + std::u32string b = U"๐Ÿ˜€c๐Ÿ˜"; + REQUIRE(a.find_last_not_of(b) == 29); + REQUIRE(a.find_last_not_of(b, 10) == 9); + REQUIRE(a.find_last_not_of(b, 31) == 29); + } + + SECTION("Literal string") { + REQUIRE(a.find_last_not_of(U"๐Ÿ˜€c๐Ÿ˜") == 29); + REQUIRE(a.find_last_not_of(U"๐Ÿ˜€c๐Ÿ˜", 10) == 9); + REQUIRE(a.find_last_not_of(U"๐Ÿ˜€c๐Ÿ˜", 31) == 29); + } + + SECTION("Literal substring") { + REQUIRE(a.find_last_not_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 0, 3) == string::npos); + REQUIRE(a.find_last_not_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 10, 3) == 9); + REQUIRE(a.find_last_not_of(U"๐Ÿ˜€c๐Ÿ˜zxc", 31, 3) == 29); + } + + SECTION("Char") { + REQUIRE(a.find_last_not_of(U'๐Ÿ˜€', 0) == 0); + REQUIRE(a.find_last_not_of(U'๐Ÿ˜€', 10) == 9); + REQUIRE(a.find_last_not_of(U'๐Ÿ˜', 31) == 29); + } + + SECTION("String view") { + REQUIRE(a.find_last_not_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 0) == string::npos); + REQUIRE(a.find_last_not_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 10) == 9); + REQUIRE(a.find_last_not_of(std::u32string_view(U"๐Ÿ˜€c๐Ÿ˜"), 31) == 29); + } + } + } + } +} \ No newline at end of file diff --git a/tests/unit_tests/small_string_make.cpp b/tests/unit_tests/small_string_make.cpp new file mode 100644 index 0000000..f8fc4f0 --- /dev/null +++ b/tests/unit_tests/small_string_make.cpp @@ -0,0 +1,713 @@ +#ifndef SMALL_BUILD_TESTS_WITH_PCH +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#endif + +// UTF8 string literals are really not safe in MSVC. +// u8"" doesn't work properly even with escape sequences. +// More recent versions might improve on that a little, but we will still +// need a more robust solution to support older versions in any case. +// Until then, it seems like the most robust solution is to initialize +// small::strings with U"...", even if that requires converting the +// codepoints. +constexpr bool is_windows() { +#if defined(_WIN32) + return true; +#else + return false; +#endif +} + +TEST_CASE("String Rule of 5") { + using namespace small; + + auto equal_il = [](const auto &sm_string, std::initializer_list il) -> bool { + return std::equal(sm_string.begin(), sm_string.end(), il.begin(), il.end()); + }; + + SECTION("Constructor") { + SECTION("Default") { + string a; + REQUIRE(a.empty()); + REQUIRE(a.size() == 0); // NOLINT(readability-container-size-empty) + REQUIRE(a.size_codepoints() == 0); + REQUIRE(equal_il(a, {})); + } + + SECTION("Allocator") { + std::allocator alloc; + string a(alloc); + REQUIRE(a.empty()); + REQUIRE(equal_il(a, {})); + REQUIRE(a.get_allocator() == alloc); + } + + SECTION("From char value") { + SECTION("Zero values") { + std::allocator alloc; + string c(0, 'x', alloc); // NOLINT(bugprone-string-constructor) + REQUIRE(c.empty()); + REQUIRE(c.size() == 0); // NOLINT(readability-container-size-empty) + REQUIRE(c.size_codepoints() == 0); + REQUIRE(c == ""); // NOLINT(readability-container-size-empty) + REQUIRE(c == U""); // NOLINT(readability-container-size-empty) + REQUIRE(c.get_allocator() == alloc); + } + + SECTION("Constant values") { + std::allocator alloc; + string c(3, 'x', alloc); + REQUIRE_FALSE(c.empty()); + REQUIRE(c.size() == 3); + REQUIRE(c.size_codepoints() == 3); + REQUIRE(c == "xxx"); + REQUIRE(c == U"xxx"); + REQUIRE(c.get_allocator() == alloc); + } + + SECTION("From UTF16 value") { + std::allocator alloc; + string c(3, u'x', alloc); + REQUIRE_FALSE(c.empty()); + REQUIRE(c.size() == 3); + REQUIRE(c.size_codepoints() == 3); + REQUIRE(c == "xxx"); + REQUIRE(c == u"xxx"); + REQUIRE(c.get_allocator() == alloc); + } + + SECTION("From multibyte UTF16 value") { + // We don't provide full support/conversions for multi-code-unit UTF16 for now, + // but other uni-code-unit UTF16 strings should be fine. + // In any case, UTF8 and UTF32 should be able to represent anything. + // You can use UTF32 as an intermediary if you need a case that is not supported. + std::allocator alloc; + string c(3, u'รก', alloc); + REQUIRE_FALSE(c.empty()); + REQUIRE(c.size_codepoints() == 3); + REQUIRE(c.size() == 6); + REQUIRE(c == "รกรกรก"); + REQUIRE(c == u"รกรกรก"); + REQUIRE(c.get_allocator() == alloc); + } + + SECTION("From utf32 value") { + std::allocator alloc; + string c(3, U'x', alloc); + REQUIRE_FALSE(c.empty()); + REQUIRE(c.size() == 3); + REQUIRE(c.size_codepoints() == 3); + REQUIRE(c == "xxx"); + REQUIRE(c == U"xxx"); + REQUIRE(c.get_allocator() == alloc); + } + + SECTION("From multibyte utf32 value") { + std::allocator alloc; + string c(3, U'๐Ÿ˜€', alloc); + REQUIRE_FALSE(c.empty()); + REQUIRE(c.size_codepoints() == 3); + REQUIRE(c.size() == 12); + REQUIRE(c == "๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); + REQUIRE(c == U"๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); + REQUIRE(c.get_allocator() == alloc); + } + } + + SECTION("From char iterators") { + SECTION("Empty range") { + std::allocator alloc; + std::string dv; + string d(dv.begin(), dv.end(), alloc); + REQUIRE(d.empty()); + REQUIRE(d.size_codepoints() == 0); + REQUIRE(d.size() == 0); // NOLINT(readability-container-size-empty) + REQUIRE(d == ""); // NOLINT(readability-container-size-empty) + REQUIRE(d == U""); // NOLINT(readability-container-size-empty) + REQUIRE(d.get_allocator() == alloc); + } + SECTION("No unicode") { + std::allocator alloc; + std::string dv = "654"; + string d(dv.begin(), dv.end(), alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 3); + REQUIRE(d.size() == 3); + REQUIRE(d == "654"); + REQUIRE(d == U"654"); + REQUIRE(d.get_allocator() == alloc); + } + SECTION("Half unicode") { + std::allocator alloc; + std::string dv = "๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"; + REQUIRE(dv.size() == 15); + string d(dv.begin(), dv.end(), alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 15); + REQUIRE(d == "๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"); + REQUIRE(d == U"๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"); + REQUIRE(d.get_allocator() == alloc); + } + SECTION("Full unicode") { + std::allocator alloc; + std::string dv = "๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"; + string d(dv.begin(), dv.end(), alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 24); + REQUIRE(d == "๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); + REQUIRE(d == U"๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); + REQUIRE(d.get_allocator() == alloc); + } + } + + SECTION("From wide char iterators") { + SECTION("No unicode") { + std::allocator alloc; + std::u32string dv = U"654"; + string d(dv.begin(), dv.end(), alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 3); + REQUIRE(d.size() == 3); + REQUIRE(d == "654"); + REQUIRE(d == U"654"); + REQUIRE(d.get_allocator() == alloc); + } + SECTION("Half unicode") { + std::allocator alloc; + std::u32string dv = U"๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"; + string d(dv.begin(), dv.end(), alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 15); + REQUIRE(d == "๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"); + REQUIRE(d == U"๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"); + REQUIRE(d.get_allocator() == alloc); + } + SECTION("Full unicode") { + std::allocator alloc; + std::u32string dv = U"๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"; + string d(dv.begin(), dv.end(), alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 24); + REQUIRE(d == "๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); + REQUIRE(d == U"๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); + REQUIRE(d.get_allocator() == alloc); + } + } + + SECTION("From codepoint iterators") { + SECTION("No unicode") { + std::allocator alloc; + string dv = U"654"; + string d(dv.begin_codepoint(), dv.end_codepoint(), alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 3); + REQUIRE(d.size() == 3); + REQUIRE(d == "654"); + REQUIRE(d == U"654"); + REQUIRE(d.get_allocator() == alloc); + } + SECTION("Half unicode") { + std::allocator alloc; + string dv = U"๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"; + string d(dv.begin_codepoint(), dv.end_codepoint(), alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 15); + REQUIRE(d == "๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"); + REQUIRE(d == U"๐Ÿ˜€6๐Ÿ˜€5๐Ÿ˜€4"); + REQUIRE(d.get_allocator() == alloc); + } + SECTION("Full unicode") { + std::allocator alloc; + string dv = U"๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"; + string d(dv.begin_codepoint(), dv.end_codepoint(), alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 24); + REQUIRE(d == "๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); + REQUIRE(d == U"๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); + REQUIRE(d.get_allocator() == alloc); + } + } + + SECTION("From substring") { + SECTION("From begin") { + std::allocator alloc; + string dv = "123456"; + string d(dv, 3, alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 3); + REQUIRE(d.size() == 3); + REQUIRE(d == "456"); + REQUIRE(d == U"456"); + REQUIRE(d.get_allocator() == alloc); + } + + SECTION("From range") { + std::allocator alloc; + string dv = "123456"; + string d(dv, 2, 2, alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 2); + REQUIRE(d.size() == 2); + REQUIRE(d == "34"); + REQUIRE(d == U"34"); + REQUIRE(d.get_allocator() == alloc); + } + + SECTION("From npos range") { + std::allocator alloc; + string dv = "123456"; + string d(dv, 2, string::npos, alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 4); + REQUIRE(d.size() == 4); + REQUIRE(d == "3456"); + REQUIRE(d == U"3456"); + REQUIRE(d.get_allocator() == alloc); + } + + SECTION("Literal string count") { + SECTION("Char") { + std::allocator alloc; + string d("123456", 2, alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 2); + REQUIRE(d.size() == 2); + REQUIRE(d == "12"); + REQUIRE(d == U"12"); + REQUIRE(d.get_allocator() == alloc); + } + + SECTION("Wide char") { + std::allocator alloc; + string d(U"123456", 2, alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 2); + REQUIRE(d.size() == 2); + REQUIRE(d == "12"); + REQUIRE(d == U"12"); + REQUIRE(d.get_allocator() == alloc); + } + } + } + + SECTION("From literal") { + SECTION("Char") { + std::allocator alloc; + string d("123456", alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 6); + REQUIRE(d == "123456"); + REQUIRE(d == U"123456"); + REQUIRE(d.get_allocator() == alloc); + } + SECTION("Wide char") { + std::allocator alloc; + string d(U"123456", alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 6); + REQUIRE(d == "123456"); + REQUIRE(d == U"123456"); + REQUIRE(d.get_allocator() == alloc); + } + } + + SECTION("From initializer list") { + SECTION("Char") { + std::allocator alloc; + string d({'1', '2', '3', '4', '5', '6'}, alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 6); + REQUIRE(d == "123456"); + REQUIRE(d == U"123456"); + REQUIRE(d.get_allocator() == alloc); + } + SECTION("Wide char") { + std::allocator alloc; + string d({U'1', U'2', U'3', U'4', U'5', U'6'}, alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 6); + REQUIRE(d == "123456"); + REQUIRE(d == U"123456"); + REQUIRE(d.get_allocator() == alloc); + } + } + + SECTION("From string view") { + SECTION("Char") { + std::allocator alloc; + string d(std::string_view("123456"), alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 6); + REQUIRE(d == "123456"); + REQUIRE(d == U"123456"); + REQUIRE(d.get_allocator() == alloc); + } + SECTION("Wide char") { + std::allocator alloc; + string d(std::u32string_view(U"123456"), alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 6); + REQUIRE(d == "123456"); + REQUIRE(d == U"123456"); + REQUIRE(d.get_allocator() == alloc); + } + } + + SECTION("From std string") { + SECTION("Char") { + std::allocator alloc; + string d(std::string("123456"), alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 6); + REQUIRE(d == "123456"); + REQUIRE(d == U"123456"); + REQUIRE(d.get_allocator() == alloc); + } + SECTION("Wide char") { + std::allocator alloc; + string d(std::u32string(U"123456"), alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 6); + REQUIRE(d == "123456"); + REQUIRE(d == U"123456"); + REQUIRE(d.get_allocator() == alloc); + } + } + + SECTION("Rule of five") { + SECTION("Copy") { + string dv = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; + string d(dv); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 15); + REQUIRE(d == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(dv.size_codepoints() == 6); + REQUIRE(dv.size() == 15); + REQUIRE(dv == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(dv == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(d == dv); + } + + SECTION("Copy and set alloc") { + std::allocator alloc; + string dv = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; + string d(dv, alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 15); + REQUIRE(d == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(dv.size_codepoints() == 6); + REQUIRE(dv.size() == 15); + REQUIRE(dv == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(dv == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(d == dv); + REQUIRE(d.get_allocator() == alloc); + } + + SECTION("Move") { + string dv = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; + string d(std::move(dv)); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 15); + REQUIRE(d == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(dv.size_codepoints() == 0); // NOLINT(readability-container-size-empty,bugprone-use-after-move) + REQUIRE(dv.size() == 0); // NOLINT(readability-container-size-empty,bugprone-use-after-move) + REQUIRE(dv == ""); // NOLINT(readability-container-size-empty,bugprone-use-after-move) + REQUIRE(dv == U""); // NOLINT(readability-container-size-empty,bugprone-use-after-move) + REQUIRE(dv.empty()); + // is null terminated + REQUIRE(dv[0] == '\0'); + } + + if constexpr (not is_windows()) { + SECTION("Move and set alloc") { + std::allocator alloc; + // There's no safe way to do that on MSVC :O + string dv = u8"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; + string d(std::move(dv), alloc); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 15); + REQUIRE(d == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(dv.size_codepoints() == 0); // NOLINT(bugprone-use-after-move) + REQUIRE(dv.size() == 0); // NOLINT(readability-container-size-empty) + REQUIRE(dv == ""); // NOLINT(readability-container-size-empty) + REQUIRE(dv == U""); // NOLINT(readability-container-size-empty) + REQUIRE(dv.empty()); + // is null terminated + REQUIRE(dv[0] == '\0'); + REQUIRE(d.get_allocator() == alloc); + } + } + } + } + + SECTION("Assignment Operator") { + if constexpr (not is_windows()) { + SECTION("String") { + string dv = u8"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; + string d; + d = dv; + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 15); + REQUIRE(d == u8"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(dv.size_codepoints() == 6); + REQUIRE(dv.size() == 15); + REQUIRE(dv == u8"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(dv == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(d == dv); + } + } + + SECTION("Move String") { + string dv = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; + string d; + d = std::move(dv); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 15); + REQUIRE(d == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(dv.size_codepoints() == 0); // NOLINT(bugprone-use-after-move) + REQUIRE(dv.size() == 0); // NOLINT(bugprone-use-after-move,readability-container-size-empty) + REQUIRE(dv == ""); // NOLINT(bugprone-use-after-move,readability-container-size-empty) + REQUIRE(dv == U""); // NOLINT(bugprone-use-after-move,readability-container-size-empty) + REQUIRE_FALSE(d == dv); + REQUIRE(dv.size() == 0); // NOLINT(bugprone-use-after-move,readability-container-size-empty) + REQUIRE(dv.front() == '\0'); + } + + SECTION("Literal") { + string d; + d = "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 15); + REQUIRE(d == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + } + + SECTION("Wide Literal") { + string d; + d = U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"; + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 15); + REQUIRE(d == "1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + REQUIRE(d == U"1๐Ÿ˜€2๐Ÿ˜€3๐Ÿ˜€"); + } + + SECTION("Char") { + string d; + d = '1'; + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 1); + REQUIRE(d.size() == 1); + REQUIRE(d == "1"); + REQUIRE(d == U"1"); + } + + SECTION("Wide Char") { + string d; + d = U'1'; + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 1); + REQUIRE(d.size() == 1); + REQUIRE(d == "1"); + REQUIRE(d == U"1"); + } + + SECTION("Unicode Wide Char") { + string d; + d = U'๐Ÿ˜€'; + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 1); + REQUIRE(d.size() == 4); + REQUIRE(d == "๐Ÿ˜€"); + REQUIRE(d == U"๐Ÿ˜€"); + } + } + + SECTION("Assign") { + SECTION("Char") { + string d; + d.assign(3, '1'); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 3); + REQUIRE(d.size() == 3); + REQUIRE(d == "111"); + REQUIRE(d == U"111"); + } + + SECTION("Wide Char") { + string d; + d.assign(3, U'1'); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 3); + REQUIRE(d.size() == 3); + REQUIRE(d == "111"); + REQUIRE(d == U"111"); + } + + SECTION("Unicode Wide Char") { + string d; + d.assign(3, U'๐Ÿ˜€'); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 3); + REQUIRE(d.size() == 12); + REQUIRE(d == "๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); + REQUIRE(d == U"๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); + } + + SECTION("Substring") { + string dv = "123456"; + string d; + d.assign(dv, 2, 2); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 2); + REQUIRE(d.size() == 2); + REQUIRE(d == "34"); + REQUIRE(d == U"34"); + REQUIRE(dv.size_codepoints() == 6); + REQUIRE(dv.size() == 6); + REQUIRE(dv == "123456"); + REQUIRE(dv == U"123456"); + REQUIRE_FALSE(d == dv); + } + + SECTION("String") { + string dv = "123456"; + string d; + d.assign(dv); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 6); + REQUIRE(d == "123456"); + REQUIRE(d == U"123456"); + REQUIRE(dv.size_codepoints() == 6); + REQUIRE(dv.size() == 6); + REQUIRE(dv == "123456"); + REQUIRE(dv == U"123456"); + REQUIRE(d == dv); + } + + SECTION("String Move") { + string dv = "123456"; + string d; + d.assign(std::move(dv)); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 6); + REQUIRE(d == "123456"); + REQUIRE(d == U"123456"); + REQUIRE(dv.size_codepoints() == 0); // NOLINT(bugprone-use-after-move) + REQUIRE(dv.size() == 0); // NOLINT(bugprone-use-after-move,readability-container-size-empty) + REQUIRE(dv == ""); // NOLINT(bugprone-use-after-move,readability-container-size-empty) + REQUIRE(dv == U""); // NOLINT(bugprone-use-after-move,readability-container-size-empty) + REQUIRE(dv.front() == '\0'); + REQUIRE_FALSE(d == dv); + } + + SECTION("Literal") { + string d; + d.assign("123456", 3); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 3); + REQUIRE(d.size() == 3); + REQUIRE(d == "123"); + REQUIRE(d == U"123"); + } + + SECTION("Wide Literal") { + string d; + d.assign(U"123456", 3); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 3); + REQUIRE(d.size() == 3); + REQUIRE(d == "123"); + REQUIRE(d == U"123"); + } + + SECTION("Initializer list") { + string d; + d.assign({'1', '2', '3', '4', '5', '6'}); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 6); + REQUIRE(d == "123456"); + REQUIRE(d == U"123456"); + } + + SECTION("String view") { + string d; + d.assign(std::string_view("123456")); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 6); + REQUIRE(d == "123456"); + REQUIRE(d == U"123456"); + } + + SECTION("Wide string view") { + string d; + d.assign(std::u32string_view(U"123456")); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 6); + REQUIRE(d.size() == 6); + REQUIRE(d == "123456"); + REQUIRE(d == U"123456"); + } + + SECTION("Substring view") { + string d; + d.assign(std::string_view("123456"), 2, 2); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 2); + REQUIRE(d.size() == 2); + REQUIRE(d == "34"); + REQUIRE(d == U"34"); + } + + SECTION("Wide string view") { + string d; + d.assign(std::u32string_view(U"123456"), 2, 2); + REQUIRE_FALSE(d.empty()); + REQUIRE(d.size_codepoints() == 2); + REQUIRE(d.size() == 2); + REQUIRE(d == "34"); + REQUIRE(d == U"34"); + } + } +} \ No newline at end of file diff --git a/tests/unit_tests/small_string_modify.cpp b/tests/unit_tests/small_string_modify.cpp new file mode 100644 index 0000000..4c8b89a --- /dev/null +++ b/tests/unit_tests/small_string_modify.cpp @@ -0,0 +1,821 @@ +#ifndef SMALL_BUILD_TESTS_WITH_PCH +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#endif + +// UTF8 string literals are really not safe in MSVC. +// u8"" doesn't work properly even with escape sequences. +// More recent versions might improve on that a little, but we will still +// need a more robust solution to support older versions in any case. +// Until then, it seems like the most robust solution is to initialize +// small::strings with U"...", even if that requires converting the +// codepoints. +constexpr bool is_windows() { +#if defined(_WIN32) + return true; +#else + return false; +#endif +} + +TEST_CASE("String Modify") { + using namespace small; + + SECTION("Resize") { + SECTION("Code units") { + string a = "1๐Ÿ˜€3"; + REQUIRE_FALSE(is_malformed(a)); + a.resize(4); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() >= 13); + REQUIRE(a.capacity() <= 15); + REQUIRE(a.size_codepoints() == 1); + REQUIRE(is_malformed(a)); + + a = "1๐Ÿ˜€3"; + REQUIRE_FALSE(is_malformed(a)); + a.resize(20); + REQUIRE(a.size() == 20); + REQUIRE(a.max_size() > 20); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() > 20); + REQUIRE(a.size_codepoints() == 17); + REQUIRE_FALSE(is_malformed(a)); + + a = "1๐Ÿ˜€3"; + a.resize(14, 'x'); + REQUIRE(a.size() == 6 + 8); + REQUIRE(a.size_codepoints() == 3 + 8); + REQUIRE(a.max_size() > 14); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() > 14); + REQUIRE_FALSE(is_malformed(a)); + + a = "1๐Ÿ˜€3"; + a.resize(14, U'x'); + REQUIRE(a.size() == 6 + 8); + REQUIRE(a.size_codepoints() == 3 + 8); + REQUIRE(a.max_size() > 14); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() > 14); + REQUIRE_FALSE(is_malformed(a)); + + a = "1๐Ÿ˜€3"; // <- size 6 + a.resize(14, U'๐Ÿ˜€'); // <- size 6 + 8 = 14 (two extra codepoints) + REQUIRE(a.size_codepoints() == 5); + REQUIRE(a.size() == 14); + REQUIRE(a.max_size() > 40); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() > 14); + REQUIRE_FALSE(is_malformed(a)); + + a = "1๐Ÿ˜€3"; + a.shrink_to_fit(); + REQUIRE(a.size() == 6); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() > a.size()); + REQUIRE_FALSE(is_malformed(a)); + } + + SECTION("Code points") { + string a = "1๐Ÿ˜€3"; + REQUIRE_FALSE(is_malformed(a)); + a.resize(string::codepoint_index(4)); + REQUIRE(a.size() == 7); + REQUIRE(a.max_size() > 7); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() >= 13); + REQUIRE(a.capacity() <= 17); + REQUIRE(a.size_codepoints() == 4); + REQUIRE_FALSE(is_malformed(a)); + + a = "1๐Ÿ˜€3"; + REQUIRE_FALSE(is_malformed(a)); + a.resize(string::codepoint_index(20)); + REQUIRE(a.size() == 23); + REQUIRE(a.max_size() > 23); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() > 23); + REQUIRE(a.size_codepoints() == 20); + REQUIRE_FALSE(is_malformed(a)); + + a = "1๐Ÿ˜€3"; + a.resize(string::codepoint_index(14), 'x'); + REQUIRE(a.size() == 6 + 14 - 3); + REQUIRE(a.size_codepoints() == 3 + 11); + REQUIRE(a.max_size() > 14); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() > 14); + REQUIRE_FALSE(is_malformed(a)); + + a = "1๐Ÿ˜€3"; + a.resize(string::codepoint_index(14), U'x'); + REQUIRE(a.size() == 6 + 11); + REQUIRE(a.size_codepoints() == 3 + 11); + REQUIRE(a.max_size() > 17); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() > 17); + REQUIRE_FALSE(is_malformed(a)); + + a = "1๐Ÿ˜€3"; + a.resize(string::codepoint_index(14), U'๐Ÿ˜€'); + REQUIRE(a.size_codepoints() == 14); + REQUIRE(a.size() == 12 * 4 + 2); + REQUIRE(a.max_size() > 40); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() > 14); + REQUIRE_FALSE(is_malformed(a)); + } + } + + SECTION("Clear") { + string a = "1๐Ÿ˜€3"; + a.clear(); + REQUIRE(a.empty()); + REQUIRE(a.size() == 0); // NOLINT(readability-container-size-empty) + REQUIRE(a.size_codepoints() == 0); + REQUIRE(a.max_size() > 10); + REQUIRE(a.capacity() > a.size()); + REQUIRE_FALSE(is_malformed(a)); + } + + SECTION("Insert") { + SECTION("Char") { + SECTION("At index") { + SECTION("One element") { + string a = "124"; + a.insert(2, 1, '3'); + REQUIRE(a == "1234"); + } + SECTION("Multiple elements") { + string a = "abcz"; + a.insert(3, 3, '.'); + REQUIRE(a == "abc...z"); + } + SECTION("Unicode") { + string a = "abcz"; + a.insert(3, 3, U'๐Ÿ˜€'); + REQUIRE(a == "abc๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€z"); + } + } + + SECTION("At codepoint") { + SECTION("One element") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(string::codepoint_index(2), 1, '3'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); + } + SECTION("Multiple elements") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(string::codepoint_index(2), 3, '.'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚...๐Ÿ˜"); + } + SECTION("Unicode") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(string::codepoint_index(2), 3, U'๐Ÿ˜€'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); + } + } + + SECTION("At iterator") { + SECTION("One element") { + string a = "124"; + a.insert(a.begin() + 2, 1, '3'); + REQUIRE(a == "1234"); + } + SECTION("Multiple elements") { + string a = "abcz"; + a.insert(a.begin() + 3, 3, '.'); + REQUIRE(a == "abc...z"); + } + SECTION("Unicode") { + string a = "abcz"; + a.insert(a.begin() + 3, 3, U'๐Ÿ˜€'); + REQUIRE(a == "abc๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€z"); + } + } + + SECTION("At codepoint iterator") { + SECTION("One element") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(a.begin_codepoint() + string::codepoint_index(2), 1, '3'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); + } + SECTION("Multiple elements") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(a.begin_codepoint() + string::codepoint_index(2), 3, '.'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚...๐Ÿ˜"); + } + SECTION("Unicode") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(a.begin_codepoint() + string::codepoint_index(2), 3, U'๐Ÿ˜€'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("Literal string") { + SECTION("At index") { + SECTION("One element") { + string a = "124"; + a.insert(2, "3"); + REQUIRE(a == "1234"); + } + SECTION("Multiple elements") { + string a = "abcz"; + a.insert(3, "defgh"); + REQUIRE(a == "abcdefghz"); + } + SECTION("Unicode") { + string a = "abcz"; + a.insert(3, U"๐Ÿ™‚๐Ÿ˜€"); + REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€z"); + } + } + + SECTION("At codepoint") { + SECTION("One element") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(string::codepoint_index(2), "3"); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); + } + SECTION("Multiple elements") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(string::codepoint_index(2), "defgh"); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚defgh๐Ÿ˜"); + } + SECTION("Unicode") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(string::codepoint_index(2), U"๐Ÿ™‚๐Ÿ˜€"); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("Partial literal string") { + SECTION("At index") { + SECTION("One element") { + string a = "124"; + a.insert(2, "3456", 1); + REQUIRE(a == "1234"); + } + SECTION("Multiple elements") { + string a = "abcz"; + a.insert(3, "defghijklmn", 5); + REQUIRE(a == "abcdefghz"); + } + SECTION("Unicode") { + string a = "abcz"; + a.insert(3, U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€", 2); + REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€z"); + } + } + + SECTION("At codepoint") { + SECTION("One element") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(string::codepoint_index(2), "3456", 1); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); + } + SECTION("Multiple elements") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(string::codepoint_index(2), "defghijkl", 5); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚defgh๐Ÿ˜"); + } + SECTION("Unicode") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(string::codepoint_index(2), U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€", 2); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("Other string") { + SECTION("At index") { + SECTION("One element") { + string a = "124"; + string other("3"); + a.insert(2, other); + REQUIRE(a == "1234"); + } + SECTION("Multiple elements") { + string a = "abcz"; + string other("defgh"); + a.insert(3, other); + REQUIRE(a == "abcdefghz"); + } + SECTION("Unicode") { + string a = "abcz"; + string other(U"๐Ÿ™‚๐Ÿ˜€"); + a.insert(3, other); + REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€z"); + } + } + + SECTION("At codepoint") { + SECTION("One element") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + string other("3"); + a.insert(string::codepoint_index(2), other); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); + } + SECTION("Multiple elements") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + string other("defgh"); + a.insert(string::codepoint_index(2), other); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚defgh๐Ÿ˜"); + } + SECTION("Unicode") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + string other(U"๐Ÿ™‚๐Ÿ˜€"); + a.insert(string::codepoint_index(2), other); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("Other string suffix") { + SECTION("At index") { + SECTION("One element") { + string a = "124"; + string other("3456"); + a.insert(2, other, 1); + REQUIRE(a == "124564"); + } + SECTION("Multiple elements") { + string a = "abcz"; + string other("defghijklmn"); + a.insert(3, other, 5); + REQUIRE(a == "abcijklmnz"); + } + SECTION("Unicode") { + string a = "abcz"; + string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); + a.insert(3, other, 8); + REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€z"); + } + } + + SECTION("At codepoint") { + SECTION("One element") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + string other("3456"); + a.insert(string::codepoint_index(2), other, 1); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚456๐Ÿ˜"); + } + SECTION("Multiple elements") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + string other("defghijkl"); + a.insert(string::codepoint_index(2), other, 5); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚ijkl๐Ÿ˜"); + } + SECTION("Unicode") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); + a.insert(string::codepoint_index(2), other, 8); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("Other string codepoint suffix") { + SECTION("At index") { + SECTION("One element") { + string a = "124"; + string other("3456"); + a.insert(2, other, string::codepoint_index(1)); + REQUIRE(a == "124564"); + } + SECTION("Multiple elements") { + string a = "abcz"; + string other("defghijklmn"); + a.insert(3, other, string::codepoint_index(5)); + REQUIRE(a == "abcijklmnz"); + } + SECTION("Unicode") { + string a = "abcz"; + string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); + a.insert(3, other, string::codepoint_index(2)); + REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€z"); + } + } + + SECTION("At codepoint") { + SECTION("One element") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + string other("3456"); + a.insert(string::codepoint_index(2), other, string::codepoint_index(1)); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚456๐Ÿ˜"); + } + SECTION("Multiple elements") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + string other("defghijkl"); + a.insert(string::codepoint_index(2), other, string::codepoint_index(5)); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚ijkl๐Ÿ˜"); + } + SECTION("Unicode") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); + a.insert(string::codepoint_index(2), other, string::codepoint_index(2)); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("Other string substr") { + SECTION("At index") { + SECTION("One element") { + string a = "124"; + string other("3456"); + a.insert(2, other, 0, 1); + REQUIRE(a == "1234"); + } + SECTION("Multiple elements") { + string a = "abcz"; + string other("defghijklmn"); + a.insert(3, other, 1, 3); + REQUIRE(a == "abcefgz"); + } + SECTION("Unicode") { + string a = "abcz"; + string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); + a.insert(3, other, 4, 12); + REQUIRE(a == "abc๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€z"); + } + } + + SECTION("At codepoint") { + SECTION("One element") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + string other("3456"); + a.insert(string::codepoint_index(2), other, 1, 2); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚45๐Ÿ˜"); + } + SECTION("Multiple elements") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + string other("defghijkl"); + a.insert(string::codepoint_index(2), other, 5, 2); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚ij๐Ÿ˜"); + } + SECTION("Unicode") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); + a.insert(string::codepoint_index(2), other, 12, 8); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜"); + } + } + } + + SECTION("Other string codepoint substr") { + SECTION("At index") { + SECTION("One element") { + string a = "124"; + string other("3456"); + a.insert(2, other, string::codepoint_index(1), string::codepoint_index(2)); + REQUIRE(a == "12454"); + } + SECTION("Multiple elements") { + string a = "abcz"; + string other("defghijklmn"); + a.insert(3, other, string::codepoint_index(1), string::codepoint_index(3)); + REQUIRE(a == "abcefgz"); + } + SECTION("Unicode") { + string a = "abcz"; + string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); + a.insert(3, other, string::codepoint_index(2), string::codepoint_index(3)); + REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚z"); + } + } + + SECTION("At codepoint") { + SECTION("One element") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + string other("3456"); + a.insert(string::codepoint_index(2), other, string::codepoint_index(1), string::codepoint_index(2)); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚45๐Ÿ˜"); + } + SECTION("Multiple elements") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + string other("defghijkl"); + a.insert(string::codepoint_index(2), other, string::codepoint_index(5), string::codepoint_index(2)); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚ij๐Ÿ˜"); + } + SECTION("Unicode") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + string other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); + a.insert(string::codepoint_index(2), other, string::codepoint_index(3), string::codepoint_index(2)); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜"); + } + } + } + + SECTION("Single char") { + SECTION("At index") { + SECTION("Unibyte") { + string a = "abcz"; + a.insert(a.begin() + 3, 'd'); + REQUIRE(a == "abcdz"); + } + SECTION("Multibyte") { + string a = "abcz"; + a.insert(a.begin() + 3, U'๐Ÿ™‚'); + REQUIRE(a == "abc๐Ÿ™‚z"); + } + } + + SECTION("At codepoint") { + SECTION("Unibyte") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(a.begin_codepoint() + string::codepoint_index(2), '3'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); + } + SECTION("Multibyte") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(a.begin_codepoint() + string::codepoint_index(2), U'๐Ÿ˜€'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("Other container iterator") { + SECTION("At index") { + SECTION("One element") { + string a = "124"; + std::string other("3"); + a.insert(a.begin() + 2, other.begin(), other.end()); + REQUIRE(a == "1234"); + } + SECTION("Multiple elements") { + string a = "abcz"; + std::string other("defgh"); + a.insert(a.begin() + 3, other.begin(), other.end()); + REQUIRE(a == "abcdefghz"); + } + SECTION("Unicode") { + string a = "abcz"; + std::u32string other(U"๐Ÿ™‚๐Ÿ˜€"); + a.insert(a.begin() + 3, other.begin(), other.end()); + REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€z"); + } + } + + SECTION("At codepoint") { + SECTION("One element") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + std::string other("3"); + a.insert(a.begin_codepoint() + string::codepoint_index(2), other.begin(), other.end()); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); + } + SECTION("Multiple elements") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + std::string other("defgh"); + a.insert(a.begin_codepoint() + string::codepoint_index(2), other.begin(), other.end()); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚defgh๐Ÿ˜"); + } + SECTION("Unicode") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + std::u32string other(U"๐Ÿ™‚๐Ÿ˜€"); + a.insert(a.begin_codepoint() + string::codepoint_index(2), other.begin(), other.end()); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("Initializer list") { + SECTION("At index") { + SECTION("One element") { + string a = "124"; + a.insert(a.begin() + 2, {'3'}); + REQUIRE(a == "1234"); + } + SECTION("Multiple elements") { + string a = "abcz"; + a.insert(a.begin() + 3, {'d', 'e', 'f', 'g', 'h'}); + REQUIRE(a == "abcdefghz"); + } + SECTION("Unicode") { + string a = "abcz"; + a.insert(a.begin() + 3, {U'๐Ÿ™‚', U'๐Ÿ˜€'}); + REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€z"); + } + } + + SECTION("At codepoint") { + SECTION("One element") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(a.begin_codepoint() + string::codepoint_index(2), {'3'}); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); + } + SECTION("Multiple elements") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + a.insert(a.begin_codepoint() + string::codepoint_index(2), {'d', 'e', 'f', 'g', 'h'}); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚defgh๐Ÿ˜"); + } + SECTION("Unicode") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + std::u32string other(U"๐Ÿ™‚๐Ÿ˜€"); + a.insert(a.begin_codepoint() + string::codepoint_index(2), {U'๐Ÿ™‚', U'๐Ÿ˜€'}); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("String view") { + SECTION("At index") { + SECTION("One element") { + string a = "124"; + std::string_view other("3"); + a.insert(2, other); + REQUIRE(a == "1234"); + } + SECTION("Multiple elements") { + string a = "abcz"; + std::string_view other("defgh"); + a.insert(3, other); + REQUIRE(a == "abcdefghz"); + } + SECTION("Unicode") { + string a = "abcz"; + std::u32string_view other(U"๐Ÿ™‚๐Ÿ˜€"); + a.insert(3, other); + REQUIRE(a == "abc๐Ÿ™‚๐Ÿ˜€z"); + } + } + + SECTION("At codepoint") { + SECTION("One element") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + std::string_view other("3"); + a.insert(string::codepoint_index(2), other); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚3๐Ÿ˜"); + } + SECTION("Multiple elements") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + std::string_view other("defgh"); + a.insert(string::codepoint_index(2), other); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚defgh๐Ÿ˜"); + } + SECTION("Unicode") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + std::u32string_view other(U"๐Ÿ™‚๐Ÿ˜€"); + a.insert(string::codepoint_index(2), other); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("String view substr") { + SECTION("At index") { + SECTION("One element") { + string a = "124"; + std::string_view other("3456"); + a.insert(2, other, 0, 1); + REQUIRE(a == "1234"); + } + SECTION("Multiple elements") { + string a = "abcz"; + std::string_view other("defghijklmn"); + a.insert(3, other, 1, 3); + REQUIRE(a == "abcefgz"); + } + SECTION("Unicode") { + string a = "abcz"; + std::u32string_view other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); + a.insert(3, other, 1, 3); + REQUIRE(a == "abc๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€z"); + } + } + + SECTION("At codepoint") { + SECTION("One element") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + std::string_view other("3456"); + a.insert(string::codepoint_index(2), other, 1, 2); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚45๐Ÿ˜"); + } + SECTION("Multiple elements") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + std::string_view other("defghijkl"); + a.insert(string::codepoint_index(2), other, 5, 2); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚ij๐Ÿ˜"); + } + SECTION("Unicode") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜"; + std::u32string_view other(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); + a.insert(string::codepoint_index(2), other, 1, 3); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + } + } + + SECTION("Erase") { + SECTION("Index suffix") { + string a = "abcdefghij"; + a.erase(3); + REQUIRE(a == "abc"); + } + SECTION("Index substr") { + string a = "abcdefghij"; + a.erase(3, 2); + REQUIRE(a == "abcfghij"); + } + SECTION("Codepoint suffix") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.erase(string::codepoint_index(3)); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€"); + } + SECTION("Codepoint substr") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.erase(string::codepoint_index(3), string::codepoint_index(2)); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + SECTION("Single position") { + string a = "abcdefghij"; + a.erase(a.begin() + 3); + REQUIRE(a == "abcefghij"); + } + SECTION("Single codepoint") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.erase(a.begin_codepoint() + string::codepoint_index(3)); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); + } + SECTION("Index range") { + string a = "abcdefghij"; + a.erase(a.begin() + 3, a.begin() + 5); + REQUIRE(a == "abcfghij"); + } + SECTION("Codepoint range") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.erase(a.begin_codepoint() + string::codepoint_index(3), a.begin_codepoint() + string::codepoint_index(5)); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + + SECTION("Push back") { + SECTION("Single position") { + string a = "abcdefghij"; + a.push_back('k'); + REQUIRE(a == "abcdefghijk"); + } + SECTION("Single codepoint") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.push_back(U'๐Ÿ˜€'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€"); + } + } + + SECTION("Pop back") { + SECTION("Single position") { + string a = "abcdefghij"; + a.pop_back(); + REQUIRE(a == "abcdefghi"); + } + SECTION("Single codepoint") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.pop_back_codepoint(); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); + } + } + + SECTION("Push \"front\"") { + SECTION("Single position") { + string a = "abcdefghij"; + a.insert(a.begin(), 'k'); + REQUIRE(a == "kabcdefghij"); + } + SECTION("Single codepoint") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.insert(a.begin(), U'๐Ÿ˜€'); + REQUIRE(a == "๐Ÿ˜€๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + + SECTION("Pop \"front\"") { + SECTION("Single position") { + string a = "abcdefghij"; + a.erase(a.begin()); + REQUIRE(a == "bcdefghij"); + } + SECTION("Single codepoint") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.erase(a.begin_codepoint()); + REQUIRE(a == "๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + +} \ No newline at end of file diff --git a/tests/unit_tests/small_string_modify_algorithms.cpp b/tests/unit_tests/small_string_modify_algorithms.cpp new file mode 100644 index 0000000..557dfde --- /dev/null +++ b/tests/unit_tests/small_string_modify_algorithms.cpp @@ -0,0 +1,1338 @@ +#ifndef SMALL_BUILD_TESTS_WITH_PCH +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#endif + +// UTF8 string literals are really not safe in MSVC. +// u8"" doesn't work properly even with escape sequences. +// More recent versions might improve on that a little, but we will still +// need a more robust solution to support older versions in any case. +// Until then, it seems like the most robust solution is to initialize +// small::strings with U"...", even if that requires converting the +// codepoints. +constexpr bool is_windows() { +#if defined(_WIN32) + return true; +#else + return false; +#endif +} + +TEST_CASE("String Modifying Algorithms") { + using namespace small; + + SECTION("Append") { + SECTION("Chars") { + SECTION("Single position") { + string a = "abcdefghij"; + a.append(3, 'k'); + REQUIRE(a == "abcdefghijkkk"); + } + SECTION("Single codepoint") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.append(3, U'๐Ÿ˜€'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€"); + } + } + SECTION("Other string") { + SECTION("Complete") { + string a = "abcdefghij"; + string b = "klmnop"; + a.append(b); + REQUIRE(a == "abcdefghijklmnop"); + } + SECTION("Suffix") { + string a = "abcdefghij"; + string b = "klmnop"; + a.append(b, 2); + REQUIRE(a == "abcdefghijmnop"); + } + SECTION("Substr") { + string a = "abcdefghij"; + string b = "klmnop"; + a.append(b, 2, 3); + REQUIRE(a == "abcdefghijmno"); + } + SECTION("Codepoint Complete") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.append(b); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + SECTION("Codepoint Suffix") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.append(b, string::codepoint_index(2)); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + SECTION("Codepoint Substr") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.append(b, string::codepoint_index(2), string::codepoint_index(3)); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); + } + } + SECTION("String Literal") { + SECTION("Complete") { + string a = "abcdefghij"; + a.append("klmnop"); + REQUIRE(a == "abcdefghijklmnop"); + } + SECTION("Prefix") { + string a = "abcdefghij"; + a.append("klmnop", 2); + REQUIRE(a == "abcdefghijkl"); + } + SECTION("Codepoint Complete") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.append("๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + SECTION("Codepoint Prefix") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.append(U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜", 2); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚"); + } + } + + SECTION("Iterator ranges") { + SECTION("Complete") { + string a = "abcdefghij"; + std::string b = "klmnop"; + a.append(b.begin(), b.end()); + REQUIRE(a == "abcdefghijklmnop"); + } + SECTION("Prefix") { + string a = "abcdefghij"; + std::string b = "klmnop"; + a.append(b.begin(), b.begin() + 2); + REQUIRE(a == "abcdefghijkl"); + } + SECTION("Codepoint Complete") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + std::u32string b = U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.append(b.begin(), b.end()); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + SECTION("Codepoint Prefix") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + std::u32string b = U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.append(b.begin(), b.begin() + 2); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚"); + } + } + + SECTION("Initializer list") { + SECTION("Complete") { + string a = "abcdefghij"; + a.append({'k', 'l', 'm', 'n', 'o', 'p'}); + REQUIRE(a == "abcdefghijklmnop"); + } + SECTION("Codepoint Complete") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.append({U'๐Ÿ˜', U'๐Ÿ™‚', U'๐Ÿ˜€', U'๐Ÿ™‚', U'๐Ÿ˜€', U'๐Ÿ˜'}); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + + SECTION("Other string view") { + SECTION("Complete") { + string a = "abcdefghij"; + std::string_view b = "klmnop"; + a.append(b); + REQUIRE(a == "abcdefghijklmnop"); + } + SECTION("Suffix") { + string a = "abcdefghij"; + std::string_view b = "klmnop"; + a.append(b, 2); + REQUIRE(a == "abcdefghijmnop"); + } + SECTION("Substr") { + string a = "abcdefghij"; + std::string_view b = "klmnop"; + a.append(b, 2, 3); + REQUIRE(a == "abcdefghijmno"); + } + SECTION("Codepoint Complete") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + std::string_view b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.append(b); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + SECTION("Codepoint Suffix") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + std::u32string_view b = U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.append(b, 2); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + SECTION("Codepoint Substr") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + std::u32string_view b = U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.append(b, 2, 3); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€"); + } + } + } + + SECTION("Operator +=") { + SECTION("Other string") { + SECTION("Complete") { + string a = "abcdefghij"; + string b = "klmnop"; + a += b; + REQUIRE(a == "abcdefghijklmnop"); + } + SECTION("Codepoint Complete") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a += b; + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + SECTION("Chars") { + SECTION("Single position") { + string a = "abcdefghij"; + a += 'k'; + REQUIRE(a == "abcdefghijk"); + } + SECTION("Single codepoint") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a += U'๐Ÿ˜€'; + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€"); + } + } + SECTION("String Literal") { + SECTION("Complete") { + string a = "abcdefghij"; + a += "klmnop"; + REQUIRE(a == "abcdefghijklmnop"); + } + SECTION("Codepoint Complete") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a += "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + + SECTION("Initializer list") { + SECTION("Complete") { + string a = "abcdefghij"; + a += {'k', 'l', 'm', 'n', 'o', 'p'}; + REQUIRE(a == "abcdefghijklmnop"); + } + SECTION("Codepoint Complete") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a += {U'๐Ÿ˜', U'๐Ÿ™‚', U'๐Ÿ˜€', U'๐Ÿ™‚', U'๐Ÿ˜€', U'๐Ÿ˜'}; + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + + SECTION("Other string view") { + SECTION("Complete") { + string a = "abcdefghij"; + std::string_view b = "klmnop"; + a += b; + REQUIRE(a == "abcdefghijklmnop"); + } + SECTION("Codepoint Complete") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + std::string_view b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a += b; + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("Starts with") { + SECTION("String view") { + SECTION("UTF8 rhs") { + string a = "abcdefghij"; + SECTION("Starts not-empty") { + std::string_view b = "abcde"; + REQUIRE(a.starts_with(b)); + } + + SECTION("Might find but does not start with") { + std::string_view b = "bcdef"; + REQUIRE_FALSE(a.starts_with(b)); + } + + SECTION("Always start with empty") { + std::string_view b = ""; // NOLINT(readability-redundant-string-init) + REQUIRE(a.starts_with(b)); + } + + SECTION("Cannot start with if empty") { + a.clear(); + std::string_view b = "bcdef"; + REQUIRE_FALSE(a.starts_with(b)); + } + + SECTION("Always start if both empty") { + a.clear(); + std::string_view b = ""; // NOLINT(readability-redundant-string-init) + REQUIRE(a.starts_with(b)); + } + } + + if constexpr (not is_windows()) { + SECTION("UTF32 rhs") { + string a = u8"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + SECTION("Starts not-empty") { + std::u32string_view b = U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€"; + REQUIRE(a.starts_with(b)); + } + + SECTION("Might find but does not start with") { + std::u32string_view b = U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚"; + REQUIRE_FALSE(a.starts_with(b)); + } + + SECTION("Always start with empty") { + std::u32string_view b = U""; // NOLINT(readability-redundant-string-init) + REQUIRE(a.starts_with(b)); + } + + SECTION("Cannot start with if empty") { + a.clear(); + std::u32string_view b = U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€"; + REQUIRE_FALSE(a.starts_with(b)); + } + + SECTION("Always start if both empty") { + a.clear(); + std::u32string_view b = U""; // NOLINT(readability-redundant-string-init) + REQUIRE(a.starts_with(b)); + } + } + } + } + + SECTION("Char") { + SECTION("UTF8 rhs") { + string a = "abcdefghij"; + SECTION("Starts not-empty") { REQUIRE(a.starts_with('a')); } + + SECTION("Might find but does not start with") { REQUIRE_FALSE(a.starts_with('b')); } + + SECTION("Cannot start with if empty") { + a.clear(); + REQUIRE_FALSE(a.starts_with('a')); + } + } + SECTION("UTF32 rhs") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + SECTION("Starts not-empty") { REQUIRE(a.starts_with(U'๐Ÿ˜')); } + + SECTION("Might find but does not start with") { REQUIRE_FALSE(a.starts_with(U'๐Ÿ™‚')); } + + SECTION("Cannot start with if empty") { + a.clear(); + REQUIRE_FALSE(a.starts_with(U'๐Ÿ˜')); + } + } + } + + SECTION("String literal") { + SECTION("UTF8 rhs") { + string a = "abcdefghij"; + SECTION("Starts not-empty") { REQUIRE(a.starts_with("abcde")); } + + SECTION("Might find but does not start with") { REQUIRE_FALSE(a.starts_with("bcdef")); } + + SECTION("Always start with empty") { REQUIRE(a.starts_with("")); } + + SECTION("Cannot start with if empty") { + a.clear(); + REQUIRE_FALSE(a.starts_with("bcdef")); + } + + SECTION("Always start if both empty") { + a.clear(); + REQUIRE(a.starts_with("")); + } + } + SECTION("UTF32 rhs") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + SECTION("Starts not-empty") { REQUIRE(a.starts_with(U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€")); } + + SECTION("Might find but does not start with") { REQUIRE_FALSE(a.starts_with(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚")); } + + SECTION("Always start with empty") { REQUIRE(a.starts_with(U"")); } + + SECTION("Cannot start with if empty") { + a.clear(); + REQUIRE_FALSE(a.starts_with(U"๐Ÿ˜๐Ÿ™‚๐Ÿ˜€")); + } + + SECTION("Always start if both empty") { + a.clear(); + REQUIRE(a.starts_with(U"")); + } + } + } + } + + SECTION("Ends with") { + SECTION("String view") { + SECTION("UTF8 rhs") { + string a = "abcdefghij"; + SECTION("Ends not-empty") { + std::string_view b = "ghij"; + REQUIRE(a.ends_with(b)); + } + + SECTION("Might find but does not end with") { + std::string_view b = "bcdef"; + REQUIRE_FALSE(a.ends_with(b)); + } + + SECTION("Always end with empty") { + std::string_view b = ""; // NOLINT(readability-redundant-string-init) + REQUIRE(a.ends_with(b)); + } + + SECTION("Cannot end with if empty") { + a.clear(); + std::string_view b = "ghij"; + REQUIRE_FALSE(a.ends_with(b)); + } + + SECTION("Always end if both empty") { + a.clear(); + std::string_view b = ""; // NOLINT(readability-redundant-string-init) + REQUIRE(a.ends_with(b)); + } + } + SECTION("UTF32 rhs") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + SECTION("Ends not-empty") { + std::u32string_view b = U"๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + REQUIRE(a.ends_with(b)); + } + + SECTION("Might find but does not end with") { + std::u32string_view b = U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚"; + REQUIRE_FALSE(a.ends_with(b)); + } + + SECTION("Always end with empty") { + std::u32string_view b = U""; // NOLINT(readability-redundant-string-init) + REQUIRE(a.ends_with(b)); + } + + SECTION("Cannot end with if empty") { + a.clear(); + std::u32string_view b = U"๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + REQUIRE_FALSE(a.ends_with(b)); + } + + SECTION("Always end if both empty") { + a.clear(); + std::u32string_view b = U""; // NOLINT(readability-redundant-string-init) + REQUIRE(a.ends_with(b)); + } + } + } + + SECTION("Char") { + SECTION("UTF8 rhs") { + string a = "abcdefghij"; + SECTION("Ends not-empty") { REQUIRE(a.ends_with('j')); } + + SECTION("Might find but does not end with") { REQUIRE_FALSE(a.ends_with('b')); } + + SECTION("Cannot end with if empty") { + a.clear(); + REQUIRE_FALSE(a.ends_with('j')); + } + } + SECTION("UTF32 rhs") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + SECTION("Ends not-empty") { REQUIRE(a.ends_with(U'๐Ÿ˜')); } + + SECTION("Might find but does not end with") { REQUIRE_FALSE(a.ends_with(U'๐Ÿ™‚')); } + + SECTION("Cannot end with if empty") { + a.clear(); + REQUIRE_FALSE(a.ends_with(U'๐Ÿ˜')); + } + } + } + + SECTION("String literal") { + SECTION("UTF8 rhs") { + string a = "abcdefghij"; + SECTION("Ends not-empty") { REQUIRE(a.ends_with("ghij")); } + + SECTION("Might find but does not end with") { REQUIRE_FALSE(a.ends_with("bcdef")); } + + SECTION("Always end with empty") { REQUIRE(a.ends_with("")); } + + SECTION("Cannot end with if empty") { + a.clear(); + REQUIRE_FALSE(a.ends_with("bcdef")); + } + + SECTION("Always end if both empty") { + a.clear(); + REQUIRE(a.ends_with("")); + } + } + SECTION("UTF32 rhs") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + SECTION("Ends not-empty") { REQUIRE(a.ends_with(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ˜")); } + + SECTION("Might find but does not end with") { REQUIRE_FALSE(a.ends_with(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚")); } + + SECTION("Always end with empty") { REQUIRE(a.ends_with(U"")); } + + SECTION("Cannot end with if empty") { + a.clear(); + REQUIRE_FALSE(a.ends_with(U"๐Ÿ™‚๐Ÿ˜€๐Ÿ˜")); + } + + SECTION("Always end if both empty") { + a.clear(); + REQUIRE(a.ends_with(U"")); + } + } + } + } + + SECTION("Contains") { + SECTION("String view") { + SECTION("UTF8 rhs") { + string a = "abcdefghij"; + SECTION("Contains start") { + std::string_view b = "abc"; + REQUIRE(a.contains(b)); + } + + SECTION("Contains middle") { + std::string_view b = "def"; + REQUIRE(a.contains(b)); + } + + SECTION("Contains end") { + std::string_view b = "hij"; + REQUIRE(a.contains(b)); + } + + SECTION("Does not contain") { + std::string_view b = "ijk"; + REQUIRE_FALSE(a.contains(b)); + } + + SECTION("Always contains empty") { + std::string_view b = ""; // NOLINT(readability-redundant-string-init) + REQUIRE(a.contains(b)); + } + + SECTION("Cannot contain if empty") { + a.clear(); + std::string_view b = "ghij"; + REQUIRE_FALSE(a.contains(b)); + } + + SECTION("Always contains if both empty") { + a.clear(); + std::string_view b = ""; // NOLINT(readability-redundant-string-init) + REQUIRE(a.contains(b)); + } + } + SECTION("UTF32 rhs") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + SECTION("Contains start") { + std::u32string_view b = U"๐Ÿ˜๐Ÿ™‚"; + REQUIRE(a.contains(b)); + } + + SECTION("Contains middle") { + std::u32string_view b = U"๐Ÿ˜€๐Ÿ™‚"; + REQUIRE(a.contains(b)); + } + + SECTION("Contains end") { + std::u32string_view b = U"๐Ÿ˜€๐Ÿ˜"; + REQUIRE(a.contains(b)); + } + + SECTION("Does not contain") { + std::u32string_view b = U"๐Ÿ˜๐Ÿ˜€"; + REQUIRE_FALSE(a.contains(b)); + } + + SECTION("Always contains empty") { + std::u32string_view b = U""; // NOLINT(readability-redundant-string-init) + REQUIRE(a.contains(b)); + } + + SECTION("Cannot contain if empty") { + a.clear(); + std::u32string_view b = U"๐Ÿ˜๐Ÿ™‚"; + REQUIRE_FALSE(a.contains(b)); + } + + SECTION("Always contains if both empty") { + a.clear(); + std::u32string_view b = U""; // NOLINT(readability-redundant-string-init) + REQUIRE(a.contains(b)); + } + } + } + + SECTION("Char") { + SECTION("UTF8 rhs") { + string a = "abcdefghij"; + SECTION("Start") { REQUIRE(a.contains('a')); } + + SECTION("Middle") { REQUIRE(a.contains('f')); } + + SECTION("End") { REQUIRE(a.contains('j')); } + + SECTION("Cannot contains if empty") { + a.clear(); + REQUIRE_FALSE(a.contains('j')); + } + } + SECTION("UTF32 rhs") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + SECTION("Start") { REQUIRE(a.contains(U'๐Ÿ˜')); } + + SECTION("Middle") { REQUIRE(a.contains(U'๐Ÿ™‚')); } + + SECTION("End") { REQUIRE(a.contains(U'๐Ÿ˜')); } + + SECTION("Cannot contains if empty") { + a.clear(); + REQUIRE_FALSE(a.contains(U'๐Ÿ˜')); + } + } + } + + SECTION("String view") { + SECTION("UTF8 rhs") { + string a = "abcdefghij"; + SECTION("Contains start") { REQUIRE(a.contains("abc")); } + + SECTION("Contains middle") { REQUIRE(a.contains("def")); } + + SECTION("Contains end") { REQUIRE(a.contains("hij")); } + + SECTION("Does not contain") { REQUIRE_FALSE(a.contains("ijk")); } + + SECTION("Always contains empty") { REQUIRE(a.contains("")); } + + SECTION("Cannot contain if empty") { + a.clear(); + REQUIRE_FALSE(a.contains("ghij")); + } + + SECTION("Always contains if both empty") { + a.clear(); + REQUIRE(a.contains("")); + } + } + SECTION("UTF32 rhs") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + SECTION("Contains start") { REQUIRE(a.contains(U"๐Ÿ˜๐Ÿ™‚")); } + + SECTION("Contains middle") { REQUIRE(a.contains(U"๐Ÿ˜€๐Ÿ™‚")); } + + SECTION("Contains end") { REQUIRE(a.contains(U"๐Ÿ˜€๐Ÿ˜")); } + + SECTION("Does not contain") { REQUIRE_FALSE(a.contains(U"๐Ÿ˜๐Ÿ˜€")); } + + SECTION("Always contains empty") { REQUIRE(a.contains(U"")); } + + SECTION("Cannot contain if empty") { + a.clear(); + REQUIRE_FALSE(a.contains(U"๐Ÿ˜๐Ÿ™‚")); + } + + SECTION("Always contains if both empty") { + a.clear(); + REQUIRE(a.contains(U"")); + } + } + } + } + + SECTION("Replace") { + SECTION("Other string") { + SECTION("Replace code units") { + string a = "abcdefghij"; + + SECTION("Replace start") { + string b = "xxx"; + a.replace(a.begin(), a.begin() + 3, b); + REQUIRE(a == "xxxdefghij"); + } + + SECTION("Replace middle") { + string b = "xxx"; + a.replace(a.begin() + 3, a.begin() + 6, b); + REQUIRE(a == "abcxxxghij"); + } + + SECTION("Replace end") { + string b = "xxx"; + a.replace(a.begin() + 7, a.begin() + 10, b); + REQUIRE(a == "abcdefgxxx"); + } + } + + SECTION("Replace code points") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + + SECTION("Replace start") { + string b = "xxx"; + a.replace(a.begin_codepoint(), a.begin_codepoint() + 3, b); + REQUIRE(a == "xxx๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace middle") { + string b = "xxx"; + a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, b); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xxx๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace end") { + string b = "xxx"; + a.replace(a.begin_codepoint() + 4, a.begin_codepoint() + 6, b); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚xxx"); + } + } + + SECTION("Replace code units with substr") { + string a = "abcdefghij"; + + SECTION("Replace with suffix") { + string b = "123"; + a.replace(3, 3, b, 1); + REQUIRE(a == "abc23ghij"); + } + + SECTION("Replace with substr") { + string b = "123"; + a.replace(3, 3, b, 1, 1); + REQUIRE(a == "abc2ghij"); + } + + SECTION("Replace with code point suffix") { + string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.replace(3, 3, b, string::codepoint_index(2)); + REQUIRE(a == "abc๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜ghij"); + } + + SECTION("Replace with code point substr") { + string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.replace(3, 3, b, string::codepoint_index(2), string::codepoint_index(2)); + REQUIRE(a == "abc๐Ÿ˜€๐Ÿ™‚ghij"); + } + } + + SECTION("Replace code points with substr") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + + SECTION("Replace with suffix") { + string b = "123"; + a.replace(string::codepoint_index(2), string::codepoint_index(2), b, 1); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚23๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace with substr") { + string b = "123"; + a.replace(string::codepoint_index(2), string::codepoint_index(2), b, 1, 1); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚2๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace with code point suffix") { + string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.replace(string::codepoint_index(2), string::codepoint_index(2), b, string::codepoint_index(2)); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace with code point substr") { + string b = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + a.replace(string::codepoint_index(2), string::codepoint_index(2), b, string::codepoint_index(2), + string::codepoint_index(2)); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("Iterators") { + SECTION("Code units iterator") { + string a = "abcdefghij"; + SECTION("Rhs is smaller") { + string b = "123"; + a.replace(a.begin() + 3, a.begin() + 5, b.begin() + 1, b.begin() + 2); + REQUIRE(a == "abc2fghij"); + } + + SECTION("Rhs is same size") { + string b = "123"; + a.replace(a.begin() + 3, a.begin() + 5, b.begin() + 1, b.begin() + 3); + REQUIRE(a == "abc23fghij"); + } + + SECTION("Rhs is larger") { + string b = "123"; + a.replace(a.begin() + 3, a.begin() + 5, b.begin() + 0, b.begin() + 3); + REQUIRE(a == "abc123fghij"); + } + } + + SECTION("Code point iterator") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + SECTION("Rhs is smaller") { + string b = "๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ"; + a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, b.begin_codepoint() + 1, + b.begin_codepoint() + 2); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™ƒ๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Rhs is same size") { + string b = "๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ"; + a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, b.begin_codepoint() + 1, + b.begin_codepoint() + 3); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Rhs is larger") { + string b = "๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ"; + a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, b.begin_codepoint() + 1, + b.begin_codepoint() + 4); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("String literal") { + SECTION("Replace code unit indexes") { + string a = "abcdefghij"; + + SECTION("Replace start") { + a.replace(0, 0 + 3, "xxx"); + REQUIRE(a == "xxxdefghij"); + } + + SECTION("Replace middle") { + a.replace(3, 3, "xxx"); + REQUIRE(a == "abcxxxghij"); + } + + SECTION("Replace end") { + a.replace(7, 3, "xxx"); + REQUIRE(a == "abcdefgxxx"); + } + } + + SECTION("Replace code unit indexes with substr") { + string a = "abcdefghij"; + + SECTION("Replace start") { + a.replace(0, 0 + 3, "xxx", 2); + REQUIRE(a == "xxdefghij"); + } + + SECTION("Replace middle") { + a.replace(3, 3, "xxx", 2); + REQUIRE(a == "abcxxghij"); + } + + SECTION("Replace end") { + a.replace(7, 3, "xxx", 2); + REQUIRE(a == "abcdefgxx"); + } + } + + SECTION("Replace code point indexes") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + + SECTION("Replace start") { + a.replace(string::codepoint_index(0), string::codepoint_index(3), U"๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ"); + REQUIRE(a == "๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace middle") { + a.replace(string::codepoint_index(2), string::codepoint_index(2), U"๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ"); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace end") { + a.replace(string::codepoint_index(4), string::codepoint_index(2), U"๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ"); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ"); + } + } + + SECTION("Replace code point indexes with substr") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + + SECTION("Replace start") { + a.replace(string::codepoint_index(0), string::codepoint_index(2), U"๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ", 2); + REQUIRE(a == "๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace middle") { + a.replace(string::codepoint_index(2), string::codepoint_index(2), U"๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ", 2); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace end") { + a.replace(string::codepoint_index(4), string::codepoint_index(2), U"๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ๐Ÿ™ƒ", 2); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ™ƒ๐Ÿ™ƒ"); + } + } + + SECTION("Replace code units iterators") { + string a = "abcdefghij"; + + SECTION("Replace start") { + a.replace(a.begin(), a.begin() + 3, "xxx"); + REQUIRE(a == "xxxdefghij"); + } + + SECTION("Replace middle") { + a.replace(a.begin() + 3, a.begin() + 6, "xxx"); + REQUIRE(a == "abcxxxghij"); + } + + SECTION("Replace end") { + a.replace(a.begin() + 7, a.begin() + 10, "xxx"); + REQUIRE(a == "abcdefgxxx"); + } + } + + SECTION("Replace code units iterators with substr") { + string a = "abcdefghij"; + + SECTION("Replace start") { + a.replace(a.begin(), a.begin() + 3, "xxx", 2); + REQUIRE(a == "xxdefghij"); + } + + SECTION("Replace middle") { + a.replace(a.begin() + 3, a.begin() + 6, "xxx", 2); + REQUIRE(a == "abcxxghij"); + } + + SECTION("Replace end") { + a.replace(a.begin() + 7, a.begin() + 10, "xxx", 2); + REQUIRE(a == "abcdefgxx"); + } + } + + SECTION("Replace code points") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + + SECTION("Replace start") { + a.replace(a.begin_codepoint(), a.begin_codepoint() + 3, "xxx"); + REQUIRE(a == "xxx๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace middle") { + a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, "xxx"); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xxx๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace end") { + a.replace(a.begin_codepoint() + 4, a.begin_codepoint() + 6, "xxx"); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚xxx"); + } + } + + SECTION("Replace code points with substr") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + + SECTION("Replace start") { + a.replace(a.begin_codepoint(), a.begin_codepoint() + 3, "xxx", 2); + REQUIRE(a == "xx๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace middle") { + a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, "xxx", 2); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xx๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace end") { + a.replace(a.begin_codepoint() + 4, a.begin_codepoint() + 6, "xxx", 2); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚xx"); + } + } + + SECTION("Replace code units with substr") { + string a = "abcdefghij"; + + SECTION("Replace with suffix") { + a.replace(3, 3, "123", 1); + REQUIRE(a == "abc1ghij"); + } + + SECTION("Replace with substr") { + a.replace(3, 3, "123", 1, 1); + REQUIRE(a == "abc2ghij"); + } + + SECTION("Replace with code point suffix") { + a.replace(3, 3, "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜", 8); + REQUIRE(a == "abc๐Ÿ˜๐Ÿ™‚ghij"); + } + + SECTION("Replace with code point substr") { + a.replace(3, 3, "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜", 8, 8); + REQUIRE(a == "abc๐Ÿ˜€๐Ÿ™‚ghij"); + } + } + + SECTION("Replace code points with substr") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + + SECTION("Replace with suffix") { + a.replace(string::codepoint_index(2), string::codepoint_index(2), "123", 1); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚1๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace with substr") { + a.replace(string::codepoint_index(2), string::codepoint_index(2), "123", 1, 1); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚2๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace with code point suffix") { + a.replace(string::codepoint_index(2), string::codepoint_index(2), "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜", 8); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace with code point substr") { + a.replace(string::codepoint_index(2), string::codepoint_index(2), "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜", 8, 8); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("Char") { + SECTION("Replace code unit indexes") { + string a = "abcdefghij"; + + SECTION("Smaller") { + a.replace(3, 2, 1, 'x'); + REQUIRE(a == "abcxfghij"); + } + + SECTION("Same size") { + a.replace(3, 2, 2, 'x'); + REQUIRE(a == "abcxxfghij"); + } + + SECTION("Larger") { + a.replace(3, 2, 3, 'x'); + REQUIRE(a == "abcxxxfghij"); + } + + SECTION("Wide char") { + a.replace(3, 2, 1, U'๐Ÿ˜€'); + REQUIRE(a == "abc๐Ÿ˜€fghij"); + } + + SECTION("Wide char twice") { + a.replace(3, 2, 2, U'๐Ÿ˜€'); + REQUIRE(a == "abc๐Ÿ˜€๐Ÿ˜€fghij"); + } + + SECTION("Wide char 3x") { + a.replace(3, 2, 3, U'๐Ÿ˜€'); + REQUIRE(a == "abc๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€fghij"); + } + } + + SECTION("Replace code point indexes") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + + SECTION("Smaller") { + a.replace(string::codepoint_index(2), string::codepoint_index(2), 1, 'x'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚x๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Same size") { + a.replace(string::codepoint_index(2), string::codepoint_index(2), 2, 'x'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xx๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Larger") { + a.replace(string::codepoint_index(2), string::codepoint_index(2), 3, 'x'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xxx๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Wide char") { + a.replace(string::codepoint_index(2), string::codepoint_index(2), 1, U'๐Ÿ˜€'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Wide char twice") { + a.replace(string::codepoint_index(2), string::codepoint_index(2), 2, U'๐Ÿ˜€'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Wide char 3x") { + a.replace(string::codepoint_index(2), string::codepoint_index(2), 3, U'๐Ÿ˜€'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); + } + } + + SECTION("Replace code unit iterators") { + string a = "abcdefghij"; + + SECTION("Smaller") { + a.replace(a.begin() + 3, a.begin() + 3 + 2, 1, 'x'); + REQUIRE(a == "abcxfghij"); + } + + SECTION("Same size") { + a.replace(a.begin() + 3, a.begin() + 3 + 2, 2, 'x'); + REQUIRE(a == "abcxxfghij"); + } + + SECTION("Larger") { + a.replace(a.begin() + 3, a.begin() + 3 + 2, 3, 'x'); + REQUIRE(a == "abcxxxfghij"); + } + + SECTION("Wide char") { + a.replace(a.begin() + 3, a.begin() + 3 + 2, 1, U'๐Ÿ˜€'); + REQUIRE(a == "abc๐Ÿ˜€fghij"); + } + + SECTION("Wide char twice") { + a.replace(a.begin() + 3, a.begin() + 3 + 2, 2, U'๐Ÿ˜€'); + REQUIRE(a == "abc๐Ÿ˜€๐Ÿ˜€fghij"); + } + + SECTION("Wide char 3x") { + a.replace(a.begin() + 3, a.begin() + 3 + 2, 3, U'๐Ÿ˜€'); + REQUIRE(a == "abc๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€fghij"); + } + } + + SECTION("Replace code point iterators") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + + SECTION("Smaller") { + a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 2 + 2, 1, 'x'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚x๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Same size") { + a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 2 + 2, 2, 'x'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xx๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Larger") { + a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 2 + 2, 3, 'x'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xxx๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Wide char") { + a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 2 + 2, 1, U'๐Ÿ˜€'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Wide char twice") { + a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 2 + 2, 2, U'๐Ÿ˜€'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Wide char 3x") { + a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 2 + 2, 3, U'๐Ÿ˜€'); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜€๐Ÿ˜"); + } + } + } + + SECTION("Initializer list") { + SECTION("Replace code unit iterators") { + string a = "abcdefghij"; + + SECTION("Replace start") { + a.replace(a.begin(), a.begin() + 3, {'x', 'x', 'x'}); + REQUIRE(a == "xxxdefghij"); + } + + SECTION("Replace middle") { + a.replace(a.begin() + 3, a.begin() + 6, {'x', 'x', 'x'}); + REQUIRE(a == "abcxxxghij"); + } + + SECTION("Replace end") { + a.replace(a.begin() + 7, a.begin() + 10, {'x', 'x', 'x'}); + REQUIRE(a == "abcdefgxxx"); + } + } + + SECTION("Replace code point iterators") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + + SECTION("Replace start") { + a.replace(a.begin_codepoint(), a.begin_codepoint() + 3, {'x', 'x', 'x'}); + REQUIRE(a == "xxx๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace middle") { + a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, {'x', 'x', 'x'}); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xxx๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace end") { + a.replace(a.begin_codepoint() + 4, a.begin_codepoint() + 6, {'x', 'x', 'x'}); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚xxx"); + } + } + } + + SECTION("String view") { + SECTION("Replace code unit indexes") { + string a = "abcdefghij"; + + SECTION("Replace start") { + std::string_view b = "xxx"; + a.replace(0, 3, b); + REQUIRE(a == "xxxdefghij"); + } + + SECTION("Replace middle") { + std::string_view b = "xxx"; + a.replace(3, 3, b); + REQUIRE(a == "abcxxxghij"); + } + + SECTION("Replace end") { + std::string_view b = "xxx"; + a.replace(7, 3, b); + REQUIRE(a == "abcdefgxxx"); + } + } + + SECTION("Replace code point indexes") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + + SECTION("Replace start") { + std::string_view b = "xxx"; + a.replace(string::codepoint_index(0), string::codepoint_index(3), b); + REQUIRE(a == "xxx๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace middle") { + std::string_view b = "xxx"; + a.replace(string::codepoint_index(2), string::codepoint_index(2), b); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xxx๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace end") { + std::string_view b = "xxx"; + a.replace(string::codepoint_index(4), string::codepoint_index(2), b); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚xxx"); + } + } + + SECTION("Replace code unit iterators") { + string a = "abcdefghij"; + + SECTION("Replace start") { + std::string_view b = "xxx"; + a.replace(a.begin(), a.begin() + 3, b); + REQUIRE(a == "xxxdefghij"); + } + + SECTION("Replace middle") { + std::string_view b = "xxx"; + a.replace(a.begin() + 3, a.begin() + 6, b); + REQUIRE(a == "abcxxxghij"); + } + + SECTION("Replace end") { + std::string_view b = "xxx"; + a.replace(a.begin() + 7, a.begin() + 10, b); + REQUIRE(a == "abcdefgxxx"); + } + } + + SECTION("Replace code point iterators") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + + SECTION("Replace start") { + std::string_view b = "xxx"; + a.replace(a.begin_codepoint(), a.begin_codepoint() + 3, b); + REQUIRE(a == "xxx๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace middle") { + std::string_view b = "xxx"; + a.replace(a.begin_codepoint() + 2, a.begin_codepoint() + 4, b); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xxx๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace end") { + std::string_view b = "xxx"; + a.replace(a.begin_codepoint() + 4, a.begin_codepoint() + 6, b); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚xxx"); + } + } + + SECTION("Replace code unit indexes with substr") { + string a = "abcdefghij"; + + SECTION("Replace start") { + std::string_view b = "xxx"; + a.replace(0, 3, b, 1); + REQUIRE(a == "xxdefghij"); + } + + SECTION("Replace middle") { + std::string_view b = "xxx"; + a.replace(3, 3, b, 1); + REQUIRE(a == "abcxxghij"); + } + + SECTION("Replace end") { + std::string_view b = "xxx"; + a.replace(7, 3, b, 1); + REQUIRE(a == "abcdefgxx"); + } + } + + SECTION("Replace code point indexes with substr") { + string a = "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"; + + SECTION("Replace start") { + std::string_view b = "xxx"; + a.replace(string::codepoint_index(0), string::codepoint_index(3), b, 1); + REQUIRE(a == "xx๐Ÿ™‚๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace middle") { + std::string_view b = "xxx"; + a.replace(string::codepoint_index(2), string::codepoint_index(2), b, 1); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚xx๐Ÿ˜€๐Ÿ˜"); + } + + SECTION("Replace end") { + std::string_view b = "xxx"; + a.replace(string::codepoint_index(4), string::codepoint_index(2), b, 1); + REQUIRE(a == "๐Ÿ˜๐Ÿ™‚๐Ÿ˜€๐Ÿ™‚xx"); + } + } + } + } +} \ No newline at end of file diff --git a/tests/unit_tests/small_string_non_member.cpp b/tests/unit_tests/small_string_non_member.cpp new file mode 100644 index 0000000..2bbb1b3 --- /dev/null +++ b/tests/unit_tests/small_string_non_member.cpp @@ -0,0 +1,236 @@ +#ifndef SMALL_BUILD_TESTS_WITH_PCH +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#endif + +// UTF8 string literals are really not safe in MSVC. +// u8"" doesn't work properly even with escape sequences. +// More recent versions might improve on that a little, but we will still +// need a more robust solution to support older versions in any case. +// Until then, it seems like the most robust solution is to initialize +// small::strings with U"...", even if that requires converting the +// codepoints. +constexpr bool is_windows() { +#if defined(_WIN32) + return true; +#else + return false; +#endif +} + +TEST_CASE("String Non-Member") { + using namespace small; + + SECTION("Non-member") { + SECTION("Concatenate strings") { + SECTION("const string & + const string &") { + string lhs = "abc"; + string rhs = "def"; + string c = lhs + rhs; + REQUIRE(c == "abcdef"); + } + SECTION("const string & + const char *") { + string lhs = "abc"; + string c = lhs + "def"; + REQUIRE(c == "abcdef"); + } + SECTION("const string & + char ") { + string lhs = "abc"; + char rhs = 'd'; + string c = lhs + rhs; + REQUIRE(c == "abcd"); + } + SECTION("const char * + const string &") { + string rhs = "def"; + string c = "abc" + rhs; + REQUIRE(c == "abcdef"); + } + SECTION("char + const string &") { + char lhs = 'a'; + string rhs = "def"; + string c = lhs + rhs; + REQUIRE(c == "adef"); + } + SECTION("string && + string &&") { + string lhs = "abc"; + string rhs = "def"; + string c = std::move(lhs) + std::move(rhs); + REQUIRE(c == "abcdef"); + } + SECTION("string && + const string &") { + string lhs = "abc"; + string rhs = "def"; + string c = std::move(lhs) + rhs; + REQUIRE(c == "abcdef"); + } + SECTION("string && + const char *") { + string lhs = "abc"; + string c = std::move(lhs) + "def"; + REQUIRE(c == "abcdef"); + } + SECTION("string && + char ") { + string lhs = "abc"; + char rhs = 'd'; + string c = std::move(lhs) + rhs; + REQUIRE(c == "abcd"); + } + SECTION("const string & + string &&") { + string lhs = "abc"; + string rhs = "def"; + string c = lhs + std::move(rhs); + REQUIRE(c == "abcdef"); + } + SECTION("const char * + string &&") { + string rhs = "def"; + string c = "abc" + std::move(rhs); + REQUIRE(c == "abcdef"); + } + SECTION("char + string &&") { + char lhs = 'a'; + string rhs = "def"; + string c = lhs + std::move(rhs); + REQUIRE(c == "adef"); + } + } + + SECTION("Erase") { + string cnt(10, ' '); + std::iota(cnt.begin(), cnt.end(), '0'); + + SECTION("Values") { + erase(cnt, '3'); + REQUIRE(cnt == "012456789"); + } + + SECTION("Condition") { + size_t n_erased = erase_if(cnt, [](char x) { return (x - '0') % 2 == 0; }); + REQUIRE(cnt == "13579"); + REQUIRE(n_erased == 5); + } + } + + SECTION("Streams") { + small::string a = "123456"; + + SECTION("Output") { + std::stringstream ss; + ss << a; + REQUIRE(ss.str() == "123456"); + } + + SECTION("Input") { + std::stringstream ss; + ss << "123"; + ss >> a; + REQUIRE(a == "123"); + } + + SECTION("Getline") { + std::stringstream ss; + ss << "123 456\n789\n"; + getline(ss, a); + REQUIRE(a == "123 456"); + } + } + + SECTION("String to number") { + SECTION("Integer") { + small::string i = "123"; + std::unique_ptr size = std::make_unique(0); + SECTION("stoi") { + int n = stoi(i, size.get(), 10); + REQUIRE(n == 123); + REQUIRE(*size == 3); + } + SECTION("stol") { + long n = stol(i, size.get(), 10); + REQUIRE(n == 123); + REQUIRE(*size == 3); + } + SECTION("stoll") { + long long n = stoll(i, size.get(), 10); + REQUIRE(n == 123); + REQUIRE(*size == 3); + } + SECTION("stoul") { + unsigned long n = stoul(i, size.get(), 10); + REQUIRE(n == 123); + REQUIRE(*size == 3); + } + SECTION("stoull") { + unsigned long long n = stoull(i, size.get(), 10); + REQUIRE(n == 123); + REQUIRE(*size == 3); + } + } + + SECTION("Floating") { + small::string d = "123.456"; + std::unique_ptr size = std::make_unique(0); + SECTION("stof") { + float n = stof(d, size.get()); + REQUIRE(n >= 123.455); + REQUIRE(n <= 123.457); + REQUIRE(*size == 7); + } + SECTION("stod") { + double n = stod(d, size.get()); + REQUIRE(n >= 123.455); + REQUIRE(n <= 123.457); + REQUIRE(*size == 7); + } + SECTION("stold") { + long double n = stold(d, size.get()); + REQUIRE(n >= 123.455); + REQUIRE(n <= 123.457); + REQUIRE(*size == 7); + } + } + } + + SECTION("Number to string") { + REQUIRE(small::to_string(static_cast(123)) == "123"); + REQUIRE(small::to_string(static_cast(123)) == "123"); + REQUIRE(small::to_string(static_cast(123)) == "123"); + REQUIRE(small::to_string(static_cast(123)) == "123"); + REQUIRE(small::to_string(static_cast(123)) == "123"); + REQUIRE(small::to_string(static_cast(123)) == "123"); + REQUIRE(small::to_string(static_cast(123)) == "123"); + REQUIRE(small::to_string(static_cast(123)) == "123"); + REQUIRE(small::to_string(static_cast(123)) == "123"); + } + + SECTION("Hash") { + SECTION("Isolated") { + std::hash hasher; + string a = "abc"; + REQUIRE_FALSE(hasher(a) == 0); + } + + SECTION("Hash table") { + std::unordered_set s; + s.insert("abc"); + s.insert("def"); + s.insert("ghi"); + REQUIRE(s.size() == 3); + } + } + + SECTION("Relocatable in inline vector") { + small::vector v(5); + v.emplace_back("new str"); + v.emplace(v.begin() + 3, "middle str"); + REQUIRE(v.size() == 7); + } + } +} \ No newline at end of file diff --git a/tests/unit_tests/small_vector.cpp b/tests/unit_tests/small_vector.cpp deleted file mode 100644 index 0737915..0000000 --- a/tests/unit_tests/small_vector.cpp +++ /dev/null @@ -1,1960 +0,0 @@ -// C++ -#include -#include -#include -#include -#include -#include - -// External -#include - -// Small -#include -#include // NOLINT(modernize-deprecated-headers) -#include - -// A relocatable custom type -struct custom_type { - enum class custom_enum { even, odd }; - custom_type() {} // NOLINT(modernize-use-equals-default,cppcoreguidelines-pro-type-member-init) - custom_type(const std::string &v) // NOLINT(google-explicit-constructor) - : type_(v.size() & 1 ? custom_enum::even : custom_enum::odd), name_(v), url_("https://" + v), - version_(v.size() < 4 ? std::optional(std::nullopt) : std::optional(static_cast(v.size()))), - tag_(v.substr(2)), - system_(v.substr(0, 2)), - raw_(v) {} - custom_type(const char *v) : custom_type(std::string(v)) {} // NOLINT(google-explicit-constructor) - custom_enum type_; - std::string name_; - std::string url_; - std::optional version_{std::nullopt}; - std::optional tag_{std::nullopt}; - std::optional system_{std::nullopt}; - std::optional raw_{std::nullopt}; -}; - -// Allow comparing with std::string to make tests easier -bool operator==(const custom_type &lhs, const custom_type &rhs) { return lhs.raw_ == rhs.raw_; } -bool operator!=(const custom_type &lhs, const custom_type &rhs) { return !(rhs == lhs); } - -bool operator==(const custom_type &lhs, const std::string &rhs) { return lhs.raw_ == rhs; } -bool operator!=(const custom_type &lhs, const std::string &rhs) { return !(lhs == rhs); } -bool operator==(const std::string &lhs, const custom_type &rhs) { return lhs == rhs.raw_; } -bool operator!=(const std::string &lhs, const custom_type &rhs) { return !(lhs == rhs); } - -bool operator==(const custom_type &lhs, const char *rhs) { return lhs.raw_ == std::string(rhs); } -bool operator!=(const custom_type &lhs, const char *rhs) { return !(lhs == rhs); } -bool operator==(const char *lhs, const custom_type &rhs) { return std::string(lhs) == rhs.raw_; } -bool operator!=(const char *lhs, const custom_type &rhs) { return !(lhs == rhs); } - -bool operator<(const custom_type &lhs, const custom_type &rhs) { return lhs.raw_ < rhs.raw_; } -bool operator>(const custom_type &lhs, const custom_type &rhs) { return rhs < lhs; } -bool operator<=(const custom_type &lhs, const custom_type &rhs) { return !(rhs < lhs); } -bool operator>=(const custom_type &lhs, const custom_type &rhs) { return !(lhs < rhs); } - -bool operator<(const custom_type &lhs, const std::string &rhs) { return lhs.raw_ < rhs; } -bool operator>(const custom_type &lhs, const std::string &rhs) { return rhs < lhs; } -bool operator<=(const custom_type &lhs, const std::string &rhs) { return !(rhs < lhs); } -bool operator>=(const custom_type &lhs, const std::string &rhs) { return !(lhs < rhs); } - -namespace small { - // The custom type has no internal pointers so we can relocate it faster - // Most types might be relocatable, but we have to conservatively assume they are not - template <> struct is_relocatable : std::true_type {}; - - // Make strings relocatable since we are here anyway - template <> struct is_relocatable : std::true_type {}; - - // Vectors of custom type should have 10 inlined values by default for some reason, - // so we don't need to specify this default value for every small vector - template <> struct default_inline_storage : std::integral_constant {}; -} // namespace small - -TEST_CASE("Vector") { - using namespace small; - - SECTION("POD values") { - STATIC_REQUIRE(is_relocatable_v); - auto equal_il = [](const auto &sm_vector, std::initializer_list il) -> bool { - return std::equal(sm_vector.begin(), sm_vector.end(), il.begin(), il.end()); - }; - - SECTION("Constructor") { - SECTION("Asserts") { - REQUIRE(std::is_copy_constructible_v>); - REQUIRE(std::is_copy_assignable_v>); - REQUIRE(std::is_move_constructible_v>); - REQUIRE(std::is_move_assignable_v>); - - REQUIRE(std::is_copy_constructible_v, 5>>); - REQUIRE(std::is_copy_assignable_v, 5>>); - REQUIRE(std::is_move_constructible_v, 5>>); - REQUIRE(std::is_move_assignable_v, 5>>); - } - - SECTION("Default") { - vector a; - REQUIRE(a.empty()); - REQUIRE(equal_il(a, {})); - } - - SECTION("Allocator") { - std::allocator alloc; - vector> a(alloc); - REQUIRE(a.empty()); - REQUIRE(equal_il(a, {})); - REQUIRE(a.get_allocator() == alloc); - } - - SECTION("With size") { - std::allocator alloc; - vector b(3, alloc); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 3); - REQUIRE(b.get_allocator() == alloc); - } - - SECTION("From value") { - std::allocator alloc; - vector c(3, 1, alloc); - REQUIRE(c.size() == 3); - REQUIRE_FALSE(c.empty()); - REQUIRE(equal_il(c, {1, 1, 1})); - REQUIRE(c.get_allocator() == alloc); - } - - SECTION("From Iterators") { - std::allocator alloc; - std::vector dv = {6, 5, 4}; - vector d(dv.begin(), dv.end(), alloc); - REQUIRE(d.size() == 3); - REQUIRE_FALSE(d.empty()); - REQUIRE(equal_il(d, {6, 5, 4})); - REQUIRE(d.get_allocator() == alloc); - } - - SECTION("From initializer list") { - vector e = {1, 2}; - REQUIRE(e.size() == 2); - REQUIRE_FALSE(e.empty()); - REQUIRE(equal_il(e, {1, 2})); - } - - SECTION("From ranges") { - std::vector v = {1, 2, 3}; - vector e(v); - REQUIRE(e.size() == 3); - REQUIRE_FALSE(e.empty()); - REQUIRE(equal_il(e, {1, 2, 3})); - } - } - - SECTION("Assign") { - SECTION("From initializer list") { - vector a; - REQUIRE(a.empty()); - a = {6, 5, 4}; - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {6, 5, 4})); - } - - SECTION("From another small vector") { - vector a; - REQUIRE(a.empty()); - a = {6, 5, 4}; - - vector b; - REQUIRE(b.empty()); - b = a; - REQUIRE(b.size() == 3); - REQUIRE_FALSE(b.empty()); - REQUIRE(a == b); - } - - SECTION("From iterators") { - vector a; - REQUIRE(a.empty()); - std::vector v = {6, 5, 4}; - a.assign(v.begin(), v.end()); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {6, 5, 4})); - } - - SECTION("From size and value") { - vector a; - REQUIRE(a.empty()); - a.assign(3, 1); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 1, 1})); - } - - SECTION("From initializer list") { - vector a; - REQUIRE(a.empty()); - a.assign({6, 5, 4}); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {6, 5, 4})); - } - - SECTION("Fill") { - vector a(3, 1); - REQUIRE_FALSE(a.empty()); - a.fill(2); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {2, 2, 2})); - } - - SECTION("Swap") { - vector a(4, 1); - vector b(3, 2); - - std::initializer_list ar = {1, 1, 1, 1}; - std::initializer_list br = {2, 2, 2}; - - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 4); - REQUIRE(equal_il(a, ar)); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 3); - REQUIRE(equal_il(b, br)); - - a.swap(b); - - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 3); - REQUIRE(equal_il(a, br)); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 4); - REQUIRE(equal_il(b, ar)); - - std::swap(a, b); - - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 4); - REQUIRE(equal_il(a, ar)); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 3); - REQUIRE(equal_il(b, br)); - } - } - - SECTION("Iterators") { - vector a = {1, 2, 3}; - - REQUIRE(a.begin() == a.data()); - REQUIRE(a.end() == a.data() + a.size()); - REQUIRE_FALSE(a.end() == a.data() + a.capacity()); - REQUIRE(*a.begin() == 1); - REQUIRE(*std::prev(a.end()) == 3); - - REQUIRE(a.cbegin() == a.data()); - REQUIRE(a.cend() == a.data() + a.size()); - REQUIRE_FALSE(a.cend() == a.data() + a.capacity()); - REQUIRE(*a.cbegin() == 1); - REQUIRE(*std::prev(a.cend()) == 3); - - REQUIRE(*a.rbegin() == 3); - REQUIRE(*std::prev(a.rend()) == 1); - - REQUIRE(*a.crbegin() == 3); - REQUIRE(*std::prev(a.crend()) == 1); - } - - SECTION("Capacity") { - vector a = {1, 2, 3}; - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() == 5); - - a.reserve(10); - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() >= 10); - - a.shrink_to_fit(); - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() == 5); - - a.resize(4); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() == 5); - - a.shrink_to_fit(); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() == 5); - } - - SECTION("Element access") { - vector a = {1, 2, 3}; - REQUIRE(a[0] == 1); - REQUIRE(a[1] == 2); - REQUIRE(a[2] == 3); - REQUIRE(a.at(0) == 1); - REQUIRE(a.at(1) == 2); - REQUIRE(a.at(2) == 3); - REQUIRE_THROWS(a.at(3) == 4); - REQUIRE_THROWS(a.at(4) == 5); - REQUIRE(a.front() == 1); - REQUIRE(a.back() == 3); - REQUIRE(*a.data() == 1); - REQUIRE(*(a.data() + 1) == 2); - REQUIRE(*(a.data() + 2) == 3); - REQUIRE(*(a.data() + a.size() - 1) == 3); - REQUIRE(*(a.data() + a.size() - 2) == 2); - REQUIRE(*(a.data() + a.size() - 3) == 1); - } - - SECTION("Modifiers") { - vector a = {1, 2, 3}; - a.push_back(4); - REQUIRE(a.back() == 4); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 2, 3, 4})); - - // NOLINTNEXTLINE(performance-move-const-arg) - a.push_back(std::move(5)); - REQUIRE(a.back() == 5); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 2, 3, 4, 5})); - - a.pop_back(); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 2, 3, 4})); - - a.emplace_back(5); - REQUIRE(a.back() == 5); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 2, 3, 4, 5})); - - a.pop_back(); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 2, 3, 4})); - - auto it = a.emplace(a.begin() + 2, 10); - REQUIRE(it == a.begin() + 2); - REQUIRE(a.back() == 4); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 2, 10, 3, 4})); - - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 2, 10})); - - it = a.insert(a.begin() + 1, 20); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 20, 2, 10})); - - // NOLINTNEXTLINE(performance-move-const-arg) - it = a.insert(a.begin() + 2, std::move(30)); - REQUIRE(it == a.begin() + 2); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 20, 30, 2, 10})); - - a.pop_back(); - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 20})); - - it = a.insert(a.begin() + 1, 2, 10); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 10, 10, 20})); - - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 10})); - - std::initializer_list src = {2, 4, 8}; - it = a.insert(a.begin() + 1, src.begin(), src.end()); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 2, 4, 8, 10})); - - a.pop_back(); - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 2})); - - it = a.insert(a.begin() + 1, {2, 4, 8}); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 2, 4, 8, 2})); - - it = a.erase(a.begin() + 1); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 4, 8, 2})); - - it = a.erase(a.begin() + 1, a.begin() + 3); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 2})); - - a.clear(); - // NOLINTNEXTLINE(readability-container-size-empty) - REQUIRE(a.size() == 0); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE(a.empty()); - REQUIRE(equal_il(a, {})); - - a.resize(2); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - - a.resize(4, 5); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a[2] == 5); - REQUIRE(a[3] == 5); - } - - SECTION("Element access errors") { - vector a = {1, 2, 3}; - try { - a.at(4); - } catch (std::exception &e) { - REQUIRE(e.what() == std::string_view("at: cannot access element after vector::size()")); - } - } - - SECTION("Relational Operators") { - vector a = {1, 2, 3}; - vector b = {2, 4, 5}; - - REQUIRE_FALSE(a == b); - REQUIRE(a != b); - REQUIRE(a < b); - REQUIRE(a <= b); - REQUIRE_FALSE(a > b); - REQUIRE_FALSE(a >= b); - } - - SECTION("From raw vector") { - auto a = to_vector({1, 2, 3}); - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() > 3); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 2, 3})); - - auto b = to_vector({1, 2, 3}); - REQUIRE(b.size() == 3); - REQUIRE(b.max_size() > 5); - REQUIRE(b.capacity() == 5); - REQUIRE_FALSE(b.empty()); - REQUIRE(equal_il(b, {1, 2, 3})); - - int cr[] = {1, 2, 3}; - auto c = to_vector(cr); - REQUIRE(c.size() == 3); - REQUIRE(c.max_size() > 3); - REQUIRE(c.is_inline()); - REQUIRE(c.capacity() == small::default_inline_storage_v); - REQUIRE(c.capacity() == 5); - REQUIRE_FALSE(c.empty()); - REQUIRE(equal_il(b, {1, 2, 3})); - } - } - - SECTION("String values") { - STATIC_REQUIRE(is_relocatable_v); - auto equal_il = [](const auto &sm_vector, std::initializer_list il) -> bool { - return std::equal(sm_vector.begin(), sm_vector.end(), il.begin(), il.end()); - }; - - SECTION("Constructor") { - SECTION("Asserts") { - REQUIRE(std::is_copy_constructible_v>); - REQUIRE(std::is_copy_assignable_v>); - REQUIRE(std::is_move_constructible_v>); - REQUIRE(std::is_move_assignable_v>); - - REQUIRE(std::is_copy_constructible_v, 5>>); - REQUIRE(std::is_copy_assignable_v, 5>>); - REQUIRE(std::is_move_constructible_v, 5>>); - REQUIRE(std::is_move_assignable_v, 5>>); - } - - SECTION("Default") { - vector a; - REQUIRE(a.empty()); - REQUIRE(equal_il(a, {})); - } - - SECTION("Allocator") { - std::allocator alloc; - vector> a(alloc); - REQUIRE(a.empty()); - REQUIRE(equal_il(a, {})); - REQUIRE(a.get_allocator() == alloc); - } - - SECTION("With size") { - std::allocator alloc; - vector b(3, alloc); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 3); - REQUIRE(b.get_allocator() == alloc); - } - - SECTION("From value") { - std::allocator alloc; - vector c(3, "one", alloc); - REQUIRE(c.size() == 3); - REQUIRE_FALSE(c.empty()); - REQUIRE(equal_il(c, {"one", "one", "one"})); - REQUIRE(c.get_allocator() == alloc); - } - - SECTION("From Iterators") { - std::allocator alloc; - std::vector dv = {"six", "five", "four"}; - vector d(dv.begin(), dv.end(), alloc); - REQUIRE(d.size() == 3); - REQUIRE_FALSE(d.empty()); - REQUIRE(equal_il(d, {"six", "five", "four"})); - REQUIRE(d.get_allocator() == alloc); - } - - SECTION("From initializer list") { - vector e = {"one", "two"}; - REQUIRE(e.size() == 2); - REQUIRE_FALSE(e.empty()); - REQUIRE(equal_il(e, {"one", "two"})); - } - - SECTION("From ranges") { - std::vector v = {"one", "two", "three"}; - vector e(v); - REQUIRE(e.size() == 3); - REQUIRE_FALSE(e.empty()); - REQUIRE(equal_il(e, {"one", "two", "three"})); - } - } - - SECTION("Assign") { - SECTION("From initializer list") { - vector a; - REQUIRE(a.empty()); - a = {"six", "five", "four"}; - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"six", "five", "four"})); - } - - SECTION("From another small vector") { - vector a; - REQUIRE(a.empty()); - a = {"six", "five", "four"}; - - vector b; - REQUIRE(b.empty()); - b = a; - REQUIRE(b.size() == 3); - REQUIRE_FALSE(b.empty()); - REQUIRE(a == b); - } - - SECTION("From iterators") { - vector a; - REQUIRE(a.empty()); - std::vector v = {"six", "five", "four"}; - a.assign(v.begin(), v.end()); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"six", "five", "four"})); - } - - SECTION("From size and value") { - vector a; - REQUIRE(a.empty()); - a.assign(3, "one"); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "one", "one"})); - } - - SECTION("From initializer list") { - vector a; - REQUIRE(a.empty()); - a.assign({"six", "five", "four"}); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"six", "five", "four"})); - } - - SECTION("Fill") { - vector a(3, "one"); - REQUIRE_FALSE(a.empty()); - a.fill("two"); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"two", "two", "two"})); - } - - SECTION("Swap") { - vector a(4, "one"); - vector b(3, "two"); - - std::initializer_list ar = {"one", "one", "one", "one"}; - std::initializer_list br = {"two", "two", "two"}; - - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 4); - REQUIRE(equal_il(a, ar)); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 3); - REQUIRE(equal_il(b, br)); - - a.swap(b); - - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 3); - REQUIRE(equal_il(a, br)); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 4); - REQUIRE(equal_il(b, ar)); - - std::swap(a, b); - - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 4); - REQUIRE(equal_il(a, ar)); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 3); - REQUIRE(equal_il(b, br)); - } - } - - SECTION("Iterators") { - vector a = {"one", "two", "three"}; - - REQUIRE(a.begin() == a.data()); - REQUIRE(a.end() == a.data() + a.size()); - REQUIRE_FALSE(a.end() == a.data() + a.capacity()); - REQUIRE(*a.begin() == "one"); - REQUIRE(*std::prev(a.end()) == "three"); - - REQUIRE(a.cbegin() == a.data()); - REQUIRE(a.cend() == a.data() + a.size()); - REQUIRE_FALSE(a.cend() == a.data() + a.capacity()); - REQUIRE(*a.cbegin() == "one"); - REQUIRE(*std::prev(a.cend()) == "three"); - - REQUIRE(*a.rbegin() == "three"); - REQUIRE(*std::prev(a.rend()) == "one"); - - REQUIRE(*a.crbegin() == "three"); - REQUIRE(*std::prev(a.crend()) == "one"); - } - - SECTION("Capacity") { - vector a = {"one", "two", "three"}; - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() == 5); - - a.reserve(10); - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() >= 10); - - a.shrink_to_fit(); - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() == 5); - - a.resize(4); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() == 5); - - a.shrink_to_fit(); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() == 5); - } - - SECTION("Element access") { - vector a = {"one", "two", "three"}; - REQUIRE(a[0] == "one"); - REQUIRE(a[1] == "two"); - REQUIRE(a[2] == "three"); - REQUIRE(a.at(0) == "one"); - REQUIRE(a.at(1) == "two"); - REQUIRE(a.at(2) == "three"); - REQUIRE_THROWS(a.at(3) == "four"); - REQUIRE_THROWS(a.at(4) == "five"); - REQUIRE(a.front() == "one"); - REQUIRE(a.back() == "three"); - REQUIRE(*a.data() == "one"); - REQUIRE(*(a.data() + 1) == "two"); - REQUIRE(*(a.data() + 2) == "three"); - REQUIRE(*(a.data() + a.size() - 1) == "three"); - REQUIRE(*(a.data() + a.size() - 2) == "two"); - REQUIRE(*(a.data() + a.size() - 3) == "one"); - } - - SECTION("Modifiers") { - vector a = {"one", "two", "three"}; - std::string tmp = "four"; - a.push_back(tmp); - REQUIRE(a.back() == "four"); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "three", "four"})); - - // NOLINTNEXTLINE(performance-move-const-arg) - std::string tmp2 = "five"; - a.push_back(std::move(tmp2)); - REQUIRE(a.back() == "five"); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "three", "four", "five"})); - - a.pop_back(); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "three", "four"})); - - a.emplace_back("five"); - REQUIRE(a.back() == "five"); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "three", "four", "five"})); - - a.pop_back(); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "three", "four"})); - - auto it = a.emplace(a.begin() + 2, "ten"); - REQUIRE(it == a.begin() + 2); - REQUIRE(a.back() == "four"); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "ten", "three", "four"})); - - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "ten"})); - - it = a.insert(a.begin() + 1, "twenty"); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "twenty", "two", "ten"})); - - // NOLINTNEXTLINE(performance-move-const-arg) - it = a.insert(a.begin() + 2, std::move("thirty")); - REQUIRE(it == a.begin() + 2); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "twenty", "thirty", "two", "ten"})); - - a.pop_back(); - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "twenty"})); - - it = a.insert(a.begin() + 1, 2, "ten"); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "ten", "ten", "twenty"})); - - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "ten"})); - - std::initializer_list src = {"two", "four", "eight"}; - it = a.insert(a.begin() + 1, src.begin(), src.end()); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "four", "eight", "ten"})); - - a.pop_back(); - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two"})); - - it = a.insert(a.begin() + 1, {"two", "four", "eight"}); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "four", "eight", "two"})); - - it = a.erase(a.begin() + 1); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "four", "eight", "two"})); - - it = a.erase(a.begin() + 1, a.begin() + 3); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two"})); - - a.clear(); - // NOLINTNEXTLINE(readability-container-size-empty) - REQUIRE(a.size() == 0); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE(a.empty()); - REQUIRE(equal_il(a, {})); - - a.resize(2); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - - a.resize(4, "five"); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a[2] == "five"); - REQUIRE(a[3] == "five"); - } - - SECTION("Element access errors") { - vector a = {"one", "two", "three"}; - try { - a.at(4); - } catch (std::exception &e) { - REQUIRE(e.what() == std::string_view("at: cannot access element after vector::size()")); - } - } - - SECTION("Relational Operators") { - vector a = {"one", "two", "three"}; - vector b = {"two", "four", "five"}; - - REQUIRE_FALSE(a == b); - REQUIRE(a != b); - REQUIRE(a < b); - REQUIRE(a <= b); - REQUIRE_FALSE(a > b); - REQUIRE_FALSE(a >= b); - } - - SECTION("From raw vector") { - auto a = to_vector({"one", "two", "three"}); - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() > 3); - REQUIRE(a.capacity() == default_inline_storage_v); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "three"})); - - auto b = to_vector({"one", "two", "three"}); - REQUIRE(b.size() == 3); - REQUIRE(b.max_size() > 5); - REQUIRE(b.capacity() == 5); - REQUIRE_FALSE(b.empty()); - REQUIRE(equal_il(b, {"one", "two", "three"})); - - std::string cr[] = {"one", "two", "three"}; - auto c = to_vector(cr); - REQUIRE(c.size() == 3); - REQUIRE(c.max_size() > 3); - REQUIRE(c.capacity() == 5); - REQUIRE(c.capacity() == default_inline_storage_v); - REQUIRE_FALSE(c.empty()); - REQUIRE(equal_il(b, {"one", "two", "three"})); - } - } - - SECTION("Custom values") { - STATIC_REQUIRE(is_relocatable_v); - auto equal_il = [](const auto &sm_vector, std::initializer_list il) -> bool { - return std::equal(sm_vector.begin(), sm_vector.end(), il.begin(), il.end()); - }; - - SECTION("Constructor") { - SECTION("Asserts") { - REQUIRE(std::is_copy_constructible_v>); - REQUIRE(std::is_copy_assignable_v>); - REQUIRE(std::is_move_constructible_v>); - REQUIRE(std::is_move_assignable_v>); - - REQUIRE(std::is_copy_constructible_v, 5>>); - REQUIRE(std::is_copy_assignable_v, 5>>); - REQUIRE(std::is_move_constructible_v, 5>>); - REQUIRE(std::is_move_assignable_v, 5>>); - } - - SECTION("Default") { - vector a; - REQUIRE(a.empty()); - REQUIRE(equal_il(a, {})); - } - - SECTION("Allocator") { - std::allocator alloc; - vector> a(alloc); - REQUIRE(a.empty()); - REQUIRE(equal_il(a, {})); - REQUIRE(a.get_allocator() == alloc); - } - - SECTION("With size") { - std::allocator alloc; - vector b(3, alloc); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 3); - REQUIRE(b.get_allocator() == alloc); - } - - SECTION("From value") { - std::allocator alloc; - vector c(3, "one", alloc); - REQUIRE(c.size() == 3); - REQUIRE_FALSE(c.empty()); - REQUIRE(equal_il(c, {"one", "one", "one"})); - REQUIRE(c.get_allocator() == alloc); - } - - SECTION("From Iterators") { - std::allocator alloc; - std::vector dv = {"six", "five", "four"}; - vector d(dv.begin(), dv.end(), alloc); - REQUIRE(d.size() == 3); - REQUIRE_FALSE(d.empty()); - REQUIRE(equal_il(d, {"six", "five", "four"})); - REQUIRE(d.get_allocator() == alloc); - } - - SECTION("From initializer list") { - vector e = {"one", "two"}; - REQUIRE(e.size() == 2); - REQUIRE_FALSE(e.empty()); - REQUIRE(equal_il(e, {"one", "two"})); - } - - SECTION("From ranges") { - std::vector v = {"one", "two", "three"}; - vector e(v); - REQUIRE(e.size() == 3); - REQUIRE_FALSE(e.empty()); - REQUIRE(equal_il(e, {"one", "two", "three"})); - } - } - - SECTION("Assign") { - SECTION("From initializer list") { - vector a; - REQUIRE(a.empty()); - a = {"six", "five", "four"}; - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"six", "five", "four"})); - } - - SECTION("From another small vector") { - vector a; - REQUIRE(a.empty()); - a = {"six", "five", "four"}; - - vector b; - REQUIRE(b.empty()); - b = a; - REQUIRE(b.size() == 3); - REQUIRE_FALSE(b.empty()); - REQUIRE(a == b); - } - - SECTION("From iterators") { - vector a; - REQUIRE(a.empty()); - std::vector v = {"six", "five", "four"}; - a.assign(v.begin(), v.end()); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"six", "five", "four"})); - } - - SECTION("From size and value") { - vector a; - REQUIRE(a.empty()); - a.assign(3, "one"); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "one", "one"})); - } - - SECTION("From initializer list") { - vector a; - REQUIRE(a.empty()); - a.assign({"six", "five", "four"}); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"six", "five", "four"})); - } - - SECTION("Fill") { - vector a(3, "one"); - REQUIRE_FALSE(a.empty()); - a.fill("two"); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"two", "two", "two"})); - } - - SECTION("Swap") { - vector a(4, "one"); - vector b(3, "two"); - - std::initializer_list ar = {"one", "one", "one", "one"}; - std::initializer_list br = {"two", "two", "two"}; - - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 4); - REQUIRE(equal_il(a, ar)); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 3); - REQUIRE(equal_il(b, br)); - - a.swap(b); - - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 3); - REQUIRE(equal_il(a, br)); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 4); - REQUIRE(equal_il(b, ar)); - - std::swap(a, b); - - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 4); - REQUIRE(equal_il(a, ar)); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 3); - REQUIRE(equal_il(b, br)); - } - } - - SECTION("Iterators") { - vector a = {"one", "two", "three"}; - - REQUIRE(a.begin() == a.data()); - REQUIRE(a.end() == a.data() + a.size()); - REQUIRE_FALSE(a.end() == a.data() + a.capacity()); - REQUIRE(*a.begin() == "one"); - REQUIRE(*std::prev(a.end()) == "three"); - - REQUIRE(a.cbegin() == a.data()); - REQUIRE(a.cend() == a.data() + a.size()); - REQUIRE_FALSE(a.cend() == a.data() + a.capacity()); - REQUIRE(*a.cbegin() == "one"); - REQUIRE(*std::prev(a.cend()) == "three"); - - REQUIRE(*a.rbegin() == "three"); - REQUIRE(*std::prev(a.rend()) == "one"); - - REQUIRE(*a.crbegin() == "three"); - REQUIRE(*std::prev(a.crend()) == "one"); - } - - SECTION("Capacity") { - /* - * The inline capacity depends on the platform, but these values don't vary a lot - */ - vector a = {"one", "two", "three"}; - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.is_inline()); - REQUIRE(a.capacity() == 5); - - a.reserve(10); - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() >= 10); - - a.shrink_to_fit(); - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() == 5); - - a.resize(4); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() == 5); - - a.shrink_to_fit(); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() == 5); - } - - SECTION("Element access") { - vector a = {"one", "two", "three"}; - REQUIRE(a[0] == "one"); - REQUIRE(a[1] == "two"); - REQUIRE(a[2] == "three"); - REQUIRE(a.at(0) == "one"); - REQUIRE(a.at(1) == "two"); - REQUIRE(a.at(2) == "three"); - REQUIRE_THROWS(a.at(3) == "four"); - REQUIRE_THROWS(a.at(4) == "five"); - REQUIRE(a.front() == "one"); - REQUIRE(a.back() == "three"); - REQUIRE(*a.data() == "one"); - REQUIRE(*(a.data() + 1) == "two"); - REQUIRE(*(a.data() + 2) == "three"); - REQUIRE(*(a.data() + a.size() - 1) == "three"); - REQUIRE(*(a.data() + a.size() - 2) == "two"); - REQUIRE(*(a.data() + a.size() - 3) == "one"); - } - - SECTION("Modifiers") { - vector a = {"one", "two", "three"}; - a.push_back("four"); - REQUIRE(a.back() == "four"); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "three", "four"})); - - // NOLINTNEXTLINE(performance-move-const-arg) - a.push_back(std::move("five")); - REQUIRE(a.back() == "five"); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "three", "four", "five"})); - - a.pop_back(); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "three", "four"})); - - a.emplace_back("five"); - REQUIRE(a.back() == "five"); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "three", "four", "five"})); - - a.pop_back(); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "three", "four"})); - - auto it = a.emplace(a.begin() + 2, "ten"); - REQUIRE(it == a.begin() + 2); - REQUIRE(a.back() == "four"); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "ten", "three", "four"})); - - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "ten"})); - - it = a.insert(a.begin() + 1, "twenty"); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "twenty", "two", "ten"})); - - // NOLINTNEXTLINE(performance-move-const-arg) - it = a.insert(a.begin() + 2, std::move("thirty")); - REQUIRE(it == a.begin() + 2); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "twenty", "thirty", "two", "ten"})); - - a.pop_back(); - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "twenty"})); - - it = a.insert(a.begin() + 1, 2, "ten"); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "ten", "ten", "twenty"})); - - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "ten"})); - - std::initializer_list src = {"two", "four", "eight"}; - it = a.insert(a.begin() + 1, src.begin(), src.end()); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "four", "eight", "ten"})); - - a.pop_back(); - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two"})); - - it = a.insert(a.begin() + 1, {"two", "four", "eight"}); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "four", "eight", "two"})); - - it = a.erase(a.begin() + 1); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "four", "eight", "two"})); - - it = a.erase(a.begin() + 1, a.begin() + 3); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two"})); - - a.clear(); - // NOLINTNEXTLINE(readability-container-size-empty) - REQUIRE(a.size() == 0); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE(a.empty()); - REQUIRE(equal_il(a, {})); - - a.resize(2); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - - a.resize(4, "five"); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() > 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a[2] == "five"); - REQUIRE(a[3] == "five"); - } - - SECTION("Element access errors") { - vector a = {"one", "two", "three"}; - try { - a.at(4); - } catch (std::exception &e) { - REQUIRE(e.what() == std::string_view("at: cannot access element after vector::size()")); - } - } - - SECTION("Relational Operators") { - vector a = {"one", "two", "three"}; - vector b = {"two", "four", "five"}; - - REQUIRE_FALSE(a == b); - REQUIRE(a != b); - REQUIRE(a < b); - REQUIRE(a <= b); - REQUIRE_FALSE(a > b); - REQUIRE_FALSE(a >= b); - } - - SECTION("From raw vector") { - auto a = to_vector({"one", "two", "three"}); - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() > 3); - REQUIRE(a.capacity() == 5); - REQUIRE(a.capacity() == default_inline_storage_v); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {"one", "two", "three"})); - - auto b = to_vector({"one", "two", "three"}); - REQUIRE(b.size() == 3); - REQUIRE(b.max_size() > 5); - REQUIRE(b.capacity() == 5); - REQUIRE_FALSE(b.empty()); - REQUIRE(equal_il(b, {"one", "two", "three"})); - - custom_type cr[] = {"one", "two", "three"}; - auto c = to_vector(cr); - REQUIRE(c.size() == 3); - REQUIRE(c.max_size() > 3); - REQUIRE(c.capacity() == 10); - REQUIRE(c.capacity() == default_inline_storage_v); - REQUIRE_FALSE(c.empty()); - REQUIRE(equal_il(b, {"one", "two", "three"})); - } - } -} - -TEST_CASE("Max size vector") { - using namespace small; - - auto equal_il = [](const auto &sm_array, std::initializer_list il) -> bool { - return std::equal(sm_array.begin(), sm_array.end(), il.begin(), il.end()); - }; - - auto full = [](const auto &sm_array) -> bool { - return sm_array.is_inline() && sm_array.size() == sm_array.capacity(); - }; - - SECTION("Constructor") { - SECTION("Asserts") { - REQUIRE(std::is_copy_constructible_v>); - REQUIRE(std::is_copy_assignable_v>); - REQUIRE(std::is_move_constructible_v>); - REQUIRE(std::is_move_assignable_v>); - - REQUIRE(std::is_copy_constructible_v, 5>>); - REQUIRE(std::is_copy_assignable_v, 5>>); - REQUIRE(std::is_move_constructible_v, 5>>); - REQUIRE(std::is_move_assignable_v, 5>>); - } - - SECTION("Default") { - max_size_vector a; - REQUIRE(a.empty()); - REQUIRE(equal_il(a, {})); - } - - SECTION("With size") { - max_size_vector b(3); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 3); - } - - SECTION("From value") { - max_size_vector c(3, 1); - REQUIRE(c.size() == 3); - REQUIRE_FALSE(c.empty()); - REQUIRE(equal_il(c, {1, 1, 1})); - } - - SECTION("From Iterators") { - std::vector dv = {6, 5, 4}; - max_size_vector d(dv.begin(), dv.end()); - REQUIRE(d.size() == 3); - REQUIRE_FALSE(d.empty()); - REQUIRE(equal_il(d, {6, 5, 4})); - } - - SECTION("From initializer list") { - max_size_vector e = {1, 2}; - REQUIRE(e.size() == 2); - REQUIRE_FALSE(e.empty()); - REQUIRE(equal_il(e, {1, 2})); - } - } - - SECTION("Assign") { - SECTION("From initializer list") { - max_size_vector a; - REQUIRE(a.empty()); - a = {6, 5, 4}; - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {6, 5, 4})); - } - - SECTION("From another small array") { - max_size_vector a; - REQUIRE(a.empty()); - a = {6, 5, 4}; - - max_size_vector b; - REQUIRE(b.empty()); - b = a; - REQUIRE(b.size() == 3); - REQUIRE_FALSE(b.empty()); - REQUIRE(a == b); - } - - SECTION("From iterators") { - max_size_vector a; - REQUIRE(a.empty()); - std::vector v = {6, 5, 4}; - a.assign(v.begin(), v.end()); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {6, 5, 4})); - } - - SECTION("From size and value") { - max_size_vector a; - REQUIRE(a.empty()); - a.assign(3, 1); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {1, 1, 1})); - } - - SECTION("From initializer list") { - max_size_vector a; - REQUIRE(a.empty()); - a.assign({6, 5, 4}); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {6, 5, 4})); - } - - SECTION("Fill") { - max_size_vector a(3, 1); - REQUIRE_FALSE(a.empty()); - a.fill(2); - REQUIRE(a.size() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(equal_il(a, {2, 2, 2})); - } - - SECTION("Swap") { - max_size_vector a(4, 1); - max_size_vector b(3, 2); - - std::initializer_list ar = {1, 1, 1, 1}; - std::initializer_list br = {2, 2, 2}; - - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 4); - REQUIRE(equal_il(a, ar)); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 3); - REQUIRE(equal_il(b, br)); - - a.swap(b); - - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 3); - REQUIRE(equal_il(a, br)); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 4); - REQUIRE(equal_il(b, ar)); - - std::swap(a, b); - - REQUIRE_FALSE(a.empty()); - REQUIRE(a.size() == 4); - REQUIRE(equal_il(a, ar)); - REQUIRE_FALSE(b.empty()); - REQUIRE(b.size() == 3); - REQUIRE(equal_il(b, br)); - } - } - - SECTION("Iterators") { - max_size_vector a = {1, 2, 3}; - - REQUIRE(a.begin() == a.data()); - REQUIRE(a.end() == a.data() + a.size()); - REQUIRE_FALSE(a.end() == a.data() + a.capacity()); - REQUIRE(*a.begin() == 1); - REQUIRE(*std::prev(a.end()) == 3); - - REQUIRE(a.cbegin() == a.data()); - REQUIRE(a.cend() == a.data() + a.size()); - REQUIRE_FALSE(a.cend() == a.data() + a.capacity()); - REQUIRE(*a.cbegin() == 1); - REQUIRE(*std::prev(a.cend()) == 3); - - REQUIRE(*a.rbegin() == 3); - REQUIRE(*std::prev(a.rend()) == 1); - - REQUIRE(*a.crbegin() == 3); - REQUIRE(*std::prev(a.crend()) == 1); - } - - SECTION("Capacity") { - max_size_vector a = {1, 2, 3}; - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(full(a)); - } - - SECTION("Element access") { - max_size_vector a = {1, 2, 3}; - REQUIRE(a[0] == 1); - REQUIRE(a[1] == 2); - REQUIRE(a[2] == 3); - REQUIRE(a.at(0) == 1); - REQUIRE(a.at(1) == 2); - REQUIRE(a.at(2) == 3); - REQUIRE_THROWS(a.at(3) == 4); - REQUIRE_THROWS(a.at(4) == 5); - REQUIRE(a.front() == 1); - REQUIRE(a.back() == 3); - REQUIRE(*a.data() == 1); - REQUIRE(*(a.data() + 1) == 2); - REQUIRE(*(a.data() + 2) == 3); - REQUIRE(*(a.data() + a.size() - 1) == 3); - REQUIRE(*(a.data() + a.size() - 2) == 2); - REQUIRE(*(a.data() + a.size() - 3) == 1); - } - - SECTION("Modifiers") { - max_size_vector a = {1, 2, 3}; - a.push_back(4); - REQUIRE(a.back() == 4); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE_FALSE(full(a)); - REQUIRE(equal_il(a, {1, 2, 3, 4})); - - // NOLINTNEXTLINE(performance-move-const-arg) - a.push_back(std::move(5)); - REQUIRE(a.back() == 5); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(full(a)); - REQUIRE(equal_il(a, {1, 2, 3, 4, 5})); - - a.pop_back(); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE_FALSE(full(a)); - REQUIRE(equal_il(a, {1, 2, 3, 4})); - - a.emplace_back(5); - REQUIRE(a.back() == 5); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(full(a)); - REQUIRE(equal_il(a, {1, 2, 3, 4, 5})); - - a.pop_back(); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE_FALSE(full(a)); - REQUIRE(equal_il(a, {1, 2, 3, 4})); - - auto it = a.emplace(a.begin() + 2, 10); - REQUIRE(it == a.begin() + 2); - REQUIRE(a.back() == 4); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(full(a)); - REQUIRE(equal_il(a, {1, 2, 10, 3, 4})); - - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE_FALSE(full(a)); - REQUIRE(equal_il(a, {1, 2, 10})); - - it = a.insert(a.begin() + 1, 20); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE_FALSE(full(a)); - REQUIRE(equal_il(a, {1, 20, 2, 10})); - - // NOLINTNEXTLINE(performance-move-const-arg) - it = a.insert(a.begin() + 2, std::move(30)); - REQUIRE(it == a.begin() + 2); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(full(a)); - REQUIRE(equal_il(a, {1, 20, 30, 2, 10})); - - a.pop_back(); - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE_FALSE(full(a)); - REQUIRE(equal_il(a, {1, 20})); - - it = a.insert(a.begin() + 1, 2, 10); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE_FALSE(full(a)); - REQUIRE(equal_il(a, {1, 10, 10, 20})); - - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE_FALSE(full(a)); - REQUIRE(equal_il(a, {1, 10})); - - std::initializer_list src = {2, 4, 8}; - it = a.insert(a.begin() + 1, src.begin(), src.end()); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(full(a)); - REQUIRE(equal_il(a, {1, 2, 4, 8, 10})); - - a.pop_back(); - a.pop_back(); - a.pop_back(); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE_FALSE(full(a)); - REQUIRE(equal_il(a, {1, 2})); - - it = a.insert(a.begin() + 1, {2, 4, 8}); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 5); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE(full(a)); - REQUIRE(equal_il(a, {1, 2, 4, 8, 2})); - - it = a.erase(a.begin() + 1); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE_FALSE(full(a)); - REQUIRE(equal_il(a, {1, 4, 8, 2})); - - it = a.erase(a.begin() + 1, a.begin() + 3); - REQUIRE(it == a.begin() + 1); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE_FALSE(full(a)); - REQUIRE(equal_il(a, {1, 2})); - - a.clear(); - // NOLINTNEXTLINE(readability-container-size-empty) - REQUIRE(a.size() == 0); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE(a.empty()); - REQUIRE_FALSE(full(a)); - REQUIRE(equal_il(a, {})); - - a.resize(2); - REQUIRE(a.size() == 2); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE_FALSE(full(a)); - - a.resize(4, 5); - REQUIRE(a.size() == 4); - REQUIRE(a.max_size() == 5); - REQUIRE(a.capacity() == 5); - REQUIRE_FALSE(a.empty()); - REQUIRE_FALSE(full(a)); - REQUIRE(a[2] == 5); - REQUIRE(a[3] == 5); - } - - SECTION("Element access errors") { - max_size_vector a = {1, 2, 3}; - try { - a.at(4); - } catch (std::exception &e) { - REQUIRE(e.what() == std::string_view("at: cannot access element after vector::size()")); - } - } - - SECTION("Relational Operators") { - max_size_vector a = {1, 2, 3}; - max_size_vector b = {2, 4, 5}; - - REQUIRE_FALSE(a == b); - REQUIRE(a != b); - REQUIRE(a < b); - REQUIRE(a <= b); - REQUIRE_FALSE(a > b); - REQUIRE_FALSE(a >= b); - } - - SECTION("From raw array") { - auto a = to_small_array({1, 2, 3}); - REQUIRE(a.size() == 3); - REQUIRE(a.max_size() == 3); - REQUIRE(a.capacity() == 3); - REQUIRE_FALSE(a.empty()); - REQUIRE(a.full()); - REQUIRE(equal_il(a, {1, 2, 3})); - - auto b = to_small_array({1, 2, 3}); - REQUIRE(b.size() == 3); - REQUIRE(b.max_size() == 5); - REQUIRE(b.capacity() == 5); - REQUIRE_FALSE(b.empty()); - REQUIRE_FALSE(b.full()); - REQUIRE(equal_il(b, {1, 2, 3})); - - int cr[] = {1, 2, 3}; - auto c = to_small_array(cr); - REQUIRE(c.size() == 3); - REQUIRE(c.max_size() == 3); - REQUIRE(c.capacity() == 3); - REQUIRE_FALSE(c.empty()); - REQUIRE(c.full()); - REQUIRE(equal_il(b, {1, 2, 3})); - } -} - -TEST_CASE("Pointer wrapper") { - using namespace small; - - SECTION("Constructor") { - SECTION("Empty") { [[maybe_unused]] pointer_wrapper p; } - - SECTION("From pointer") { - int a = 2; - pointer_wrapper p(&a); - REQUIRE(p.base() == &a); - } - - SECTION("From another pointer wrapper") { - int a = 2; - pointer_wrapper p1(&a); - REQUIRE(p1.base() == &a); - - pointer_wrapper p2(p1); - REQUIRE(p2.base() == &a); - } - } - - int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - pointer_wrapper begin(&a[0]); - pointer_wrapper end(&a[0] + 9); - - SECTION("Element access") { - REQUIRE(begin != end); - REQUIRE(*begin == 1); - REQUIRE(*std::prev(end) == 9); - REQUIRE(begin.base() == &a[0]); - REQUIRE(begin[0] == 1); - REQUIRE(begin[1] == 2); - REQUIRE(begin[2] == 3); - } - - SECTION("Modifiers") { - ++begin; - REQUIRE(*begin == 2); - begin++; - REQUIRE(*begin == 3); - --begin; - REQUIRE(*begin == 2); - begin--; - REQUIRE(*begin == 1); - auto it = begin + 1; - REQUIRE(*it == 2); - it = begin + 2; - REQUIRE(*it == 3); - begin += 2; - REQUIRE(*begin == 3); - it = begin - 1; - REQUIRE(*it == 2); - it = begin - 2; - REQUIRE(*it == 1); - begin -= 2; - REQUIRE(*begin == 1); - } - - SECTION("Algorithms") { - int b[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; - pointer_wrapper b_begin(&b[0]); - pointer_wrapper b_end(&b[0] + 9); - - std::copy(begin, end, b_begin); - REQUIRE(std::equal(begin, end, b_begin, b_end)); - } -} \ No newline at end of file diff --git a/tests/unit_tests/string_small_vector.cpp b/tests/unit_tests/string_small_vector.cpp new file mode 100644 index 0000000..4b16e40 --- /dev/null +++ b/tests/unit_tests/string_small_vector.cpp @@ -0,0 +1,483 @@ +#ifndef SMALL_BUILD_TESTS_WITH_PCH +// C++ +#include +#include +#include +#include +#include +#include + +// External +#include + +// Small +#include +#endif + +namespace small { + // Make strings relocatable since we are here anyway + // template <> struct is_relocatable : std::true_type {}; +} // namespace small + +TEST_CASE("String Vector") { + using namespace small; + + // std::string is not always relocatable + STATIC_REQUIRE(!is_relocatable_v); + auto equal_il = [](const auto &sm_vector, std::initializer_list il) -> bool { + return std::equal(sm_vector.begin(), sm_vector.end(), il.begin(), il.end()); + }; + + SECTION("Constructor") { + SECTION("Asserts") { + REQUIRE(std::is_copy_constructible_v>); + REQUIRE(std::is_copy_assignable_v>); + REQUIRE(std::is_move_constructible_v>); + REQUIRE(std::is_move_assignable_v>); + + REQUIRE(std::is_copy_constructible_v, 5>>); + REQUIRE(std::is_copy_assignable_v, 5>>); + REQUIRE(std::is_move_constructible_v, 5>>); + REQUIRE(std::is_move_assignable_v, 5>>); + } + + SECTION("Default") { + vector a; + REQUIRE(a.empty()); + REQUIRE(equal_il(a, {})); + } + + SECTION("Allocator") { + std::allocator alloc; + vector> a(alloc); + REQUIRE(a.empty()); + REQUIRE(equal_il(a, {})); + REQUIRE(a.get_allocator() == alloc); + } + + SECTION("With size") { + std::allocator alloc; + vector b(3, alloc); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 3); + REQUIRE(b.get_allocator() == alloc); + } + + SECTION("From value") { + std::allocator alloc; + vector c(3, "one", alloc); + REQUIRE(c.size() == 3); + REQUIRE_FALSE(c.empty()); + REQUIRE(equal_il(c, {"one", "one", "one"})); + REQUIRE(c.get_allocator() == alloc); + } + + SECTION("From Iterators") { + std::allocator alloc; + std::vector dv = {"six", "five", "four"}; + vector d(dv.begin(), dv.end(), alloc); + REQUIRE(d.size() == 3); + REQUIRE_FALSE(d.empty()); + REQUIRE(equal_il(d, {"six", "five", "four"})); + REQUIRE(d.get_allocator() == alloc); + } + + SECTION("From initializer list") { + vector e = {"one", "two"}; + REQUIRE(e.size() == 2); + REQUIRE_FALSE(e.empty()); + REQUIRE(equal_il(e, {"one", "two"})); + } + + SECTION("From ranges") { + std::vector v = {"one", "two", "three"}; + vector e(v); + REQUIRE(e.size() == 3); + REQUIRE_FALSE(e.empty()); + REQUIRE(equal_il(e, {"one", "two", "three"})); + } + } + + SECTION("Assign") { + SECTION("From initializer list") { + vector a; + REQUIRE(a.empty()); + a = {"six", "five", "four"}; + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"six", "five", "four"})); + } + + SECTION("From another small vector") { + vector a; + REQUIRE(a.empty()); + a = {"six", "five", "four"}; + + vector b; + REQUIRE(b.empty()); + b = a; + REQUIRE(b.size() == 3); + REQUIRE_FALSE(b.empty()); + REQUIRE(a == b); + } + + SECTION("From iterators") { + vector a; + REQUIRE(a.empty()); + std::vector v = {"six", "five", "four"}; + a.assign(v.begin(), v.end()); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"six", "five", "four"})); + } + + SECTION("From size and value") { + vector a; + REQUIRE(a.empty()); + a.assign(3, "one"); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "one", "one"})); + } + + SECTION("From initializer list") { + vector a; + REQUIRE(a.empty()); + a.assign({"six", "five", "four"}); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"six", "five", "four"})); + } + + SECTION("Fill") { + vector a(3, "one"); + REQUIRE_FALSE(a.empty()); + a.fill("two"); + REQUIRE(a.size() == 3); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"two", "two", "two"})); + } + + SECTION("Swap") { + vector a(4, "one"); + vector b(3, "two"); + + std::initializer_list ar = {"one", "one", "one", "one"}; + std::initializer_list br = {"two", "two", "two"}; + + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 4); + REQUIRE(equal_il(a, ar)); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 3); + REQUIRE(equal_il(b, br)); + + a.swap(b); + + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 3); + REQUIRE(equal_il(a, br)); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 4); + REQUIRE(equal_il(b, ar)); + + std::swap(a, b); + + REQUIRE_FALSE(a.empty()); + REQUIRE(a.size() == 4); + REQUIRE(equal_il(a, ar)); + REQUIRE_FALSE(b.empty()); + REQUIRE(b.size() == 3); + REQUIRE(equal_il(b, br)); + } + } + + SECTION("Iterators") { + vector a = {"one", "two", "three"}; + + REQUIRE(a.begin() == a.data()); + REQUIRE(a.end() == a.data() + a.size()); + REQUIRE_FALSE(a.end() == a.data() + a.capacity()); + REQUIRE(*a.begin() == "one"); + REQUIRE(*std::prev(a.end()) == "three"); + + REQUIRE(a.cbegin() == a.data()); + REQUIRE(a.cend() == a.data() + a.size()); + REQUIRE_FALSE(a.cend() == a.data() + a.capacity()); + REQUIRE(*a.cbegin() == "one"); + REQUIRE(*std::prev(a.cend()) == "three"); + + REQUIRE(*a.rbegin() == "three"); + REQUIRE(*std::prev(a.rend()) == "one"); + + REQUIRE(*a.crbegin() == "three"); + REQUIRE(*std::prev(a.crend()) == "one"); + } + + SECTION("Capacity") { + vector a = {"one", "two", "three"}; + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() == 5); + + a.reserve(10); + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() >= 10); + + a.shrink_to_fit(); + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() == 5); + + a.resize(4); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() == 5); + + a.shrink_to_fit(); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a.capacity() == 5); + } + + SECTION("Element access") { + vector a = {"one", "two", "three"}; + REQUIRE(a[0] == "one"); + REQUIRE(a[1] == "two"); + REQUIRE(a[2] == "three"); + REQUIRE(a.at(0) == "one"); + REQUIRE(a.at(1) == "two"); + REQUIRE(a.at(2) == "three"); + REQUIRE_THROWS(a.at(3) == "four"); + REQUIRE_THROWS(a.at(4) == "five"); + REQUIRE(a.front() == "one"); + REQUIRE(a.back() == "three"); + REQUIRE(*a.data() == "one"); + REQUIRE(*(a.data() + 1) == "two"); + REQUIRE(*(a.data() + 2) == "three"); + REQUIRE(*(a.data() + a.size() - 1) == "three"); + REQUIRE(*(a.data() + a.size() - 2) == "two"); + REQUIRE(*(a.data() + a.size() - 3) == "one"); + } + + SECTION("Modifiers") { + vector a = {"one", "two", "three"}; + std::string tmp = "four"; + a.push_back(tmp); + REQUIRE(a.back() == "four"); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "three", "four"})); + + // NOLINTNEXTLINE(performance-move-const-arg) + std::string tmp2 = "five"; + a.push_back(std::move(tmp2)); + REQUIRE(a.back() == "five"); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "three", "four", "five"})); + + a.pop_back(); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "three", "four"})); + + a.emplace_back("five"); + REQUIRE(a.back() == "five"); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "three", "four", "five"})); + + a.pop_back(); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "three", "four"})); + + auto it = a.emplace(a.begin() + 2, "ten"); + REQUIRE(it == a.begin() + 2); + auto &b = a.back(); + REQUIRE(b == "four"); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "ten", "three", "four"})); + + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "ten"})); + + it = a.insert(a.begin() + 1, "twenty"); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "twenty", "two", "ten"})); + + // NOLINTNEXTLINE(performance-move-const-arg) + it = a.insert(a.begin() + 2, std::move("thirty")); + REQUIRE(it == a.begin() + 2); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "twenty", "thirty", "two", "ten"})); + + a.pop_back(); + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "twenty"})); + + it = a.insert(a.begin() + 1, 2, "ten"); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "ten", "ten", "twenty"})); + + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "ten"})); + + std::initializer_list src = {"two", "four", "eight"}; + it = a.insert(a.begin() + 1, src.begin(), src.end()); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "four", "eight", "ten"})); + + a.pop_back(); + a.pop_back(); + a.pop_back(); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two"})); + + it = a.insert(a.begin() + 1, {"two", "four", "eight"}); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 5); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "four", "eight", "two"})); + + it = a.erase(a.begin() + 1); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "four", "eight", "two"})); + + it = a.erase(a.begin() + 1, a.begin() + 3); + REQUIRE(it == a.begin() + 1); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two"})); + + a.clear(); + // NOLINTNEXTLINE(readability-container-size-empty) + REQUIRE(a.size() == 0); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE(a.empty()); + REQUIRE(equal_il(a, {})); + + a.resize(2); + REQUIRE(a.size() == 2); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + + a.resize(4, "five"); + REQUIRE(a.size() == 4); + REQUIRE(a.max_size() > 5); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(a[2] == "five"); + REQUIRE(a[3] == "five"); + } + + SECTION("Element access errors") { + vector a = {"one", "two", "three"}; + try { + a.at(4); + } catch (std::exception &e) { + REQUIRE(e.what() == std::string_view("at: cannot access element after vector::size()")); + } + } + + SECTION("Relational Operators") { + vector a = {"one", "two", "three"}; + vector b = {"two", "four", "five"}; + + REQUIRE_FALSE(a == b); + REQUIRE(a != b); + REQUIRE(a < b); + REQUIRE(a <= b); + REQUIRE_FALSE(a > b); + REQUIRE_FALSE(a >= b); + } + + SECTION("From raw vector") { + auto a = to_vector({"one", "two", "three"}); + REQUIRE(a.size() == 3); + REQUIRE(a.max_size() > 3); + REQUIRE(a.capacity() == default_inline_storage_v); + REQUIRE(a.capacity() == 5); + REQUIRE_FALSE(a.empty()); + REQUIRE(equal_il(a, {"one", "two", "three"})); + + auto b = to_vector({"one", "two", "three"}); + REQUIRE(b.size() == 3); + REQUIRE(b.max_size() > 5); + REQUIRE(b.capacity() == 5); + REQUIRE_FALSE(b.empty()); + REQUIRE(equal_il(b, {"one", "two", "three"})); + + std::string cr[] = {"one", "two", "three"}; + auto c = to_vector(cr); + REQUIRE(c.size() == 3); + REQUIRE(c.max_size() > 3); + REQUIRE(c.capacity() == 5); + REQUIRE(c.capacity() == default_inline_storage_v); + REQUIRE_FALSE(c.empty()); + REQUIRE(equal_il(b, {"one", "two", "three"})); + } +} diff --git a/tests/unit_tests/unicode_functions.cpp b/tests/unit_tests/unicode_functions.cpp new file mode 100644 index 0000000..e522442 --- /dev/null +++ b/tests/unit_tests/unicode_functions.cpp @@ -0,0 +1,544 @@ +#ifndef SMALL_BUILD_TESTS_WITH_PCH +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#endif + +TEST_CASE("Unicode") { + using namespace small; + + SECTION("UTF8") { + utf8_char_type a = 'g'; + // utf8_char_type b = 'รก'; // <- can't fit in 8 bits + // utf8_char_type c = '๐Ÿ˜€'; + std::basic_string d = "g"; + std::basic_string e = "รก"; + std::basic_string f = "๐Ÿ˜€"; + SECTION("Check") { + // Check container sizes + REQUIRE(d.size() == 1); + REQUIRE(e.size() == 2); + REQUIRE(f.size() == 4); + + // Identify continuation bytes + REQUIRE_FALSE(is_utf8_continuation(d[0])); + REQUIRE_FALSE(is_utf8_continuation(e[0])); + REQUIRE(is_utf8_continuation(e[1])); + REQUIRE_FALSE(is_utf8_continuation(f[0])); + REQUIRE(is_utf8_continuation(f[1])); + REQUIRE(is_utf8_continuation(f[2])); + REQUIRE(is_utf8_continuation(f[3])); + + // Identify utf size from first char + REQUIRE(utf8_size(a) == 1); + REQUIRE(utf8_size(d[0]) == 1); + REQUIRE(utf8_size(e[0]) == 2); + REQUIRE(utf8_size(e[1]) == 1); + REQUIRE(utf8_size(f[0]) == 4); + REQUIRE(utf8_size(f[1]) == 1); + REQUIRE(utf8_size(f[2]) == 1); + REQUIRE(utf8_size(f[3]) == 1); + + // Identify continuation bytes (inferring input type) + REQUIRE_FALSE(is_utf_continuation(d[0])); + REQUIRE_FALSE(is_utf_continuation(e[0])); + REQUIRE(is_utf_continuation(e[1])); + REQUIRE_FALSE(is_utf_continuation(f[0])); + REQUIRE(is_utf_continuation(f[1])); + REQUIRE(is_utf_continuation(f[2])); + REQUIRE(is_utf_continuation(f[3])); + + // Identify utf size from first char (inferring input type) + REQUIRE(utf_size(a, 1) == 1); + REQUIRE(utf_size(d[0], 1) == 1); + REQUIRE(utf_size(e[0], 2) == 2); + REQUIRE(utf_size(e[1], 1) == 1); + REQUIRE(utf_size(f[0], 4) == 4); + REQUIRE(utf_size(f[1], 4) == 1); + REQUIRE(utf_size(f[2], 4) == 1); + REQUIRE(utf_size(f[3], 4) == 1); + } + SECTION("To UTF16") { + utf16_char_type buf[2]; + + REQUIRE(from_utf8_to_utf16(&a, 1, buf, 2) == 1); + utf32_char_type r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(from_utf8_to_utf16(d.begin(), d.size(), buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(from_utf8_to_utf16(e.begin(), e.size(), buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(from_utf8_to_utf16(f.begin(), f.size(), buf, 2) == 2); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + + // Inferring type from input + REQUIRE(to_utf16(&a, 1, buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf16(d.begin(), d.size(), buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf16(e.begin(), e.size(), buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf16(f.begin(), f.size(), buf, 2) == 2); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + + // Inferring type from input and output + REQUIRE(to_utf(&a, 1, buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf(d.begin(), d.size(), buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf(e.begin(), e.size(), buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf(f.begin(), f.size(), buf, 2) == 2); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + } + + SECTION("To UTF32") { + utf32_char_type r; + + r = from_utf8_to_utf32(&a, 1); + REQUIRE(r == U'g'); + + r = from_utf8_to_utf32(d.begin(), d.size()); + REQUIRE(r == U'g'); + + r = from_utf8_to_utf32(e.begin(), e.size()); + REQUIRE(r == U'รก'); + + r = from_utf8_to_utf32(f.begin(), f.size()); + REQUIRE(r == U'๐Ÿ˜€'); + + // Inferring type from input + REQUIRE(to_utf32(&a, 1, &r, 1) == 1); + REQUIRE(r == U'g'); + + REQUIRE(to_utf32(d.begin(), d.size(), &r, 1) == 1); + REQUIRE(r == U'g'); + + REQUIRE(to_utf32(e.begin(), e.size(), &r, 1) == 1); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf32(f.begin(), f.size(), &r, 1) == 1); + REQUIRE(r == U'๐Ÿ˜€'); + + // Inferring type from input and output + REQUIRE(to_utf(&a, 1, &r, 1) == 1); + REQUIRE(r == U'g'); + + REQUIRE(to_utf(d.begin(), d.size(), &r, 1) == 1); + REQUIRE(r == U'g'); + + REQUIRE(to_utf(e.begin(), e.size(), &r, 1) == 1); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf(f.begin(), f.size(), &r, 1) == 1); + REQUIRE(r == U'๐Ÿ˜€'); + } + } + SECTION("UTF16") { + utf16_char_type a = u'g'; + utf16_char_type b = u'รก'; + // utf16_char_type c = u'๐Ÿ˜€'; // <- can't fit in a char + std::basic_string d = u"g"; + std::basic_string e = u"รก"; + std::basic_string f = u"๐Ÿ˜€"; + + SECTION("Check") { + // Check container sizes + REQUIRE(d.size() == 1); + REQUIRE(e.size() == 1); + REQUIRE(f.size() == 2); + + // Identify surrogate code units + REQUIRE_FALSE(is_utf16_surrogate(a)); + REQUIRE_FALSE(is_utf16_surrogate(b)); + REQUIRE_FALSE(is_utf16_surrogate(d[0])); + REQUIRE_FALSE(is_utf16_surrogate(e[0])); + REQUIRE(is_utf16_surrogate(f[0])); + REQUIRE(is_utf16_surrogate(f[1])); + + // Identify high and low surrogate code units + REQUIRE_FALSE(is_utf16_high_surrogate(a)); + REQUIRE_FALSE(is_utf16_low_surrogate(a)); + REQUIRE_FALSE(is_utf16_high_surrogate(b)); + REQUIRE_FALSE(is_utf16_low_surrogate(b)); + REQUIRE_FALSE(is_utf16_high_surrogate(d[0])); + REQUIRE_FALSE(is_utf16_low_surrogate(d[0])); + REQUIRE_FALSE(is_utf16_high_surrogate(e[0])); + REQUIRE_FALSE(is_utf16_low_surrogate(e[0])); + REQUIRE(is_utf16_high_surrogate(f[0])); + REQUIRE_FALSE(is_utf16_low_surrogate(f[0])); + REQUIRE_FALSE(is_utf16_high_surrogate(f[1])); + REQUIRE(is_utf16_low_surrogate(f[1])); + + // Identify continuation code units (alias for low surrogates) + REQUIRE_FALSE(is_utf16_continuation(a)); + REQUIRE_FALSE(is_utf16_continuation(b)); + REQUIRE_FALSE(is_utf16_continuation(d[0])); + REQUIRE_FALSE(is_utf16_continuation(e[0])); + REQUIRE_FALSE(is_utf16_continuation(f[0])); + REQUIRE(is_utf16_continuation(f[1])); + + // Identify utf size from first char + REQUIRE(utf16_size(a) == 1); + REQUIRE(utf16_size(b) == 1); + REQUIRE(utf16_size(d[0]) == 1); + REQUIRE(utf16_size(e[0]) == 1); + REQUIRE(utf16_size(f[0]) == 2); + REQUIRE(utf16_size(f[1]) == 1); + + // Identify continuation code units identifying input type + REQUIRE_FALSE(is_utf_continuation(a)); + REQUIRE_FALSE(is_utf_continuation(b)); + REQUIRE_FALSE(is_utf_continuation(d[0])); + REQUIRE_FALSE(is_utf_continuation(e[0])); + REQUIRE_FALSE(is_utf_continuation(f[0])); + REQUIRE(is_utf_continuation(f[1])); + + // Identify utf size from first char identifying input type + REQUIRE(utf_size(a, 1) == 1); + REQUIRE(utf_size(b, 1) == 1); + REQUIRE(utf_size(d[0], 1) == 1); + REQUIRE(utf_size(e[0], 1) == 1); + REQUIRE(utf_size(f[0], 2) == 2); + REQUIRE(utf_size(f[1], 2) == 1); + } + SECTION("To UTF8") { + utf8_char_type buf[8]; + + REQUIRE(from_utf16_to_utf8(&a, 1, buf, 8) == 1); + utf32_char_type r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(from_utf16_to_utf8(&b, 1, buf, 8) == 2); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(from_utf16_to_utf8(d.begin(), d.size(), buf, 8) == 1); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(from_utf16_to_utf8(e.begin(), e.size(), buf, 8) == 2); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(from_utf16_to_utf8(f.begin(), f.size(), buf, 8) == 4); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + + // Inferring type from input + REQUIRE(to_utf8(&a, 1, buf, 8) == 1); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf8(&b, 1, buf, 8) == 2); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf8(d.begin(), d.size(), buf, 8) == 1); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf8(e.begin(), e.size(), buf, 8) == 2); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf8(f.begin(), f.size(), buf, 8) == 4); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + + // Inferring type from input and output + REQUIRE(to_utf(&a, 1, buf, 8) == 1); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf(d.begin(), d.size(), buf, 8) == 1); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf(e.begin(), e.size(), buf, 8) == 2); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf(f.begin(), f.size(), buf, 8) == 4); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + } + SECTION("To UTF32") { + REQUIRE(utf16_surrogates_to_utf32(f[0], f[1]) == U'๐Ÿ˜€'); + + utf32_char_type r; + + r = from_utf16_to_utf32(&a, 1); + REQUIRE(r == U'g'); + + r = from_utf16_to_utf32(&b, 1); + REQUIRE(r == U'รก'); + + r = from_utf16_to_utf32(d.begin(), d.size()); + REQUIRE(r == U'g'); + + r = from_utf16_to_utf32(e.begin(), e.size()); + REQUIRE(r == U'รก'); + + r = from_utf16_to_utf32(f.begin(), f.size()); + REQUIRE(r == U'๐Ÿ˜€'); + + // Inferring type from input + REQUIRE(to_utf32(&a, 1, &r, 1) == 1); + REQUIRE(r == U'g'); + + REQUIRE(to_utf32(&b, 1, &r, 1) == 1); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf32(d.begin(), d.size(), &r, 1) == 1); + REQUIRE(r == U'g'); + + REQUIRE(to_utf32(e.begin(), e.size(), &r, 1) == 1); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf32(f.begin(), f.size(), &r, 1) == 1); + REQUIRE(r == U'๐Ÿ˜€'); + + // Inferring type from input and output + REQUIRE(to_utf(&a, 1, &r, 1) == 1); + REQUIRE(r == U'g'); + + REQUIRE(to_utf(d.begin(), d.size(), &r, 1) == 1); + REQUIRE(r == U'g'); + + REQUIRE(to_utf(e.begin(), e.size(), &r, 1) == 1); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf(f.begin(), f.size(), &r, 1) == 1); + REQUIRE(r == U'๐Ÿ˜€'); + } + } + SECTION("UTF32") { + utf32_char_type a = U'g'; + utf32_char_type b = U'รก'; + utf32_char_type c = U'๐Ÿ˜€'; + std::basic_string d = U"g"; + std::basic_string e = U"รก"; + std::basic_string f = U"๐Ÿ˜€"; + SECTION("Check") { + // Check container sizes + REQUIRE(d.size() == 1); + REQUIRE(e.size() == 1); + REQUIRE(f.size() == 1); + + // Identify continuation code units (always false for utf32) + REQUIRE_FALSE(is_utf32_continuation(a)); + REQUIRE_FALSE(is_utf32_continuation(b)); + REQUIRE_FALSE(is_utf32_continuation(d[0])); + REQUIRE_FALSE(is_utf32_continuation(e[0])); + REQUIRE_FALSE(is_utf32_continuation(f[0])); + + // Identify utf size from first char (always 1 for utf32) + REQUIRE(utf32_size(a) == 1); + REQUIRE(utf32_size(b) == 1); + REQUIRE(utf32_size(c) == 1); + REQUIRE(utf32_size(d[0]) == 1); + REQUIRE(utf32_size(e[0]) == 1); + REQUIRE(utf32_size(f[0]) == 1); + + // Identify continuation code units identifying input type + REQUIRE_FALSE(is_utf_continuation(a)); + REQUIRE_FALSE(is_utf_continuation(b)); + REQUIRE_FALSE(is_utf_continuation(d[0])); + REQUIRE_FALSE(is_utf_continuation(e[0])); + REQUIRE_FALSE(is_utf_continuation(f[0])); + + // Identify utf size from first char identifying input type + REQUIRE(utf_size(a, 1) == 1); + REQUIRE(utf_size(b, 1) == 1); + REQUIRE(utf_size(c, 1) == 1); + REQUIRE(utf_size(d[0], 1) == 1); + REQUIRE(utf_size(e[0], 1) == 1); + REQUIRE(utf_size(f[0], 1) == 1); + } + SECTION("To UTF8") { + utf8_char_type buf[8]; + + REQUIRE(from_utf32_to_utf8(a, buf, 8) == 1); + utf32_char_type r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(from_utf32_to_utf8(b, buf, 8) == 2); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(from_utf32_to_utf8(c, buf, 8) == 4); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + + REQUIRE(from_utf32_to_utf8(d.front(), buf, 8) == 1); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(from_utf32_to_utf8(e.front(), buf, 8) == 2); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(from_utf32_to_utf8(f.front(), buf, 8) == 4); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + + // Inferring type from input + REQUIRE(to_utf8(&a, 1, buf, 8) == 1); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf8(&b, 1, buf, 8) == 2); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf8(&c, 1, buf, 8) == 4); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + + REQUIRE(to_utf8(d.begin(), d.size(), buf, 8) == 1); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf8(e.begin(), e.size(), buf, 8) == 2); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf8(f.begin(), f.size(), buf, 8) == 4); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + + // Inferring type from input and output + REQUIRE(to_utf(&a, 1, buf, 8) == 1); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf(&b, 1, buf, 8) == 2); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf(&c, 1, buf, 8) == 4); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + + REQUIRE(to_utf(d.begin(), d.size(), buf, 8) == 1); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf(e.begin(), e.size(), buf, 8) == 2); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf(f.begin(), f.size(), buf, 8) == 4); + r = from_utf8_to_utf32(buf, utf8_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + } + + SECTION("To UTF16") { + utf16_char_type buf[2]; + + REQUIRE(from_utf32_to_utf16(a, buf, 2) == 1); + utf32_char_type r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(from_utf32_to_utf16(b, buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(from_utf32_to_utf16(c, buf, 2) == 2); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + + REQUIRE(from_utf32_to_utf16(d.front(), buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(from_utf32_to_utf16(e.front(), buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(from_utf32_to_utf16(f.front(), buf, 2) == 2); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + + // Inferring type from input + REQUIRE(to_utf16(&a, 1, buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf16(&b, 1, buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf16(&c, 1, buf, 2) == 2); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + + REQUIRE(to_utf16(d.begin(), d.size(), buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf16(e.begin(), e.size(), buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf16(f.begin(), f.size(), buf, 2) == 2); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + + // Inferring type from input and output + REQUIRE(to_utf(&a, 1, buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf(&b, 1, buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf(&c, 1, buf, 2) == 2); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + + REQUIRE(to_utf(d.begin(), d.size(), buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'g'); + + REQUIRE(to_utf(e.begin(), e.size(), buf, 2) == 1); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'รก'); + + REQUIRE(to_utf(f.begin(), f.size(), buf, 2) == 2); + r = from_utf16_to_utf32(buf, utf16_size(buf[0])); + REQUIRE(r == U'๐Ÿ˜€'); + } + } +} \ No newline at end of file