aboutsummaryrefslogtreecommitdiff
path: root/libs/kstd/tests/src
diff options
context:
space:
mode:
Diffstat (limited to 'libs/kstd/tests/src')
-rw-r--r--libs/kstd/tests/src/flat_map.cpp288
-rw-r--r--libs/kstd/tests/src/vector.cpp223
2 files changed, 511 insertions, 0 deletions
diff --git a/libs/kstd/tests/src/flat_map.cpp b/libs/kstd/tests/src/flat_map.cpp
new file mode 100644
index 0000000..cde136a
--- /dev/null
+++ b/libs/kstd/tests/src/flat_map.cpp
@@ -0,0 +1,288 @@
+#include <kstd/flat_map>
+#include <kstd/tests/os_panic.hpp>
+
+#include <catch2/catch_test_macros.hpp>
+
+#include <functional>
+
+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());
+ }
+ }
+
+ 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/vector.cpp b/libs/kstd/tests/src/vector.cpp
index 0735c9a..b7971f4 100644
--- a/libs/kstd/tests/src/vector.cpp
+++ b/libs/kstd/tests/src/vector.cpp
@@ -475,6 +475,20 @@ SCENARIO("Vector modifiers", "[vector]")
REQUIRE(it == v.begin());
}
}
+
+ WHEN("inserting an lvalue element")
+ {
+ auto const value = 42;
+ 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] == 42);
+ REQUIRE(it == v.begin());
+ }
+ }
}
GIVEN("A populated vector")
@@ -597,6 +611,22 @@ SCENARIO("Vector modifiers", "[vector]")
}
}
+ 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);
@@ -649,6 +679,114 @@ SCENARIO("Vector modifiers", "[vector]")
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);
+ }
+ }
}
}
@@ -868,6 +1006,91 @@ SCENARIO("Vector modifier move semantics", "[vector]")
REQUIRE(v[3].was_moved);
}
}
+
+ WHEN("erasing an element in the middle")
+ {
+ for (auto & elem : v)
+ {
+ elem.was_copied = false;
+ elem.was_moved = false;
+ }
+
+ 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_FALSE(v[0].was_moved);
+ REQUIRE_FALSE(v[0].was_copied);
+
+ REQUIRE(v[1].value == 30);
+ REQUIRE(v[1].was_moved);
+ REQUIRE_FALSE(v[1].was_copied);
+
+ REQUIRE(it == v.begin() + 1);
+ }
+ }
+
+ WHEN("erasing the last element")
+ {
+ for (auto & elem : v)
+ {
+ elem.was_copied = false;
+ elem.was_moved = false;
+ }
+
+ 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_FALSE(v[0].was_moved);
+ REQUIRE_FALSE(v[0].was_copied);
+
+ REQUIRE(v[1].value == 20);
+ REQUIRE_FALSE(v[1].was_moved);
+ REQUIRE_FALSE(v[1].was_copied);
+
+ 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.was_copied = false;
+ elem.was_moved = false;
+ }
+
+ 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_FALSE(v[0].was_moved);
+ REQUIRE_FALSE(v[0].was_copied);
+
+ REQUIRE(v[1].value == 40);
+ REQUIRE(v[1].was_moved);
+ REQUIRE_FALSE(v[1].was_copied);
+
+ REQUIRE(v[2].value == 50);
+ REQUIRE(v[2].was_moved);
+ REQUIRE_FALSE(v[2].was_copied);
+
+ REQUIRE(it == v.begin() + 1);
+ }
+ }
}
}