blob: 6ce210f059e550d8f2baa591ed56662e9d76c363 [file] [log] [blame]
#include <gtest/gtest.h>
#include <optional>
#include <stdplus/handle/copyable.hpp>
#include <string>
#include <utility>
#include <vector>
namespace stdplus
{
namespace
{
static std::vector<int> reffed;
static int stored_ref = 0;
static std::vector<int> 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<int>::Handle<drop, ref>;
using StoreHandle = Copyable<int, std::string, int>::Handle<drop, ref>;
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<int> 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<int> 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<int> 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