blob: cd17c54a35e973e8696834adc8ef3b82ec086d46 [file] [log] [blame]
William A. Kennington IIIe847ef82018-11-02 17:29:15 -07001#include <gtest/gtest.h>
2#include <optional>
3#include <stdplus/handle/copyable.hpp>
4#include <string>
5#include <utility>
6#include <vector>
7
8namespace stdplus
9{
10namespace
11{
12
13static std::vector<int> reffed;
14static int stored_ref = 0;
15static std::vector<int> dropped;
16static int stored_drop = 0;
17
William A. Kennington III7910ae02019-11-11 12:13:25 -080018struct SimpleRef
19{
20 int operator()(const int& i) noexcept
21 {
22 reffed.push_back(i);
23 return i + 1;
24 }
25};
26
William A. Kennington IIIe847ef82018-11-02 17:29:15 -070027int ref(const int& i)
28{
William A. Kennington III7910ae02019-11-11 12:13:25 -080029 return SimpleRef()(i);
William A. Kennington IIIe847ef82018-11-02 17:29:15 -070030}
31
William A. Kennington III7910ae02019-11-11 12:13:25 -080032struct SimpleDrop
33{
34 void operator()(int&& i) noexcept
35 {
36 dropped.push_back(std::move(i));
37 }
38};
39
William A. Kennington IIIe847ef82018-11-02 17:29:15 -070040void drop(int&& i)
41{
William A. Kennington III7910ae02019-11-11 12:13:25 -080042 SimpleDrop()(std::move(i));
William A. Kennington IIIe847ef82018-11-02 17:29:15 -070043}
44
William A. Kennington III7910ae02019-11-11 12:13:25 -080045struct StoreRef
William A. Kennington IIIe847ef82018-11-02 17:29:15 -070046{
William A. Kennington III7910ae02019-11-11 12:13:25 -080047 int operator()(const int& i, std::string&, int& si)
48 {
49 reffed.push_back(i);
50 // Make sure we can update the stored data
51 stored_ref = si++;
52 return i + 1;
53 }
54};
William A. Kennington IIIe847ef82018-11-02 17:29:15 -070055
William A. Kennington III7910ae02019-11-11 12:13:25 -080056struct StoreDrop
William A. Kennington IIIe847ef82018-11-02 17:29:15 -070057{
William A. Kennington III7910ae02019-11-11 12:13:25 -080058 void operator()(int&& i, std::string&, int& si)
59 {
60 dropped.push_back(std::move(i));
61 // Make sure we can update the stored data
62 stored_drop = si++;
63 }
64};
William A. Kennington IIIe847ef82018-11-02 17:29:15 -070065
William A. Kennington III7910ae02019-11-11 12:13:25 -080066using SimpleHandleOld = Copyable<int>::Handle<drop, ref>;
67using SimpleHandle = Copyable<int>::HandleF<SimpleDrop, SimpleRef>;
68using StoreHandle =
69 Copyable<int, std::string, int>::HandleF<StoreDrop, StoreRef>;
William A. Kennington IIIe847ef82018-11-02 17:29:15 -070070
William A. Kennington III1007be92019-11-11 12:18:37 -080071static_assert(std::is_nothrow_copy_constructible_v<SimpleHandle>);
72static_assert(std::is_nothrow_move_constructible_v<SimpleHandle>);
73static_assert(std::is_nothrow_move_assignable_v<SimpleHandle>);
74static_assert(std::is_nothrow_destructible_v<SimpleHandle>);
75static_assert(noexcept(std::declval<SimpleHandle>().reset()));
76static_assert(!std::is_nothrow_copy_constructible_v<StoreHandle>);
77// http://cplusplus.github.io/LWG/lwg-active.html#2116
78// static_assert(std::is_nothrow_move_constructible_v<StoreHandle>);
79static_assert(!std::is_nothrow_move_assignable_v<StoreHandle>);
80static_assert(!std::is_nothrow_destructible_v<StoreHandle>);
81static_assert(!noexcept(std::declval<StoreHandle>().reset()));
82
William A. Kennington IIIe847ef82018-11-02 17:29:15 -070083class CopyableHandleTest : public ::testing::Test
84{
85 protected:
86 void SetUp()
87 {
88 reffed.clear();
89 dropped.clear();
90 }
91
92 void TearDown()
93 {
94 EXPECT_TRUE(reffed.empty());
95 EXPECT_TRUE(dropped.empty());
96 }
97};
98
99TEST_F(CopyableHandleTest, EmptyNoStorage)
100{
William A. Kennington III7910ae02019-11-11 12:13:25 -0800101 SimpleHandleOld h(std::nullopt);
William A. Kennington IIIe847ef82018-11-02 17:29:15 -0700102 EXPECT_FALSE(h);
103 EXPECT_THROW(h.value(), std::bad_optional_access);
104 h.reset();
105 EXPECT_FALSE(h);
106 EXPECT_THROW(h.value(), std::bad_optional_access);
107}
108
109TEST_F(CopyableHandleTest, EmptyWithStorage)
110{
111 auto maybeV = std::nullopt;
112 StoreHandle h(maybeV, "str", 5);
113 EXPECT_FALSE(h);
114 EXPECT_THROW(h.value(), std::bad_optional_access);
115 h.reset(maybeV);
116 EXPECT_FALSE(h);
117 EXPECT_THROW(h.value(), std::bad_optional_access);
118}
119
120TEST_F(CopyableHandleTest, SimplePopulated)
121{
122 constexpr int expected = 3;
123 {
124 int val = expected;
125 SimpleHandle h(std::move(val));
126 EXPECT_TRUE(h);
127 EXPECT_EQ(expected, *h);
128 EXPECT_EQ(expected, h.value());
129 EXPECT_TRUE(dropped.empty());
130 }
131 EXPECT_EQ(std::vector{expected}, dropped);
132 dropped.clear();
133}
134
135TEST_F(CopyableHandleTest, OptionalPopulated)
136{
137 constexpr int expected = 3;
138 {
139 std::optional<int> maybeVal{expected};
140 SimpleHandle h(std::move(maybeVal));
141 EXPECT_TRUE(h);
142 EXPECT_EQ(expected, *h);
143 EXPECT_EQ(expected, h.value());
144 EXPECT_TRUE(dropped.empty());
145 }
146 EXPECT_TRUE(reffed.empty());
147 EXPECT_EQ(std::vector{expected}, dropped);
148 dropped.clear();
149 {
150 const std::optional<int> maybeVal{expected};
151 SimpleHandle h(maybeVal);
152 EXPECT_TRUE(h);
153 EXPECT_EQ(expected + 1, *h);
154 EXPECT_EQ(expected + 1, h.value());
155 EXPECT_EQ(std::vector{expected}, reffed);
156 reffed.clear();
157 EXPECT_TRUE(dropped.empty());
158 }
159 EXPECT_EQ(std::vector{expected + 1}, dropped);
160 dropped.clear();
161}
162
163TEST_F(CopyableHandleTest, SimplePopulatedWithStorage)
164{
165 constexpr int expected = 3;
166 {
167 StoreHandle h(expected, std::string{"str"}, 5);
168 EXPECT_TRUE(h);
169 EXPECT_EQ(expected + 1, *h);
170 EXPECT_EQ(expected + 1, h.value());
171 EXPECT_EQ(5, stored_ref);
172 EXPECT_EQ(std::vector{expected}, reffed);
173 reffed.clear();
174 EXPECT_TRUE(dropped.empty());
175 }
176 EXPECT_EQ(6, stored_drop);
177 EXPECT_EQ(std::vector{expected + 1}, dropped);
178 dropped.clear();
179}
180
181TEST_F(CopyableHandleTest, ResetPopulatedWithStorage)
182{
183 constexpr int expected = 3;
184 const std::string s{"str"};
185 StoreHandle h(int{expected}, s, 5);
186 EXPECT_TRUE(dropped.empty());
187 h.reset(std::nullopt);
188 EXPECT_FALSE(h);
189 EXPECT_THROW(h.value(), std::bad_optional_access);
190 EXPECT_EQ(5, stored_drop);
191 EXPECT_EQ(std::vector{expected}, dropped);
192 dropped.clear();
193}
194
195TEST_F(CopyableHandleTest, ResetNewPopulated)
196{
197 constexpr int expected = 3, expected2 = 10;
198 {
199 SimpleHandle h(int{expected});
200 EXPECT_TRUE(dropped.empty());
201 h.reset(int{expected2});
202 EXPECT_TRUE(h);
203 EXPECT_EQ(expected2, *h);
204 EXPECT_EQ(expected2, h.value());
205 EXPECT_EQ(std::vector{expected}, dropped);
206 dropped.clear();
207 }
208 EXPECT_EQ(std::vector{expected2}, dropped);
209 dropped.clear();
210}
211
212TEST_F(CopyableHandleTest, ResetCopyPopulated)
213{
214 constexpr int expected = 3, expected2 = 10;
215 {
216 SimpleHandle h(int{expected});
217 EXPECT_TRUE(reffed.empty());
218 EXPECT_TRUE(dropped.empty());
219 const std::optional<int> maybe2{expected2};
220 h.reset(maybe2);
221 EXPECT_TRUE(h);
222 EXPECT_EQ(expected2 + 1, *h);
223 EXPECT_EQ(expected2 + 1, h.value());
224 EXPECT_EQ(std::vector{expected2}, reffed);
225 reffed.clear();
226 EXPECT_EQ(std::vector{expected}, dropped);
227 dropped.clear();
228 }
229 EXPECT_EQ(std::vector{expected2 + 1}, dropped);
230 dropped.clear();
231}
232
233TEST_F(CopyableHandleTest, ResetCopyPopulatedWithStorage)
234{
235 constexpr int expected = 3, expected2 = 10;
236 {
237 StoreHandle h(int{expected}, "str", 5);
238 EXPECT_TRUE(dropped.empty());
239 h.reset(expected2);
240 EXPECT_TRUE(h);
241 EXPECT_EQ(expected2 + 1, *h);
242 EXPECT_EQ(expected2 + 1, h.value());
243 EXPECT_EQ(5, stored_ref);
244 EXPECT_EQ(std::vector{expected2}, reffed);
245 reffed.clear();
246 EXPECT_EQ(6, stored_drop);
247 EXPECT_EQ(std::vector{expected}, dropped);
248 dropped.clear();
249 }
250 EXPECT_EQ(7, stored_drop);
251 EXPECT_EQ(std::vector{expected2 + 1}, dropped);
252 dropped.clear();
253}
254
255TEST_F(CopyableHandleTest, MoveConstructWithStorage)
256{
257 constexpr int expected = 3;
258 StoreHandle h1(int{expected}, "str", 5);
259 {
260 StoreHandle h2(std::move(h1));
261 EXPECT_TRUE(dropped.empty());
262 EXPECT_FALSE(h1);
263 EXPECT_THROW(h1.value(), std::bad_optional_access);
264 EXPECT_TRUE(h2);
265 EXPECT_EQ(expected, *h2);
266 EXPECT_EQ(expected, h2.value());
267 }
268 EXPECT_EQ(5, stored_drop);
269 EXPECT_EQ(std::vector{expected}, dropped);
270 dropped.clear();
271}
272
273TEST_F(CopyableHandleTest, MoveAssignWithStorage)
274{
275 constexpr int expected = 3, expected2 = 10;
276 {
277 StoreHandle h1(int{expected}, "str", 5);
278 StoreHandle h2(int{expected2}, "str", 10);
279 EXPECT_TRUE(dropped.empty());
280
281 h2 = std::move(h1);
282 EXPECT_EQ(10, stored_drop);
283 EXPECT_EQ(std::vector{expected2}, dropped);
284 dropped.clear();
285 EXPECT_FALSE(h1);
286 EXPECT_THROW(h1.value(), std::bad_optional_access);
287 EXPECT_TRUE(h2);
288 EXPECT_EQ(expected, *h2);
289 EXPECT_EQ(expected, h2.value());
290 }
291 EXPECT_EQ(5, stored_drop);
292 EXPECT_EQ(std::vector{expected}, dropped);
293 dropped.clear();
294}
295
296TEST_F(CopyableHandleTest, CopyConstructSrcEmptyWithStorage)
297{
298 StoreHandle h1(std::nullopt, "str", 5);
299 StoreHandle h2(h1);
300}
301
302TEST_F(CopyableHandleTest, CopyConstructWithStorage)
303{
304 constexpr int expected = 3;
305 StoreHandle h1(int{expected}, "str", 5);
306 StoreHandle h2(h1);
307 EXPECT_EQ(5, stored_ref);
308 EXPECT_EQ(std::vector{expected}, reffed);
309 reffed.clear();
310
311 h1.reset();
312 EXPECT_EQ(5, stored_drop);
313 EXPECT_EQ(std::vector{expected}, dropped);
314 dropped.clear();
315 h2.reset();
316 EXPECT_EQ(6, stored_drop);
317 EXPECT_EQ(std::vector{expected + 1}, dropped);
318 dropped.clear();
319}
320
321TEST_F(CopyableHandleTest, CopyAssignBothEmptyWithStorage)
322{
323 StoreHandle h1(std::nullopt, "str", 5);
324 StoreHandle h2(std::nullopt, "str", 10);
325 h2 = h1;
326}
327
328TEST_F(CopyableHandleTest, CopyAssignSrcEmptyWithStorage)
329{
330 constexpr int expected = 3;
331 StoreHandle h1(std::nullopt, "str", 5);
332 StoreHandle h2(int{expected}, "str", 10);
333 h2 = h1;
334 EXPECT_EQ(10, stored_drop);
335 EXPECT_EQ(std::vector{expected}, dropped);
336 dropped.clear();
337}
338
339TEST_F(CopyableHandleTest, CopyAssignDstEmptyWithStorage)
340{
341 constexpr int expected = 3;
342 StoreHandle h1(int{expected}, "str", 5);
343 StoreHandle h2(std::nullopt, "str", 10);
344 h2 = h1;
345 EXPECT_EQ(5, stored_ref);
346 EXPECT_EQ(std::vector{expected}, reffed);
347 reffed.clear();
348
349 h1.reset();
350 EXPECT_EQ(5, stored_drop);
351 EXPECT_EQ(std::vector{expected}, dropped);
352 dropped.clear();
353 h2.reset();
354 EXPECT_EQ(6, stored_drop);
355 EXPECT_EQ(std::vector{expected + 1}, dropped);
356 dropped.clear();
357}
358
359TEST_F(CopyableHandleTest, CopyAssignWithStorage)
360{
361 constexpr int expected = 3, expected2 = 15;
362 StoreHandle h1(int{expected}, "str", 5);
363 StoreHandle h2(int{expected2}, "str", 10);
364 h2 = h1;
365 EXPECT_EQ(10, stored_drop);
366 EXPECT_EQ(std::vector{expected2}, dropped);
367 dropped.clear();
368 EXPECT_EQ(5, stored_ref);
369 EXPECT_EQ(std::vector{expected}, reffed);
370 reffed.clear();
371
372 h1.reset();
373 EXPECT_EQ(5, stored_drop);
374 EXPECT_EQ(std::vector{expected}, dropped);
375 dropped.clear();
376 h2.reset();
377 EXPECT_EQ(6, stored_drop);
378 EXPECT_EQ(std::vector{expected + 1}, dropped);
379 dropped.clear();
380}
381
382} // namespace
383} // namespace stdplus