From 073efba1940d6f8d8c3f8e4675c56a3b6c5cb75b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 15 Jun 2026 10:36:58 +0200 Subject: kstd: move string tests --- libs/kstd/CMakeLists.txt | 1 - libs/kstd/kstd/bits/basic_string.test.cpp | 1962 --------------------------- libs/kstd/kstd/string.test.cpp | 2035 +++++++++++++++++++++++++++-- 3 files changed, 1921 insertions(+), 2077 deletions(-) delete mode 100644 libs/kstd/kstd/bits/basic_string.test.cpp diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index d85f003..5a95757 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -77,7 +77,6 @@ if(BUILD_TESTING) "kstd/flat_map.test.cpp" "kstd/format.test.cpp" "kstd/vector.test.cpp" - "kstd/bits/basic_string.test.cpp" "kstd/bits/observer_ptr.test.cpp" "kstd/test_support/os_panic.test.cpp" "kstd/string.test.cpp" diff --git a/libs/kstd/kstd/bits/basic_string.test.cpp b/libs/kstd/kstd/bits/basic_string.test.cpp deleted file mode 100644 index 8f3a00d..0000000 --- a/libs/kstd/kstd/bits/basic_string.test.cpp +++ /dev/null @@ -1,1962 +0,0 @@ -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using char_string = kstd::basic_string; - -SCENARIO("Basic string of char initialization and construction", "[string]") -{ - THEN("All type aliases are present") - { - REQUIRE(std::is_same_v>); - REQUIRE(std::is_same_v); - REQUIRE(std::is_same_v>); - REQUIRE(std::is_same_v>::size_type>); - REQUIRE( - std::is_same_v>::difference_type>); - REQUIRE(std::is_same_v); - REQUIRE(std::is_same_v); - REQUIRE(std::is_same_v>::pointer>); - REQUIRE(std::is_same_v>::const_pointer>); - REQUIRE(std::is_same_v); - REQUIRE(std::is_same_v); - REQUIRE(std::is_same_v>); - REQUIRE(std::is_same_v>); - } - - THEN("npos is present") - { - REQUIRE(char_string::npos == char_string::size_type(-1)); - } - - GIVEN("An empty context") - { - WHEN("constructing by default") - { - auto s = char_string{}; - - THEN("the string is empty") - { - REQUIRE(s.empty()); - } - - THEN("the size is equal to zero") - { - REQUIRE(s.size() == 0); - } - - THEN("the length is equal to zero") - { - REQUIRE(s.length() == 0); - } - - THEN("at raises a panic") - { - REQUIRE_THROWS_AS(s.at(0), kstd::tests::os_panic); - } - - THEN("data returns a pointer poiting to a null byte") - { - REQUIRE(*s.data() == '\0'); - } - - THEN("c_str returns a pointer poiting to a null byte") - { - REQUIRE(*s.c_str() == '\0'); - } - - THEN("the string is convertible to an empty string view") - { - auto view = static_cast(s); - REQUIRE(view.empty()); - } - } - - WHEN("constructing with 10 copies of the letter 'a'") - { - auto s = char_string{10, 'a'}; - - THEN("the string is not empty") - { - REQUIRE_FALSE(s.empty()); - } - - THEN("the size is equal to 10") - { - REQUIRE(s.size() == 10); - } - - THEN("the length is equal to 10") - { - REQUIRE(s.length() == 10); - } - - THEN("the capacity is equal to 15") - { - REQUIRE(s.capacity() == 15); - } - - THEN("at(0) returns a") - { - REQUIRE(s.at(0) == 'a'); - } - - THEN("at(size() - 1) returns a") - { - REQUIRE(s.at(s.size() - 1) == 'a'); - } - - THEN("[0] returns a") - { - REQUIRE(s[0] == 'a'); - } - - THEN("[size() - 1] returns a") - { - REQUIRE(s[s.size() - 1] == 'a'); - } - - THEN("front returns a") - { - REQUIRE(s.front() == 'a'); - } - - THEN("back returns a") - { - REQUIRE(s.back() == 'a'); - } - - THEN("data returns a pointer pointing to an a") - { - REQUIRE(*s.data() == 'a'); - } - - THEN("c_str returns a pointer pointing to an a") - { - REQUIRE(*s.c_str() == 'a'); - } - - THEN("c_str points to the start of a c-string of length 10") - { - REQUIRE(std::strlen(s.c_str()) == 10); - } - - THEN("the string converts to a string view of length 10") - { - auto view = static_cast(s); - REQUIRE(view.length() == 10); - } - } - - WHEN("constructing with 20 copies of the letter 'a'") - { - auto s = char_string{20, 'a'}; - - THEN("the string is not empty") - { - REQUIRE_FALSE(s.empty()); - } - - THEN("the size is equal to 20") - { - REQUIRE(s.size() == 20); - } - - THEN("the length is equal to 20") - { - REQUIRE(s.length() == 20); - } - - THEN("the capacity is equal to 20") - { - REQUIRE(s.capacity() == 20); - } - - THEN("at(0) returns a") - { - REQUIRE(s.at(0) == 'a'); - } - - THEN("at(size() - 1) returns a") - { - REQUIRE(s.at(s.size() - 1) == 'a'); - } - - THEN("[0] returns a") - { - REQUIRE(s[0] == 'a'); - } - - THEN("[size() - 1] returns a") - { - REQUIRE(s[s.size() - 1] == 'a'); - } - - THEN("front returns a") - { - REQUIRE(s.front() == 'a'); - } - - THEN("back returns a") - { - REQUIRE(s.back() == 'a'); - } - - THEN("data returns a pointer pointing to an a") - { - REQUIRE(*s.data() == 'a'); - } - - THEN("c_str returns a pointer pointing to an a") - { - REQUIRE(*s.c_str() == 'a'); - } - - THEN("c_str points to the start of a c-string of length 20") - { - REQUIRE(std::strlen(s.c_str()) == 20); - } - - THEN("the string converts to a string view of length 20") - { - auto view = static_cast(s); - REQUIRE(view.length() == 20); - } - } - - WHEN("constructing with an input iterator pair of 10 characters") - { - auto source = std::istringstream{"abcdefghij"}; - auto s = char_string{std::istream_iterator{source}, std::istream_iterator{}}; - - THEN("the string is not empty") - { - REQUIRE_FALSE(s.empty()); - } - - THEN("the size is equal to 10") - { - REQUIRE(s.size() == 10); - } - - THEN("the length is equal to 10") - { - REQUIRE(s.length() == 10); - } - - THEN("the capacity is equal to 15") - { - REQUIRE(s.capacity() == 15); - } - - THEN("at(0) returns a") - { - REQUIRE(s.at(0) == 'a'); - } - - THEN("at(size() - 1) returns j") - { - REQUIRE(s.at(s.size() - 1) == 'j'); - } - - THEN("[0] returns a") - { - REQUIRE(s[0] == 'a'); - } - - THEN("[size() - 1] returns j") - { - REQUIRE(s[s.size() - 1] == 'j'); - } - - THEN("front returns a") - { - REQUIRE(s.front() == 'a'); - } - - THEN("back returns j") - { - REQUIRE(s.back() == 'j'); - } - - THEN("data returns a pointer pointing to an a") - { - REQUIRE(*s.data() == 'a'); - } - - THEN("c_str returns a pointer pointing to an a") - { - REQUIRE(*s.c_str() == 'a'); - } - - THEN("c_str points to the start of a c-string of length 10") - { - REQUIRE(std::strlen(s.c_str()) == 10); - } - - THEN("the string converts to a string view of length 10") - { - auto view = static_cast(s); - REQUIRE(view.length() == 10); - } - } - - WHEN("constructing with an input iterator pair of 20 characters") - { - auto source = std::istringstream{"abcdefghijABCDEFGHIJ"}; - auto s = char_string{std::istream_iterator{source}, std::istream_iterator{}}; - - THEN("the string is not empty") - { - REQUIRE_FALSE(s.empty()); - } - - THEN("the size is equal to 20") - { - REQUIRE(s.size() == 20); - } - - THEN("the length is equal to 20") - { - REQUIRE(s.length() == 20); - } - - THEN("the capacity is greater than or equal to 20") - { - REQUIRE(s.capacity() >= 20); - } - - THEN("at(0) returns a") - { - REQUIRE(s.at(0) == 'a'); - } - - THEN("at(size() - 1) returns J") - { - REQUIRE(s.at(s.size() - 1) == 'J'); - } - - THEN("[0] returns a") - { - REQUIRE(s[0] == 'a'); - } - - THEN("[size() - 1] returns J") - { - REQUIRE(s[s.size() - 1] == 'J'); - } - - THEN("front returns a") - { - REQUIRE(s.front() == 'a'); - } - - THEN("back returns J") - { - REQUIRE(s.back() == 'J'); - } - - THEN("data returns a pointer pointing to an a") - { - REQUIRE(*s.data() == 'a'); - } - - THEN("c_str returns a pointer pointing to an a") - { - REQUIRE(*s.c_str() == 'a'); - } - - THEN("c_str points to the start of a c-string of length 20") - { - REQUIRE(std::strlen(s.c_str()) == 20); - } - - THEN("the string converts to a string view of length 20") - { - auto view = static_cast(s); - REQUIRE(view.length() == 20); - } - } - - WHEN("constructing with a forward iterator pair of 10 characters") - { - auto source = std::forward_list{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}; - auto s = char_string{source.cbegin(), source.cend()}; - - THEN("the string is not empty") - { - REQUIRE_FALSE(s.empty()); - } - - THEN("the size is equal to 10") - { - REQUIRE(s.size() == 10); - } - - THEN("the length is equal to 10") - { - REQUIRE(s.length() == 10); - } - - THEN("the capacity is equal to 15") - { - REQUIRE(s.capacity() == 15); - } - - THEN("at(0) returns a") - { - REQUIRE(s.at(0) == 'a'); - } - - THEN("at(size() - 1) returns j") - { - REQUIRE(s.at(s.size() - 1) == 'j'); - } - - THEN("[0] returns a") - { - REQUIRE(s[0] == 'a'); - } - - THEN("[size() - 1] returns j") - { - REQUIRE(s[s.size() - 1] == 'j'); - } - - THEN("front returns a") - { - REQUIRE(s.front() == 'a'); - } - - THEN("back returns j") - { - REQUIRE(s.back() == 'j'); - } - - THEN("data returns a pointer pointing to an a") - { - REQUIRE(*s.data() == 'a'); - } - - THEN("c_str returns a pointer pointing to an a") - { - REQUIRE(*s.c_str() == 'a'); - } - - THEN("c_str points to the start of a c-string of length 10") - { - REQUIRE(std::strlen(s.c_str()) == 10); - } - - THEN("the string converts to a string view of length 10") - { - auto view = static_cast(s); - REQUIRE(view.length() == 10); - } - } - - WHEN("constructing with a forward iterator pair of 20 characters") - { - auto source = std::forward_list{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'}; - auto s = char_string{source.cbegin(), source.cend()}; - - THEN("the string is not empty") - { - REQUIRE_FALSE(s.empty()); - } - - THEN("the size is equal to 20") - { - REQUIRE(s.size() == 20); - } - - THEN("the length is equal to 20") - { - REQUIRE(s.length() == 20); - } - - THEN("the capacity is equal to 20") - { - REQUIRE(s.capacity() == 20); - } - - THEN("at(0) returns a") - { - REQUIRE(s.at(0) == 'a'); - } - - THEN("at(size() - 1) returns J") - { - REQUIRE(s.at(s.size() - 1) == 'J'); - } - - THEN("[0] returns a") - { - REQUIRE(s[0] == 'a'); - } - - THEN("[size() - 1] returns J") - { - REQUIRE(s[s.size() - 1] == 'J'); - } - - THEN("front returns a") - { - REQUIRE(s.front() == 'a'); - } - - THEN("back returns J") - { - REQUIRE(s.back() == 'J'); - } - - THEN("data returns a pointer pointing to an a") - { - REQUIRE(*s.data() == 'a'); - } - - THEN("c_str returns a pointer pointing to an a") - { - REQUIRE(*s.c_str() == 'a'); - } - - THEN("c_str points to the start of a c-string of length 20") - { - REQUIRE(std::strlen(s.c_str()) == 20); - } - - THEN("the string converts to a string view of length 20") - { - auto view = static_cast(s); - REQUIRE(view.length() == 20); - } - } - - WHEN("constructing from a null pointer with zero size") - { - auto s = char_string{static_cast(nullptr), 0}; - - THEN("the string is empty") - { - REQUIRE(s.empty()); - } - - THEN("the size is equal to 0") - { - REQUIRE(s.size() == 0); - } - - THEN("the length is equal to 0") - { - REQUIRE(s.length() == 0); - } - - THEN("the capacity is equal to 15") - { - REQUIRE(s.capacity() == 15); - } - - THEN("at raises a panic") - { - REQUIRE_THROWS_AS(s.at(0), kstd::tests::os_panic); - } - - THEN("data returns a pointer poiting to a null byte") - { - REQUIRE(*s.data() == '\0'); - } - - THEN("c_str returns a pointer poiting to a null byte") - { - REQUIRE(*s.c_str() == '\0'); - } - - THEN("the string is convertible to an empty string view") - { - auto view = static_cast(s); - REQUIRE(view.empty()); - } - } - - WHEN("constructing from a from a null pointer and non-zero size") - { - THEN("a panic is raised") - { - REQUIRE_THROWS_AS((char_string{static_cast(nullptr), 1}), kstd::tests::os_panic); - } - } - - WHEN("constructing from a non-null pointer and zero size") - { - auto ptr = "abcd"; - auto s = char_string{ptr, 0}; - - THEN("the string is empty") - { - REQUIRE(s.empty()); - } - - THEN("the size is equal to 0") - { - REQUIRE(s.size() == 0); - } - - THEN("the length is equal to 0") - { - REQUIRE(s.length() == 0); - } - - THEN("the capacity is equal to 15") - { - REQUIRE(s.capacity() == 15); - } - - THEN("at raises a panic") - { - REQUIRE_THROWS_AS(s.at(0), kstd::tests::os_panic); - } - - THEN("data returns a pointer poiting to a null byte") - { - REQUIRE(*s.data() == '\0'); - } - - THEN("c_str returns a pointer poiting to a null byte") - { - REQUIRE(*s.c_str() == '\0'); - } - - THEN("the string is convertible to an empty string view") - { - auto view = static_cast(s); - REQUIRE(view.empty()); - } - } - - WHEN("constructing from a non-null pointer and a size of 4") - { - auto ptr = "abcd"; - auto s = char_string{ptr, 4}; - - THEN("the string is not empty") - { - REQUIRE_FALSE(s.empty()); - } - - THEN("the size is equal to 4") - { - REQUIRE(s.size() == 4); - } - - THEN("the length is equal to 4") - { - REQUIRE(s.length() == 4); - } - - THEN("the capacity is equal to 15") - { - REQUIRE(s.capacity() == 15); - } - - THEN("at(0) returns a") - { - REQUIRE(s.at(0) == 'a'); - } - - THEN("at(size() - 1) returns d") - { - REQUIRE(s.at(s.size() - 1) == 'd'); - } - - THEN("[0] returns a") - { - REQUIRE(s[0] == 'a'); - } - - THEN("[size() - 1] returns d") - { - REQUIRE(s[s.size() - 1] == 'd'); - } - - THEN("front returns a") - { - REQUIRE(s.front() == 'a'); - } - - THEN("back returns d") - { - REQUIRE(s.back() == 'd'); - } - - THEN("data returns a pointer pointing to an a") - { - REQUIRE(*s.data() == 'a'); - } - - THEN("c_str returns a pointer pointing to an a") - { - REQUIRE(*s.c_str() == 'a'); - } - - THEN("c_str points to the start of a c-string of length 4") - { - REQUIRE(std::strlen(s.c_str()) == 4); - } - - THEN("the string converts to a string view of length 4") - { - auto view = static_cast(s); - REQUIRE(view.length() == 4); - } - } - - WHEN("constructing from a non-null pointer and a size of 20") - { - auto ptr = "abcdefghijABCDEFGHIJ"; - auto s = char_string{ptr, 20}; - - THEN("the string is not empty") - { - REQUIRE_FALSE(s.empty()); - } - - THEN("the size is equal to 20") - { - REQUIRE(s.size() == 20); - } - - THEN("the length is equal to 20") - { - REQUIRE(s.length() == 20); - } - - THEN("the capacity is equal to 20") - { - REQUIRE(s.capacity() == 20); - } - - THEN("at(0) returns a") - { - REQUIRE(s.at(0) == 'a'); - } - - THEN("at(size() - 1) returns J") - { - REQUIRE(s.at(s.size() - 1) == 'J'); - } - - THEN("[0] returns a") - { - REQUIRE(s[0] == 'a'); - } - - THEN("[size() - 1] returns J") - { - REQUIRE(s[s.size() - 1] == 'J'); - } - - THEN("front returns a") - { - REQUIRE(s.front() == 'a'); - } - - THEN("back returns J") - { - REQUIRE(s.back() == 'J'); - } - - THEN("data returns a pointer pointing to an a") - { - REQUIRE(*s.data() == 'a'); - } - - THEN("c_str returns a pointer pointing to an a") - { - REQUIRE(*s.c_str() == 'a'); - } - - THEN("c_str points to the start of a c-string of length 20") - { - REQUIRE(std::strlen(s.c_str()) == 20); - } - - THEN("the string converts to a string view of length 20") - { - auto view = static_cast(s); - REQUIRE(view.length() == 20); - } - } - - WHEN("constructing from a C-style string of length 4") - { - auto ptr = "abcd"; - auto s = char_string{ptr}; - - THEN("the string is not empty") - { - REQUIRE_FALSE(s.empty()); - } - - THEN("the size is equal to 4") - { - REQUIRE(s.size() == 4); - } - - THEN("the length is equal to 4") - { - REQUIRE(s.length() == 4); - } - - THEN("the capacity is equal to 15") - { - REQUIRE(s.capacity() == 15); - } - - THEN("at(0) returns a") - { - REQUIRE(s.at(0) == 'a'); - } - - THEN("at(size() - 1) returns d") - { - REQUIRE(s.at(s.size() - 1) == 'd'); - } - - THEN("[0] returns a") - { - REQUIRE(s[0] == 'a'); - } - - THEN("[size() - 1] returns d") - { - REQUIRE(s[s.size() - 1] == 'd'); - } - - THEN("front returns a") - { - REQUIRE(s.front() == 'a'); - } - - THEN("back returns d") - { - REQUIRE(s.back() == 'd'); - } - - THEN("data returns a pointer pointing to an a") - { - REQUIRE(*s.data() == 'a'); - } - - THEN("c_str returns a pointer pointing to an a") - { - REQUIRE(*s.c_str() == 'a'); - } - - THEN("c_str points to the start of a c-string of length 4") - { - REQUIRE(std::strlen(s.c_str()) == 4); - } - - THEN("the string converts to a string view of length 4") - { - auto view = static_cast(s); - REQUIRE(view.length() == 4); - } - } - - WHEN("constructing from a C-style string of length 20") - { - auto ptr = "abcdefghijABCDEFGHIJ"; - auto s = char_string{ptr}; - - THEN("the string is not empty") - { - REQUIRE_FALSE(s.empty()); - } - - THEN("the size is equal to 20") - { - REQUIRE(s.size() == 20); - } - - THEN("the length is equal to 20") - { - REQUIRE(s.length() == 20); - } - - THEN("the capacity is equal to 20") - { - REQUIRE(s.capacity() == 20); - } - - THEN("at(0) returns a") - { - REQUIRE(s.at(0) == 'a'); - } - - THEN("at(size() - 1) returns J") - { - REQUIRE(s.at(s.size() - 1) == 'J'); - } - - THEN("[0] returns a") - { - REQUIRE(s[0] == 'a'); - } - - THEN("[size() - 1] returns J") - { - REQUIRE(s[s.size() - 1] == 'J'); - } - - THEN("front returns a") - { - REQUIRE(s.front() == 'a'); - } - - THEN("back returns J") - { - REQUIRE(s.back() == 'J'); - } - - THEN("data returns a pointer pointing to an a") - { - REQUIRE(*s.data() == 'a'); - } - - THEN("c_str returns a pointer pointing to an a") - { - REQUIRE(*s.c_str() == 'a'); - } - - THEN("c_str points to the start of a c-string of length 20") - { - REQUIRE(std::strlen(s.c_str()) == 20); - } - - THEN("the string converts to a string view of length 20") - { - auto view = static_cast(s); - REQUIRE(view.length() == 20); - } - } - - WHEN("constructing from a string view of length 4") - { - using namespace std::string_view_literals; - - auto view = "abcd"sv; - auto s = char_string{view}; - - THEN("the string is not empty") - { - REQUIRE_FALSE(s.empty()); - } - - THEN("the size is equal to 4") - { - REQUIRE(s.size() == 4); - } - - THEN("the length is equal to 4") - { - REQUIRE(s.length() == 4); - } - - THEN("the capacity is equal to 15") - { - REQUIRE(s.capacity() == 15); - } - - THEN("at(0) returns a") - { - REQUIRE(s.at(0) == 'a'); - } - - THEN("at(size() - 1) returns d") - { - REQUIRE(s.at(s.size() - 1) == 'd'); - } - - THEN("[0] returns a") - { - REQUIRE(s[0] == 'a'); - } - - THEN("[size() - 1] returns d") - { - REQUIRE(s[s.size() - 1] == 'd'); - } - - THEN("front returns a") - { - REQUIRE(s.front() == 'a'); - } - - THEN("back returns d") - { - REQUIRE(s.back() == 'd'); - } - - THEN("data returns a pointer pointing to an a") - { - REQUIRE(*s.data() == 'a'); - } - - THEN("c_str returns a pointer pointing to an a") - { - REQUIRE(*s.c_str() == 'a'); - } - - THEN("c_str points to the start of a c-string of length 4") - { - REQUIRE(std::strlen(s.c_str()) == 4); - } - - THEN("the string converts to a string view of length 4") - { - auto view = static_cast(s); - REQUIRE(view.length() == 4); - } - } - - WHEN("constructing from a string view of length 20") - { - using namespace std::string_view_literals; - - auto view = "abcdefghijABCDEFGHIJ"sv; - auto s = char_string{view}; - - THEN("the string is not empty") - { - REQUIRE_FALSE(s.empty()); - } - - THEN("the size is equal to 20") - { - REQUIRE(s.size() == 20); - } - - THEN("the length is equal to 20") - { - REQUIRE(s.length() == 20); - } - - THEN("the capacity is equal to 20") - { - REQUIRE(s.capacity() == 20); - } - - THEN("at(0) returns a") - { - REQUIRE(s.at(0) == 'a'); - } - - THEN("at(size() - 1) returns J") - { - REQUIRE(s.at(s.size() - 1) == 'J'); - } - - THEN("[0] returns a") - { - REQUIRE(s[0] == 'a'); - } - - THEN("[size() - 1] returns J") - { - REQUIRE(s[s.size() - 1] == 'J'); - } - - THEN("front returns a") - { - REQUIRE(s.front() == 'a'); - } - - THEN("back returns J") - { - REQUIRE(s.back() == 'J'); - } - - THEN("data returns a pointer pointing to an a") - { - REQUIRE(*s.data() == 'a'); - } - - THEN("c_str returns a pointer pointing to an a") - { - REQUIRE(*s.c_str() == 'a'); - } - - THEN("c_str points to the start of a c-string of length 20") - { - REQUIRE(std::strlen(s.c_str()) == 20); - } - - THEN("the string converts to a string view of length 20") - { - auto view = static_cast(s); - REQUIRE(view.length() == 20); - } - } - - WHEN("constructing from a substring of a string view of length 4") - { - using namespace std::string_view_literals; - - auto view = "abcd"sv; - auto s = char_string{view, 1, 4}; - - THEN("the string is not empty") - { - REQUIRE_FALSE(s.empty()); - } - - THEN("the size is equal to 3") - { - REQUIRE(s.size() == 3); - } - - THEN("the length is equal to 3") - { - REQUIRE(s.length() == 3); - } - - THEN("the capacity is equal to 15") - { - REQUIRE(s.capacity() == 15); - } - - THEN("at(0) returns b") - { - REQUIRE(s.at(0) == 'b'); - } - - THEN("at(size() - 1) returns d") - { - REQUIRE(s.at(s.size() - 1) == 'd'); - } - - THEN("[0] returns b") - { - REQUIRE(s[0] == 'b'); - } - - THEN("[size() - 1] returns d") - { - REQUIRE(s[s.size() - 1] == 'd'); - } - - THEN("front returns b") - { - REQUIRE(s.front() == 'b'); - } - - THEN("back returns d") - { - REQUIRE(s.back() == 'd'); - } - - THEN("data returns a pointer pointing to an b") - { - REQUIRE(*s.data() == 'b'); - } - - THEN("c_str returns a pointer pointing to an b") - { - REQUIRE(*s.c_str() == 'b'); - } - - THEN("c_str points to the start of a c-string of length 3") - { - REQUIRE(std::strlen(s.c_str()) == 3); - } - - THEN("the string converts to a string view of length 3") - { - auto view = static_cast(s); - REQUIRE(view.length() == 3); - } - } - - WHEN("constructing from a substring of a string view of length 20") - { - using namespace std::string_view_literals; - - auto view = "abcdefghijABCDEFGHIJ"sv; - auto s = char_string{view, 1, 20}; - - THEN("the string is not empty") - { - REQUIRE_FALSE(s.empty()); - } - - THEN("the size is equal to 19") - { - REQUIRE(s.size() == 19); - } - - THEN("the length is equal to 19") - { - REQUIRE(s.length() == 19); - } - - THEN("the capacity is equal to 19") - { - REQUIRE(s.capacity() == 19); - } - - THEN("at(0) returns b") - { - REQUIRE(s.at(0) == 'b'); - } - - THEN("at(size() - 1) returns J") - { - REQUIRE(s.at(s.size() - 1) == 'J'); - } - - THEN("[0] returns b") - { - REQUIRE(s[0] == 'b'); - } - - THEN("[size() - 1] returns J") - { - REQUIRE(s[s.size() - 1] == 'J'); - } - - THEN("front returns b") - { - REQUIRE(s.front() == 'b'); - } - - THEN("back returns J") - { - REQUIRE(s.back() == 'J'); - } - - THEN("data returns a pointer pointing to an b") - { - REQUIRE(*s.data() == 'b'); - } - - THEN("c_str returns a pointer pointing to an b") - { - REQUIRE(*s.c_str() == 'b'); - } - - THEN("c_str points to the start of a c-string of length 19") - { - REQUIRE(std::strlen(s.c_str()) == 19); - } - - THEN("the string converts to a string view of length 19") - { - auto view = static_cast(s); - REQUIRE(view.length() == 19); - } - } - } - - GIVEN("An existing short string, of length 10") - { - auto other = char_string{"abcdefghij"}; - - WHEN("constructing by copy") - { - auto s = other; - - THEN("the sizes are identical") - { - REQUIRE(s.size() == other.size()); - } - - THEN("the capacities are idendtical") - { - REQUIRE(s.capacity() == other.capacity()); - } - - THEN("the underlying strings are identical") - { - REQUIRE_FALSE(std::strcmp(s.data(), other.data())); - } - } - - WHEN("constructing by move") - { - auto s = std::move(other); - - THEN("size is equal to 10") - { - REQUIRE(s.size() == 10); - } - - THEN("capacity is equal to 15") - { - REQUIRE(s.capacity() == 15); - } - - THEN("front() return an a") - { - REQUIRE(s.front() == 'a'); - } - - THEN("back() return a j") - { - REQUIRE(s.back() == 'j'); - } - - THEN("The moved from object's size is 0") - { - REQUIRE(other.size() == 0); - } - - THEN("The moved from object's capacity is 15") - { - REQUIRE(other.capacity() == 15); - } - - THEN("c_str() on the moved from object points to a null byte") - { - REQUIRE(*other.c_str() == '\0'); - } - } - } - - GIVEN("An existing short string, of length 20") - { - auto other = char_string{"abcdefghijABCDEFGHIJ"}; - - WHEN("constructing by copy") - { - auto s = other; - - THEN("the sizes are identical") - { - REQUIRE(s.size() == other.size()); - } - - THEN("the capacities are idendtical") - { - REQUIRE(s.capacity() == other.capacity()); - } - - THEN("the underlying strings are identical") - { - REQUIRE_FALSE(std::strcmp(s.data(), other.data())); - } - } - - WHEN("constructing by move") - { - auto s = std::move(other); - - THEN("size is equal to 20") - { - REQUIRE(s.size() == 20); - } - - THEN("capacity is equal to 20") - { - REQUIRE(s.capacity() == 20); - } - - THEN("front() return an a") - { - REQUIRE(s.front() == 'a'); - } - - THEN("back() return a J") - { - REQUIRE(s.back() == 'J'); - } - - THEN("The moved from object's size is 0") - { - REQUIRE(other.size() == 0); - } - - THEN("The moved from object's capacity is 15") - { - REQUIRE(other.capacity() == 15); - } - - THEN("c_str() on the moved from object points to a null byte") - { - REQUIRE(*other.c_str() == '\0'); - } - } - } -} - -SCENARIO("Basic string assignment", "[string]") -{ - GIVEN("Two short strings") - { - auto s1 = char_string{"abcd"}; - auto s2 = char_string{"defghij"}; - - WHEN("copy assigning the shorter to the longer one") - { - s2 = s1; - - THEN("the new length of the longer one is equal to the length of the shorter one") - { - REQUIRE(s2.length() == s1.length()); - } - - THEN("the underlying data of the two is identical") - { - REQUIRE_FALSE(std::strcmp(s1.data(), s2.data())); - } - } - - WHEN("copy assigning the longer to the shorter one") - { - s1 = s2; - - THEN("the new length of the shorter one is equal to the length of the longer one") - { - REQUIRE(s1.length() == s2.length()); - } - - THEN("the underlying data of the two is identical") - { - REQUIRE_FALSE(std::strcmp(s2.data(), s1.data())); - } - } - - WHEN("move assigning the shorter to the longer one") - { - s2 = std::move(s1); - - THEN("the new length of the longer one is equal to the original length of the shorter one") - { - REQUIRE(s2.length() == 4); - } - - THEN("the length of the moved from one is 0") - { - REQUIRE(s1.length() == 0); - } - - THEN("the capacity of the moved from one is 15") - { - REQUIRE(s1.capacity() == 15); - } - - THEN("the capacity of the moved to one is 15") - { - REQUIRE(s2.capacity() == 15); - } - } - - WHEN("move assigning the longer to the shorter one") - { - s1 = std::move(s2); - - THEN("the new length of the shorter one is equal to the original length of the longer one") - { - REQUIRE(s1.length() == 7); - } - - THEN("the length of the moved from one is 0") - { - REQUIRE(s2.length() == 0); - } - - THEN("the capacity of the moved from one is 15") - { - REQUIRE(s2.capacity() == 15); - } - - THEN("the capacity of the moved to one is 15") - { - REQUIRE(s1.capacity() == 15); - } - } - } - - GIVEN("One short and one long string") - { - auto s1 = char_string{"abcd"}; - auto s2 = char_string{"ABCDEFGHIJabcdefghij"}; - - WHEN("copy assigning the shorter to the longer one") - { - s2 = s1; - - THEN("the new length of the longer one is equal to the length of the shorter one") - { - REQUIRE(s2.length() == s1.length()); - } - - THEN("the new capacity of the longer one is 15") - { - REQUIRE(s2.capacity() == 15); - } - - THEN("the underlying data of the two is identical") - { - REQUIRE_FALSE(std::strcmp(s1.data(), s2.data())); - } - } - - WHEN("copy assigning the longer to the shorter one") - { - s1 = s2; - - THEN("the new length of the shorter one is equal to the length of the longer one") - { - REQUIRE(s1.length() == s2.length()); - } - - THEN("the new capacity of the shorter one is 20") - { - REQUIRE(s1.capacity() == 20); - } - - THEN("the underlying data of the two is identical") - { - REQUIRE_FALSE(std::strcmp(s2.data(), s1.data())); - } - } - - WHEN("move assigning the shorter to the longer one") - { - s2 = std::move(s1); - - THEN("the new length of the longer one is equal to the original length of the shorter one") - { - REQUIRE(s2.length() == 4); - } - - THEN("the length of the moved from one is 0") - { - REQUIRE(s1.length() == 0); - } - - THEN("the capacity of the moved from one is 15") - { - REQUIRE(s1.capacity() == 15); - } - - THEN("the capacity of the moved to one is 15") - { - REQUIRE(s2.capacity() == 15); - } - } - - WHEN("move assigning the longer to the shorter one") - { - s1 = std::move(s2); - - THEN("the new length of the shorter one is equal to the original length of the longer one") - { - REQUIRE(s1.length() == 20); - } - - THEN("the length of the moved from one is 0") - { - REQUIRE(s2.length() == 0); - } - - THEN("the capacity of the moved from one is 15") - { - REQUIRE(s2.capacity() == 15); - } - - THEN("the capacity of the moved to one is 15") - { - REQUIRE(s1.capacity() == 20); - } - } - } - - GIVEN("Two long strings") - { - auto s1 = char_string{"abcdefghijABCDEFGH"}; - auto s2 = char_string{"ABCDEFGHIJabcdefghij"}; - - WHEN("copy assigning the shorter to the longer one") - { - s2 = s1; - - THEN("the new length of the longer one is equal to the length of the shorter one") - { - REQUIRE(s2.length() == s1.length()); - } - - THEN("the new capacity of the longer one is still 20") - { - REQUIRE(s2.capacity() == 20); - } - - THEN("the underlying data of the two is identical") - { - REQUIRE_FALSE(std::strcmp(s1.data(), s2.data())); - } - } - - WHEN("copy assigning the longer to the shorter one") - { - s1 = s2; - - THEN("the new length of the shorter one is equal to the length of the longer one") - { - REQUIRE(s1.length() == s2.length()); - } - - THEN("the new capacity of the shorter one is 20") - { - REQUIRE(s1.capacity() == 20); - } - - THEN("the underlying data of the two is identical") - { - REQUIRE_FALSE(std::strcmp(s2.data(), s1.data())); - } - } - - WHEN("move assigning the shorter to the longer one") - { - s2 = std::move(s1); - - THEN("the new length of the longer one is equal to the original length of the shorter one") - { - REQUIRE(s2.length() == 18); - } - - THEN("the length of the moved from one is 0") - { - REQUIRE(s1.length() == 0); - } - - THEN("the capacity of the moved from one is 15") - { - REQUIRE(s1.capacity() == 15); - } - - THEN("the capacity of the moved to one is 15") - { - REQUIRE(s2.capacity() == 18); - } - } - - WHEN("move assigning the longer to the shorter one") - { - s1 = std::move(s2); - - THEN("the new length of the shorter one is equal to the original length of the longer one") - { - REQUIRE(s1.length() == 20); - } - - THEN("the length of the moved from one is 0") - { - REQUIRE(s2.length() == 0); - } - - THEN("the capacity of the moved from one is 15") - { - REQUIRE(s2.capacity() == 15); - } - - THEN("the capacity of the moved to one is 15") - { - REQUIRE(s1.capacity() == 20); - } - } - } - - GIVEN("An short string") - { - auto s = char_string{"abcd"}; - - WHEN("assigning a new, shorter c-style string of length 3") - { - s = "def"; - - THEN("the length is equal to 3") - { - REQUIRE(s.length() == 3); - } - } - - WHEN("assigning a new, longer, c-style string of length 5") - { - s = "defgh"; - - THEN("the length is equal to 5") - { - REQUIRE(s.length() == 5); - } - } - - WHEN("assigning a new, longer, c-style string of length 20") - { - s = "ABCDEFGHIJabcdefghij"; - - THEN("the length is equal to 20") - { - REQUIRE(s.length() == 20); - } - } - - WHEN("assigning a single character") - { - s = 'z'; - - THEN("the length is equal to 1") - { - REQUIRE(s.length() == 1); - } - } - - WHEN("assigning an shorter initializer list of length 3") - { - s = {'d', 'e', 'f'}; - - THEN("the length is equal to 3") - { - REQUIRE(s.length() == 3); - } - } - - WHEN("assigning an longer initializer list of length 5") - { - s = {'d', 'e', 'f', 'g', 'h'}; - - THEN("the length is equal to 5") - { - REQUIRE(s.length() == 5); - } - } - - WHEN("assigning an longer initializer list of length 20") - { - s = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}; - - THEN("the length is equal to 20") - { - REQUIRE(s.length() == 20); - } - } - - WHEN("assigning from a shorter string view of length 3") - { - using namespace std::string_view_literals; - - s = "def"sv; - - THEN("the length is equal to 3") - { - REQUIRE(s.length() == 3); - } - } - - WHEN("assigning from a longer string view of length 5") - { - using namespace std::string_view_literals; - - s = "defgh"sv; - - THEN("the length is equal to 5") - { - REQUIRE(s.length() == 5); - } - } - - WHEN("assigning from a longer string view of length 20") - { - using namespace std::string_view_literals; - - s = "ABCDEFGHIJabcdefghij"sv; - - THEN("the length is equal to 20") - { - REQUIRE(s.length() == 20); - } - } - } - - GIVEN("An long string") - { - auto s = char_string{"abcdefghijABCDEFGHIJ"}; - - WHEN("assigning a new, shorter c-style string of length 3") - { - s = "def"; - - THEN("the length is equal to 3") - { - REQUIRE(s.length() == 3); - } - } - - WHEN("assigning a new, longer, c-style string of length 22") - { - s = "ABCDEFGHIJabcdefghijkl"; - - THEN("the length is equal to 22") - { - REQUIRE(s.length() == 22); - } - } - - WHEN("assigning a single character") - { - s = 'z'; - - THEN("the length is equal to 1") - { - REQUIRE(s.length() == 1); - } - } - - WHEN("assigning an shorter initializer list of length 3") - { - s = {'d', 'e', 'f'}; - - THEN("the length is equal to 3") - { - REQUIRE(s.length() == 3); - } - } - - WHEN("assigning an longer initializer list of length 22") - { - s = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'a', - 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'}; - - THEN("the length is equal to 22") - { - REQUIRE(s.length() == 22); - } - } - - WHEN("assigning from a shorter string view of length 3") - { - using namespace std::string_view_literals; - - s = "def"sv; - - THEN("the length is equal to 3") - { - REQUIRE(s.length() == 3); - } - } - - WHEN("assigning from a longer string view of length 22") - { - using namespace std::string_view_literals; - - s = "ABCDEFGHIJabcdefghijkl"sv; - - THEN("the length is equal to 22") - { - REQUIRE(s.length() == 22); - } - } - } -} - -SCENARIO("Basic string of char modifiers", "[string]") -{ - GIVEN("A short string") - { - auto s = char_string{"abcd"}; - auto old_capacity = s.capacity(); - auto old_size = s.size(); - auto old_data = s.data(); - - WHEN("reserving a smaller capacity") - { - s.reserve(1); - - THEN("the capacity does not change") - { - REQUIRE(s.capacity() == old_capacity); - } - - THEN("the content stays the same") - { - REQUIRE(s == "abcd"); - } - - THEN("the size stays the same") - { - REQUIRE(s.size() == old_size); - } - - THEN("the data pointer stays the same") - { - REQUIRE(s.data() == old_data); - } - } - - WHEN("reserving equal capacity") - { - s.reserve(old_capacity); - - THEN("the capacity does not change") - { - REQUIRE(s.capacity() == old_capacity); - } - - THEN("the content stays the same") - { - REQUIRE(s == "abcd"); - } - - THEN("the size stays the same") - { - REQUIRE(s.size() == old_size); - } - - THEN("the data pointer stays the same") - { - REQUIRE(static_cast(s.data()) == static_cast(old_data)); - } - } - - WHEN("reserving larger capacity") - { - s.reserve(old_capacity + 1); - - THEN("the capacity increases") - { - REQUIRE(s.capacity() >= old_capacity + 1); - } - - THEN("the content stays the same") - { - REQUIRE(s == "abcd"); - } - - THEN("the size stays the same") - { - REQUIRE(s.size() == old_size); - } - - THEN("the data pointer changes") - { - REQUIRE(s.data() != old_data); - } - } - } -} diff --git a/libs/kstd/kstd/string.test.cpp b/libs/kstd/kstd/string.test.cpp index b81cd3a..e5925aa 100644 --- a/libs/kstd/kstd/string.test.cpp +++ b/libs/kstd/kstd/string.test.cpp @@ -1,158 +1,1959 @@ #include +#include +#include + #include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TEST_CASE("String static interface") +{ + REQUIRE(std::is_same_v>); + REQUIRE(std::is_same_v); + REQUIRE(std::is_same_v>); + REQUIRE(std::is_same_v>::size_type>); + REQUIRE(std::is_same_v>::difference_type>); + REQUIRE(std::is_same_v); + REQUIRE(std::is_same_v); + REQUIRE(std::is_same_v>::pointer>); + REQUIRE(std::is_same_v>::const_pointer>); + REQUIRE(std::is_same_v); + REQUIRE(std::is_same_v); + REQUIRE(std::is_same_v>); + REQUIRE(std::is_same_v>); + + REQUIRE(kstd::string::npos == kstd::string::size_type(-1)); +} + +SCENARIO("String initialization and construction", "[string]") +{ + GIVEN("An empty context") + { + WHEN("constructing by default") + { + auto s = kstd::string{}; + + THEN("the string is empty") + { + REQUIRE(s.empty()); + } + + THEN("the size is equal to zero") + { + REQUIRE(s.size() == 0); + } + + THEN("the length is equal to zero") + { + REQUIRE(s.length() == 0); + } + + THEN("at raises a panic") + { + REQUIRE_THROWS_AS(s.at(0), kstd::tests::os_panic); + } + + THEN("data returns a pointer poiting to a null byte") + { + REQUIRE(*s.data() == '\0'); + } + + THEN("c_str returns a pointer poiting to a null byte") + { + REQUIRE(*s.c_str() == '\0'); + } + + THEN("the string is convertible to an empty string view") + { + auto view = static_cast(s); + REQUIRE(view.empty()); + } + } + + WHEN("constructing with 10 copies of the letter 'a'") + { + auto s = kstd::string{10, 'a'}; + + THEN("the string is not empty") + { + REQUIRE_FALSE(s.empty()); + } + + THEN("the size is equal to 10") + { + REQUIRE(s.size() == 10); + } + + THEN("the length is equal to 10") + { + REQUIRE(s.length() == 10); + } + + THEN("the capacity is equal to 15") + { + REQUIRE(s.capacity() == 15); + } + + THEN("at(0) returns a") + { + REQUIRE(s.at(0) == 'a'); + } + + THEN("at(size() - 1) returns a") + { + REQUIRE(s.at(s.size() - 1) == 'a'); + } + + THEN("[0] returns a") + { + REQUIRE(s[0] == 'a'); + } + + THEN("[size() - 1] returns a") + { + REQUIRE(s[s.size() - 1] == 'a'); + } + + THEN("front returns a") + { + REQUIRE(s.front() == 'a'); + } + + THEN("back returns a") + { + REQUIRE(s.back() == 'a'); + } + + THEN("data returns a pointer pointing to an a") + { + REQUIRE(*s.data() == 'a'); + } + + THEN("c_str returns a pointer pointing to an a") + { + REQUIRE(*s.c_str() == 'a'); + } + + THEN("c_str points to the start of a c-string of length 10") + { + REQUIRE(std::strlen(s.c_str()) == 10); + } + + THEN("the string converts to a string view of length 10") + { + auto view = static_cast(s); + REQUIRE(view.length() == 10); + } + } + + WHEN("constructing with 20 copies of the letter 'a'") + { + auto s = kstd::string{20, 'a'}; + + THEN("the string is not empty") + { + REQUIRE_FALSE(s.empty()); + } + + THEN("the size is equal to 20") + { + REQUIRE(s.size() == 20); + } + + THEN("the length is equal to 20") + { + REQUIRE(s.length() == 20); + } + + THEN("the capacity is equal to 20") + { + REQUIRE(s.capacity() == 20); + } + + THEN("at(0) returns a") + { + REQUIRE(s.at(0) == 'a'); + } + + THEN("at(size() - 1) returns a") + { + REQUIRE(s.at(s.size() - 1) == 'a'); + } + + THEN("[0] returns a") + { + REQUIRE(s[0] == 'a'); + } + + THEN("[size() - 1] returns a") + { + REQUIRE(s[s.size() - 1] == 'a'); + } + + THEN("front returns a") + { + REQUIRE(s.front() == 'a'); + } + + THEN("back returns a") + { + REQUIRE(s.back() == 'a'); + } + + THEN("data returns a pointer pointing to an a") + { + REQUIRE(*s.data() == 'a'); + } + + THEN("c_str returns a pointer pointing to an a") + { + REQUIRE(*s.c_str() == 'a'); + } + + THEN("c_str points to the start of a c-string of length 20") + { + REQUIRE(std::strlen(s.c_str()) == 20); + } + + THEN("the string converts to a string view of length 20") + { + auto view = static_cast(s); + REQUIRE(view.length() == 20); + } + } + + WHEN("constructing with an input iterator pair of 10 characters") + { + auto source = std::istringstream{"abcdefghij"}; + auto s = kstd::string{std::istream_iterator{source}, std::istream_iterator{}}; + + THEN("the string is not empty") + { + REQUIRE_FALSE(s.empty()); + } + + THEN("the size is equal to 10") + { + REQUIRE(s.size() == 10); + } + + THEN("the length is equal to 10") + { + REQUIRE(s.length() == 10); + } + + THEN("the capacity is equal to 15") + { + REQUIRE(s.capacity() == 15); + } + + THEN("at(0) returns a") + { + REQUIRE(s.at(0) == 'a'); + } + + THEN("at(size() - 1) returns j") + { + REQUIRE(s.at(s.size() - 1) == 'j'); + } + + THEN("[0] returns a") + { + REQUIRE(s[0] == 'a'); + } + + THEN("[size() - 1] returns j") + { + REQUIRE(s[s.size() - 1] == 'j'); + } + + THEN("front returns a") + { + REQUIRE(s.front() == 'a'); + } + + THEN("back returns j") + { + REQUIRE(s.back() == 'j'); + } + + THEN("data returns a pointer pointing to an a") + { + REQUIRE(*s.data() == 'a'); + } + + THEN("c_str returns a pointer pointing to an a") + { + REQUIRE(*s.c_str() == 'a'); + } + + THEN("c_str points to the start of a c-string of length 10") + { + REQUIRE(std::strlen(s.c_str()) == 10); + } + + THEN("the string converts to a string view of length 10") + { + auto view = static_cast(s); + REQUIRE(view.length() == 10); + } + } + + WHEN("constructing with an input iterator pair of 20 characters") + { + auto source = std::istringstream{"abcdefghijABCDEFGHIJ"}; + auto s = kstd::string{std::istream_iterator{source}, std::istream_iterator{}}; + + THEN("the string is not empty") + { + REQUIRE_FALSE(s.empty()); + } + + THEN("the size is equal to 20") + { + REQUIRE(s.size() == 20); + } + + THEN("the length is equal to 20") + { + REQUIRE(s.length() == 20); + } + + THEN("the capacity is greater than or equal to 20") + { + REQUIRE(s.capacity() >= 20); + } + + THEN("at(0) returns a") + { + REQUIRE(s.at(0) == 'a'); + } + + THEN("at(size() - 1) returns J") + { + REQUIRE(s.at(s.size() - 1) == 'J'); + } + + THEN("[0] returns a") + { + REQUIRE(s[0] == 'a'); + } + + THEN("[size() - 1] returns J") + { + REQUIRE(s[s.size() - 1] == 'J'); + } + + THEN("front returns a") + { + REQUIRE(s.front() == 'a'); + } + + THEN("back returns J") + { + REQUIRE(s.back() == 'J'); + } + + THEN("data returns a pointer pointing to an a") + { + REQUIRE(*s.data() == 'a'); + } + + THEN("c_str returns a pointer pointing to an a") + { + REQUIRE(*s.c_str() == 'a'); + } + + THEN("c_str points to the start of a c-string of length 20") + { + REQUIRE(std::strlen(s.c_str()) == 20); + } + + THEN("the string converts to a string view of length 20") + { + auto view = static_cast(s); + REQUIRE(view.length() == 20); + } + } + + WHEN("constructing with a forward iterator pair of 10 characters") + { + auto source = std::forward_list{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}; + auto s = kstd::string{source.cbegin(), source.cend()}; + + THEN("the string is not empty") + { + REQUIRE_FALSE(s.empty()); + } + + THEN("the size is equal to 10") + { + REQUIRE(s.size() == 10); + } + + THEN("the length is equal to 10") + { + REQUIRE(s.length() == 10); + } + + THEN("the capacity is equal to 15") + { + REQUIRE(s.capacity() == 15); + } + + THEN("at(0) returns a") + { + REQUIRE(s.at(0) == 'a'); + } + + THEN("at(size() - 1) returns j") + { + REQUIRE(s.at(s.size() - 1) == 'j'); + } + + THEN("[0] returns a") + { + REQUIRE(s[0] == 'a'); + } + + THEN("[size() - 1] returns j") + { + REQUIRE(s[s.size() - 1] == 'j'); + } + + THEN("front returns a") + { + REQUIRE(s.front() == 'a'); + } + + THEN("back returns j") + { + REQUIRE(s.back() == 'j'); + } + + THEN("data returns a pointer pointing to an a") + { + REQUIRE(*s.data() == 'a'); + } + + THEN("c_str returns a pointer pointing to an a") + { + REQUIRE(*s.c_str() == 'a'); + } + + THEN("c_str points to the start of a c-string of length 10") + { + REQUIRE(std::strlen(s.c_str()) == 10); + } + + THEN("the string converts to a string view of length 10") + { + auto view = static_cast(s); + REQUIRE(view.length() == 10); + } + } + + WHEN("constructing with a forward iterator pair of 20 characters") + { + auto source = std::forward_list{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'}; + auto s = kstd::string{source.cbegin(), source.cend()}; + + THEN("the string is not empty") + { + REQUIRE_FALSE(s.empty()); + } + + THEN("the size is equal to 20") + { + REQUIRE(s.size() == 20); + } + + THEN("the length is equal to 20") + { + REQUIRE(s.length() == 20); + } + + THEN("the capacity is equal to 20") + { + REQUIRE(s.capacity() == 20); + } + + THEN("at(0) returns a") + { + REQUIRE(s.at(0) == 'a'); + } + + THEN("at(size() - 1) returns J") + { + REQUIRE(s.at(s.size() - 1) == 'J'); + } + + THEN("[0] returns a") + { + REQUIRE(s[0] == 'a'); + } + + THEN("[size() - 1] returns J") + { + REQUIRE(s[s.size() - 1] == 'J'); + } + + THEN("front returns a") + { + REQUIRE(s.front() == 'a'); + } + + THEN("back returns J") + { + REQUIRE(s.back() == 'J'); + } + + THEN("data returns a pointer pointing to an a") + { + REQUIRE(*s.data() == 'a'); + } + + THEN("c_str returns a pointer pointing to an a") + { + REQUIRE(*s.c_str() == 'a'); + } + + THEN("c_str points to the start of a c-string of length 20") + { + REQUIRE(std::strlen(s.c_str()) == 20); + } + + THEN("the string converts to a string view of length 20") + { + auto view = static_cast(s); + REQUIRE(view.length() == 20); + } + } + + WHEN("constructing from a null pointer with zero size") + { + auto s = kstd::string{static_cast(nullptr), 0}; + + THEN("the string is empty") + { + REQUIRE(s.empty()); + } + + THEN("the size is equal to 0") + { + REQUIRE(s.size() == 0); + } + + THEN("the length is equal to 0") + { + REQUIRE(s.length() == 0); + } + + THEN("the capacity is equal to 15") + { + REQUIRE(s.capacity() == 15); + } + + THEN("at raises a panic") + { + REQUIRE_THROWS_AS(s.at(0), kstd::tests::os_panic); + } + + THEN("data returns a pointer poiting to a null byte") + { + REQUIRE(*s.data() == '\0'); + } + + THEN("c_str returns a pointer poiting to a null byte") + { + REQUIRE(*s.c_str() == '\0'); + } + + THEN("the string is convertible to an empty string view") + { + auto view = static_cast(s); + REQUIRE(view.empty()); + } + } + + WHEN("constructing from a from a null pointer and non-zero size") + { + THEN("a panic is raised") + { + REQUIRE_THROWS_AS((kstd::string{static_cast(nullptr), 1}), kstd::tests::os_panic); + } + } + + WHEN("constructing from a non-null pointer and zero size") + { + auto ptr = "abcd"; + auto s = kstd::string{ptr, 0}; + + THEN("the string is empty") + { + REQUIRE(s.empty()); + } + + THEN("the size is equal to 0") + { + REQUIRE(s.size() == 0); + } + + THEN("the length is equal to 0") + { + REQUIRE(s.length() == 0); + } + + THEN("the capacity is equal to 15") + { + REQUIRE(s.capacity() == 15); + } + + THEN("at raises a panic") + { + REQUIRE_THROWS_AS(s.at(0), kstd::tests::os_panic); + } + + THEN("data returns a pointer poiting to a null byte") + { + REQUIRE(*s.data() == '\0'); + } + + THEN("c_str returns a pointer poiting to a null byte") + { + REQUIRE(*s.c_str() == '\0'); + } + + THEN("the string is convertible to an empty string view") + { + auto view = static_cast(s); + REQUIRE(view.empty()); + } + } + + WHEN("constructing from a non-null pointer and a size of 4") + { + auto ptr = "abcd"; + auto s = kstd::string{ptr, 4}; + + THEN("the string is not empty") + { + REQUIRE_FALSE(s.empty()); + } + + THEN("the size is equal to 4") + { + REQUIRE(s.size() == 4); + } + + THEN("the length is equal to 4") + { + REQUIRE(s.length() == 4); + } + + THEN("the capacity is equal to 15") + { + REQUIRE(s.capacity() == 15); + } + + THEN("at(0) returns a") + { + REQUIRE(s.at(0) == 'a'); + } + + THEN("at(size() - 1) returns d") + { + REQUIRE(s.at(s.size() - 1) == 'd'); + } + + THEN("[0] returns a") + { + REQUIRE(s[0] == 'a'); + } + + THEN("[size() - 1] returns d") + { + REQUIRE(s[s.size() - 1] == 'd'); + } + + THEN("front returns a") + { + REQUIRE(s.front() == 'a'); + } + + THEN("back returns d") + { + REQUIRE(s.back() == 'd'); + } + + THEN("data returns a pointer pointing to an a") + { + REQUIRE(*s.data() == 'a'); + } + + THEN("c_str returns a pointer pointing to an a") + { + REQUIRE(*s.c_str() == 'a'); + } + + THEN("c_str points to the start of a c-string of length 4") + { + REQUIRE(std::strlen(s.c_str()) == 4); + } + + THEN("the string converts to a string view of length 4") + { + auto view = static_cast(s); + REQUIRE(view.length() == 4); + } + } + + WHEN("constructing from a non-null pointer and a size of 20") + { + auto ptr = "abcdefghijABCDEFGHIJ"; + auto s = kstd::string{ptr, 20}; + + THEN("the string is not empty") + { + REQUIRE_FALSE(s.empty()); + } + + THEN("the size is equal to 20") + { + REQUIRE(s.size() == 20); + } + + THEN("the length is equal to 20") + { + REQUIRE(s.length() == 20); + } + + THEN("the capacity is equal to 20") + { + REQUIRE(s.capacity() == 20); + } + + THEN("at(0) returns a") + { + REQUIRE(s.at(0) == 'a'); + } + + THEN("at(size() - 1) returns J") + { + REQUIRE(s.at(s.size() - 1) == 'J'); + } + + THEN("[0] returns a") + { + REQUIRE(s[0] == 'a'); + } + + THEN("[size() - 1] returns J") + { + REQUIRE(s[s.size() - 1] == 'J'); + } + + THEN("front returns a") + { + REQUIRE(s.front() == 'a'); + } + + THEN("back returns J") + { + REQUIRE(s.back() == 'J'); + } + + THEN("data returns a pointer pointing to an a") + { + REQUIRE(*s.data() == 'a'); + } + + THEN("c_str returns a pointer pointing to an a") + { + REQUIRE(*s.c_str() == 'a'); + } + + THEN("c_str points to the start of a c-string of length 20") + { + REQUIRE(std::strlen(s.c_str()) == 20); + } + + THEN("the string converts to a string view of length 20") + { + auto view = static_cast(s); + REQUIRE(view.length() == 20); + } + } + + WHEN("constructing from a C-style string of length 4") + { + auto ptr = "abcd"; + auto s = kstd::string{ptr}; + + THEN("the string is not empty") + { + REQUIRE_FALSE(s.empty()); + } + + THEN("the size is equal to 4") + { + REQUIRE(s.size() == 4); + } + + THEN("the length is equal to 4") + { + REQUIRE(s.length() == 4); + } + + THEN("the capacity is equal to 15") + { + REQUIRE(s.capacity() == 15); + } + + THEN("at(0) returns a") + { + REQUIRE(s.at(0) == 'a'); + } + + THEN("at(size() - 1) returns d") + { + REQUIRE(s.at(s.size() - 1) == 'd'); + } + + THEN("[0] returns a") + { + REQUIRE(s[0] == 'a'); + } + + THEN("[size() - 1] returns d") + { + REQUIRE(s[s.size() - 1] == 'd'); + } + + THEN("front returns a") + { + REQUIRE(s.front() == 'a'); + } + + THEN("back returns d") + { + REQUIRE(s.back() == 'd'); + } + + THEN("data returns a pointer pointing to an a") + { + REQUIRE(*s.data() == 'a'); + } + + THEN("c_str returns a pointer pointing to an a") + { + REQUIRE(*s.c_str() == 'a'); + } + + THEN("c_str points to the start of a c-string of length 4") + { + REQUIRE(std::strlen(s.c_str()) == 4); + } + + THEN("the string converts to a string view of length 4") + { + auto view = static_cast(s); + REQUIRE(view.length() == 4); + } + } + + WHEN("constructing from a C-style string of length 20") + { + auto ptr = "abcdefghijABCDEFGHIJ"; + auto s = kstd::string{ptr}; + + THEN("the string is not empty") + { + REQUIRE_FALSE(s.empty()); + } + + THEN("the size is equal to 20") + { + REQUIRE(s.size() == 20); + } + + THEN("the length is equal to 20") + { + REQUIRE(s.length() == 20); + } + + THEN("the capacity is equal to 20") + { + REQUIRE(s.capacity() == 20); + } + + THEN("at(0) returns a") + { + REQUIRE(s.at(0) == 'a'); + } + + THEN("at(size() - 1) returns J") + { + REQUIRE(s.at(s.size() - 1) == 'J'); + } + + THEN("[0] returns a") + { + REQUIRE(s[0] == 'a'); + } + + THEN("[size() - 1] returns J") + { + REQUIRE(s[s.size() - 1] == 'J'); + } + + THEN("front returns a") + { + REQUIRE(s.front() == 'a'); + } + + THEN("back returns J") + { + REQUIRE(s.back() == 'J'); + } + + THEN("data returns a pointer pointing to an a") + { + REQUIRE(*s.data() == 'a'); + } + + THEN("c_str returns a pointer pointing to an a") + { + REQUIRE(*s.c_str() == 'a'); + } + + THEN("c_str points to the start of a c-string of length 20") + { + REQUIRE(std::strlen(s.c_str()) == 20); + } + + THEN("the string converts to a string view of length 20") + { + auto view = static_cast(s); + REQUIRE(view.length() == 20); + } + } + + WHEN("constructing from a string view of length 4") + { + using namespace std::string_view_literals; + + auto view = "abcd"sv; + auto s = kstd::string{view}; + + THEN("the string is not empty") + { + REQUIRE_FALSE(s.empty()); + } + + THEN("the size is equal to 4") + { + REQUIRE(s.size() == 4); + } + + THEN("the length is equal to 4") + { + REQUIRE(s.length() == 4); + } + + THEN("the capacity is equal to 15") + { + REQUIRE(s.capacity() == 15); + } + + THEN("at(0) returns a") + { + REQUIRE(s.at(0) == 'a'); + } + + THEN("at(size() - 1) returns d") + { + REQUIRE(s.at(s.size() - 1) == 'd'); + } + + THEN("[0] returns a") + { + REQUIRE(s[0] == 'a'); + } + + THEN("[size() - 1] returns d") + { + REQUIRE(s[s.size() - 1] == 'd'); + } + + THEN("front returns a") + { + REQUIRE(s.front() == 'a'); + } + + THEN("back returns d") + { + REQUIRE(s.back() == 'd'); + } + + THEN("data returns a pointer pointing to an a") + { + REQUIRE(*s.data() == 'a'); + } + + THEN("c_str returns a pointer pointing to an a") + { + REQUIRE(*s.c_str() == 'a'); + } + + THEN("c_str points to the start of a c-string of length 4") + { + REQUIRE(std::strlen(s.c_str()) == 4); + } + + THEN("the string converts to a string view of length 4") + { + auto view = static_cast(s); + REQUIRE(view.length() == 4); + } + } + + WHEN("constructing from a string view of length 20") + { + using namespace std::string_view_literals; + + auto view = "abcdefghijABCDEFGHIJ"sv; + auto s = kstd::string{view}; + + THEN("the string is not empty") + { + REQUIRE_FALSE(s.empty()); + } + + THEN("the size is equal to 20") + { + REQUIRE(s.size() == 20); + } + + THEN("the length is equal to 20") + { + REQUIRE(s.length() == 20); + } + + THEN("the capacity is equal to 20") + { + REQUIRE(s.capacity() == 20); + } + + THEN("at(0) returns a") + { + REQUIRE(s.at(0) == 'a'); + } + + THEN("at(size() - 1) returns J") + { + REQUIRE(s.at(s.size() - 1) == 'J'); + } + + THEN("[0] returns a") + { + REQUIRE(s[0] == 'a'); + } + + THEN("[size() - 1] returns J") + { + REQUIRE(s[s.size() - 1] == 'J'); + } + + THEN("front returns a") + { + REQUIRE(s.front() == 'a'); + } + + THEN("back returns J") + { + REQUIRE(s.back() == 'J'); + } + + THEN("data returns a pointer pointing to an a") + { + REQUIRE(*s.data() == 'a'); + } + + THEN("c_str returns a pointer pointing to an a") + { + REQUIRE(*s.c_str() == 'a'); + } + + THEN("c_str points to the start of a c-string of length 20") + { + REQUIRE(std::strlen(s.c_str()) == 20); + } + + THEN("the string converts to a string view of length 20") + { + auto view = static_cast(s); + REQUIRE(view.length() == 20); + } + } + + WHEN("constructing from a substring of a string view of length 4") + { + using namespace std::string_view_literals; + + auto view = "abcd"sv; + auto s = kstd::string{view, 1, 4}; + + THEN("the string is not empty") + { + REQUIRE_FALSE(s.empty()); + } + + THEN("the size is equal to 3") + { + REQUIRE(s.size() == 3); + } + + THEN("the length is equal to 3") + { + REQUIRE(s.length() == 3); + } + + THEN("the capacity is equal to 15") + { + REQUIRE(s.capacity() == 15); + } + + THEN("at(0) returns b") + { + REQUIRE(s.at(0) == 'b'); + } + + THEN("at(size() - 1) returns d") + { + REQUIRE(s.at(s.size() - 1) == 'd'); + } + + THEN("[0] returns b") + { + REQUIRE(s[0] == 'b'); + } + + THEN("[size() - 1] returns d") + { + REQUIRE(s[s.size() - 1] == 'd'); + } + + THEN("front returns b") + { + REQUIRE(s.front() == 'b'); + } + + THEN("back returns d") + { + REQUIRE(s.back() == 'd'); + } + + THEN("data returns a pointer pointing to an b") + { + REQUIRE(*s.data() == 'b'); + } + + THEN("c_str returns a pointer pointing to an b") + { + REQUIRE(*s.c_str() == 'b'); + } + + THEN("c_str points to the start of a c-string of length 3") + { + REQUIRE(std::strlen(s.c_str()) == 3); + } + + THEN("the string converts to a string view of length 3") + { + auto view = static_cast(s); + REQUIRE(view.length() == 3); + } + } + + WHEN("constructing from a substring of a string view of length 20") + { + using namespace std::string_view_literals; + + auto view = "abcdefghijABCDEFGHIJ"sv; + auto s = kstd::string{view, 1, 20}; + + THEN("the string is not empty") + { + REQUIRE_FALSE(s.empty()); + } + + THEN("the size is equal to 19") + { + REQUIRE(s.size() == 19); + } + + THEN("the length is equal to 19") + { + REQUIRE(s.length() == 19); + } + + THEN("the capacity is equal to 19") + { + REQUIRE(s.capacity() == 19); + } + + THEN("at(0) returns b") + { + REQUIRE(s.at(0) == 'b'); + } + + THEN("at(size() - 1) returns J") + { + REQUIRE(s.at(s.size() - 1) == 'J'); + } + + THEN("[0] returns b") + { + REQUIRE(s[0] == 'b'); + } + + THEN("[size() - 1] returns J") + { + REQUIRE(s[s.size() - 1] == 'J'); + } + + THEN("front returns b") + { + REQUIRE(s.front() == 'b'); + } + + THEN("back returns J") + { + REQUIRE(s.back() == 'J'); + } + + THEN("data returns a pointer pointing to an b") + { + REQUIRE(*s.data() == 'b'); + } + + THEN("c_str returns a pointer pointing to an b") + { + REQUIRE(*s.c_str() == 'b'); + } + + THEN("c_str points to the start of a c-string of length 19") + { + REQUIRE(std::strlen(s.c_str()) == 19); + } + + THEN("the string converts to a string view of length 19") + { + auto view = static_cast(s); + REQUIRE(view.length() == 19); + } + } + } + + GIVEN("An existing short string, of length 10") + { + auto other = kstd::string{"abcdefghij"}; + + WHEN("constructing by copy") + { + auto s = other; + + THEN("the sizes are identical") + { + REQUIRE(s.size() == other.size()); + } + + THEN("the capacities are idendtical") + { + REQUIRE(s.capacity() == other.capacity()); + } + + THEN("the underlying strings are identical") + { + REQUIRE_FALSE(std::strcmp(s.data(), other.data())); + } + } + + WHEN("constructing by move") + { + auto s = std::move(other); + + THEN("size is equal to 10") + { + REQUIRE(s.size() == 10); + } + + THEN("capacity is equal to 15") + { + REQUIRE(s.capacity() == 15); + } + + THEN("front() return an a") + { + REQUIRE(s.front() == 'a'); + } + + THEN("back() return a j") + { + REQUIRE(s.back() == 'j'); + } + + THEN("The moved from object's size is 0") + { + REQUIRE(other.size() == 0); + } + + THEN("The moved from object's capacity is 15") + { + REQUIRE(other.capacity() == 15); + } + + THEN("c_str() on the moved from object points to a null byte") + { + REQUIRE(*other.c_str() == '\0'); + } + } + } + + GIVEN("An existing short string, of length 20") + { + auto other = kstd::string{"abcdefghijABCDEFGHIJ"}; + + WHEN("constructing by copy") + { + auto s = other; + + THEN("the sizes are identical") + { + REQUIRE(s.size() == other.size()); + } + + THEN("the capacities are idendtical") + { + REQUIRE(s.capacity() == other.capacity()); + } + + THEN("the underlying strings are identical") + { + REQUIRE_FALSE(std::strcmp(s.data(), other.data())); + } + } + + WHEN("constructing by move") + { + auto s = std::move(other); + + THEN("size is equal to 20") + { + REQUIRE(s.size() == 20); + } + + THEN("capacity is equal to 20") + { + REQUIRE(s.capacity() == 20); + } + + THEN("front() return an a") + { + REQUIRE(s.front() == 'a'); + } + + THEN("back() return a J") + { + REQUIRE(s.back() == 'J'); + } + + THEN("The moved from object's size is 0") + { + REQUIRE(other.size() == 0); + } + + THEN("The moved from object's capacity is 15") + { + REQUIRE(other.capacity() == 15); + } + + THEN("c_str() on the moved from object points to a null byte") + { + REQUIRE(*other.c_str() == '\0'); + } + } + } +} + +SCENARIO("String assignment", "[string]") +{ + GIVEN("Two short strings") + { + auto s1 = kstd::string{"abcd"}; + auto s2 = kstd::string{"defghij"}; + + WHEN("copy assigning the shorter to the longer one") + { + s2 = s1; + + THEN("the new length of the longer one is equal to the length of the shorter one") + { + REQUIRE(s2.length() == s1.length()); + } + + THEN("the underlying data of the two is identical") + { + REQUIRE_FALSE(std::strcmp(s1.data(), s2.data())); + } + } + + WHEN("copy assigning the longer to the shorter one") + { + s1 = s2; + + THEN("the new length of the shorter one is equal to the length of the longer one") + { + REQUIRE(s1.length() == s2.length()); + } + + THEN("the underlying data of the two is identical") + { + REQUIRE_FALSE(std::strcmp(s2.data(), s1.data())); + } + } + + WHEN("move assigning the shorter to the longer one") + { + s2 = std::move(s1); + + THEN("the new length of the longer one is equal to the original length of the shorter one") + { + REQUIRE(s2.length() == 4); + } + + THEN("the length of the moved from one is 0") + { + REQUIRE(s1.length() == 0); + } + + THEN("the capacity of the moved from one is 15") + { + REQUIRE(s1.capacity() == 15); + } + + THEN("the capacity of the moved to one is 15") + { + REQUIRE(s2.capacity() == 15); + } + } + + WHEN("move assigning the longer to the shorter one") + { + s1 = std::move(s2); + + THEN("the new length of the shorter one is equal to the original length of the longer one") + { + REQUIRE(s1.length() == 7); + } + + THEN("the length of the moved from one is 0") + { + REQUIRE(s2.length() == 0); + } + + THEN("the capacity of the moved from one is 15") + { + REQUIRE(s2.capacity() == 15); + } + + THEN("the capacity of the moved to one is 15") + { + REQUIRE(s1.capacity() == 15); + } + } + } + + GIVEN("One short and one long string") + { + auto s1 = kstd::string{"abcd"}; + auto s2 = kstd::string{"ABCDEFGHIJabcdefghij"}; + + WHEN("copy assigning the shorter to the longer one") + { + s2 = s1; + + THEN("the new length of the longer one is equal to the length of the shorter one") + { + REQUIRE(s2.length() == s1.length()); + } + + THEN("the new capacity of the longer one is 15") + { + REQUIRE(s2.capacity() == 15); + } + + THEN("the underlying data of the two is identical") + { + REQUIRE_FALSE(std::strcmp(s1.data(), s2.data())); + } + } + + WHEN("copy assigning the longer to the shorter one") + { + s1 = s2; + + THEN("the new length of the shorter one is equal to the length of the longer one") + { + REQUIRE(s1.length() == s2.length()); + } + + THEN("the new capacity of the shorter one is 20") + { + REQUIRE(s1.capacity() == 20); + } + + THEN("the underlying data of the two is identical") + { + REQUIRE_FALSE(std::strcmp(s2.data(), s1.data())); + } + } + + WHEN("move assigning the shorter to the longer one") + { + s2 = std::move(s1); + + THEN("the new length of the longer one is equal to the original length of the shorter one") + { + REQUIRE(s2.length() == 4); + } + + THEN("the length of the moved from one is 0") + { + REQUIRE(s1.length() == 0); + } + + THEN("the capacity of the moved from one is 15") + { + REQUIRE(s1.capacity() == 15); + } + + THEN("the capacity of the moved to one is 15") + { + REQUIRE(s2.capacity() == 15); + } + } + + WHEN("move assigning the longer to the shorter one") + { + s1 = std::move(s2); + + THEN("the new length of the shorter one is equal to the original length of the longer one") + { + REQUIRE(s1.length() == 20); + } + + THEN("the length of the moved from one is 0") + { + REQUIRE(s2.length() == 0); + } + + THEN("the capacity of the moved from one is 15") + { + REQUIRE(s2.capacity() == 15); + } + + THEN("the capacity of the moved to one is 15") + { + REQUIRE(s1.capacity() == 20); + } + } + } -SCENARIO("String initialization and construction", "[string]") -{ - GIVEN("Nothing") + GIVEN("Two long strings") { - WHEN("constructing an empty string") + auto s1 = kstd::string{"abcdefghijABCDEFGH"}; + auto s2 = kstd::string{"ABCDEFGHIJabcdefghij"}; + + WHEN("copy assigning the shorter to the longer one") { - auto str = kstd::string{}; + s2 = s1; - THEN("the size is zero and therefore the string is empty") + THEN("the new length of the longer one is equal to the length of the shorter one") { - REQUIRE(str.empty()); - REQUIRE(str.size() == 0); + REQUIRE(s2.length() == s1.length()); } - THEN("the string is empty") + THEN("the new capacity of the longer one is still 20") { - REQUIRE(str == std::string_view{}); + REQUIRE(s2.capacity() == 20); + } + + THEN("the underlying data of the two is identical") + { + REQUIRE_FALSE(std::strcmp(s1.data(), s2.data())); } } - } - GIVEN("A string view") - { - auto view = std::string_view{"Blub Blub"}; + WHEN("copy assigning the longer to the shorter one") + { + s1 = s2; + + THEN("the new length of the shorter one is equal to the length of the longer one") + { + REQUIRE(s1.length() == s2.length()); + } + + THEN("the new capacity of the shorter one is 20") + { + REQUIRE(s1.capacity() == 20); + } + + THEN("the underlying data of the two is identical") + { + REQUIRE_FALSE(std::strcmp(s2.data(), s1.data())); + } + } + + WHEN("move assigning the shorter to the longer one") + { + s2 = std::move(s1); + + THEN("the new length of the longer one is equal to the original length of the shorter one") + { + REQUIRE(s2.length() == 18); + } + + THEN("the length of the moved from one is 0") + { + REQUIRE(s1.length() == 0); + } + + THEN("the capacity of the moved from one is 15") + { + REQUIRE(s1.capacity() == 15); + } + + THEN("the capacity of the moved to one is 15") + { + REQUIRE(s2.capacity() == 18); + } + } - WHEN("constructing a string from string_view") + WHEN("move assigning the longer to the shorter one") { - auto str = kstd::string{view}; + s1 = std::move(s2); - THEN("the string is not empty and has the same size as the view") + THEN("the new length of the shorter one is equal to the original length of the longer one") { - REQUIRE_FALSE(str.empty()); - REQUIRE(str.size() == view.size()); + REQUIRE(s1.length() == 20); } - THEN("the string contains the same characters as the view") + THEN("the length of the moved from one is 0") { - REQUIRE(str == view); + REQUIRE(s2.length() == 0); + } + + THEN("the capacity of the moved from one is 15") + { + REQUIRE(s2.capacity() == 15); + } + + THEN("the capacity of the moved to one is 15") + { + REQUIRE(s1.capacity() == 20); } } } - GIVEN("A C-style string") + GIVEN("An short string") { - auto c_str = "Blub Blub"; + auto s = kstd::string{"abcd"}; - WHEN("constructing a string from the C-style string") + WHEN("assigning a new, shorter c-style string of length 3") { - auto str = kstd::string{c_str}; + s = "def"; - THEN("the string is not empty and has the same size as the C-style string") + THEN("the length is equal to 3") { - REQUIRE_FALSE(str.empty()); - REQUIRE(str.size() == std::strlen(c_str)); + REQUIRE(s.length() == 3); } + } + + WHEN("assigning a new, longer, c-style string of length 5") + { + s = "defgh"; - THEN("the string contains the same characters as the C-style string") + THEN("the length is equal to 5") { - REQUIRE(str == c_str); + REQUIRE(s.length() == 5); } } - } - GIVEN("A character") - { - auto ch = 'x'; + WHEN("assigning a new, longer, c-style string of length 20") + { + s = "ABCDEFGHIJabcdefghij"; + + THEN("the length is equal to 20") + { + REQUIRE(s.length() == 20); + } + } - WHEN("constructing a string from the character") + WHEN("assigning a single character") { - auto str = kstd::string{ch}; + s = 'z'; - THEN("the string is not empty and has size 1") + THEN("the length is equal to 1") { - REQUIRE_FALSE(str.empty()); - REQUIRE(str.size() == 1); + REQUIRE(s.length() == 1); } + } + + WHEN("assigning an shorter initializer list of length 3") + { + s = {'d', 'e', 'f'}; - THEN("the string contains the same character as the given character") + THEN("the length is equal to 3") { - REQUIRE(str == std::string_view{&ch, 1}); + REQUIRE(s.length() == 3); } } - } - GIVEN("Another string") - { - auto other = kstd::string{"Blub Blub"}; + WHEN("assigning an longer initializer list of length 5") + { + s = {'d', 'e', 'f', 'g', 'h'}; + + THEN("the length is equal to 5") + { + REQUIRE(s.length() == 5); + } + } - WHEN("copy constructing a new string") + WHEN("assigning an longer initializer list of length 20") { - auto str = kstd::string{other}; + s = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}; - THEN("the new string contains the same characters as the original") + THEN("the length is equal to 20") { - REQUIRE(static_cast(str) == static_cast(other)); + REQUIRE(s.length() == 20); } } - auto str = kstd::string{"Blub"}; + WHEN("assigning from a shorter string view of length 3") + { + using namespace std::string_view_literals; + + s = "def"sv; + + THEN("the length is equal to 3") + { + REQUIRE(s.length() == 3); + } + } + + WHEN("assigning from a longer string view of length 5") + { + using namespace std::string_view_literals; + + s = "defgh"sv; + + THEN("the length is equal to 5") + { + REQUIRE(s.length() == 5); + } + } - WHEN("copy assigning another string") + WHEN("assigning from a longer string view of length 20") { - auto other = kstd::string{"Blub Blub"}; - str = other; + using namespace std::string_view_literals; - THEN("the string contains the same characters as the assigned string") + s = "ABCDEFGHIJabcdefghij"sv; + + THEN("the length is equal to 20") { - REQUIRE(static_cast(str) == static_cast(other)); + REQUIRE(s.length() == 20); } } } - GIVEN("A string") + GIVEN("An long string") { - auto str = kstd::string{"Hello"}; + auto s = kstd::string{"abcdefghijABCDEFGHIJ"}; - WHEN("copy assigning a string view") + WHEN("assigning a new, shorter c-style string of length 3") { - auto view = std::string_view{"Hello, world!"}; - str = view; + s = "def"; - THEN("the string contains the same characters as the assigned view") + THEN("the length is equal to 3") { - REQUIRE(str == view); + REQUIRE(s.length() == 3); } } - } - GIVEN("A string") - { - auto str = kstd::string{"Hello"}; + WHEN("assigning a new, longer, c-style string of length 22") + { + s = "ABCDEFGHIJabcdefghijkl"; + + THEN("the length is equal to 22") + { + REQUIRE(s.length() == 22); + } + } + + WHEN("assigning a single character") + { + s = 'z'; + + THEN("the length is equal to 1") + { + REQUIRE(s.length() == 1); + } + } + + WHEN("assigning an shorter initializer list of length 3") + { + s = {'d', 'e', 'f'}; + + THEN("the length is equal to 3") + { + REQUIRE(s.length() == 3); + } + } + + WHEN("assigning an longer initializer list of length 22") + { + s = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'a', + 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'}; - WHEN("copy assigning a C-style string") + THEN("the length is equal to 22") + { + REQUIRE(s.length() == 22); + } + } + + WHEN("assigning from a shorter string view of length 3") + { + using namespace std::string_view_literals; + + s = "def"sv; + + THEN("the length is equal to 3") + { + REQUIRE(s.length() == 3); + } + } + + WHEN("assigning from a longer string view of length 22") { - auto c_str = "Hello, world!"; - str = c_str; + using namespace std::string_view_literals; + + s = "ABCDEFGHIJabcdefghijkl"sv; - THEN("the string contains the same characters as the assigned C-style string") + THEN("the length is equal to 22") { - REQUIRE(str == c_str); + REQUIRE(s.length() == 22); } } } } -SCENARIO("String concatenation", "[string]") +SCENARIO("String modifiers", "[string]") { + GIVEN("A short string") + { + auto s = kstd::string{"abcd"}; + auto old_capacity = s.capacity(); + auto old_size = s.size(); + auto old_data = s.data(); + + WHEN("reserving a smaller capacity") + { + s.reserve(1); + + THEN("the capacity does not change") + { + REQUIRE(s.capacity() == old_capacity); + } + + THEN("the content stays the same") + { + REQUIRE(s == "abcd"); + } + + THEN("the size stays the same") + { + REQUIRE(s.size() == old_size); + } + + THEN("the data pointer stays the same") + { + REQUIRE(s.data() == old_data); + } + } + + WHEN("reserving equal capacity") + { + s.reserve(old_capacity); + + THEN("the capacity does not change") + { + REQUIRE(s.capacity() == old_capacity); + } + + THEN("the content stays the same") + { + REQUIRE(s == "abcd"); + } + + THEN("the size stays the same") + { + REQUIRE(s.size() == old_size); + } + + THEN("the data pointer stays the same") + { + REQUIRE(static_cast(s.data()) == static_cast(old_data)); + } + } + + WHEN("reserving larger capacity") + { + s.reserve(old_capacity + 1); + + THEN("the capacity increases") + { + REQUIRE(s.capacity() >= old_capacity + 1); + } + + THEN("the content stays the same") + { + REQUIRE(s == "abcd"); + } + + THEN("the size stays the same") + { + REQUIRE(s.size() == old_size); + } + + THEN("the data pointer changes") + { + REQUIRE(s.data() != old_data); + } + } + } + GIVEN("Two strings") { auto str1 = kstd::string{"Blub"}; @@ -187,21 +1988,6 @@ SCENARIO("String concatenation", "[string]") REQUIRE(str1.size() == str2.size() + 4); } } - - WHEN("using operator+ to concatenate the two strings into a new string") - { - auto str3 = str1 + str2; - - THEN("the new string contains the characters of both strings concatenated") - { - REQUIRE(str3 == "Blub Blub"); - } - - THEN("the size of the new string is the sum of the sizes of both strings") - { - REQUIRE(str3.size() == str1.size() + str2.size()); - } - } } GIVEN("A string and a string view") @@ -260,6 +2046,51 @@ SCENARIO("String concatenation", "[string]") } } } + + GIVEN("A non-empty string") + { + auto str = kstd::string{"Blub Blub"}; + + WHEN("clearing the string") + { + str.clear(); + + THEN("the string is empty and has size zero") + { + REQUIRE(str.empty()); + REQUIRE(str.size() == 0); + } + + THEN("the string contains no characters") + { + REQUIRE(str == std::string_view{}); + } + } + } +} + +SCENARIO("String concatenation", "[string]") +{ + GIVEN("Two strings") + { + auto str1 = kstd::string{"Blub"}; + auto str2 = kstd::string{" Blub"}; + + WHEN("using operator+ to concatenate the two strings into a new string") + { + auto str3 = str1 + str2; + + THEN("the new string contains the characters of both strings concatenated") + { + REQUIRE(str3 == "Blub Blub"); + } + + THEN("the size of the new string is the sum of the sizes of both strings") + { + REQUIRE(str3.size() == str1.size() + str2.size()); + } + } + } } SCENARIO("String conversion and comparison", "[string]") @@ -317,30 +2148,6 @@ SCENARIO("String conversion and comparison", "[string]") } } -SCENARIO("String clearing", "[string]") -{ - GIVEN("A non-empty string") - { - auto str = kstd::string{"Blub Blub"}; - - WHEN("clearing the string") - { - str.clear(); - - THEN("the string is empty and has size zero") - { - REQUIRE(str.empty()); - REQUIRE(str.size() == 0); - } - - THEN("the string contains no characters") - { - REQUIRE(str == std::string_view{}); - } - } - } -} - SCENARIO("String iteration", "[string]") { GIVEN("A string") -- cgit v1.2.3