aboutsummaryrefslogtreecommitdiff
path: root/libs/kstd/tests/src/observer_ptr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/kstd/tests/src/observer_ptr.cpp')
-rw-r--r--libs/kstd/tests/src/observer_ptr.cpp359
1 files changed, 359 insertions, 0 deletions
diff --git a/libs/kstd/tests/src/observer_ptr.cpp b/libs/kstd/tests/src/observer_ptr.cpp
new file mode 100644
index 0000000..006ebde
--- /dev/null
+++ b/libs/kstd/tests/src/observer_ptr.cpp
@@ -0,0 +1,359 @@
+#include <kstd/memory>
+#include <kstd/tests/os_panic.hpp>
+
+#include <catch2/catch_test_macros.hpp>
+
+#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")
+ {
+ int arr[] = {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