aboutsummaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-03-23 10:32:15 +0100
committerFelix Morgner <felix.morgner@ost.ch>2026-03-23 10:32:15 +0100
commit48a2c33d205397adeaad385aebc1d1e008915b3e (patch)
tree379265414d551747585a1f86b9f390539ef2dfeb /libs
parent754012dd458985a6a4953c99204c6651318892b2 (diff)
downloadteachos-48a2c33d205397adeaad385aebc1d1e008915b3e.tar.xz
teachos-48a2c33d205397adeaad385aebc1d1e008915b3e.zip
ci: enable test builds
Diffstat (limited to 'libs')
-rw-r--r--libs/kstd/CMakeLists.txt11
-rw-r--r--libs/kstd/tests/include/kstd/tests/os_panic.hpp23
-rw-r--r--libs/kstd/tests/os_mock.cpp15
-rw-r--r--libs/kstd/tests/src/os_panic.cpp15
-rw-r--r--libs/kstd/tests/src/vector.cpp395
-rw-r--r--libs/kstd/tests/vector.cpp11
6 files changed, 442 insertions, 28 deletions
diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt
index 2f360cd..06543ab 100644
--- a/libs/kstd/CMakeLists.txt
+++ b/libs/kstd/CMakeLists.txt
@@ -44,8 +44,12 @@ endif()
if(NOT CMAKE_CROSSCOMPILING)
add_executable("kstd_tests"
- "tests/vector.cpp"
- "tests/os_mock.cpp"
+ "tests/src/vector.cpp"
+ "tests/src/os_panic.cpp"
+ )
+
+ target_include_directories("kstd_tests" PRIVATE
+ "tests/include"
)
target_link_libraries("kstd_tests" PRIVATE
@@ -59,5 +63,8 @@ if(NOT CMAKE_CROSSCOMPILING)
EXCLUDE_FROM_ALL NO
)
+ enable_coverage("kstd")
+ enable_coverage("kstd_tests")
+
catch_discover_tests("kstd_tests")
endif() \ No newline at end of file
diff --git a/libs/kstd/tests/include/kstd/tests/os_panic.hpp b/libs/kstd/tests/include/kstd/tests/os_panic.hpp
new file mode 100644
index 0000000..4396a9f
--- /dev/null
+++ b/libs/kstd/tests/include/kstd/tests/os_panic.hpp
@@ -0,0 +1,23 @@
+#ifndef KSTD_TESTS_OS_PANIC_HPP
+#define KSTD_TESTS_OS_PANIC_HPP
+
+#include <source_location>
+#include <stdexcept>
+#include <string>
+
+namespace kstd::tests
+{
+
+ struct os_panic : std::runtime_error
+ {
+ os_panic(std::string message, std::source_location location)
+ : std::runtime_error{message}
+ , location(location)
+ {}
+
+ std::source_location location;
+ };
+
+} // namespace kstd::tests
+
+#endif \ No newline at end of file
diff --git a/libs/kstd/tests/os_mock.cpp b/libs/kstd/tests/os_mock.cpp
deleted file mode 100644
index 39b7f0d..0000000
--- a/libs/kstd/tests/os_mock.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <exception>
-#include <format>
-#include <source_location>
-#include <stdexcept>
-#include <string_view>
-
-namespace kstd::os
-{
- auto panic(std::string_view message, std::source_location location)
- {
- auto full_message =
- std::format("OS Panic Handler called '{}' at {}:{}", message, location.file_name(), location.line());
- throw std::runtime_error{full_message};
- }
-} // namespace kstd::os \ No newline at end of file
diff --git a/libs/kstd/tests/src/os_panic.cpp b/libs/kstd/tests/src/os_panic.cpp
new file mode 100644
index 0000000..3eae6ff
--- /dev/null
+++ b/libs/kstd/tests/src/os_panic.cpp
@@ -0,0 +1,15 @@
+#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/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
diff --git a/libs/kstd/tests/vector.cpp b/libs/kstd/tests/vector.cpp
deleted file mode 100644
index 3a45008..0000000
--- a/libs/kstd/tests/vector.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#include <kstd/vector>
-
-#include <catch2/catch_test_macros.hpp>
-
-TEST_CASE("Creating an empty vector")
-{
- kstd::vector<int> v;
- REQUIRE(v.empty());
- REQUIRE(v.size() == 0);
- REQUIRE(v.capacity() == 0);
-}