#include #include #include #include #include #include namespace stdplus { namespace { static std::vector reffed; static int stored_ref = 0; static std::vector dropped; static int stored_drop = 0; int ref(const int& i) { reffed.push_back(i); return i + 1; } void drop(int&& i) { dropped.push_back(std::move(i)); } int ref(const int& i, std::string&, int& si) { reffed.push_back(i); // Make sure we can update the stored data stored_ref = si++; return i + 1; } void drop(int&& i, std::string&, int& si) { dropped.push_back(std::move(i)); // Make sure we can update the stored data stored_drop = si++; } using SimpleHandle = Copyable::Handle; using StoreHandle = Copyable::Handle; class CopyableHandleTest : public ::testing::Test { protected: void SetUp() { reffed.clear(); dropped.clear(); } void TearDown() { EXPECT_TRUE(reffed.empty()); EXPECT_TRUE(dropped.empty()); } }; TEST_F(CopyableHandleTest, EmptyNoStorage) { SimpleHandle h(std::nullopt); EXPECT_FALSE(h); EXPECT_THROW(h.value(), std::bad_optional_access); h.reset(); EXPECT_FALSE(h); EXPECT_THROW(h.value(), std::bad_optional_access); } TEST_F(CopyableHandleTest, EmptyWithStorage) { auto maybeV = std::nullopt; StoreHandle h(maybeV, "str", 5); EXPECT_FALSE(h); EXPECT_THROW(h.value(), std::bad_optional_access); h.reset(maybeV); EXPECT_FALSE(h); EXPECT_THROW(h.value(), std::bad_optional_access); } TEST_F(CopyableHandleTest, SimplePopulated) { constexpr int expected = 3; { int val = expected; SimpleHandle h(std::move(val)); EXPECT_TRUE(h); EXPECT_EQ(expected, *h); EXPECT_EQ(expected, h.value()); EXPECT_TRUE(dropped.empty()); } EXPECT_EQ(std::vector{expected}, dropped); dropped.clear(); } TEST_F(CopyableHandleTest, OptionalPopulated) { constexpr int expected = 3; { std::optional maybeVal{expected}; SimpleHandle h(std::move(maybeVal)); EXPECT_TRUE(h); EXPECT_EQ(expected, *h); EXPECT_EQ(expected, h.value()); EXPECT_TRUE(dropped.empty()); } EXPECT_TRUE(reffed.empty()); EXPECT_EQ(std::vector{expected}, dropped); dropped.clear(); { const std::optional maybeVal{expected}; SimpleHandle h(maybeVal); EXPECT_TRUE(h); EXPECT_EQ(expected + 1, *h); EXPECT_EQ(expected + 1, h.value()); EXPECT_EQ(std::vector{expected}, reffed); reffed.clear(); EXPECT_TRUE(dropped.empty()); } EXPECT_EQ(std::vector{expected + 1}, dropped); dropped.clear(); } TEST_F(CopyableHandleTest, SimplePopulatedWithStorage) { constexpr int expected = 3; { StoreHandle h(expected, std::string{"str"}, 5); EXPECT_TRUE(h); EXPECT_EQ(expected + 1, *h); EXPECT_EQ(expected + 1, h.value()); EXPECT_EQ(5, stored_ref); EXPECT_EQ(std::vector{expected}, reffed); reffed.clear(); EXPECT_TRUE(dropped.empty()); } EXPECT_EQ(6, stored_drop); EXPECT_EQ(std::vector{expected + 1}, dropped); dropped.clear(); } TEST_F(CopyableHandleTest, ResetPopulatedWithStorage) { constexpr int expected = 3; const std::string s{"str"}; StoreHandle h(int{expected}, s, 5); EXPECT_TRUE(dropped.empty()); h.reset(std::nullopt); EXPECT_FALSE(h); EXPECT_THROW(h.value(), std::bad_optional_access); EXPECT_EQ(5, stored_drop); EXPECT_EQ(std::vector{expected}, dropped); dropped.clear(); } TEST_F(CopyableHandleTest, ResetNewPopulated) { constexpr int expected = 3, expected2 = 10; { SimpleHandle h(int{expected}); EXPECT_TRUE(dropped.empty()); h.reset(int{expected2}); EXPECT_TRUE(h); EXPECT_EQ(expected2, *h); EXPECT_EQ(expected2, h.value()); EXPECT_EQ(std::vector{expected}, dropped); dropped.clear(); } EXPECT_EQ(std::vector{expected2}, dropped); dropped.clear(); } TEST_F(CopyableHandleTest, ResetCopyPopulated) { constexpr int expected = 3, expected2 = 10; { SimpleHandle h(int{expected}); EXPECT_TRUE(reffed.empty()); EXPECT_TRUE(dropped.empty()); const std::optional maybe2{expected2}; h.reset(maybe2); EXPECT_TRUE(h); EXPECT_EQ(expected2 + 1, *h); EXPECT_EQ(expected2 + 1, h.value()); EXPECT_EQ(std::vector{expected2}, reffed); reffed.clear(); EXPECT_EQ(std::vector{expected}, dropped); dropped.clear(); } EXPECT_EQ(std::vector{expected2 + 1}, dropped); dropped.clear(); } TEST_F(CopyableHandleTest, ResetCopyPopulatedWithStorage) { constexpr int expected = 3, expected2 = 10; { StoreHandle h(int{expected}, "str", 5); EXPECT_TRUE(dropped.empty()); h.reset(expected2); EXPECT_TRUE(h); EXPECT_EQ(expected2 + 1, *h); EXPECT_EQ(expected2 + 1, h.value()); EXPECT_EQ(5, stored_ref); EXPECT_EQ(std::vector{expected2}, reffed); reffed.clear(); EXPECT_EQ(6, stored_drop); EXPECT_EQ(std::vector{expected}, dropped); dropped.clear(); } EXPECT_EQ(7, stored_drop); EXPECT_EQ(std::vector{expected2 + 1}, dropped); dropped.clear(); } TEST_F(CopyableHandleTest, MoveConstructWithStorage) { constexpr int expected = 3; StoreHandle h1(int{expected}, "str", 5); { StoreHandle h2(std::move(h1)); EXPECT_TRUE(dropped.empty()); EXPECT_FALSE(h1); EXPECT_THROW(h1.value(), std::bad_optional_access); EXPECT_TRUE(h2); EXPECT_EQ(expected, *h2); EXPECT_EQ(expected, h2.value()); } EXPECT_EQ(5, stored_drop); EXPECT_EQ(std::vector{expected}, dropped); dropped.clear(); } TEST_F(CopyableHandleTest, MoveAssignWithStorage) { constexpr int expected = 3, expected2 = 10; { StoreHandle h1(int{expected}, "str", 5); StoreHandle h2(int{expected2}, "str", 10); EXPECT_TRUE(dropped.empty()); h2 = std::move(h1); EXPECT_EQ(10, stored_drop); EXPECT_EQ(std::vector{expected2}, dropped); dropped.clear(); EXPECT_FALSE(h1); EXPECT_THROW(h1.value(), std::bad_optional_access); EXPECT_TRUE(h2); EXPECT_EQ(expected, *h2); EXPECT_EQ(expected, h2.value()); } EXPECT_EQ(5, stored_drop); EXPECT_EQ(std::vector{expected}, dropped); dropped.clear(); } TEST_F(CopyableHandleTest, CopyConstructSrcEmptyWithStorage) { StoreHandle h1(std::nullopt, "str", 5); StoreHandle h2(h1); } TEST_F(CopyableHandleTest, CopyConstructWithStorage) { constexpr int expected = 3; StoreHandle h1(int{expected}, "str", 5); StoreHandle h2(h1); EXPECT_EQ(5, stored_ref); EXPECT_EQ(std::vector{expected}, reffed); reffed.clear(); h1.reset(); EXPECT_EQ(5, stored_drop); EXPECT_EQ(std::vector{expected}, dropped); dropped.clear(); h2.reset(); EXPECT_EQ(6, stored_drop); EXPECT_EQ(std::vector{expected + 1}, dropped); dropped.clear(); } TEST_F(CopyableHandleTest, CopyAssignBothEmptyWithStorage) { StoreHandle h1(std::nullopt, "str", 5); StoreHandle h2(std::nullopt, "str", 10); h2 = h1; } TEST_F(CopyableHandleTest, CopyAssignSrcEmptyWithStorage) { constexpr int expected = 3; StoreHandle h1(std::nullopt, "str", 5); StoreHandle h2(int{expected}, "str", 10); h2 = h1; EXPECT_EQ(10, stored_drop); EXPECT_EQ(std::vector{expected}, dropped); dropped.clear(); } TEST_F(CopyableHandleTest, CopyAssignDstEmptyWithStorage) { constexpr int expected = 3; StoreHandle h1(int{expected}, "str", 5); StoreHandle h2(std::nullopt, "str", 10); h2 = h1; EXPECT_EQ(5, stored_ref); EXPECT_EQ(std::vector{expected}, reffed); reffed.clear(); h1.reset(); EXPECT_EQ(5, stored_drop); EXPECT_EQ(std::vector{expected}, dropped); dropped.clear(); h2.reset(); EXPECT_EQ(6, stored_drop); EXPECT_EQ(std::vector{expected + 1}, dropped); dropped.clear(); } TEST_F(CopyableHandleTest, CopyAssignWithStorage) { constexpr int expected = 3, expected2 = 15; StoreHandle h1(int{expected}, "str", 5); StoreHandle h2(int{expected2}, "str", 10); h2 = h1; EXPECT_EQ(10, stored_drop); EXPECT_EQ(std::vector{expected2}, dropped); dropped.clear(); EXPECT_EQ(5, stored_ref); EXPECT_EQ(std::vector{expected}, reffed); reffed.clear(); h1.reset(); EXPECT_EQ(5, stored_drop); EXPECT_EQ(std::vector{expected}, dropped); dropped.clear(); h2.reset(); EXPECT_EQ(6, stored_drop); EXPECT_EQ(std::vector{expected + 1}, dropped); dropped.clear(); } } // namespace } // namespace stdplus