#include "kstd/tests/os_panic.hpp" #include #include #include #include #include #include SCENARIO("Vector initialization and construction", "[vector]") { GIVEN("An empty context") { WHEN("constructing by default") { kstd::vector 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 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 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{1, 2, 3}; WHEN("constructing from a random-access iterator range") { auto v = kstd::vector{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{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 source = {1, 2, 3, 4, 5}; WHEN("copy constructing a new vector") { kstd::vector 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 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 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 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 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 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 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); } } } }