diff options
Diffstat (limited to 'libs/kstd/tests/src/vector.cpp')
| -rw-r--r-- | libs/kstd/tests/src/vector.cpp | 395 |
1 files changed, 395 insertions, 0 deletions
diff --git a/libs/kstd/tests/src/vector.cpp b/libs/kstd/tests/src/vector.cpp new file mode 100644 index 0000000..cb1b182 --- /dev/null +++ b/libs/kstd/tests/src/vector.cpp @@ -0,0 +1,395 @@ +#include "kstd/tests/os_panic.hpp" + +#include <kstd/ranges> +#include <kstd/vector> + +#include <catch2/catch_test_macros.hpp> + +#include <array> +#include <ranges> +#include <utility> + +SCENARIO("Vector initialization and construction", "[vector]") +{ + GIVEN("An empty context") + { + WHEN("constructing by default") + { + kstd::vector<int> v; + + 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") + { + kstd::vector<int> v(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") + { + kstd::vector<int> v = {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") + { + kstd::vector<int> source = {1, 2, 3, 4, 5}; + + WHEN("copy constructing a new vector") + { + kstd::vector<int> copy(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") + { + kstd::vector<int> moved(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") + { + kstd::vector<int> v = {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") + { + kstd::vector<int> v = {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") + { + kstd::vector<int> v; + + 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") + { + kstd::vector<int> v; + + 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()); + } + } + } + + GIVEN("A populated vector with excess capacity") + { + kstd::vector<int> v{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); + } + } + } +}
\ No newline at end of file |
