diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-06-15 10:36:58 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-06-15 10:36:58 +0200 |
| commit | 073efba1940d6f8d8c3f8e4675c56a3b6c5cb75b (patch) | |
| tree | 60c24721d8407ca684b962e14e02429f8923ee0d /libs | |
| parent | 9fb4af5d56fcd0568137c5bf431f2f72807938a5 (diff) | |
| download | kernel-073efba1940d6f8d8c3f8e4675c56a3b6c5cb75b.tar.xz kernel-073efba1940d6f8d8c3f8e4675c56a3b6c5cb75b.zip | |
kstd: move string tests
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/kstd/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | libs/kstd/kstd/bits/basic_string.test.cpp | 1962 | ||||
| -rw-r--r-- | libs/kstd/kstd/string.test.cpp | 2007 |
3 files changed, 1907 insertions, 2063 deletions
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 <kstd/bits/basic_string.hpp> - -#include <kstd/allocator> -#include <kstd/test_support/os_panic.hpp> - -#include <catch2/catch_test_macros.hpp> - -#include <cstring> -#include <forward_list> -#include <initializer_list> -#include <iterator> -#include <memory> -#include <sstream> -#include <string_view> -#include <type_traits> -#include <utility> - -using char_string = kstd::basic_string<char>; - -SCENARIO("Basic string of char initialization and construction", "[string]") -{ - THEN("All type aliases are present") - { - REQUIRE(std::is_same_v<char_string::traits_type, kstd::char_traits<char>>); - REQUIRE(std::is_same_v<char_string::value_type, char>); - REQUIRE(std::is_same_v<char_string::allocator_type, kstd::allocator<char>>); - REQUIRE(std::is_same_v<char_string::size_type, std::allocator_traits<kstd::allocator<char>>::size_type>); - REQUIRE( - std::is_same_v<char_string::difference_type, std::allocator_traits<kstd::allocator<char>>::difference_type>); - REQUIRE(std::is_same_v<char_string::reference, char &>); - REQUIRE(std::is_same_v<char_string::const_reference, char const &>); - REQUIRE(std::is_same_v<char_string::pointer, std::allocator_traits<kstd::allocator<char>>::pointer>); - REQUIRE(std::is_same_v<char_string::const_pointer, std::allocator_traits<kstd::allocator<char>>::const_pointer>); - REQUIRE(std::is_same_v<char_string::iterator, char *>); - REQUIRE(std::is_same_v<char_string::const_iterator, char const *>); - REQUIRE(std::is_same_v<char_string::reverse_iterator, std::reverse_iterator<char *>>); - REQUIRE(std::is_same_v<char_string::const_reverse_iterator, std::reverse_iterator<char const *>>); - } - - 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<std::string_view>(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<std::string_view>(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<std::string_view>(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<char>{source}, std::istream_iterator<char>{}}; - - 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<std::string_view>(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<char>{source}, std::istream_iterator<char>{}}; - - 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<std::string_view>(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<std::string_view>(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<std::string_view>(s); - REQUIRE(view.length() == 20); - } - } - - WHEN("constructing from a null pointer with zero size") - { - auto s = char_string{static_cast<char const *>(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<std::string_view>(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<char const *>(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<std::string_view>(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<std::string_view>(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<std::string_view>(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<std::string_view>(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<std::string_view>(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<std::string_view>(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<std::string_view>(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<std::string_view>(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<std::string_view>(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<void const *>(s.data()) == static_cast<void const *>(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 <kstd/string> +#include <kstd/allocator> +#include <kstd/test_support/os_panic.hpp> + #include <catch2/catch_test_macros.hpp> #include <algorithm> #include <cstring> +#include <forward_list> +#include <iterator> +#include <memory> +#include <sstream> #include <string_view> +#include <type_traits> +#include <utility> + +TEST_CASE("String static interface") +{ + REQUIRE(std::is_same_v<kstd::string::traits_type, kstd::char_traits<char>>); + REQUIRE(std::is_same_v<kstd::string::value_type, char>); + REQUIRE(std::is_same_v<kstd::string::allocator_type, kstd::allocator<char>>); + REQUIRE(std::is_same_v<kstd::string::size_type, std::allocator_traits<kstd::allocator<char>>::size_type>); + REQUIRE(std::is_same_v<kstd::string::difference_type, std::allocator_traits<kstd::allocator<char>>::difference_type>); + REQUIRE(std::is_same_v<kstd::string::reference, char &>); + REQUIRE(std::is_same_v<kstd::string::const_reference, char const &>); + REQUIRE(std::is_same_v<kstd::string::pointer, std::allocator_traits<kstd::allocator<char>>::pointer>); + REQUIRE(std::is_same_v<kstd::string::const_pointer, std::allocator_traits<kstd::allocator<char>>::const_pointer>); + REQUIRE(std::is_same_v<kstd::string::iterator, char *>); + REQUIRE(std::is_same_v<kstd::string::const_iterator, char const *>); + REQUIRE(std::is_same_v<kstd::string::reverse_iterator, std::reverse_iterator<char *>>); + REQUIRE(std::is_same_v<kstd::string::const_reverse_iterator, std::reverse_iterator<char const *>>); + + REQUIRE(kstd::string::npos == kstd::string::size_type(-1)); +} SCENARIO("String initialization and construction", "[string]") { - GIVEN("Nothing") + GIVEN("An empty context") { - WHEN("constructing an empty string") + WHEN("constructing by default") { - auto str = kstd::string{}; + auto s = kstd::string{}; - THEN("the size is zero and therefore the string is empty") + THEN("the string is empty") { - REQUIRE(str.empty()); - REQUIRE(str.size() == 0); + 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<std::string_view>(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<std::string_view>(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<std::string_view>(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<char>{source}, std::istream_iterator<char>{}}; + + 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<std::string_view>(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<char>{source}, std::istream_iterator<char>{}}; + + 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<std::string_view>(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<std::string_view>(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<std::string_view>(s); + REQUIRE(view.length() == 20); + } + } + + WHEN("constructing from a null pointer with zero size") + { + auto s = kstd::string{static_cast<char const *>(nullptr), 0}; + THEN("the string is empty") { - REQUIRE(str == std::string_view{}); + 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<std::string_view>(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<char const *>(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<std::string_view>(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<std::string_view>(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<std::string_view>(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<std::string_view>(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<std::string_view>(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<std::string_view>(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<std::string_view>(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<std::string_view>(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<std::string_view>(s); + REQUIRE(view.length() == 19); } } } - GIVEN("A string view") + GIVEN("An existing short string, of length 10") { - auto view = std::string_view{"Blub Blub"}; + auto other = kstd::string{"abcdefghij"}; + + WHEN("constructing by copy") + { + auto s = other; + + THEN("the sizes are identical") + { + REQUIRE(s.size() == other.size()); + } - WHEN("constructing a string from string_view") + 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 str = kstd::string{view}; + 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 string is not empty and has the same size as the view") + THEN("The moved from object's size is 0") { - REQUIRE_FALSE(str.empty()); - REQUIRE(str.size() == view.size()); + REQUIRE(other.size() == 0); } - THEN("the string contains the same characters as the view") + THEN("The moved from object's capacity is 15") { - REQUIRE(str == view); + REQUIRE(other.capacity() == 15); + } + + THEN("c_str() on the moved from object points to a null byte") + { + REQUIRE(*other.c_str() == '\0'); } } } - GIVEN("A C-style string") + GIVEN("An existing short string, of length 20") { - auto c_str = "Blub Blub"; + auto other = kstd::string{"abcdefghijABCDEFGHIJ"}; - WHEN("constructing a string from the C-style string") + WHEN("constructing by copy") { - auto str = kstd::string{c_str}; + auto s = other; - THEN("the string is not empty and has the same size as the C-style string") + THEN("the sizes are identical") { - REQUIRE_FALSE(str.empty()); - REQUIRE(str.size() == std::strlen(c_str)); + REQUIRE(s.size() == other.size()); } - THEN("the string contains the same characters as the C-style string") + THEN("the capacities are idendtical") { - REQUIRE(str == c_str); + 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'); } } } +} - GIVEN("A character") +SCENARIO("String assignment", "[string]") +{ + GIVEN("Two short strings") { - auto ch = 'x'; + 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; - WHEN("constructing a string from the character") + 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") { - auto str = kstd::string{ch}; + 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 string is not empty and has size 1") + THEN("the capacity of the moved from one is 15") { - REQUIRE_FALSE(str.empty()); - REQUIRE(str.size() == 1); + REQUIRE(s2.capacity() == 15); } - THEN("the string contains the same character as the given character") + THEN("the capacity of the moved to one is 15") { - REQUIRE(str == std::string_view{&ch, 1}); + REQUIRE(s1.capacity() == 15); } } } - GIVEN("Another string") + GIVEN("One short and one long string") { - auto other = kstd::string{"Blub Blub"}; + auto s1 = kstd::string{"abcd"}; + auto s2 = kstd::string{"ABCDEFGHIJabcdefghij"}; - WHEN("copy constructing a new string") + WHEN("copy assigning the shorter to the longer one") { - auto str = kstd::string{other}; + s2 = s1; - THEN("the new string contains the same characters as the original") + THEN("the new length of the longer one is equal to the length of the shorter one") { - REQUIRE(static_cast<std::string_view>(str) == static_cast<std::string_view>(other)); + 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())); } } - auto str = kstd::string{"Blub"}; + WHEN("copy assigning the longer to the shorter one") + { + s1 = s2; - WHEN("copy assigning another string") + 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") { - auto other = kstd::string{"Blub Blub"}; - str = other; + s2 = std::move(s1); - THEN("the string contains the same characters as the assigned string") + THEN("the new length of the longer one is equal to the original length of the shorter one") { - REQUIRE(static_cast<std::string_view>(str) == static_cast<std::string_view>(other)); + 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("A string") + GIVEN("Two long strings") { - auto str = kstd::string{"Hello"}; + auto s1 = kstd::string{"abcdefghijABCDEFGH"}; + auto s2 = kstd::string{"ABCDEFGHIJabcdefghij"}; - WHEN("copy assigning a string view") + WHEN("copy assigning the shorter to the longer one") { - auto view = std::string_view{"Hello, world!"}; - str = view; + s2 = s1; - THEN("the string contains the same characters as the assigned view") + THEN("the new length of the longer one is equal to the length of the shorter one") { - REQUIRE(str == view); + 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("A string") + GIVEN("An short string") { - auto str = kstd::string{"Hello"}; + auto s = kstd::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"; - WHEN("copy assigning a C-style string") + THEN("the length is equal to 20") + { + REQUIRE(s.length() == 20); + } + } + + WHEN("assigning a single character") { - auto c_str = "Hello, world!"; - str = c_str; + s = 'z'; - THEN("the string contains the same characters as the assigned C-style string") + THEN("the length is equal to 1") { - REQUIRE(str == c_str); + 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 = kstd::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("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<void const *>(s.data()) == static_cast<void const *>(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") |
