From 7a5e23259a696bf240a14200535680b42c445096 Mon Sep 17 00:00:00 2001 From: "William A. Kennington III" Date: Fri, 2 Nov 2018 17:28:35 -0700 Subject: handle/managed: Implement non-copyable handle This is a generic handle type that holds a resource and uses RAII to call a user defined function when the resource is destroyed. A future change will implement a smart file descriptor based on this interface. A follow up change will implement the copyable version. Tested: Built and run through unit tests. Change-Id: Ia8da1d662319e8fb58380ed4979bcf1b74f66dfb Signed-off-by: William A. Kennington III --- test/Makefile.am | 5 ++ test/handle/managed.cpp | 209 ++++++++++++++++++++++++++++++++++++++++++++++++ test/meson.build | 1 + 3 files changed, 215 insertions(+) create mode 100644 test/handle/managed.cpp (limited to 'test') diff --git a/test/Makefile.am b/test/Makefile.am index 1c4a5a1..45f54f4 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -7,6 +7,11 @@ gtest_ldadd = $(STDPLUS_LIBS) $(GTEST_LIBS) $(GMOCK_LIBS) -lgmock_main check_PROGRAMS = TESTS = $(check_PROGRAMS) +check_PROGRAMS += handle/managed +handle_managed_SOURCES = handle/managed.cpp +handle_managed_CPPFLAGS = $(gtest_cppflags) +handle_managed_LDADD = $(gtest_ldadd) + check_PROGRAMS += signal signal_SOURCES = signal.cpp signal_CPPFLAGS = $(gtest_cppflags) diff --git a/test/handle/managed.cpp b/test/handle/managed.cpp new file mode 100644 index 0000000..b3ba6a6 --- /dev/null +++ b/test/handle/managed.cpp @@ -0,0 +1,209 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace stdplus +{ +namespace +{ + +static std::vector dropped; +static int stored = 0; + +void drop(int&& i) +{ + dropped.push_back(std::move(i)); +} + +void drop(int&& i, std::string&, int& si) +{ + dropped.push_back(std::move(i)); + // Make sure we can update the stored data + stored = si++; +} + +using SimpleHandle = Managed::Handle; +using StoreHandle = Managed::Handle; + +class ManagedHandleTest : public ::testing::Test +{ + protected: + void SetUp() + { + dropped.clear(); + } + + void TearDown() + { + EXPECT_TRUE(dropped.empty()); + } +}; + +TEST_F(ManagedHandleTest, EmptyNoStorage) +{ + SimpleHandle h(std::nullopt); + EXPECT_FALSE(h); + EXPECT_THROW(h.value(), std::bad_optional_access); + h.reset(); + EXPECT_FALSE(h.has_value()); + EXPECT_THROW(h.value(), std::bad_optional_access); + EXPECT_EQ(std::nullopt, h.maybe_value()); +} + +TEST_F(ManagedHandleTest, EmptyWithStorage) +{ + StoreHandle h(std::nullopt, "str", 5); + EXPECT_FALSE(h); + EXPECT_THROW(h.value(), std::bad_optional_access); + h.reset(std::nullopt); + EXPECT_FALSE(h); + EXPECT_THROW(h.value(), std::bad_optional_access); + + StoreHandle h2(std::nullopt, std::make_tuple("str", 5)); + EXPECT_FALSE(h2); + EXPECT_THROW(h2.value(), std::bad_optional_access); +} + +TEST_F(ManagedHandleTest, SimplePopulated) +{ + constexpr int expected = 3; + { + int val = expected; + SimpleHandle h(std::move(val)); + EXPECT_TRUE(h.has_value()); + EXPECT_EQ(expected, *h); + EXPECT_EQ(expected, h.value()); + EXPECT_EQ(expected, h.maybe_value()); + EXPECT_TRUE(dropped.empty()); + } + EXPECT_EQ(std::vector{expected}, dropped); + dropped.clear(); +} + +TEST_F(ManagedHandleTest, 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_EQ(std::vector{expected}, dropped); + dropped.clear(); +} + +TEST_F(ManagedHandleTest, SimplePopulatedWithStorage) +{ + constexpr int expected = 3; + { + StoreHandle h(int{expected}, std::make_tuple(std::string{"str"}, 5)); + EXPECT_TRUE(h); + EXPECT_EQ(expected, *h); + EXPECT_EQ(expected, h.value()); + EXPECT_TRUE(dropped.empty()); + } + EXPECT_EQ(5, stored); + EXPECT_EQ(std::vector{expected}, dropped); + dropped.clear(); +} + +TEST_F(ManagedHandleTest, 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); + EXPECT_EQ(std::vector{expected}, dropped); + dropped.clear(); +} + +TEST_F(ManagedHandleTest, 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(ManagedHandleTest, ResetNewPopulatedWithStorage) +{ + constexpr int expected = 3, expected2 = 10; + { + StoreHandle h(int{expected}, "str", 5); + EXPECT_TRUE(dropped.empty()); + h.reset(int{expected2}); + EXPECT_TRUE(h); + EXPECT_EQ(expected2, *h); + EXPECT_EQ(expected2, h.value()); + EXPECT_EQ(5, stored); + EXPECT_EQ(std::vector{expected}, dropped); + dropped.clear(); + } + EXPECT_EQ(6, stored); + EXPECT_EQ(std::vector{expected2}, dropped); + dropped.clear(); +} + +TEST_F(ManagedHandleTest, 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); + EXPECT_EQ(std::vector{expected}, dropped); + dropped.clear(); +} + +TEST_F(ManagedHandleTest, 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); + 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); + EXPECT_EQ(std::vector{expected}, dropped); + dropped.clear(); +} + +} // namespace +} // namespace stdplus diff --git a/test/meson.build b/test/meson.build index b918d5d..812de29 100644 --- a/test/meson.build +++ b/test/meson.build @@ -3,6 +3,7 @@ gmock = dependency('gmock', disabler: true, required: build_tests) tests = [ 'signal', + 'handle/managed', ] foreach t : tests -- cgit v1.2.1