diff options
| author | William A. Kennington III <wak@google.com> | 2018-11-02 17:29:15 -0700 |
|---|---|---|
| committer | William A. Kennington III <wak@google.com> | 2019-03-29 21:14:57 +0000 |
| commit | e847ef8bbd5accd36a3287c686894418721c6798 (patch) | |
| tree | 551abef5024682e55fcca07fc26a60ac4ac2f379 /test/handle/copyable.cpp | |
| parent | 7a5e23259a696bf240a14200535680b42c445096 (diff) | |
| download | stdplus-e847ef8bbd5accd36a3287c686894418721c6798.tar.gz stdplus-e847ef8bbd5accd36a3287c686894418721c6798.zip | |
handle/copyable: Implement 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 copied or destroyed.
Tested:
Built and run through unit tests.
Change-Id: I3d23544b2e7c8d8c6686effc03b3b7433ea18bf5
Signed-off-by: William A. Kennington III <wak@google.com>
Diffstat (limited to 'test/handle/copyable.cpp')
| -rw-r--r-- | test/handle/copyable.cpp | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/test/handle/copyable.cpp b/test/handle/copyable.cpp new file mode 100644 index 0000000..6ce210f --- /dev/null +++ b/test/handle/copyable.cpp @@ -0,0 +1,347 @@ +#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 |

