blob: 0cdbe748d4e16d987dcc65e6f4af621e37f28249 [file] [log] [blame]
William A. Kennington III7a5e2322018-11-02 17:28:35 -07001#include <stdplus/handle/managed.hpp>
Patrick Williamsd1984dd2023-05-10 16:12:44 -05002
3#include <optional>
William A. Kennington III7a5e2322018-11-02 17:28:35 -07004#include <string>
5#include <tuple>
6#include <utility>
7#include <vector>
8
Patrick Williamsd1984dd2023-05-10 16:12:44 -05009#include <gtest/gtest.h>
10
William A. Kennington III7a5e2322018-11-02 17:28:35 -070011namespace stdplus
12{
13namespace
14{
15
16static std::vector<int> dropped;
17static int stored = 0;
18
William A. Kennington III7910ae02019-11-11 12:13:25 -080019struct SimpleDrop
20{
21 void operator()(int&& i) noexcept
22 {
23 dropped.push_back(std::move(i));
24 }
25};
26
William A. Kennington III7a5e2322018-11-02 17:28:35 -070027void drop(int&& i)
28{
William A. Kennington III7910ae02019-11-11 12:13:25 -080029 SimpleDrop()(std::move(i));
William A. Kennington III7a5e2322018-11-02 17:28:35 -070030}
31
William A. Kennington III7910ae02019-11-11 12:13:25 -080032struct StoreDrop
William A. Kennington III7a5e2322018-11-02 17:28:35 -070033{
William A. Kennington III7910ae02019-11-11 12:13:25 -080034 void operator()(int&& i, std::string&, int& si)
35 {
36 dropped.push_back(std::move(i));
37 // Make sure we can update the stored data
38 stored = si++;
39 }
40};
William A. Kennington III7a5e2322018-11-02 17:28:35 -070041
William A. Kennington III7910ae02019-11-11 12:13:25 -080042using SimpleHandleOld = Managed<int>::Handle<drop>;
43using SimpleHandle = Managed<int>::HandleF<SimpleDrop>;
44using StoreHandle = Managed<int, std::string, int>::HandleF<StoreDrop>;
William A. Kennington III7a5e2322018-11-02 17:28:35 -070045
William A. Kennington III1007be92019-11-11 12:18:37 -080046static_assert(std::is_nothrow_move_constructible_v<SimpleHandle>);
47static_assert(std::is_nothrow_move_assignable_v<SimpleHandle>);
48static_assert(std::is_nothrow_destructible_v<SimpleHandle>);
49static_assert(noexcept(std::declval<SimpleHandle>().reset()));
50// http://cplusplus.github.io/LWG/lwg-active.html#2116
51// static_assert(std::is_nothrow_move_constructible_v<StoreHandle>);
52static_assert(!std::is_nothrow_move_assignable_v<StoreHandle>);
53static_assert(!std::is_nothrow_destructible_v<StoreHandle>);
54static_assert(!noexcept(std::declval<StoreHandle>().reset()));
55
William A. Kennington III7a5e2322018-11-02 17:28:35 -070056class ManagedHandleTest : public ::testing::Test
57{
58 protected:
59 void SetUp()
60 {
61 dropped.clear();
62 }
63
64 void TearDown()
65 {
66 EXPECT_TRUE(dropped.empty());
67 }
68};
69
70TEST_F(ManagedHandleTest, EmptyNoStorage)
71{
William A. Kennington III7910ae02019-11-11 12:13:25 -080072 SimpleHandleOld h(std::nullopt);
William A. Kennington III7a5e2322018-11-02 17:28:35 -070073 EXPECT_FALSE(h);
74 EXPECT_THROW(h.value(), std::bad_optional_access);
William A. Kennington III079cba72019-07-01 17:28:32 -070075 EXPECT_THROW((void)h.release(), std::bad_optional_access);
William A. Kennington III7a5e2322018-11-02 17:28:35 -070076 h.reset();
77 EXPECT_FALSE(h.has_value());
78 EXPECT_THROW(h.value(), std::bad_optional_access);
William A. Kennington III079cba72019-07-01 17:28:32 -070079 EXPECT_THROW((void)h.release(), std::bad_optional_access);
William A. Kennington III7a5e2322018-11-02 17:28:35 -070080 EXPECT_EQ(std::nullopt, h.maybe_value());
William A. Kennington III079cba72019-07-01 17:28:32 -070081 EXPECT_EQ(std::nullopt, h.maybe_release());
William A. Kennington III7a5e2322018-11-02 17:28:35 -070082}
83
84TEST_F(ManagedHandleTest, EmptyWithStorage)
85{
86 StoreHandle h(std::nullopt, "str", 5);
87 EXPECT_FALSE(h);
88 EXPECT_THROW(h.value(), std::bad_optional_access);
89 h.reset(std::nullopt);
90 EXPECT_FALSE(h);
91 EXPECT_THROW(h.value(), std::bad_optional_access);
92
93 StoreHandle h2(std::nullopt, std::make_tuple<std::string, int>("str", 5));
94 EXPECT_FALSE(h2);
95 EXPECT_THROW(h2.value(), std::bad_optional_access);
96}
97
98TEST_F(ManagedHandleTest, SimplePopulated)
99{
100 constexpr int expected = 3;
101 {
102 int val = expected;
103 SimpleHandle h(std::move(val));
104 EXPECT_TRUE(h.has_value());
105 EXPECT_EQ(expected, *h);
106 EXPECT_EQ(expected, h.value());
107 EXPECT_EQ(expected, h.maybe_value());
108 EXPECT_TRUE(dropped.empty());
109 }
110 EXPECT_EQ(std::vector{expected}, dropped);
111 dropped.clear();
112}
113
114TEST_F(ManagedHandleTest, OptionalPopulated)
115{
116 constexpr int expected = 3;
117 {
118 std::optional<int> maybeVal{expected};
119 SimpleHandle h(std::move(maybeVal));
120 EXPECT_TRUE(h);
121 EXPECT_EQ(expected, *h);
122 EXPECT_EQ(expected, h.value());
123 EXPECT_TRUE(dropped.empty());
124 }
125 EXPECT_EQ(std::vector{expected}, dropped);
126 dropped.clear();
127}
128
129TEST_F(ManagedHandleTest, SimplePopulatedWithStorage)
130{
131 constexpr int expected = 3;
132 {
133 StoreHandle h(int{expected}, std::make_tuple(std::string{"str"}, 5));
134 EXPECT_TRUE(h);
135 EXPECT_EQ(expected, *h);
136 EXPECT_EQ(expected, h.value());
137 EXPECT_TRUE(dropped.empty());
138 }
139 EXPECT_EQ(5, stored);
140 EXPECT_EQ(std::vector{expected}, dropped);
141 dropped.clear();
142}
143
144TEST_F(ManagedHandleTest, ResetPopulatedWithStorage)
145{
146 constexpr int expected = 3;
147 const std::string s{"str"};
148 StoreHandle h(int{expected}, s, 5);
149 EXPECT_TRUE(dropped.empty());
150 h.reset(std::nullopt);
151 EXPECT_FALSE(h);
152 EXPECT_THROW(h.value(), std::bad_optional_access);
153 EXPECT_EQ(5, stored);
154 EXPECT_EQ(std::vector{expected}, dropped);
155 dropped.clear();
156}
157
158TEST_F(ManagedHandleTest, ResetNewPopulated)
159{
160 constexpr int expected = 3, expected2 = 10;
161 {
162 SimpleHandle h(int{expected});
163 EXPECT_TRUE(dropped.empty());
164 h.reset(int{expected2});
165 EXPECT_TRUE(h);
166 EXPECT_EQ(expected2, *h);
167 EXPECT_EQ(expected2, h.value());
168 EXPECT_EQ(std::vector{expected}, dropped);
169 dropped.clear();
170 }
171 EXPECT_EQ(std::vector{expected2}, dropped);
172 dropped.clear();
173}
174
175TEST_F(ManagedHandleTest, ResetNewPopulatedWithStorage)
176{
177 constexpr int expected = 3, expected2 = 10;
178 {
179 StoreHandle h(int{expected}, "str", 5);
180 EXPECT_TRUE(dropped.empty());
181 h.reset(int{expected2});
182 EXPECT_TRUE(h);
183 EXPECT_EQ(expected2, *h);
184 EXPECT_EQ(expected2, h.value());
185 EXPECT_EQ(5, stored);
186 EXPECT_EQ(std::vector{expected}, dropped);
187 dropped.clear();
188 }
189 EXPECT_EQ(6, stored);
190 EXPECT_EQ(std::vector{expected2}, dropped);
191 dropped.clear();
192}
193
William A. Kennington III079cba72019-07-01 17:28:32 -0700194TEST_F(ManagedHandleTest, Release)
195{
196 constexpr int expected = 3;
197 int val = expected;
198 SimpleHandle h(std::move(val));
199 EXPECT_EQ(expected, h.release());
200 EXPECT_FALSE(h);
201}
202
203TEST_F(ManagedHandleTest, MaybeRelease)
204{
205 constexpr int expected = 3;
206 int val = expected;
207 SimpleHandle h(std::move(val));
208 EXPECT_EQ(expected, h.maybe_release());
209 EXPECT_FALSE(h);
210}
211
William A. Kennington III7a5e2322018-11-02 17:28:35 -0700212TEST_F(ManagedHandleTest, MoveConstructWithStorage)
213{
214 constexpr int expected = 3;
215 StoreHandle h1(int{expected}, "str", 5);
216 {
217 StoreHandle h2(std::move(h1));
218 EXPECT_TRUE(dropped.empty());
219 EXPECT_FALSE(h1);
William A. Kennington III49d92692023-06-06 14:02:01 -0700220 // NOLINTNEXTLINE(clang-analyzer-cplusplus.Move)
William A. Kennington III7a5e2322018-11-02 17:28:35 -0700221 EXPECT_THROW(h1.value(), std::bad_optional_access);
222 EXPECT_TRUE(h2);
223 EXPECT_EQ(expected, *h2);
224 EXPECT_EQ(expected, h2.value());
225 }
226 EXPECT_EQ(5, stored);
227 EXPECT_EQ(std::vector{expected}, dropped);
228 dropped.clear();
229}
230
231TEST_F(ManagedHandleTest, MoveAssignWithStorage)
232{
233 constexpr int expected = 3, expected2 = 10;
234 {
235 StoreHandle h1(int{expected}, "str", 5);
236 StoreHandle h2(int{expected2}, "str", 10);
237 EXPECT_TRUE(dropped.empty());
238
239 h2 = std::move(h1);
240 EXPECT_EQ(10, stored);
241 EXPECT_EQ(std::vector{expected2}, dropped);
242 dropped.clear();
243 EXPECT_FALSE(h1);
William A. Kennington III49d92692023-06-06 14:02:01 -0700244 // NOLINTNEXTLINE(clang-analyzer-cplusplus.Move)
William A. Kennington III7a5e2322018-11-02 17:28:35 -0700245 EXPECT_THROW(h1.value(), std::bad_optional_access);
246 EXPECT_TRUE(h2);
247 EXPECT_EQ(expected, *h2);
248 EXPECT_EQ(expected, h2.value());
249 }
250 EXPECT_EQ(5, stored);
251 EXPECT_EQ(std::vector{expected}, dropped);
252 dropped.clear();
253}
254
255} // namespace
256} // namespace stdplus