#include #include #include #include #include #include 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{}; THEN("the observer pointer is null") { REQUIRE_FALSE(ptr); } } WHEN("constructing from a nullptr") { auto ptr = kstd::observer_ptr{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(&value); kstd::observer_ptr 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>); } } } } 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(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(ptr)); } } } GIVEN("A null observer pointer") { auto ptr = kstd::observer_ptr{}; WHEN("checking the observer pointer as a boolean") { THEN("it returns false") { REQUIRE_FALSE(static_cast(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{}; WHEN("comparing with another null observer pointer") { auto other_ptr = kstd::observer_ptr{}; THEN("they are equal") { REQUIRE(ptr == other_ptr); REQUIRE((ptr <=> other_ptr) == std::strong_ordering::equal); } } } }