aboutsummaryrefslogtreecommitdiff
path: root/libs/kstd/tests/src
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-05-02 17:12:21 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-05-02 17:12:21 +0200
commit3ab0a15fb6aba0ad9516da69589b9da8dbd63a8e (patch)
treee79c1c0911c3b712a1b02c79d84f0ce5f643bc6c /libs/kstd/tests/src
parente8904a65e49dea8ce2e1d58eaa3fb60c7cd3443e (diff)
downloadkernel-3ab0a15fb6aba0ad9516da69589b9da8dbd63a8e.tar.xz
kernel-3ab0a15fb6aba0ad9516da69589b9da8dbd63a8e.zip
libs: adopt p1204 layout for kstd
Diffstat (limited to 'libs/kstd/tests/src')
-rw-r--r--libs/kstd/tests/src/flat_map.cpp314
-rw-r--r--libs/kstd/tests/src/format.cpp114
-rw-r--r--libs/kstd/tests/src/observer_ptr.cpp360
-rw-r--r--libs/kstd/tests/src/os_panic.cpp15
-rw-r--r--libs/kstd/tests/src/string.cpp445
-rw-r--r--libs/kstd/tests/src/vector.cpp2003
6 files changed, 0 insertions, 3251 deletions
diff --git a/libs/kstd/tests/src/flat_map.cpp b/libs/kstd/tests/src/flat_map.cpp
deleted file mode 100644
index 2b793d9..0000000
--- a/libs/kstd/tests/src/flat_map.cpp
+++ /dev/null
@@ -1,314 +0,0 @@
-#include <kstd/flat_map>
-
-#include <kstd/tests/os_panic.hpp>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <functional>
-#include <type_traits>
-#include <utility>
-
-SCENARIO("Flat Map initialization and construction", "[flat_map]")
-{
- GIVEN("An empty context")
- {
- WHEN("constructing by default")
- {
- auto map = kstd::flat_map<int, int>{};
-
- THEN("the Flat Map does not contain elements")
- {
- REQUIRE_FALSE(map.contains(1));
- }
- }
- }
-}
-
-SCENARIO("Flat Map modifiers", "[flat_map]")
-{
- GIVEN("An empty Flat Map")
- {
- auto map = kstd::flat_map<int, int>{};
-
- WHEN("emplacing a new element")
- {
- auto [it, inserted] = map.emplace(1, 100);
-
- THEN("the map contains the new element")
- {
- REQUIRE(inserted);
- REQUIRE(map.contains(1));
- }
- }
-
- WHEN("emplacing an existing element")
- {
- map.emplace(1, 100);
- auto [it, inserted] = map.emplace(1, 200);
-
- THEN("the map does not insert the duplicate")
- {
- REQUIRE_FALSE(inserted);
- REQUIRE(map.contains(1));
- }
- }
- }
-}
-
-SCENARIO("Flat Map element access", "[flat_map]")
-{
- GIVEN("A populated Flat Map")
- {
- auto map = kstd::flat_map<int, int>{};
- map.emplace(1, 10);
- map.emplace(2, 20);
- map.emplace(3, 30);
-
- WHEN("accessing an existing element with at()")
- {
- auto & val = map.at(2);
-
- THEN("it returns a reference to the mapped value")
- {
- REQUIRE(val == 20);
- }
-
- THEN("the mapped value can be modified")
- {
- val = 200;
- REQUIRE(map.at(2) == 200);
- }
- }
-
- WHEN("accessing a non-existent element with at()")
- {
- THEN("it panics")
- {
- REQUIRE_THROWS_AS(map.at(4), kstd::tests::os_panic);
- }
- }
- }
-
- GIVEN("A const populated Flat Map")
- {
- auto map_builder = kstd::flat_map<int, int>{};
- map_builder.emplace(1, 10);
- map_builder.emplace(2, 20);
- auto const map = map_builder;
-
- WHEN("accessing an existing element with const at()")
- {
- auto const & val = map.at(2);
-
- THEN("it returns a const reference to the mapped value")
- {
- REQUIRE(val == 20);
- }
- }
-
- WHEN("accessing a non-existent element with const at()")
- {
- THEN("it panics")
- {
- REQUIRE_THROWS_AS(map.at(4), kstd::tests::os_panic);
- }
- }
- }
-}
-
-SCENARIO("Flat Map iterators", "[flat_map]")
-{
- GIVEN("A populated Flat Map")
- {
- auto map = kstd::flat_map<int, int>{};
- map.emplace(1, 10);
- map.emplace(2, 20);
- map.emplace(3, 30);
-
- WHEN("using forward iterators")
- {
- THEN("they navigate the elements in the correct forward order")
- {
- auto it = map.begin();
- REQUIRE(it != map.end());
- REQUIRE((*it).first == 1);
-
- ++it;
- REQUIRE(it != map.end());
- REQUIRE((*it).first == 2);
-
- ++it;
- REQUIRE(it != map.end());
- REQUIRE((*it).first == 3);
-
- ++it;
- REQUIRE(it == map.end());
- }
-
- THEN("const forward iterators provide correct access")
- {
- auto it = map.cbegin();
- REQUIRE(it != map.cend());
- REQUIRE((*it).first == 1);
-
- ++it;
- REQUIRE(it != map.cend());
- REQUIRE((*it).first == 2);
-
- ++it;
- REQUIRE(it != map.cend());
- REQUIRE((*it).first == 3);
-
- ++it;
- REQUIRE(it == map.cend());
- }
-
- THEN("assignment through the proxy modifies the mapped value")
- {
- auto it = map.begin();
-
- *it = std::pair{1, 100};
-
- REQUIRE(it->second == 100);
- REQUIRE(map.at(1) == 100);
- }
-
- THEN("structured bindings evaluate correctly")
- {
- auto it = map.cbegin();
-
- auto [key, value] = *it;
-
- REQUIRE(key == 1);
- REQUIRE(value == 10);
-
- STATIC_REQUIRE(std::is_same_v<decltype(key), int const &>);
- STATIC_REQUIRE(std::is_same_v<decltype(value), int const &>);
- }
- }
-
- WHEN("using reverse iterators")
- {
- THEN("they navigate the elements in the correct reverse order")
- {
- auto it = map.rbegin();
- REQUIRE(it != map.rend());
- REQUIRE((*it).first == 3);
-
- ++it;
- REQUIRE(it != map.rend());
- REQUIRE((*it).first == 2);
-
- ++it;
- REQUIRE(it != map.rend());
- REQUIRE((*it).first == 1);
-
- ++it;
- REQUIRE(it == map.rend());
- }
-
- THEN("const reverse iterators provide correct access")
- {
- auto it = map.crbegin();
- REQUIRE(it != map.crend());
- REQUIRE((*it).first == 3);
-
- ++it;
- REQUIRE(it != map.crend());
- REQUIRE((*it).first == 2);
-
- ++it;
- REQUIRE(it != map.crend());
- REQUIRE((*it).first == 1);
-
- ++it;
- REQUIRE(it == map.crend());
- }
- }
- }
-
- GIVEN("an empty Flat Map")
- {
- auto map = kstd::flat_map<int, int>{};
-
- WHEN("getting iterators")
- {
- THEN("begin() equals end() and cbegin() equals cend()")
- {
- REQUIRE(map.begin() == map.end());
- REQUIRE(map.cbegin() == map.cend());
- }
-
- THEN("rbegin() equals rend() and crbegin() equals crend()")
- {
- REQUIRE(map.rbegin() == map.rend());
- REQUIRE(map.crbegin() == map.crend());
- }
- }
- }
-}
-
-SCENARIO("Flat Map heterogeneous element access", "[flat_map]")
-{
- GIVEN("A populated Flat Map with a transparent comparator")
- {
- auto map = kstd::flat_map<int, int, std::less<void>>{};
- map.emplace(1, 10);
- map.emplace(2, 20);
- map.emplace(3, 30);
-
- WHEN("accessing an existing element with a different key type via at()")
- {
- long const key = 2L;
- auto & val = map.at(key);
-
- THEN("it returns a reference to the mapped value")
- {
- REQUIRE(val == 20);
- }
-
- THEN("the mapped value can be modified")
- {
- val = 200;
- REQUIRE(map.at(2L) == 200);
- }
- }
-
- WHEN("accessing a non-existent element with a different key type via at()")
- {
- long const key = 4L;
- THEN("it panics")
- {
- REQUIRE_THROWS_AS(map.at(key), kstd::tests::os_panic);
- }
- }
- }
-
- GIVEN("A const populated Flat Map with a transparent comparator")
- {
- auto map_builder = kstd::flat_map<int, int, std::less<void>>{};
- map_builder.emplace(1, 10);
- map_builder.emplace(2, 20);
- auto const map = map_builder;
-
- WHEN("accessing an existing element with a different key type via const at()")
- {
- long const key = 2L;
- auto const & val = map.at(key);
-
- THEN("it returns a const reference to the mapped value")
- {
- REQUIRE(val == 20);
- }
- }
-
- WHEN("accessing a non-existent element with a different key type via const at()")
- {
- long const key = 4L;
- THEN("it panics")
- {
- REQUIRE_THROWS_AS(map.at(key), kstd::tests::os_panic);
- }
- }
- }
-}
diff --git a/libs/kstd/tests/src/format.cpp b/libs/kstd/tests/src/format.cpp
deleted file mode 100644
index 624779a..0000000
--- a/libs/kstd/tests/src/format.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-#include <kstd/format>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <iterator>
-#include <sstream>
-
-SCENARIO("Formatting to a new string", "[format]")
-{
- GIVEN("a format string without any placeholders")
- {
- auto const & fmt = "This is a test";
-
- WHEN("calling format with without any arguments.")
- {
- auto result = kstd::format(fmt);
-
- THEN("the result is the unmodified string")
- {
- REQUIRE(result == "This is a test");
- }
- }
-
- WHEN("calling format with additional arguments")
- {
- auto result = kstd::format(fmt, 1, 2, 3);
-
- THEN("the result is the unmodified string")
- {
- REQUIRE(result == "This is a test");
- }
- }
- }
-
- GIVEN("a format string with placeholders")
- {
- auto const & fmt = "Here are some placeholders: {} {} {}";
-
- WHEN("calling format with the same number of arguments as there are placeholders")
- {
- auto result = kstd::format(fmt, 1, true, 'a');
-
- THEN("the result is the formatted string")
- {
- REQUIRE(result == "Here are some placeholders: 1 true a");
- }
- }
-
- WHEN("calling format with too many arguments")
- {
- auto result = kstd::format(fmt, 2, false, 'b', 4, 5, 6);
-
- THEN("the result is the formatted string")
- {
- REQUIRE(result == "Here are some placeholders: 2 false b");
- }
- }
- }
-}
-
-SCENARIO("Formatting to an output iterator", "[format]")
-{
- auto buffer = std::ostringstream{};
-
- GIVEN("a format string without any placeholders")
- {
- auto const & fmt = "This is a test";
-
- WHEN("calling format with without any arguments.")
- {
- kstd::format_to(std::ostream_iterator<char>{buffer}, fmt);
-
- THEN("the unmodified string is written to the iterator")
- {
- REQUIRE(buffer.str() == "This is a test");
- }
- }
-
- WHEN("calling format with additional arguments")
- {
- kstd::format_to(std::ostream_iterator<char>{buffer}, fmt, 1, 2, 3);
-
- THEN("the unmodified string is written to the iterator")
- {
- REQUIRE(buffer.str() == "This is a test");
- }
- }
- }
-
- GIVEN("a format string with placeholders")
- {
- auto const & fmt = "Here are some placeholders: {} {} {}";
-
- WHEN("calling format with the same number of arguments as there are placeholders")
- {
- kstd::format_to(std::ostream_iterator<char>{buffer}, fmt, 1, true, -100);
-
- THEN("the formatted string is written to the iterator")
- {
- REQUIRE(buffer.str() == "Here are some placeholders: 1 true -100");
- }
- }
-
- WHEN("calling format with too many arguments")
- {
- kstd::format_to(std::ostream_iterator<char>{buffer}, fmt, 2, false, -200, 4, 5, 6);
-
- THEN("the formatted string is written to the iterator")
- {
- REQUIRE(buffer.str() == "Here are some placeholders: 2 false -200");
- }
- }
- }
-} \ No newline at end of file
diff --git a/libs/kstd/tests/src/observer_ptr.cpp b/libs/kstd/tests/src/observer_ptr.cpp
deleted file mode 100644
index 0c94892..0000000
--- a/libs/kstd/tests/src/observer_ptr.cpp
+++ /dev/null
@@ -1,360 +0,0 @@
-#include <kstd/memory>
-#include <kstd/tests/os_panic.hpp>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <array>
-#include <compare>
-#include <type_traits>
-#include <utility>
-
-namespace
-{
- struct Base
- {
- };
-
- struct Derived : Base
- {
- };
-
- struct Element
- {
- int value{};
-
- constexpr auto operator<=>(Element const &) const noexcept = default;
- };
-} // namespace
-
-SCENARIO("Observer Pointer initialization and construction", "[observer_ptr]")
-{
- GIVEN("An empty context")
- {
- WHEN("constructing by default")
- {
- auto ptr = kstd::observer_ptr<int>{};
-
- THEN("the observer pointer is null")
- {
- REQUIRE_FALSE(ptr);
- }
- }
-
- WHEN("constructing from a nullptr")
- {
- auto ptr = kstd::observer_ptr<int>{nullptr};
-
- THEN("the observer pointer is null")
- {
- REQUIRE_FALSE(ptr);
- }
- }
-
- WHEN("constructing from a raw pointer")
- {
- auto value = 1;
- auto ptr = kstd::observer_ptr{&value};
-
- THEN("the observer pointer is not null")
- {
- REQUIRE(ptr);
- }
-
- THEN("the observer pointer points to the correct object")
- {
- REQUIRE(&*ptr == &value);
- }
- }
-
- WHEN("copy constructing from an existing observer pointer")
- {
- auto value = 1;
- auto ptr = kstd::observer_ptr{&value};
- auto copy = ptr;
-
- THEN("the new observer pointer points to the same object as the other observer pointer")
- {
- REQUIRE(&*copy == &value);
- }
- }
-
- WHEN("copy constructing from an existing observer pointer with a compatible type")
- {
- auto value = Derived{};
- auto ptr = kstd::observer_ptr<Derived>(&value);
- kstd::observer_ptr<Base> copy = ptr;
-
- THEN("the new observer pointer points to the same object as the other observer pointer")
- {
- REQUIRE(&*copy == &value);
- }
- }
-
- WHEN("copy assigning from an existing observer pointer")
- {
- auto value = 1;
- auto ptr = kstd::observer_ptr{&value};
- auto copy = ptr;
-
- THEN("the new observer pointer points to the same object as the other observer pointer")
- {
- REQUIRE(&*copy == &value);
- }
- }
-
- WHEN("move constructing from an existing observer pointer")
- {
- auto value = 1;
- auto ptr = kstd::observer_ptr{&value};
- auto copy = std::move(ptr);
-
- THEN("the new observer pointer points to the same object as the other observer pointer")
- {
- REQUIRE(&*copy == &value);
- }
- }
-
- WHEN("move assigning from an existing observer pointer")
- {
- auto value = 1;
- auto ptr = kstd::observer_ptr{&value};
- auto copy = std::move(ptr);
-
- THEN("the new observer pointer points to the same object as the other observer pointer")
- {
- REQUIRE(&*copy == &value);
- }
- }
-
- WHEN("constructing an observer pointer using make_observer")
- {
- auto value = 1;
- auto ptr = kstd::make_observer(&value);
-
- THEN("the observer pointer points to the correct object")
- {
- REQUIRE(&*ptr == &value);
- }
-
- THEN("the observe pointer has the correct element type")
- {
- STATIC_REQUIRE(std::is_same_v<decltype(ptr), kstd::observer_ptr<int>>);
- }
- }
- }
-}
-
-SCENARIO("Observer pointer modifiers", "[observer_ptr]")
-{
- GIVEN("A non-null observer pointer")
- {
- auto value = 1;
- auto ptr = kstd::observer_ptr{&value};
-
- WHEN("releasing the observer pointer")
- {
- auto raw_ptr = ptr.release();
-
- THEN("the observer pointer is null")
- {
- REQUIRE_FALSE(ptr);
- }
-
- THEN("the returned pointer points to the correct object")
- {
- REQUIRE(raw_ptr == &value);
- }
- }
-
- WHEN("resetting the observer pointer to nullptr")
- {
- ptr.reset();
-
- THEN("the observer pointer is null")
- {
- REQUIRE_FALSE(ptr);
- }
- }
-
- WHEN("resetting the observer pointer to a new object")
- {
- auto other_value = 2;
- ptr.reset(&other_value);
-
- THEN("the observer pointer points to the new object")
- {
- REQUIRE(&*ptr == &other_value);
- }
- }
-
- WHEN("swapping it with another observer pointer")
- {
- auto other_value = 2;
- auto other_ptr = kstd::observer_ptr{&other_value};
- ptr.swap(other_ptr);
-
- THEN("the observer pointer points to the other object")
- {
- REQUIRE(&*ptr == &other_value);
- }
-
- THEN("the other observer pointer points to the original object")
- {
- REQUIRE(&*other_ptr == &value);
- }
- }
-
- WHEN("using namespace-level swap to swap it with another observer pointer")
- {
- using std::swap;
- auto other_value = 2;
- auto other_ptr = kstd::observer_ptr{&other_value};
- swap(ptr, other_ptr);
-
- THEN("the observer pointer points to the other object")
- {
- REQUIRE(&*ptr == &other_value);
- }
-
- THEN("the other observer pointer points to the original object")
- {
- REQUIRE(&*other_ptr == &value);
- }
- }
- }
-}
-
-SCENARIO("Observer pointer observers", "[observer_ptr]")
-{
- GIVEN("A non-null observer pointer")
- {
- auto value = Element{1};
- auto ptr = kstd::observer_ptr{&value};
-
- WHEN("getting the raw pointer")
- {
- auto raw_ptr = ptr.get();
-
- THEN("the raw pointer points to the correct object")
- {
- REQUIRE(raw_ptr == &value);
- }
- }
-
- WHEN("dereferencing the observer pointer")
- {
- auto dereferenced = *ptr;
-
- THEN("the dereferenced value is the correct value")
- {
- REQUIRE(dereferenced == value);
- }
- }
-
- WHEN("writing through the observer pointer with the arrow operator")
- {
- ptr->value = 2;
-
- THEN("the value is updated")
- {
- REQUIRE(value.value == 2);
- }
- }
-
- WHEN("converting the observer pointer to a raw pointer")
- {
- auto raw_ptr = static_cast<Element *>(ptr);
-
- THEN("the raw pointer points to the correct object")
- {
- REQUIRE(raw_ptr == &value);
- }
- }
-
- WHEN("checking the observer pointer as a boolean")
- {
- THEN("it returns true")
- {
- REQUIRE(static_cast<bool>(ptr));
- }
- }
- }
-
- GIVEN("A null observer pointer")
- {
- auto ptr = kstd::observer_ptr<Element>{};
-
- WHEN("checking the observer pointer as a boolean")
- {
- THEN("it returns false")
- {
- REQUIRE_FALSE(static_cast<bool>(ptr));
- }
- }
-
- WHEN("dereferencing the observer pointer")
- {
- THEN("the observer pointer panics")
- {
- REQUIRE_THROWS_AS(*ptr, kstd::tests::os_panic);
- }
- }
-
- WHEN("writing through the observer pointer with the arrow operator")
- {
- THEN("the observer pointer panics")
- {
- REQUIRE_THROWS_AS(ptr->value = 2, kstd::tests::os_panic);
- }
- }
- }
-}
-
-SCENARIO("Observer pointer comparisons", "[observer_ptr]")
-{
- GIVEN("Observer pointers to elements of an array")
- {
- auto arr = std::array{1, 2};
- auto ptr1 = kstd::observer_ptr{&arr[0]};
- auto ptr2 = kstd::observer_ptr{&arr[1]};
-
- WHEN("comparing the same observer pointer")
- {
- THEN("they are equal")
- {
- REQUIRE(ptr1 == ptr1);
- REQUIRE((ptr1 <=> ptr1) == std::strong_ordering::equal);
- }
- }
-
- WHEN("comparing different observer pointers")
- {
- THEN("they are ordered correctly")
- {
- REQUIRE(ptr1 != ptr2);
- REQUIRE(ptr1 < ptr2);
- REQUIRE(ptr1 <= ptr2);
- REQUIRE(ptr2 > ptr1);
- REQUIRE(ptr2 >= ptr1);
- REQUIRE((ptr1 <=> ptr2) == std::strong_ordering::less);
- REQUIRE((ptr2 <=> ptr1) == std::strong_ordering::greater);
- }
- }
- }
-
- GIVEN("A null observer pointer")
- {
- auto ptr = kstd::observer_ptr<int>{};
-
- WHEN("comparing with another null observer pointer")
- {
- auto other_ptr = kstd::observer_ptr<int>{};
-
- THEN("they are equal")
- {
- REQUIRE(ptr == other_ptr);
- REQUIRE((ptr <=> other_ptr) == std::strong_ordering::equal);
- }
- }
- }
-} \ No newline at end of file
diff --git a/libs/kstd/tests/src/os_panic.cpp b/libs/kstd/tests/src/os_panic.cpp
deleted file mode 100644
index 0759763..0000000
--- a/libs/kstd/tests/src/os_panic.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <kstd/tests/os_panic.hpp>
-
-#include <source_location>
-#include <string>
-#include <string_view>
-
-namespace kstd::os
-{
-
- auto panic(std::string_view message, std::source_location location)
- {
- throw kstd::tests::os_panic{std::string{message}, location};
- }
-
-} // namespace kstd::os \ No newline at end of file
diff --git a/libs/kstd/tests/src/string.cpp b/libs/kstd/tests/src/string.cpp
deleted file mode 100644
index 53d7c9a..0000000
--- a/libs/kstd/tests/src/string.cpp
+++ /dev/null
@@ -1,445 +0,0 @@
-#include <kstd/string>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <algorithm>
-#include <cstring>
-#include <string_view>
-
-SCENARIO("String initialization and construction", "[string]")
-{
- GIVEN("Nothing")
- {
- WHEN("constructing an empty string")
- {
- auto str = kstd::string{};
-
- THEN("the size is zero and therefore the string is empty")
- {
- REQUIRE(str.empty());
- REQUIRE(str.size() == 0);
- }
-
- THEN("the string is empty")
- {
- REQUIRE(str.view() == std::string_view{});
- }
- }
- }
-
- GIVEN("A string view")
- {
- auto view = std::string_view{"Blub Blub"};
-
- WHEN("constructing a string from string_view")
- {
- auto str = kstd::string{view};
-
- THEN("the string is not empty and has the same size as the view")
- {
- REQUIRE(!str.empty());
- REQUIRE(str.size() == view.size());
- }
-
- THEN("the string contains the same characters as the view")
- {
- REQUIRE(str.view() == view);
- }
- }
- }
-
- GIVEN("A C-style string")
- {
- auto c_str = "Blub Blub";
-
- WHEN("constructing a string from the C-style string")
- {
- auto str = kstd::string{c_str};
-
- THEN("the string is not empty and has the same size as the C-style string")
- {
- REQUIRE(!str.empty());
- REQUIRE(str.size() == std::strlen(c_str));
- }
-
- THEN("the string contains the same characters as the C-style string")
- {
- REQUIRE(str.view() == c_str);
- }
- }
- }
-
- GIVEN("A character")
- {
- auto ch = 'x';
-
- WHEN("constructing a string from the character")
- {
- auto str = kstd::string{ch};
-
- THEN("the string is not empty and has size 1")
- {
- REQUIRE(!str.empty());
- REQUIRE(str.size() == 1);
- }
-
- THEN("the string contains the same character as the given character")
- {
- REQUIRE(str.view() == std::string_view{&ch, 1});
- }
- }
- }
-
- GIVEN("Another string")
- {
- auto other = kstd::string{"Blub Blub"};
-
- WHEN("copy constructing a new string")
- {
- auto str = kstd::string{other};
-
- THEN("the new string contains the same characters as the original")
- {
- REQUIRE(str.view() == other.view());
- }
- }
-
- auto str = kstd::string{"Blub"};
-
- WHEN("copy assigning another string")
- {
- auto other = kstd::string{"Blub Blub"};
- str = other;
-
- THEN("the string contains the same characters as the assigned string")
- {
- REQUIRE(str.view() == other.view());
- }
- }
- }
-
- GIVEN("A string")
- {
- auto str = kstd::string{"Hello"};
-
- WHEN("copy assigning a string view")
- {
- auto view = std::string_view{"Hello, world!"};
- str = view;
-
- THEN("the string contains the same characters as the assigned view")
- {
- REQUIRE(str.view() == view);
- }
- }
- }
-
- GIVEN("A string")
- {
- auto str = kstd::string{"Hello"};
-
- WHEN("copy assigning a C-style string")
- {
- auto c_str = "Hello, world!";
- str = c_str;
-
- THEN("the string contains the same characters as the assigned C-style string")
- {
- REQUIRE(str.view() == c_str);
- }
- }
- }
-}
-
-SCENARIO("String concatenation", "[string]")
-{
- GIVEN("Two strings")
- {
- auto str1 = kstd::string{"Blub"};
- auto str2 = kstd::string{" Blub"};
-
- WHEN("appending the second string to the first string")
- {
- str1.append(str2);
-
- THEN("the first string contains the characters of both strings concatenated")
- {
- REQUIRE(str1.view() == "Blub Blub");
- }
-
- THEN("the size of the first string is the sum of the sizes of both strings")
- {
- REQUIRE(str1.size() == str2.size() + 4);
- }
- }
-
- WHEN("using operator+= to append the second string to the first string")
- {
- str1 += str2;
-
- THEN("the first string contains the characters of both strings concatenated")
- {
- REQUIRE(str1.view() == "Blub Blub");
- }
-
- THEN("the size of the first string is the sum of the sizes of both strings")
- {
- 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.view() == "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")
- {
- auto str = kstd::string{"Blub"};
- auto view = std::string_view{" Blub"};
-
- WHEN("appending the string view to the string")
- {
- str.append(view);
-
- THEN("the string contains the characters of both the original string and the appended view concatenated")
- {
- REQUIRE(str.view() == "Blub Blub");
- }
-
- THEN("the size of the string is the sum of the sizes of the original string and the appended view")
- {
- REQUIRE(str.size() == view.size() + 4);
- }
- }
- }
-
- GIVEN("A string and a character")
- {
- auto str = kstd::string{"Blub"};
- auto ch = '!';
-
- WHEN("appending the character to the string")
- {
- str.push_back(ch);
-
- THEN("the string contains the original characters followed by the appended character")
- {
- REQUIRE(str.view() == "Blub!");
- }
-
- THEN("the size of the string is one more than the original size")
- {
- REQUIRE(str.size() == 5);
- }
- }
-
- WHEN("using operator+= to append the character to the string")
- {
- str += ch;
-
- THEN("the string contains the original characters followed by the appended character")
- {
- REQUIRE(str.view() == "Blub!");
- }
-
- THEN("the size of the string is one more than the original size")
- {
- REQUIRE(str.size() == 5);
- }
- }
- }
-}
-
-SCENARIO("String conversion and comparison", "[string]")
-{
- GIVEN("An unsigned integer")
- {
- constexpr auto value1 = 12345u;
- constexpr auto value2 = 0u;
-
- WHEN("converting the unsigned integer to a string")
- {
- auto str1 = kstd::to_string(value1);
- auto str2 = kstd::to_string(value2);
-
- THEN("the string contains the decimal representation of the unsigned integer")
- {
- REQUIRE(str1.view() == "12345");
- REQUIRE(str2.view() == "0");
- }
- }
- }
-
- GIVEN("Two strings with the same characters")
- {
- auto str1 = kstd::string{"Blub Blub"};
- auto str2 = kstd::string{"Blub Blub"};
-
- THEN("the strings are equal")
- {
- REQUIRE(str1 == str2);
- }
-
- THEN("the strings are not unequal")
- {
- REQUIRE(!(str1 != str2));
- }
- }
-
- GIVEN("A string and a string view with the same characters")
- {
- auto str = kstd::string{"Blub Blub"};
- auto view = std::string_view{"Blub Blub"};
-
- THEN("the string and the string view are equal")
- {
- REQUIRE(str == view);
- REQUIRE(view == str);
- }
-
- THEN("the string and the string view are not unequal")
- {
- REQUIRE(!(str != view));
- REQUIRE(!(view != str));
- }
- }
-}
-
-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.view() == std::string_view{});
- }
- }
- }
-}
-
-SCENARIO("String iteration", "[string]")
-{
- GIVEN("A string")
- {
- auto str = kstd::string{"Blub"};
-
- WHEN("iterating over the characters of the string as string_view using a range-based for loop")
- {
- kstd::string result;
-
- for (auto ch : str.view())
- {
- result.push_back(ch);
- }
-
- THEN("the iterated characters are the same as the characters in the string")
- {
- REQUIRE(result == str);
- }
- }
-
- WHEN("using std::ranges::for_each to iterate over the characters of the string")
- {
- kstd::string result;
-
- std::ranges::for_each(str, [&result](auto ch) { result.push_back(ch); });
-
- THEN("the iterated characters are the same as the characters in the string")
- {
- REQUIRE(result == str);
- }
- }
-
- WHEN("using front and back to access the first and last characters of the string")
- {
- THEN("front returns the first character of the string")
- {
- REQUIRE(str.front() == 'B');
- }
-
- THEN("back returns the last character of the string")
- {
- REQUIRE(str.back() == 'b');
- }
- }
- }
-
- GIVEN("A const string")
- {
- auto const str = kstd::string{"Blub"};
-
- WHEN("iterating over the characters of the string as string_view using a range-based for loop")
- {
- kstd::string result;
-
- for (auto ch : str.view())
- {
- result.push_back(ch);
- }
-
- THEN("the iterated characters are the same as the characters in the string")
- {
- REQUIRE(result == str.view());
- }
- }
-
- WHEN("using front and back to access the first and last characters of the string")
- {
- THEN("front returns the first character of the string")
- {
- REQUIRE(str.front() == 'B');
- }
-
- THEN("back returns the last character of the string")
- {
- REQUIRE(str.back() == 'b');
- }
- }
- }
-
- GIVEN("An empty string")
- {
- auto str = kstd::string{};
-
- WHEN("iterating over the characters of an empty string")
- {
- kstd::string result;
-
- for (auto ch : str.view())
- {
- result.push_back(ch);
- }
-
- THEN("no characters are iterated and the result is an empty string")
- {
- REQUIRE(result.empty());
- REQUIRE(result.size() == 0);
- REQUIRE(result.view() == std::string_view{});
- }
- }
- }
-}
diff --git a/libs/kstd/tests/src/vector.cpp b/libs/kstd/tests/src/vector.cpp
deleted file mode 100644
index 4fb3559..0000000
--- a/libs/kstd/tests/src/vector.cpp
+++ /dev/null
@@ -1,2003 +0,0 @@
-#include <kstd/vector>
-
-#include <kstd/ranges>
-#include <kstd/tests/os_panic.hpp>
-#include <kstd/tests/test_types.hpp>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <array>
-#include <iterator>
-#include <ranges>
-#include <utility>
-
-SCENARIO("Vector initialization and construction", "[vector]")
-{
- GIVEN("An empty context")
- {
- WHEN("constructing by default")
- {
- auto v = kstd::vector<int>{};
-
- THEN("the vector is empty")
- {
- REQUIRE(v.empty());
- }
-
- THEN("the size and capacity are zero")
- {
- REQUIRE(v.size() == 0);
- REQUIRE(v.capacity() == 0);
- }
- }
-
- WHEN("constructing with a specific size")
- {
- auto v = kstd::vector<int>(10);
-
- THEN("the vector is not empty")
- {
- REQUIRE_FALSE(v.empty());
- }
-
- THEN("the size is and capacity match the specified value")
- {
- REQUIRE(v.size() == 10);
- REQUIRE(v.capacity() == 10);
- }
- }
-
- WHEN("constructing from an initializer list")
- {
- auto v = kstd::vector<int>{1, 2, 3, 4, 5};
-
- THEN("the vector is not empty")
- {
- REQUIRE_FALSE(v.empty());
- }
-
- THEN("the size is and capacity match the specified value")
- {
- REQUIRE(v.size() == 5);
- REQUIRE(v.capacity() == 5);
- }
-
- THEN("the elements are correctly initialized")
- {
- REQUIRE(v[0] == 1);
- REQUIRE(v[1] == 2);
- REQUIRE(v[2] == 3);
- REQUIRE(v[3] == 4);
- REQUIRE(v[4] == 5);
- }
- }
- }
-
- GIVEN("A non-empty range")
- {
- auto range = std::array<int, 3>{1, 2, 3};
-
- WHEN("constructing from a random-access iterator range")
- {
- auto v = kstd::vector<int>{std::begin(range), std::end(range)};
-
- THEN("the vector is not empty")
- {
- REQUIRE_FALSE(v.empty());
- }
-
- THEN("the size and capacity match the range size")
- {
- REQUIRE(v.size() == std::size(range));
- REQUIRE(v.capacity() == std::size(range));
- }
-
- THEN("the elements are correctly initialized")
- {
- REQUIRE(v[0] == 1);
- REQUIRE(v[1] == 2);
- REQUIRE(v[2] == 3);
- }
- }
-
- WHEN("constructing from a range")
- {
- auto v = kstd::vector<int>{kstd::from_range, range};
-
- THEN("the vector is not empty")
- {
- REQUIRE_FALSE(v.empty());
- }
-
- THEN("the size and capacity match the range size")
- {
- REQUIRE(v.size() == std::ranges::size(range));
- REQUIRE(v.capacity() == std::ranges::size(range));
- }
-
- THEN("the elements are correctly initialized")
- {
- REQUIRE(v[0] == 1);
- REQUIRE(v[1] == 2);
- REQUIRE(v[2] == 3);
- }
- }
- }
-
- GIVEN("A populated vector")
- {
- auto source = kstd::vector<int>{1, 2, 3, 4, 5};
-
- WHEN("copy constructing a new vector")
- {
- auto copy = kstd::vector<int>(source);
-
- THEN("the copy matches the original")
- {
- REQUIRE(copy.size() == source.size());
- REQUIRE(copy.capacity() == source.capacity());
- REQUIRE(copy[0] == 1);
- REQUIRE(copy[1] == 2);
- REQUIRE(copy[2] == 3);
- REQUIRE(copy[3] == 4);
- REQUIRE(copy[4] == 5);
- }
-
- THEN("the original is left unchanged")
- {
- REQUIRE(source.size() == 5);
- REQUIRE(source.capacity() == 5);
- REQUIRE(source[0] == 1);
- REQUIRE(source[1] == 2);
- REQUIRE(source[2] == 3);
- REQUIRE(source[3] == 4);
- REQUIRE(source[4] == 5);
- }
- }
-
- WHEN("move constructing a new vector")
- {
- auto moved = kstd::vector<int>(std::move(source));
-
- THEN("The new vector has the original elements")
- {
- REQUIRE(moved.size() == 5);
- REQUIRE(moved.capacity() == 5);
- REQUIRE(moved[0] == 1);
- REQUIRE(moved[1] == 2);
- REQUIRE(moved[2] == 3);
- REQUIRE(moved[3] == 4);
- REQUIRE(moved[4] == 5);
- }
-
- THEN("The original vector is left in a valid but unspecified state")
- {
- REQUIRE(source.empty());
- REQUIRE(source.size() == 0);
- REQUIRE(source.capacity() == 0);
- }
- }
- }
-}
-
-SCENARIO("Vector element access", "[vector]")
-{
- GIVEN("A populated vector")
- {
- auto v = kstd::vector<int>{10, 20, 30};
-
- WHEN("accessing elements for reading")
- {
- THEN("operator[] and at() return the correct elements")
- {
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 20);
- REQUIRE(v[2] == 30);
-
- REQUIRE(v.at(0) == 10);
- REQUIRE(v.at(1) == 20);
- REQUIRE(v.at(2) == 30);
- }
-
- THEN("front() and back() return the first and last elements")
- {
- REQUIRE(v.front() == 10);
- REQUIRE(v.back() == 30);
- }
-
- THEN("data() return a pointer to the contiguous storage")
- {
- auto ptr = v.data();
- REQUIRE(ptr);
- REQUIRE(ptr[0] == 10);
- REQUIRE(ptr[1] == 20);
- REQUIRE(ptr[2] == 30);
- }
-
- THEN("accessing out of bounds elements panics")
- {
- REQUIRE_THROWS_AS(v.at(3), kstd::tests::os_panic);
- }
- }
-
- WHEN("accessing elements for writing")
- {
- v[0] = 100;
- v.at(1) = 200;
- v.back() = 300;
-
- THEN("the elements are correctly modified")
- {
- REQUIRE(v[0] == 100);
- REQUIRE(v[1] == 200);
- REQUIRE(v[2] == 300);
- }
- }
- }
-}
-
-SCENARIO("Vector iterators", "[vector]")
-{
- GIVEN("A populated vector")
- {
- auto v = kstd::vector<int>{1, 2, 3};
-
- WHEN("using forward iterators")
- {
- THEN("they navigate the elements in the correct forward order")
- {
- auto it = v.begin();
- REQUIRE(it != v.end());
- REQUIRE(*it == 1);
-
- ++it;
- REQUIRE(it != v.end());
- REQUIRE(*it == 2);
-
- ++it;
- REQUIRE(it != v.end());
- REQUIRE(*it == 3);
-
- ++it;
- REQUIRE(it == v.end());
- }
-
- THEN("const forward iterators provide correct access")
- {
- auto it = v.cbegin();
- REQUIRE(it != v.cend());
- REQUIRE(*it == 1);
-
- ++it;
- REQUIRE(it != v.cend());
- REQUIRE(*it == 2);
-
- ++it;
- REQUIRE(it != v.cend());
- REQUIRE(*it == 3);
-
- ++it;
- REQUIRE(it == v.cend());
- }
- }
-
- WHEN("using reverse iterators")
- {
- THEN("they navigate the elements in the correct reverse order")
- {
- auto it = v.rbegin();
- REQUIRE(it != v.rend());
- REQUIRE(*it == 3);
-
- ++it;
- REQUIRE(it != v.rend());
- REQUIRE(*it == 2);
-
- ++it;
- REQUIRE(it != v.rend());
- REQUIRE(*it == 1);
-
- ++it;
- REQUIRE(it == v.rend());
- }
-
- THEN("const reverse iterators provide correct access")
- {
- auto it = v.crbegin();
- REQUIRE(it != v.crend());
- REQUIRE(*it == 3);
-
- ++it;
- REQUIRE(it != v.crend());
- REQUIRE(*it == 2);
-
- ++it;
- REQUIRE(it != v.crend());
- REQUIRE(*it == 1);
-
- ++it;
- REQUIRE(it == v.crend());
- }
- }
- }
-
- GIVEN("an empty vector")
- {
- auto v = kstd::vector<int>{};
-
- WHEN("getting iterators")
- {
- THEN("begin() equals end() and cbegin() equals cend()")
- {
- REQUIRE(v.begin() == v.end());
- REQUIRE(v.cbegin() == v.cend());
- }
-
- THEN("rbegin() equals rend() and crbegin() equals crend()")
- {
- REQUIRE(v.rbegin() == v.rend());
- REQUIRE(v.crbegin() == v.crend());
- }
- }
- }
-}
-
-SCENARIO("Vector capacity management", "[vector]")
-{
- GIVEN("An empty vector")
- {
- auto v = kstd::vector<int>{};
-
- WHEN("reserving space")
- {
- v.reserve(10);
-
- THEN("the capacity is at least the reserved amount")
- {
- REQUIRE(v.capacity() >= 10);
- }
-
- THEN("the size is still zero")
- {
- REQUIRE(v.size() == 0);
- }
-
- THEN("the vector is still empty")
- {
- REQUIRE(v.empty());
- }
- }
-
- WHEN("reserving space less than or equal to current capacity")
- {
- v.reserve(10);
- auto const current_capacity = v.capacity();
- v.reserve(5);
-
- THEN("the capacity remains unchanged")
- {
- REQUIRE(v.capacity() == current_capacity);
- }
- }
-
- WHEN("reserving space greater than max_size")
- {
- THEN("a panic is triggered")
- {
- REQUIRE_THROWS_AS(v.reserve(v.max_size() + 1), kstd::tests::os_panic);
- }
- }
- }
-
- GIVEN("A populated vector with excess capacity")
- {
- auto v = kstd::vector<int>{1, 2, 3};
- v.reserve(10);
-
- REQUIRE(v.capacity() == 10);
-
- WHEN("calling shrink_to_fit")
- {
- v.shrink_to_fit();
-
- THEN("the capacity is reduced to match the size")
- {
- REQUIRE(v.capacity() == 3);
- REQUIRE(v.size() == 3);
- }
-
- THEN("the elements remain unchanged")
- {
- REQUIRE(v[0] == 1);
- REQUIRE(v[1] == 2);
- REQUIRE(v[2] == 3);
- }
- }
- }
-}
-
-SCENARIO("Vector modifiers", "[vector]")
-{
- GIVEN("An empty vector")
- {
- auto v = kstd::vector<int>{};
-
- WHEN("push_back is called with a value")
- {
- v.push_back(10);
-
- THEN("the element is added and the size and capacity increase")
- {
- REQUIRE(v.size() == 1);
- REQUIRE(v.capacity() >= 1);
- REQUIRE(v.back() == 10);
- }
- }
-
- WHEN("emplace_back is called with constructor arguments")
- {
- v.emplace_back(20);
-
- THEN("the element is added and the size and capacity increase")
- {
- REQUIRE(v.size() == 1);
- REQUIRE(v.capacity() >= 1);
- REQUIRE(v.back() == 20);
- }
- }
-
- WHEN("elements are added while capacity is sufficient")
- {
- v.reserve(10);
- auto const capacity = v.capacity();
-
- v.push_back(10);
- v.emplace_back(20);
-
- THEN("the elements are added without reallocation")
- {
- REQUIRE(v.size() == 2);
- REQUIRE(v.capacity() == capacity);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 20);
- }
- }
-
- WHEN("emplace is called with the end iterator and constructor arguments")
- {
- v.emplace(v.end(), 20);
-
- THEN("the element is appended and the size and capacity increase")
- {
- REQUIRE(v.size() == 1);
- REQUIRE(v.capacity() >= 1);
- REQUIRE(v.back() == 20);
- }
- }
-
- WHEN("emplace is called while capacity is sufficient")
- {
- v.reserve(10);
- auto const capacity = v.capacity();
-
- v.emplace(v.end(), 20);
-
- THEN("the element is appended without reallocation")
- {
- REQUIRE(v.size() == 1);
- REQUIRE(v.capacity() == capacity);
- REQUIRE(v.back() == 20);
- }
- }
-
- WHEN("inserting an element")
- {
- auto it = v.insert(v.cbegin(), 40);
-
- THEN("the size and capacity increase and the element is inserted")
- {
- REQUIRE(v.size() == 1);
- REQUIRE(v.capacity() >= 1);
- REQUIRE(v[0] == 40);
- REQUIRE(it == v.begin());
- }
- }
-
- WHEN("inserting an lvalue element")
- {
- auto const value = 40;
- auto it = v.insert(v.cbegin(), value);
-
- THEN("the size and capacity increase and the element is inserted")
- {
- REQUIRE(v.size() == 1);
- REQUIRE(v.capacity() >= 1);
- REQUIRE(v[0] == 40);
- REQUIRE(it == v.begin());
- }
- }
-
- WHEN("appending a range")
- {
- auto const range = std::views::iota(0, 3);
- v.append_range(range);
-
- THEN("the size increases")
- {
- REQUIRE(v.size() == 3);
- }
-
- THEN("the capacity increases")
- {
- REQUIRE(v.capacity() >= 3);
- }
-
- THEN("the elements are appended")
- {
- REQUIRE(v[0] == 0);
- REQUIRE(v[1] == 1);
- REQUIRE(v[2] == 2);
- }
- }
-
- WHEN("appending from an input range")
- {
- auto const arr = std::array<int, 3>{1, 2, 3};
- auto const first = kstd::tests::test_input_iterator{arr.data(), arr.size()};
- auto const last = kstd::tests::test_input_iterator{};
-
- v.append_range(std::ranges::subrange{first, last});
-
- THEN("the size increases")
- {
- REQUIRE(v.size() == 3);
- }
-
- THEN("the capacity increases")
- {
- REQUIRE(v.capacity() >= 3);
- }
-
- THEN("the elements are appended")
- {
- REQUIRE(v[0] == 1);
- REQUIRE(v[1] == 2);
- REQUIRE(v[2] == 3);
- }
- }
-
- WHEN("appending from an input range with sufficient capacity")
- {
- v.reserve(3);
- auto const arr = std::array<int, 3>{1, 2, 3};
- auto const first = kstd::tests::test_input_iterator{arr.data(), arr.size()};
- auto const last = kstd::tests::test_input_iterator{};
-
- v.append_range(std::ranges::subrange{first, last});
-
- THEN("the size increases")
- {
- REQUIRE(v.size() == 3);
- }
-
- THEN("the capacity stays the same")
- {
- REQUIRE(v.capacity() == 3);
- }
-
- THEN("the elements are appended")
- {
- REQUIRE(v[0] == 1);
- REQUIRE(v[1] == 2);
- REQUIRE(v[2] == 3);
- }
- }
-
- WHEN("resizing the vector to a greater size")
- {
- v.resize(3);
-
- THEN("the size and capacity increase and the elements are value initialized")
- {
- REQUIRE(v.size() == 3);
- REQUIRE(v.capacity() >= 3);
- REQUIRE(v[0] == 0);
- REQUIRE(v[1] == 0);
- REQUIRE(v[2] == 0);
- }
- }
-
- WHEN("resizing the vector to a greater size with initial value")
- {
- v.resize(3, 2);
-
- THEN("the size and capacity increase and the elements are initialized to the given value")
- {
- REQUIRE(v.size() == 3);
- REQUIRE(v.capacity() >= 3);
- REQUIRE(v[0] == 2);
- REQUIRE(v[1] == 2);
- REQUIRE(v[2] == 2);
- }
- }
-
- WHEN("inserting a range at the beginning")
- {
- auto const arr = std::array<int, 3>{1, 2, 3};
- auto it = v.insert_range(v.begin(), arr);
-
- THEN("the size increases")
- {
- REQUIRE(v.size() == 3);
- }
-
- THEN("the capacity increases")
- {
- REQUIRE(v.capacity() >= 3);
- }
-
- THEN("the elements are inserted")
- {
- REQUIRE(v[0] == 1);
- REQUIRE(v[1] == 2);
- REQUIRE(v[2] == 3);
- }
-
- THEN("the returned iterator points to the beginning of the inserted range")
- {
- REQUIRE(it == v.begin());
- }
- }
-
- WHEN("inserting a range at the end")
- {
- auto const arr = std::array<int, 3>{1, 2, 3};
- auto it = v.insert_range(v.end(), arr);
-
- THEN("the size increases")
- {
- REQUIRE(v.size() == 3);
- }
-
- THEN("the capacity increases")
- {
- REQUIRE(v.capacity() >= 3);
- }
-
- THEN("the elements are inserted")
- {
- REQUIRE(v[0] == 1);
- REQUIRE(v[1] == 2);
- REQUIRE(v[2] == 3);
- }
-
- THEN("the returned iterator points to the beginning of the inserted range")
- {
- REQUIRE(it == v.begin());
- }
- }
-
- WHEN("inserting from an input range without sufficient capacity")
- {
- auto const arr = std::array<int, 3>{1, 2, 3};
- auto const first = kstd::tests::test_input_iterator{arr.data(), arr.size()};
- auto const last = kstd::tests::test_input_iterator{};
- auto it = v.insert_range(v.begin(), std::ranges::subrange{first, last});
-
- THEN("the size increases")
- {
- REQUIRE(v.size() == 3);
- }
-
- THEN("the capacity increases")
- {
- REQUIRE(v.capacity() >= 3);
- }
-
- THEN("the elements are inserted")
- {
- REQUIRE(v[0] == 1);
- REQUIRE(v[1] == 2);
- REQUIRE(v[2] == 3);
- }
-
- THEN("the returned iterator points to the beginning of the inserted range")
- {
- REQUIRE(it == v.begin());
- }
- }
- }
-
- GIVEN("A populated vector")
- {
- auto v = kstd::vector<int>{10, 20, 30};
- auto initial_capacity = v.capacity();
-
- WHEN("push_back is called")
- {
- v.push_back(40);
-
- THEN("the element is added and the size and capacity increase")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v.capacity() >= initial_capacity);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 20);
- REQUIRE(v[2] == 30);
- REQUIRE(v[3] == 40);
- }
- }
-
- WHEN("emplace_back is called with constructor arguments")
- {
- v.emplace_back(40);
-
- THEN("the element is added and the size and capacity increase")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v.capacity() >= initial_capacity);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 20);
- REQUIRE(v[2] == 30);
- REQUIRE(v[3] == 40);
- }
- }
-
- WHEN("emplace is called with an iterator and constructor arguments")
- {
- auto it = v.emplace(v.begin() + 2, 25);
-
- THEN("the element is inserted and the size and capacity increase")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v.capacity() >= initial_capacity);
- REQUIRE(v.at(2) == 25);
- }
-
- THEN("the returned iterator points to the inserted element")
- {
- REQUIRE(it == v.cbegin() + 2);
- REQUIRE(*it == 25);
- }
- }
-
- WHEN("emplace is called with an iterator and sufficient capacity")
- {
- v.reserve(v.size() + 1);
-
- auto it = v.emplace(v.begin() + 2, 25);
-
- THEN("the element is inserted and the size and capacity increase")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v.capacity() >= initial_capacity);
- REQUIRE(v.at(2) == 25);
- }
-
- THEN("the returned iterator points to the inserted element")
- {
- REQUIRE(it == v.cbegin() + 2);
- REQUIRE(*it == 25);
- }
- }
-
- WHEN("push_back is called with a reference to an internal element")
- {
- v.shrink_to_fit();
- auto const original_value = v[0];
-
- v.push_back(v[0]);
-
- THEN("reallocation handles the internal reference safely without dangling")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v[0] == original_value);
- REQUIRE(v.back() == original_value);
- }
- }
-
- WHEN("pop_back is called")
- {
- v.pop_back();
-
- THEN("the last element is removed and the size decreases")
- {
- REQUIRE(v.size() == 2);
- REQUIRE(v.capacity() == initial_capacity);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 20);
- }
- }
-
- WHEN("clear is called")
- {
- v.clear();
-
- THEN("the vector is empty")
- {
- REQUIRE(v.empty());
- REQUIRE(v.size() == 0);
- REQUIRE(v.capacity() == initial_capacity);
- }
- }
-
- WHEN("inserting at the beginning")
- {
- auto it = v.insert(v.cbegin(), 5);
-
- THEN("the element is inserted at the front")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v[0] == 5);
- REQUIRE(v[1] == 10);
- REQUIRE(v[2] == 20);
- REQUIRE(v[3] == 30);
- REQUIRE(it == v.begin());
- }
- }
-
- WHEN("inserting in the middle")
- {
- auto it = v.insert(v.cbegin() + 1, 15);
-
- THEN("the element is inserted in the middle")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 15);
- REQUIRE(v[2] == 20);
- REQUIRE(v[3] == 30);
- REQUIRE(it == v.begin() + 1);
- }
- }
-
- WHEN("inserting at the end")
- {
- auto it = v.insert(v.cend(), 40);
-
- THEN("the element is inserted at the back")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 20);
- REQUIRE(v[2] == 30);
- REQUIRE(v[3] == 40);
- REQUIRE(it == v.begin() + 3);
- }
- }
-
- WHEN("inserting an lvalue at the end")
- {
- auto const value = 40;
- auto it = v.insert(v.cend(), value);
-
- THEN("the element is inserted at the back")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 20);
- REQUIRE(v[2] == 30);
- REQUIRE(v[3] == 40);
- REQUIRE(it == v.begin() + 3);
- }
- }
-
- WHEN("inserting when capacity is sufficient")
- {
- v.reserve(10);
- auto const capacity = v.capacity();
-
- auto it = v.insert(v.cbegin() + 1, 15);
-
- THEN("the element is added without reallocation")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v.capacity() == capacity);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 15);
- REQUIRE(v[2] == 20);
- REQUIRE(v[3] == 30);
- REQUIRE(it == v.begin() + 1);
- }
- }
-
- WHEN("inserting a reference to an existing element with reallocation")
- {
- v.shrink_to_fit();
- REQUIRE(v.capacity() == v.size());
- auto it = v.insert(v.cbegin() + 1, v[2]);
-
- THEN("the element is correctly copied and inserted")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 30);
- REQUIRE(v[2] == 20);
- REQUIRE(v[3] == 30);
- REQUIRE(it == v.begin() + 1);
- }
- }
-
- WHEN("inserting a reference to an existing element without reallocation")
- {
- v.reserve(10);
- REQUIRE(v.capacity() > v.size());
- auto it = v.insert(v.cbegin() + 1, v[2]);
-
- THEN("the element is correctly copied and inserted")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 30);
- REQUIRE(v[2] == 20);
- REQUIRE(v[3] == 30);
- REQUIRE(it == v.begin() + 1);
- }
- }
-
- WHEN("inserting an rvalue reference to an existing element with reallocation")
- {
- v.shrink_to_fit();
- REQUIRE(v.capacity() == v.size());
- auto it = v.insert(v.cbegin() + 1, std::move(v[2]));
-
- THEN("the element is correctly moved and inserted")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 30);
- REQUIRE(v[2] == 20);
- REQUIRE(v[3] == 30);
- REQUIRE(it == v.begin() + 1);
- }
- }
-
- WHEN("inserting an rvalue reference to an existing element without reallocation")
- {
- v.reserve(10);
- REQUIRE(v.capacity() > v.size());
- auto it = v.insert(v.cbegin() + 1, std::move(v[2]));
-
- THEN("the element is correctly moved and inserted")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 30);
- REQUIRE(v[2] == 20);
- REQUIRE(v[3] == 30);
- REQUIRE(it == v.begin() + 1);
- }
- }
-
- WHEN("erasing the first element")
- {
- auto it = v.erase(v.cbegin());
-
- THEN("the first element is removed and the size decreases")
- {
- REQUIRE(v.size() == 2);
- REQUIRE(v[0] == 20);
- REQUIRE(v[1] == 30);
- REQUIRE(it == v.begin());
- }
- }
-
- WHEN("erasing a middle element")
- {
- auto it = v.erase(v.cbegin() + 1);
-
- THEN("the middle element is removed and the size decreases")
- {
- REQUIRE(v.size() == 2);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 30);
- REQUIRE(it == v.begin() + 1);
- }
- }
-
- WHEN("erasing the last element")
- {
- auto it = v.erase(v.cend() - 1);
-
- THEN("the last element is removed and the size decreases")
- {
- REQUIRE(v.size() == 2);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 20);
- REQUIRE(it == v.end());
- }
- }
-
- WHEN("erasing the end() iterator")
- {
- THEN("a panic is triggered")
- {
- REQUIRE_THROWS_AS(v.erase(v.end()), kstd::tests::os_panic);
- }
- }
-
- WHEN("erasing a range of elements")
- {
- auto it = v.erase(v.cbegin() + 1, v.cend() - 1);
-
- THEN("the specified range is removed and the size decreases")
- {
- REQUIRE(v.size() == 2);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 30);
- REQUIRE(it == v.begin() + 1);
- }
- }
-
- WHEN("erasing an empty range")
- {
- auto it = v.erase(v.cbegin() + 1, v.cbegin() + 1);
-
- THEN("the vector is unchanged")
- {
- REQUIRE(v.size() == 3);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 20);
- REQUIRE(v[2] == 30);
- REQUIRE(it == v.begin() + 1);
- }
- }
-
- WHEN("appending a range")
- {
- auto initial_size = v.size();
- v.append_range(std::views::iota(0, 3));
-
- THEN("capacity is increased")
- {
- REQUIRE(v.capacity() >= initial_capacity);
- }
-
- THEN("size is increased")
- {
- REQUIRE(v.size() == initial_size + 3);
- }
-
- THEN("the elements are appended")
- {
- REQUIRE(v[initial_size + 0] == 0);
- REQUIRE(v[initial_size + 1] == 1);
- REQUIRE(v[initial_size + 2] == 2);
- }
- }
-
- WHEN("resizing the vector to a greater size")
- {
- auto initial_size = v.size();
- v.resize(initial_size + 3);
-
- THEN("the size and capacity increase and the elements are value initialized")
- {
- REQUIRE(v.size() == initial_size + 3);
- REQUIRE(v.capacity() >= initial_size + 3);
- REQUIRE(v[initial_size + 0] == 0);
- REQUIRE(v[initial_size + 1] == 0);
- REQUIRE(v[initial_size + 2] == 0);
- }
- }
-
- WHEN("resizing the vector to a greater size with initial value")
- {
- auto initial_size = v.size();
- v.resize(initial_size + 3, 2);
-
- THEN("the size and capacity increase and the elements are initialized to the given value")
- {
- REQUIRE(v.size() == initial_size + 3);
- REQUIRE(v.capacity() >= initial_size + 3);
- REQUIRE(v[initial_size + 0] == 2);
- REQUIRE(v[initial_size + 1] == 2);
- REQUIRE(v[initial_size + 2] == 2);
- }
- }
-
- WHEN("resizing the vector to a smaller size")
- {
- v.resize(1);
-
- THEN("the size decreases and the elements are destroyed")
- {
- REQUIRE(v.size() == 1);
- REQUIRE(v[0] == 10);
- }
- }
-
- WHEN("inserting an empty range")
- {
- auto initial_size = v.size();
- auto it = v.insert_range(v.begin(), std::views::empty<int>);
-
- THEN("the size does not change")
- {
- REQUIRE(v.size() == initial_size);
- }
-
- THEN("the capacity does not change")
- {
- REQUIRE(v.capacity() == initial_capacity);
- }
-
- THEN("the content is unchanged")
- {
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 20);
- REQUIRE(v[2] == 30);
- }
-
- THEN("the returned iterator points to the position of insertion")
- {
- REQUIRE(it == v.begin());
- }
- }
-
- WHEN("inserting a range at the beginning")
- {
- auto initial_size = v.size();
- auto const arr = std::array<int, 3>{1, 2, 3};
- auto it = v.insert_range(v.begin(), arr);
-
- THEN("the size increases")
- {
- REQUIRE(v.size() == initial_size + 3);
- }
-
- THEN("the capacity increases")
- {
- REQUIRE(v.capacity() >= initial_size + 3);
- }
-
- THEN("the elements are inserted")
- {
- REQUIRE(v[0] == 1);
- REQUIRE(v[1] == 2);
- REQUIRE(v[2] == 3);
- REQUIRE(v[3] == 10);
- REQUIRE(v[4] == 20);
- REQUIRE(v[5] == 30);
- }
-
- THEN("the returned iterator points to the beginning of the inserted range")
- {
- REQUIRE(it == v.begin());
- }
- }
-
- WHEN("inserting a range at the end")
- {
- auto initial_size = v.size();
- auto const arr = std::array<int, 3>{1, 2, 3};
- auto it = v.insert_range(v.end(), arr);
-
- THEN("the size increases")
- {
- REQUIRE(v.size() == initial_size + 3);
- }
-
- THEN("the capacity increases")
- {
- REQUIRE(v.capacity() >= initial_size + 3);
- }
-
- THEN("the elements are inserted")
- {
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 20);
- REQUIRE(v[2] == 30);
- REQUIRE(v[3] == 1);
- REQUIRE(v[4] == 2);
- REQUIRE(v[5] == 3);
- }
-
- THEN("the returned iterator points to the beginning of the inserted range")
- {
- REQUIRE(it == v.begin() + initial_size);
- }
- }
-
- WHEN("inserting a range that causes reallocation")
- {
- auto initial_size = v.size();
- auto const arr = std::array<int, 3>{1, 2, 3};
- auto it = v.insert_range(v.begin() + 1, arr);
-
- THEN("the size increases")
- {
- REQUIRE(v.size() == initial_size + 3);
- }
-
- THEN("the capacity increases")
- {
- REQUIRE(v.capacity() >= initial_size + 3);
- }
-
- THEN("the elements are inserted")
- {
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 1);
- REQUIRE(v[2] == 2);
- REQUIRE(v[3] == 3);
- REQUIRE(v[4] == 20);
- REQUIRE(v[5] == 30);
- }
-
- THEN("the returned iterator points to the beginning of the inserted range")
- {
- REQUIRE(it == v.begin() + 1);
- }
- }
-
- WHEN("inserting fewer elements than the suffix without reallocation")
- {
- v.reserve(10);
- auto const capacity = v.capacity();
- auto const arr = std::array<int, 1>{1};
- auto it = v.insert_range(v.begin() + 1, arr);
-
- THEN("the elements are correctly placed")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 1);
- REQUIRE(v[2] == 20);
- REQUIRE(v[3] == 30);
- }
-
- THEN("no reallocation occurs")
- {
- REQUIRE(v.capacity() == capacity);
- }
-
- THEN("the returned iterator points to the inserted element")
- {
- REQUIRE(it == v.begin() + 1);
- }
- }
-
- WHEN("inserting fewer elements than the suffix without sufficient capacity")
- {
- v.shrink_to_fit();
- auto const arr = std::array<int, 1>{1};
- auto it = v.insert_range(v.begin() + 1, arr);
-
- THEN("the elements are correctly placed")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v[0] == 10);
- REQUIRE(v[1] == 1);
- REQUIRE(v[2] == 20);
- REQUIRE(v[3] == 30);
- }
-
- THEN("the returned iterator points to the inserted element")
- {
- REQUIRE(it == v.begin() + 1);
- }
- }
-
- WHEN("inserting from an input range without sufficient capacity")
- {
- auto const arr = std::array<int, 3>{1, 2, 3};
- auto const first = kstd::tests::test_input_iterator{arr.data(), arr.size()};
- auto const last = kstd::tests::test_input_iterator{};
- auto it = v.insert_range(v.begin(), std::ranges::subrange{first, last});
-
- THEN("the size increases")
- {
- REQUIRE(v.size() == 6);
- }
-
- THEN("the capacity increases")
- {
- REQUIRE(v.capacity() >= 6);
- }
-
- THEN("the elements are inserted")
- {
- REQUIRE(v[0] == 1);
- REQUIRE(v[1] == 2);
- REQUIRE(v[2] == 3);
- REQUIRE(v[3] == 10);
- REQUIRE(v[4] == 20);
- REQUIRE(v[5] == 30);
- }
-
- THEN("the returned iterator points to the beginning of the inserted range")
- {
- REQUIRE(it == v.begin());
- }
- }
- }
-}
-
-SCENARIO("Vector comparison", "[vector]")
-{
- GIVEN("Two identical vectors")
- {
- auto v1 = kstd::vector<int>{1, 2, 3};
- auto v2 = kstd::vector<int>{1, 2, 3};
-
- WHEN("comparing for equality")
- {
- THEN("the vectors are equal")
- {
- REQUIRE(v1 == v2);
- }
-
- THEN("the vectors and not not-equal")
- {
- REQUIRE_FALSE(v1 != v2);
- }
- }
-
- WHEN("comparing using the spaceship operator")
- {
- THEN("the vectors are equivalent")
- {
- REQUIRE((v1 <=> v2) == 0);
- REQUIRE(v1 <= v2);
- REQUIRE(v1 >= v2);
- }
- }
- }
-
- GIVEN("Two vectors of different sizes")
- {
- auto v1 = kstd::vector<int>{1, 2, 3};
- auto v2 = kstd::vector<int>{1, 2, 3, 4};
-
- WHEN("comparing for equality")
- {
- THEN("the vectors are not equal")
- {
- REQUIRE_FALSE(v1 == v2);
- }
-
- THEN("the vectors are not-equal")
- {
- REQUIRE(v1 != v2);
- }
- }
-
- WHEN("comparing for ordering")
- {
- THEN("the shorter vector evaluates as less than the longer vector")
- {
- REQUIRE(v1 < v2);
- REQUIRE(v2 > v1);
- }
- }
- }
-
- GIVEN("Two vectors of the same size but different elements")
- {
- auto v1 = kstd::vector<int>{1, 2, 3};
- auto v2 = kstd::vector<int>{1, 2, 4};
-
- WHEN("comparing for ordering")
- {
- THEN("they are ordered lexicographically")
- {
- REQUIRE(v1 < v2);
- REQUIRE(v2 > v1);
- }
- }
- }
-}
-
-SCENARIO("Vector with non-default-constructible types", "[vector]")
-{
- GIVEN("A type without a default constructor")
- {
- WHEN("constructing an empty vector")
- {
- auto v = kstd::vector<kstd::tests::non_default_constructible>{};
-
- THEN("the vector is empty")
- {
- REQUIRE(v.empty());
- }
- }
-
- WHEN("using emplace_back")
- {
- auto v = kstd::vector<kstd::tests::non_default_constructible>{};
- v.emplace_back(40);
-
- THEN("the element is added and the size and capacity increase")
- {
- REQUIRE(v.size() == 1);
- REQUIRE(v.back() == kstd::tests::non_default_constructible{40});
- }
- }
- }
-}
-
-SCENARIO("Vector with custom allocator", "[vector]")
-{
- GIVEN("a tracking allocator acting as the vector's memory manager")
- {
- auto allocations = 0;
- auto allocator = kstd::tests::tracking_allocator<int>{&allocations};
-
- WHEN("a vector uses this allocator to allocate memory")
- {
- auto v = kstd::vector<int, kstd::tests::tracking_allocator<int>>(allocator);
- REQUIRE(allocations == 0);
-
- v.reserve(10);
-
- THEN("the allocator was used to allocate memory")
- {
- REQUIRE(allocations > 0);
- }
- }
- }
-}
-
-SCENARIO("Vector modifier move semantics", "[vector]")
-{
- GIVEN("An empty vector and a move tracker element")
- {
- auto v = kstd::vector<kstd::tests::special_member_tracker>{};
- auto tracker = kstd::tests::special_member_tracker{40};
-
- WHEN("push_back is called with the move tracker")
- {
- v.push_back(std::move(tracker));
-
- THEN("the element is added and the size and capacity increase")
- {
- REQUIRE(v.size() == 1);
- REQUIRE(v.back().move_constructed_count == 1);
- REQUIRE(v.back().copy_constructed_count == 0);
- REQUIRE(v.back().value == 40);
- }
-
- THEN("the original tracker is left in a valid but unspecified state")
- {
- REQUIRE(tracker.value == -1);
- }
- }
- }
-
- GIVEN("An empty vector")
- {
- auto v = kstd::vector<kstd::tests::special_member_tracker>{};
-
- WHEN("emplace_back is called with constructor arguments")
- {
- v.emplace_back(40);
-
- THEN("the element is constructed directly, without moves or copies")
- {
- REQUIRE(v.size() == 1);
- REQUIRE(v.back().move_constructed_count == 0);
- REQUIRE(v.back().copy_constructed_count == 0);
- REQUIRE(v.back().value == 40);
- }
- }
- }
-
- GIVEN("A populated vector of move trackers")
- {
- auto v = kstd::vector<kstd::tests::special_member_tracker>{};
- v.reserve(10);
- v.emplace_back(10);
- v.emplace_back(20);
- v.emplace_back(30);
-
- WHEN("inserting an element in the middle with sufficient capacity")
- {
- auto const tracker = kstd::tests::special_member_tracker{15};
- v.insert(v.cbegin() + 1, tracker);
-
- THEN("the shifted elements are move-assigned and the new element is copy-assigned")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v[0].value == 10);
- REQUIRE(v[0].move_assigned_count == 0);
- REQUIRE(v[0].copy_assigned_count == 0);
- REQUIRE(v[1].value == 15);
- REQUIRE(v[1].move_assigned_count == 0);
- REQUIRE(v[1].copy_assigned_count == 1);
- REQUIRE(tracker.copied_from_count == 1);
- REQUIRE(v[2].value == 20);
- REQUIRE(v[2].move_assigned_count == 1);
- REQUIRE(v[2].copy_assigned_count == 0);
- REQUIRE(v[3].value == 30);
- REQUIRE(v[3].move_constructed_count == 1);
- }
- }
-
- WHEN("inserting an rvalue element in the middle with sufficient capacity")
- {
- auto tracker = kstd::tests::special_member_tracker{15};
- v.insert(v.cbegin() + 1, std::move(tracker));
-
- THEN("the shifted elements are move-assigned and the new element is move-assigned")
- {
- REQUIRE(v.size() == 4);
- REQUIRE(v[0].value == 10);
- REQUIRE(v[0].move_assigned_count == 0);
- REQUIRE(v[0].copy_assigned_count == 0);
- REQUIRE(v[1].value == 15);
- REQUIRE(v[1].move_assigned_count == 1);
- REQUIRE(v[1].copy_assigned_count == 0);
- REQUIRE(tracker.moved_from_count == 1);
- REQUIRE(v[2].value == 20);
- REQUIRE(v[2].move_assigned_count == 1);
- REQUIRE(v[3].value == 30);
- REQUIRE(v[3].move_constructed_count == 1);
- }
- }
-
- WHEN("erasing an element in the middle")
- {
- for (auto & elem : v)
- {
- elem.reset_counts();
- }
-
- auto it = v.erase(v.cbegin() + 1);
-
- THEN("the subsequent elements are move-assigned leftwards")
- {
- REQUIRE(v.size() == 2);
-
- REQUIRE(v[0].value == 10);
- REQUIRE(v[0].move_assigned_count == 0);
- REQUIRE(v[0].copy_assigned_count == 0);
-
- REQUIRE(v[1].value == 30);
- REQUIRE(v[1].move_assigned_count == 1);
- REQUIRE(v[1].copy_assigned_count == 0);
-
- REQUIRE(v.data()[2].destroyed_count == 1);
- REQUIRE(v.data()[2].moved_from_count == 1);
-
- REQUIRE(it == v.begin() + 1);
- }
- }
-
- WHEN("erasing the last element")
- {
- for (auto & elem : v)
- {
- elem.reset_counts();
- }
-
- auto it = v.erase(v.cend() - 1);
-
- THEN("no elements are moved, just the last element destroyed")
- {
- REQUIRE(v.size() == 2);
-
- REQUIRE(v[0].value == 10);
- REQUIRE(v[0].move_constructed_count == 0);
- REQUIRE(v[0].copy_constructed_count == 0);
- REQUIRE(v[0].move_assigned_count == 0);
- REQUIRE(v[0].copy_assigned_count == 0);
-
- REQUIRE(v[1].value == 20);
- REQUIRE(v[1].move_constructed_count == 0);
- REQUIRE(v[1].copy_constructed_count == 0);
- REQUIRE(v[1].move_assigned_count == 0);
- REQUIRE(v[1].copy_assigned_count == 0);
-
- REQUIRE(v.data()[2].destroyed_count == 1);
- REQUIRE(v.data()[2].moved_from_count == 0);
- REQUIRE(v.data()[2].copied_from_count == 0);
-
- REQUIRE(it == v.end());
- }
- }
-
- WHEN("erasing a range of elements in the middle")
- {
- v.emplace_back(40);
- v.emplace_back(50);
-
- for (auto & elem : v)
- {
- elem.reset_counts();
- }
-
- auto it = v.erase(v.cbegin() + 1, v.cbegin() + 3);
-
- THEN("the specified elements are destroyed and subsequent elements are move-assigned leftwards")
- {
- REQUIRE(v.size() == 3);
-
- REQUIRE(v[0].value == 10);
- REQUIRE(v[0].move_constructed_count == 0);
- REQUIRE(v[0].copy_constructed_count == 0);
- REQUIRE(v[0].move_assigned_count == 0);
- REQUIRE(v[0].copy_assigned_count == 0);
-
- REQUIRE(v[1].value == 40);
- REQUIRE(v[1].move_constructed_count == 0);
- REQUIRE(v[1].copy_constructed_count == 0);
- REQUIRE(v[1].move_assigned_count == 1);
- REQUIRE(v[1].copy_assigned_count == 0);
-
- REQUIRE(v[2].value == 50);
- REQUIRE(v[2].move_constructed_count == 0);
- REQUIRE(v[2].copy_constructed_count == 0);
- REQUIRE(v[2].move_assigned_count == 1);
- REQUIRE(v[2].copy_assigned_count == 0);
-
- REQUIRE(v.data()[3].destroyed_count == 1);
- REQUIRE(v.data()[3].moved_from_count == 1);
- REQUIRE(v.data()[3].copied_from_count == 0);
-
- REQUIRE(v.data()[4].destroyed_count == 1);
- REQUIRE(v.data()[4].moved_from_count == 1);
- REQUIRE(v.data()[4].copied_from_count == 0);
-
- REQUIRE(it == v.begin() + 1);
- }
- }
- }
-}
-
-SCENARIO("Vector advanced construction", "[vector]")
-{
- GIVEN("A count and a default value")
- {
- WHEN("constructing with count and default argument")
- {
- auto const count = 5uz;
- auto const value = 42;
- auto v = kstd::vector<int>(count, value);
-
- THEN("the vector is initialized with count copies of value")
- {
- REQUIRE(v.size() == 5);
- REQUIRE(v.capacity() == 5);
- REQUIRE(v.front() == 42);
- REQUIRE(v.back() == 42);
- }
- }
- }
-
- GIVEN("A pure input iterator range")
- {
- WHEN("constructing from input iterators")
- {
- auto const arr = std::array<int, 3>{1, 2, 3};
- auto const first = kstd::tests::test_input_iterator{arr.data(), arr.size()};
- auto const last = kstd::tests::test_input_iterator{};
-
- auto v = kstd::vector<int>(first, last);
-
- THEN("the vector is generated dynamically and initialized correctly")
- {
- REQUIRE(v.size() == 3);
- REQUIRE(v[0] == 1);
- REQUIRE(v[2] == 3);
- }
- }
- }
-
- GIVEN("A tracking allocator and a source vector")
- {
- auto allocs = 0;
- auto allocator = kstd::tests::tracking_allocator<int>{&allocs};
- auto source = kstd::vector<int, kstd::tests::tracking_allocator<int>>{allocator};
- source.push_back(1);
- source.push_back(2);
- source.push_back(3);
-
- allocs = 0;
-
- WHEN("copy constructing with an allocator")
- {
- auto copy = kstd::vector<int, kstd::tests::tracking_allocator<int>>(source, allocator);
-
- THEN("the copy succeeds and the allocator is used")
- {
- REQUIRE(copy.size() == 3);
- REQUIRE(allocs > 0);
- REQUIRE(copy[0] == 1);
- REQUIRE(copy[2] == 3);
- }
- }
-
- WHEN("move constructing with an identically comparing allocator")
- {
- auto moved = kstd::vector<int, kstd::tests::tracking_allocator<int>>(std::move(source), allocator);
-
- THEN("the move succeeds and no new allocations are made (memory is stolen)")
- {
- REQUIRE(moved.size() == 3);
- REQUIRE(allocs == 0);
- REQUIRE(moved[0] == 1);
- REQUIRE(moved[2] == 3);
- }
- }
-
- WHEN("move constructing with a non-equal allocator")
- {
- auto allocs2 = 0;
- auto allocator2 = kstd::tests::tracking_allocator<int>{&allocs2};
-
- auto moved = kstd::vector<int, kstd::tests::tracking_allocator<int>>(std::move(source), allocator2);
-
- THEN("the move allocates new memory and moves elements")
- {
- REQUIRE(allocs2 > 0);
- REQUIRE(moved.size() == 3);
- REQUIRE(source.empty());
- }
- }
- }
-}
-
-SCENARIO("Vector assignment operators", "[vector]")
-{
- GIVEN("A source vector and an empty target vector")
- {
- auto source = kstd::vector<int>{1, 2, 3};
- auto target = kstd::vector<int>{};
-
- WHEN("copy assigning")
- {
- target = source;
-
- THEN("the target matches the source")
- {
- REQUIRE(target.size() == 3);
- REQUIRE(target[0] == 1);
- REQUIRE(target[2] == 3);
- REQUIRE(source.size() == 3);
- }
- }
-
- WHEN("move assigning")
- {
- target = std::move(source);
-
- THEN("the target assumes the source's data")
- {
- REQUIRE(target.size() == 3);
- REQUIRE(target[0] == 1);
- REQUIRE(target[2] == 3);
- REQUIRE(source.empty());
- }
- }
- }
-
- GIVEN("Vectors with propagating copy allocator")
- {
- auto allocs1 = 0;
- auto allocs2 = 0;
- auto alloc1 = kstd::tests::propagating_allocator<int>{&allocs1};
- auto alloc2 = kstd::tests::propagating_allocator<int>{&allocs2};
-
- auto v1 = kstd::vector<int, kstd::tests::propagating_allocator<int>>{alloc1};
- v1.push_back(1);
- v1.push_back(2);
- auto v2 = kstd::vector<int, kstd::tests::propagating_allocator<int>>{alloc2};
-
- WHEN("copy assigning")
- {
- v2 = v1;
- THEN("the allocator propagates")
- {
- REQUIRE(v2.get_allocator() == v1.get_allocator());
- }
- }
- }
-
- GIVEN("Vectors for copy assignment overlap")
- {
- auto v1 = kstd::vector<int>{1, 2, 3};
- auto v2 = kstd::vector<int>{4, 5};
- v2.reserve(10);
-
- WHEN("copy assigning a larger vector to a smaller one with enough capacity")
- {
- v2 = v1;
- THEN("elements are copied and size is updated")
- {
- REQUIRE(v2.size() == 3);
- REQUIRE(v2.capacity() >= 10);
- REQUIRE(v2[2] == 3);
- }
- }
-
- auto v3 = kstd::vector<int>{1, 2, 3, 4};
- v3.reserve(10);
- WHEN("copy assigning a smaller vector to a larger one")
- {
- v3 = v1;
- THEN("excess elements are destroyed")
- {
- REQUIRE(v3.size() == 3);
- REQUIRE(v3[0] == 1);
- }
- }
- }
-
- GIVEN("Vectors with the same tracking allocator")
- {
- auto allocs = 0;
- auto alloc = kstd::tests::tracking_allocator<int>{&allocs};
- auto v1 = kstd::vector<int, kstd::tests::tracking_allocator<int>>{alloc};
- v1.push_back(1);
- auto v2 = kstd::vector<int, kstd::tests::tracking_allocator<int>>{alloc};
-
- WHEN("move assigning")
- {
- v2 = std::move(v1);
- THEN("memory is stolen without allocation")
- {
- REQUIRE(v2.size() == 1);
- REQUIRE(allocs == 1);
- }
- }
- }
-
- GIVEN("Vectors with different non-propagating tracking allocators")
- {
- auto allocs1 = 0;
- auto allocs2 = 0;
- auto alloc1 = kstd::tests::tracking_allocator<int>{&allocs1};
- auto alloc2 = kstd::tests::tracking_allocator<int>{&allocs2};
-
- auto v1 = kstd::vector<int, kstd::tests::tracking_allocator<int>>{alloc1};
- v1.push_back(1);
- v1.push_back(2);
- v1.push_back(3);
-
- auto v2 = kstd::vector<int, kstd::tests::tracking_allocator<int>>{alloc2};
- v2.push_back(4);
- v2.push_back(5);
-
- WHEN("move assigning a larger vector to a smaller one without enough capacity")
- {
- v2.shrink_to_fit();
- v2 = std::move(v1);
- THEN("memory is reallocated and elements are moved")
- {
- REQUIRE(v2.size() == 3);
- REQUIRE(allocs2 > 2);
- }
- }
-
- auto v3 = kstd::vector<int, kstd::tests::tracking_allocator<int>>{alloc2};
- v3.reserve(10);
- v3.push_back(4);
- v3.push_back(5);
- WHEN("move assigning a larger vector to a smaller one with enough capacity")
- {
- v3 = std::move(v1);
- THEN("elements are move-assigned over overlap and move-constructed over remainder")
- {
- REQUIRE(v3.size() == 3);
- }
- }
-
- auto v4 = kstd::vector<int, kstd::tests::tracking_allocator<int>>{alloc2};
- v4.reserve(10);
- v4.push_back(4);
- v4.push_back(5);
- v4.push_back(6);
- v4.push_back(7);
- WHEN("move assigning a smaller vector to a larger one with enough capacity")
- {
- v4 = std::move(v1);
- THEN("overlap is moved and excess is destroyed")
- {
- REQUIRE(v4.size() == 3);
- }
- }
- }
-}
-
-SCENARIO("Vector self-assignment operators", "[vector]")
-{
- GIVEN("A populated vector")
- {
- auto v = kstd::vector<int>{1, 2, 3};
- auto const initial_capacity = v.capacity();
- auto const * initial_data = v.data();
-
- WHEN("copy assigning to itself")
- {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wpragmas"
-#pragma GCC diagnostic ignored "-Wunknown-warning-option"
-#pragma GCC diagnostic ignored "-Wself-assign-overloaded"
- v = v;
-#pragma GCC diagnostic pop
-
- THEN("the vector remains unchanged")
- {
- REQUIRE(v.size() == 3);
- REQUIRE(v.capacity() == initial_capacity);
- REQUIRE(v.data() == initial_data);
- REQUIRE(v[0] == 1);
- REQUIRE(v[2] == 3);
- }
- }
-
- WHEN("move assigning to itself")
- {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wpragmas"
-#pragma GCC diagnostic ignored "-Wunknown-warning-option"
-#pragma GCC diagnostic ignored "-Wself-move"
- v = std::move(v);
-#pragma GCC diagnostic pop
-
- THEN("the vector remains unchanged")
- {
- REQUIRE(v.size() == 3);
- REQUIRE(v.capacity() == initial_capacity);
- REQUIRE(v.data() == initial_data);
- REQUIRE(v[0] == 1);
- REQUIRE(v[2] == 3);
- }
- }
- }
-}
-
-SCENARIO("Vector const accessors and copy insertion", "[vector]")
-{
- GIVEN("A const populated vector")
- {
- auto const v = kstd::vector<int>{10, 20, 30};
-
- WHEN("calling const accessors")
- {
- THEN("elements are read correctly as const references")
- {
- REQUIRE(v.front() == 10);
- REQUIRE(v.back() == 30);
- REQUIRE(v[1] == 20);
- REQUIRE(v.at(1) == 20);
- }
- }
- }
-
- GIVEN("An empty vector and a const lvalue tracker")
- {
- auto v = kstd::vector<kstd::tests::special_member_tracker>{};
- auto const tracker = kstd::tests::special_member_tracker{42};
-
- WHEN("push_back is called with the const lvalue")
- {
- v.push_back(tracker);
-
- THEN("the element is gracefully copy-constructed")
- {
- REQUIRE(v.size() == 1);
- REQUIRE(v.back().value == 42);
- REQUIRE(v.back().copy_constructed_count == 1);
- REQUIRE(v.back().move_constructed_count == 0);
- }
- }
-
- WHEN("push_back is called with a const lvalue when capacity is sufficient")
- {
- v.reserve(10);
- auto const current_capacity = v.capacity();
- v.push_back(tracker);
-
- THEN("the element is copy-constructed without reallocation")
- {
- REQUIRE(v.size() == 1);
- REQUIRE(v.capacity() == current_capacity);
- REQUIRE(v.back().value == 42);
- REQUIRE(v.back().copy_constructed_count == 1);
- REQUIRE(v.back().move_constructed_count == 0);
- }
- }
- }
-}