1 | /* |
2 | * Copyright 2014-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #include <folly/Try.h> |
18 | |
19 | #include <glog/logging.h> |
20 | |
21 | #include <folly/Memory.h> |
22 | #include <folly/Traits.h> |
23 | #include <folly/portability/GTest.h> |
24 | |
25 | using namespace folly; |
26 | |
27 | namespace { |
28 | |
29 | class A { |
30 | public: |
31 | explicit A(int x) : x_(x) {} |
32 | |
33 | int x() const { |
34 | return x_; |
35 | } |
36 | |
37 | private: |
38 | int x_; |
39 | }; |
40 | |
41 | template <bool Nothrow> |
42 | class HasCtors { |
43 | public: |
44 | explicit HasCtors(int) noexcept(Nothrow) {} |
45 | HasCtors(HasCtors&&) noexcept(Nothrow) {} |
46 | HasCtors& operator=(HasCtors&&) noexcept(Nothrow) {} |
47 | HasCtors(HasCtors const&) noexcept(Nothrow) {} |
48 | HasCtors& operator=(HasCtors const&) noexcept(Nothrow) {} |
49 | }; |
50 | |
51 | class MoveConstructOnly { |
52 | public: |
53 | MoveConstructOnly() = default; |
54 | MoveConstructOnly(const MoveConstructOnly&) = delete; |
55 | MoveConstructOnly(MoveConstructOnly&&) = default; |
56 | }; |
57 | |
58 | class MutableContainer { |
59 | public: |
60 | mutable MoveConstructOnly val; |
61 | }; |
62 | } // namespace |
63 | |
64 | TEST(Try, basic) { |
65 | A a(5); |
66 | Try<A> t_a(std::move(a)); |
67 | |
68 | Try<Unit> t_void; |
69 | |
70 | EXPECT_EQ(5, t_a.value().x()); |
71 | } |
72 | |
73 | TEST(Try, in_place) { |
74 | Try<A> t_a(in_place, 5); |
75 | |
76 | EXPECT_EQ(5, t_a.value().x()); |
77 | } |
78 | |
79 | TEST(Try, in_place_nested) { |
80 | Try<Try<A>> t_t_a(in_place, in_place, 5); |
81 | |
82 | EXPECT_EQ(5, t_t_a.value().value().x()); |
83 | } |
84 | |
85 | TEST(Try, assignmentWithThrowingCopyConstructor) { |
86 | struct MyException : std::exception {}; |
87 | struct ThrowingCopyConstructor { |
88 | int& counter_; |
89 | explicit ThrowingCopyConstructor(int& counter) : counter_(counter) { |
90 | ++counter_; |
91 | } |
92 | |
93 | [[noreturn]] ThrowingCopyConstructor( |
94 | const ThrowingCopyConstructor& other) noexcept(false) |
95 | : counter_(other.counter_) { |
96 | throw MyException{}; |
97 | } |
98 | |
99 | ThrowingCopyConstructor& operator=(const ThrowingCopyConstructor&) = delete; |
100 | |
101 | ~ThrowingCopyConstructor() { |
102 | --counter_; |
103 | } |
104 | }; |
105 | |
106 | int counter = 0; |
107 | |
108 | { |
109 | Try<ThrowingCopyConstructor> t1{in_place, counter}; |
110 | Try<ThrowingCopyConstructor> t2{in_place, counter}; |
111 | EXPECT_EQ(2, counter); |
112 | EXPECT_THROW(t2 = t1, MyException); |
113 | EXPECT_EQ(1, counter); |
114 | EXPECT_FALSE(t2.hasValue()); |
115 | EXPECT_TRUE(t1.hasValue()); |
116 | } |
117 | EXPECT_EQ(0, counter); |
118 | { |
119 | Try<ThrowingCopyConstructor> t1{in_place, counter}; |
120 | Try<ThrowingCopyConstructor> t2; |
121 | EXPECT_EQ(1, counter); |
122 | EXPECT_THROW(t2 = t1, MyException); |
123 | EXPECT_EQ(1, counter); |
124 | EXPECT_FALSE(t2.hasValue()); |
125 | EXPECT_TRUE(t1.hasValue()); |
126 | } |
127 | EXPECT_EQ(0, counter); |
128 | } |
129 | |
130 | TEST(Try, assignmentWithThrowingMoveConstructor) { |
131 | struct MyException : std::exception {}; |
132 | struct ThrowingMoveConstructor { |
133 | int& counter_; |
134 | explicit ThrowingMoveConstructor(int& counter) : counter_(counter) { |
135 | ++counter_; |
136 | } |
137 | |
138 | [[noreturn]] ThrowingMoveConstructor( |
139 | ThrowingMoveConstructor&& other) noexcept(false) |
140 | : counter_(other.counter_) { |
141 | throw MyException{}; |
142 | } |
143 | |
144 | ThrowingMoveConstructor& operator=(ThrowingMoveConstructor&&) = delete; |
145 | |
146 | ~ThrowingMoveConstructor() { |
147 | --counter_; |
148 | } |
149 | }; |
150 | |
151 | int counter = 0; |
152 | |
153 | { |
154 | Try<ThrowingMoveConstructor> t1{in_place, counter}; |
155 | Try<ThrowingMoveConstructor> t2{in_place, counter}; |
156 | EXPECT_EQ(2, counter); |
157 | EXPECT_THROW(t2 = std::move(t1), MyException); |
158 | EXPECT_EQ(1, counter); |
159 | EXPECT_FALSE(t2.hasValue()); |
160 | EXPECT_TRUE(t1.hasValue()); |
161 | } |
162 | EXPECT_EQ(0, counter); |
163 | { |
164 | Try<ThrowingMoveConstructor> t1{in_place, counter}; |
165 | Try<ThrowingMoveConstructor> t2; |
166 | EXPECT_EQ(1, counter); |
167 | EXPECT_THROW(t2 = std::move(t1), MyException); |
168 | EXPECT_EQ(1, counter); |
169 | EXPECT_FALSE(t2.hasValue()); |
170 | EXPECT_TRUE(t1.hasValue()); |
171 | } |
172 | EXPECT_EQ(0, counter); |
173 | } |
174 | |
175 | TEST(Try, emplace) { |
176 | Try<A> t; |
177 | A& t_a = t.emplace(10); |
178 | EXPECT_TRUE(t.hasValue()); |
179 | EXPECT_EQ(t_a.x(), 10); |
180 | } |
181 | |
182 | TEST(Try, emplaceWithThrowingConstructor) { |
183 | struct MyException : std::exception {}; |
184 | struct ThrowingConstructor { |
185 | explicit ThrowingConstructor(bool shouldThrow) { |
186 | if (shouldThrow) { |
187 | throw MyException{}; |
188 | } |
189 | } |
190 | }; |
191 | |
192 | { |
193 | // Try constructing from empty state to new value and constructor throws. |
194 | Try<ThrowingConstructor> t; |
195 | EXPECT_FALSE(t.hasValue()); |
196 | EXPECT_FALSE(t.hasException()); |
197 | EXPECT_THROW(t.emplace(true), MyException); |
198 | |
199 | EXPECT_FALSE(t.hasValue()); |
200 | EXPECT_FALSE(t.hasException()); |
201 | } |
202 | |
203 | { |
204 | // Initialise to value, then re-emplace with throwing constructor. |
205 | // This should reset the object back to empty. |
206 | Try<ThrowingConstructor> t{in_place, false}; |
207 | EXPECT_TRUE(t.hasValue()); |
208 | EXPECT_THROW(t.emplace(true), MyException); |
209 | EXPECT_FALSE(t.hasValue()); |
210 | EXPECT_FALSE(t.hasException()); |
211 | } |
212 | } |
213 | |
214 | TEST(Try, tryEmplace) { |
215 | Try<A> t; |
216 | A* a = tryEmplace(t, 10); |
217 | EXPECT_EQ(&t.value(), a); |
218 | EXPECT_TRUE(t.hasValue()); |
219 | EXPECT_EQ(10, t.value().x()); |
220 | } |
221 | |
222 | TEST(Try, tryEmplaceWithThrowingConstructor) { |
223 | struct MyException : std::exception {}; |
224 | struct NonInheritingException {}; |
225 | struct ThrowingConstructor { |
226 | [[noreturn]] ThrowingConstructor() noexcept(false) { |
227 | throw NonInheritingException{}; // @nolint |
228 | } |
229 | |
230 | explicit ThrowingConstructor(bool shouldThrow) { |
231 | if (shouldThrow) { |
232 | throw MyException{}; |
233 | } |
234 | } |
235 | }; |
236 | |
237 | { |
238 | Try<ThrowingConstructor> t; |
239 | EXPECT_EQ(nullptr, tryEmplace(t, true)); |
240 | EXPECT_TRUE(t.hasException()); |
241 | EXPECT_NE(t.tryGetExceptionObject<MyException>(), nullptr); |
242 | } |
243 | |
244 | { |
245 | Try<ThrowingConstructor> t; |
246 | EXPECT_EQ(nullptr, tryEmplace(t)); |
247 | EXPECT_TRUE(t.hasException()); |
248 | EXPECT_NE(t.tryGetExceptionObject<NonInheritingException>(), nullptr); |
249 | } |
250 | |
251 | { |
252 | Try<ThrowingConstructor> t; |
253 | EXPECT_NE(nullptr, tryEmplace(t, false)); |
254 | EXPECT_TRUE(t.hasValue()); |
255 | EXPECT_EQ(nullptr, tryEmplace(t, true)); |
256 | EXPECT_TRUE(t.hasException()); |
257 | EXPECT_NE(t.tryGetExceptionObject<MyException>(), nullptr); |
258 | } |
259 | } |
260 | |
261 | TEST(Try, emplaceVoidTry) { |
262 | struct MyException : std::exception {}; |
263 | Try<void> t; |
264 | t.emplace(); |
265 | EXPECT_TRUE(t.hasValue()); |
266 | t.emplaceException(folly::in_place_type<MyException>); |
267 | EXPECT_FALSE(t.hasValue()); |
268 | EXPECT_TRUE(t.hasException()); |
269 | EXPECT_TRUE(t.hasException<MyException>()); |
270 | t.emplace(); |
271 | EXPECT_TRUE(t.hasValue()); |
272 | EXPECT_FALSE(t.hasException()); |
273 | } |
274 | |
275 | TEST(Try, tryEmplaceVoidTry) { |
276 | struct MyException : std::exception {}; |
277 | Try<void> t; |
278 | tryEmplace(t); |
279 | EXPECT_TRUE(t.hasValue()); |
280 | t.emplaceException(folly::in_place_type<MyException>); |
281 | EXPECT_FALSE(t.hasValue()); |
282 | EXPECT_TRUE(t.hasException()); |
283 | EXPECT_TRUE(t.hasException<MyException>()); |
284 | t.emplace(); |
285 | EXPECT_TRUE(t.hasValue()); |
286 | EXPECT_FALSE(t.hasException()); |
287 | } |
288 | |
289 | TEST(Try, tryEmplaceWith) { |
290 | Try<std::string> t; |
291 | tryEmplaceWith(t, [] { return "hello" ; }); |
292 | EXPECT_EQ("hello" , t.value()); |
293 | } |
294 | |
295 | TEST(Try, tryEmplaceWithFunctionThrows) { |
296 | struct MyException : std::exception {}; |
297 | Try<int> t; |
298 | tryEmplaceWith(t, []() -> int { throw MyException{}; }); |
299 | EXPECT_TRUE(t.hasException()); |
300 | EXPECT_TRUE(t.hasException<MyException>()); |
301 | } |
302 | |
303 | TEST(Try, tryEmplaceWithConstructorThrows) { |
304 | struct MyException : std::exception {}; |
305 | struct ThrowingConstructor { |
306 | int value_; |
307 | explicit ThrowingConstructor(bool shouldThrow) noexcept(false) : value_(0) { |
308 | if (shouldThrow) { |
309 | throw MyException{}; |
310 | } |
311 | } |
312 | }; |
313 | |
314 | Try<ThrowingConstructor> t; |
315 | tryEmplaceWith(t, [] { return false; }); |
316 | EXPECT_TRUE(t.hasValue()); |
317 | tryEmplaceWith(t, [] { return true; }); |
318 | EXPECT_TRUE(t.hasException()); |
319 | EXPECT_TRUE(t.hasException<MyException>()); |
320 | } |
321 | |
322 | TEST(Try, tryEmplaceWithVoidTry) { |
323 | Try<void> t; |
324 | bool hasRun = false; |
325 | tryEmplaceWith(t, [&] { hasRun = true; }); |
326 | EXPECT_TRUE(t.hasValue()); |
327 | EXPECT_TRUE(hasRun); |
328 | |
329 | struct MyException : std::exception {}; |
330 | tryEmplaceWith(t, [&] { throw MyException{}; }); |
331 | EXPECT_TRUE(t.hasException()); |
332 | EXPECT_TRUE(t.hasException<MyException>()); |
333 | } |
334 | |
335 | TEST(Try, nothrow) { |
336 | using F = HasCtors<false>; |
337 | using T = HasCtors<true>; |
338 | |
339 | // default ctor |
340 | EXPECT_TRUE(std::is_nothrow_default_constructible<Try<F>>::value); |
341 | EXPECT_TRUE(std::is_nothrow_default_constructible<Try<T>>::value); |
342 | EXPECT_TRUE(std::is_nothrow_default_constructible<Try<void>>::value); |
343 | |
344 | // inner ctor - no void |
345 | EXPECT_FALSE((std::is_nothrow_constructible<Try<F>, F&&>::value)); |
346 | EXPECT_TRUE((std::is_nothrow_constructible<Try<T>, T&&>::value)); |
347 | EXPECT_FALSE((std::is_nothrow_constructible<Try<F>, F const&>::value)); |
348 | EXPECT_TRUE((std::is_nothrow_constructible<Try<T>, T const&>::value)); |
349 | |
350 | // emplacing ctor - no void |
351 | EXPECT_FALSE((std::is_nothrow_constructible<Try<F>, in_place_t, int>::value)); |
352 | EXPECT_TRUE((std::is_nothrow_constructible<Try<T>, in_place_t, int>::value)); |
353 | |
354 | // copy/move ctor/assign |
355 | EXPECT_TRUE(std::is_nothrow_constructible<Try<void>>::value); |
356 | EXPECT_FALSE(std::is_nothrow_move_constructible<Try<F>>::value); |
357 | EXPECT_TRUE(std::is_nothrow_move_constructible<Try<T>>::value); |
358 | EXPECT_TRUE(std::is_nothrow_move_constructible<Try<void>>::value); |
359 | EXPECT_FALSE(std::is_nothrow_move_assignable<Try<F>>::value); |
360 | EXPECT_TRUE(std::is_nothrow_move_assignable<Try<T>>::value); |
361 | EXPECT_TRUE(std::is_nothrow_move_assignable<Try<void>>::value); |
362 | EXPECT_FALSE(std::is_nothrow_copy_constructible<Try<F>>::value); |
363 | EXPECT_TRUE(std::is_nothrow_copy_constructible<Try<T>>::value); |
364 | EXPECT_TRUE(std::is_nothrow_copy_constructible<Try<void>>::value); |
365 | EXPECT_FALSE(std::is_nothrow_copy_assignable<Try<F>>::value); |
366 | EXPECT_TRUE(std::is_nothrow_copy_assignable<Try<T>>::value); |
367 | EXPECT_TRUE(std::is_nothrow_copy_assignable<Try<void>>::value); |
368 | |
369 | // conversion ctor - void to unit |
370 | EXPECT_TRUE((std::is_nothrow_constructible<Try<Unit>, Try<void>&&>::value)); |
371 | EXPECT_TRUE( |
372 | (std::is_nothrow_constructible<Try<Unit>, Try<void> const&>::value)); |
373 | } |
374 | |
375 | TEST(Try, MoveDereference) { |
376 | auto ptr = std::make_unique<int>(1); |
377 | auto t = Try<std::unique_ptr<int>>{std::move(ptr)}; |
378 | auto result = *std::move(t); |
379 | EXPECT_EQ(*result, 1); |
380 | } |
381 | |
382 | TEST(Try, MoveConstRvalue) { |
383 | // tests to see if Try returns a const Rvalue, this is required in the case |
384 | // where for example MutableContainer has a mutable memebr that is move only |
385 | // and you want to fetch the value from the Try and move it into a member |
386 | { |
387 | const Try<MutableContainer> t{in_place}; |
388 | auto val = MoveConstructOnly(std::move(t).value().val); |
389 | static_cast<void>(val); |
390 | } |
391 | { |
392 | const Try<MutableContainer> t{in_place}; |
393 | auto val = (*(std::move(t))).val; |
394 | static_cast<void>(val); |
395 | } |
396 | } |
397 | |
398 | TEST(Try, ValueOverloads) { |
399 | using ML = int&; |
400 | using MR = int&&; |
401 | using CL = const int&; |
402 | using CR = const int&&; |
403 | |
404 | { |
405 | auto obj = Try<int>{}; |
406 | using ActualML = decltype(obj.value()); |
407 | using ActualMR = decltype(std::move(obj).value()); |
408 | using ActualCL = decltype(as_const(obj).value()); |
409 | using ActualCR = decltype(std::move(as_const(obj)).value()); |
410 | EXPECT_TRUE((std::is_same<ML, ActualML>::value)); |
411 | EXPECT_TRUE((std::is_same<MR, ActualMR>::value)); |
412 | EXPECT_TRUE((std::is_same<CL, ActualCL>::value)); |
413 | EXPECT_TRUE((std::is_same<CR, ActualCR>::value)); |
414 | } |
415 | |
416 | { |
417 | auto obj = Try<int>{3}; |
418 | EXPECT_EQ(obj.value(), 3); |
419 | EXPECT_EQ(std::move(obj).value(), 3); |
420 | EXPECT_EQ(as_const(obj).value(), 3); |
421 | EXPECT_EQ(std::move(as_const(obj)).value(), 3); |
422 | } |
423 | |
424 | { |
425 | auto obj = Try<int>{make_exception_wrapper<std::range_error>("oops" )}; |
426 | EXPECT_THROW(obj.value(), std::range_error); |
427 | EXPECT_THROW(std::move(obj.value()), std::range_error); |
428 | EXPECT_THROW(as_const(obj.value()), std::range_error); |
429 | EXPECT_THROW(std::move(as_const(obj.value())), std::range_error); |
430 | } |
431 | } |
432 | |
433 | // Make sure we can copy Trys for copyable types |
434 | TEST(Try, copy) { |
435 | Try<int> t; |
436 | auto t2 = t; |
437 | } |
438 | |
439 | // But don't choke on move-only types |
440 | TEST(Try, moveOnly) { |
441 | Try<std::unique_ptr<int>> t; |
442 | std::vector<Try<std::unique_ptr<int>>> v; |
443 | v.reserve(10); |
444 | } |
445 | |
446 | TEST(Try, makeTryWith) { |
447 | auto func = []() { return std::make_unique<int>(1); }; |
448 | |
449 | auto result = makeTryWith(func); |
450 | EXPECT_TRUE(result.hasValue()); |
451 | EXPECT_EQ(*result.value(), 1); |
452 | } |
453 | |
454 | TEST(Try, makeTryWithThrow) { |
455 | auto func = []() -> std::unique_ptr<int> { |
456 | throw std::runtime_error("Runtime" ); |
457 | }; |
458 | |
459 | auto result = makeTryWith(func); |
460 | EXPECT_TRUE(result.hasException<std::runtime_error>()); |
461 | } |
462 | |
463 | TEST(Try, makeTryWithVoid) { |
464 | auto func = []() { return; }; |
465 | |
466 | auto result = makeTryWith(func); |
467 | EXPECT_TRUE(result.hasValue()); |
468 | } |
469 | |
470 | TEST(Try, makeTryWithVoidThrow) { |
471 | auto func = []() { throw std::runtime_error("Runtime" ); }; |
472 | |
473 | auto result = makeTryWith(func); |
474 | EXPECT_TRUE(result.hasException<std::runtime_error>()); |
475 | } |
476 | |
477 | TEST(Try, exception) { |
478 | using ML = exception_wrapper&; |
479 | using MR = exception_wrapper&&; |
480 | using CL = exception_wrapper const&; |
481 | using CR = exception_wrapper const&&; |
482 | |
483 | { |
484 | auto obj = Try<int>(); |
485 | using ActualML = decltype(obj.exception()); |
486 | using ActualMR = decltype(std::move(obj).exception()); |
487 | using ActualCL = decltype(as_const(obj).exception()); |
488 | using ActualCR = decltype(std::move(as_const(obj)).exception()); |
489 | EXPECT_TRUE((std::is_same<ML, ActualML>::value)); |
490 | EXPECT_TRUE((std::is_same<MR, ActualMR>::value)); |
491 | EXPECT_TRUE((std::is_same<CL, ActualCL>::value)); |
492 | EXPECT_TRUE((std::is_same<CR, ActualCR>::value)); |
493 | } |
494 | |
495 | { |
496 | auto obj = Try<int>(3); |
497 | EXPECT_THROW(obj.exception(), TryException); |
498 | EXPECT_THROW(std::move(obj).exception(), TryException); |
499 | EXPECT_THROW(as_const(obj).exception(), TryException); |
500 | EXPECT_THROW(std::move(as_const(obj)).exception(), TryException); |
501 | } |
502 | |
503 | { |
504 | auto obj = Try<int>(make_exception_wrapper<int>(-3)); |
505 | EXPECT_EQ(-3, *obj.exception().get_exception<int>()); |
506 | EXPECT_EQ(-3, *std::move(obj).exception().get_exception<int>()); |
507 | EXPECT_EQ(-3, *as_const(obj).exception().get_exception<int>()); |
508 | EXPECT_EQ(-3, *std::move(as_const(obj)).exception().get_exception<int>()); |
509 | } |
510 | |
511 | { |
512 | auto obj = Try<void>(); |
513 | using ActualML = decltype(obj.exception()); |
514 | using ActualMR = decltype(std::move(obj).exception()); |
515 | using ActualCL = decltype(as_const(obj).exception()); |
516 | using ActualCR = decltype(std::move(as_const(obj)).exception()); |
517 | EXPECT_TRUE((std::is_same<ML, ActualML>::value)); |
518 | EXPECT_TRUE((std::is_same<MR, ActualMR>::value)); |
519 | EXPECT_TRUE((std::is_same<CL, ActualCL>::value)); |
520 | EXPECT_TRUE((std::is_same<CR, ActualCR>::value)); |
521 | } |
522 | |
523 | { |
524 | auto obj = Try<void>(); |
525 | EXPECT_THROW(obj.exception(), TryException); |
526 | EXPECT_THROW(std::move(obj).exception(), TryException); |
527 | EXPECT_THROW(as_const(obj).exception(), TryException); |
528 | EXPECT_THROW(std::move(as_const(obj)).exception(), TryException); |
529 | } |
530 | |
531 | { |
532 | auto obj = Try<void>(make_exception_wrapper<int>(-3)); |
533 | EXPECT_EQ(-3, *obj.exception().get_exception<int>()); |
534 | EXPECT_EQ(-3, *std::move(obj).exception().get_exception<int>()); |
535 | EXPECT_EQ(-3, *as_const(obj).exception().get_exception<int>()); |
536 | EXPECT_EQ(-3, *std::move(as_const(obj)).exception().get_exception<int>()); |
537 | } |
538 | } |
539 | |
540 | template <typename E> |
541 | static E* get_exception(std::exception_ptr eptr) { |
542 | try { |
543 | std::rethrow_exception(eptr); |
544 | } catch (E& e) { |
545 | return &e; |
546 | } catch (...) { |
547 | return nullptr; |
548 | } |
549 | } |
550 | |
551 | TEST(Try, tryGetExceptionObject) { |
552 | auto epexn = std::make_exception_ptr(std::range_error("oops" )); |
553 | auto epnum = std::make_exception_ptr(17); |
554 | |
555 | auto exn = CHECK_NOTNULL(get_exception<std::range_error>(epexn)); |
556 | auto num = CHECK_NOTNULL(get_exception<int>(epnum)); |
557 | |
558 | { |
559 | auto t = Try<bool>(true); |
560 | EXPECT_EQ(nullptr, t.tryGetExceptionObject()); |
561 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>()); |
562 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>()); |
563 | } |
564 | |
565 | { |
566 | auto t = Try<bool>(exception_wrapper(epexn, *exn)); |
567 | EXPECT_EQ(exn, t.tryGetExceptionObject()); |
568 | EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>()); |
569 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>()); |
570 | } |
571 | |
572 | { |
573 | auto t = Try<bool>(exception_wrapper(epnum, *num)); |
574 | EXPECT_EQ(nullptr, t.tryGetExceptionObject()); |
575 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>()); |
576 | EXPECT_EQ(num, t.tryGetExceptionObject<int>()); |
577 | } |
578 | |
579 | { |
580 | auto t = Try<void>(); |
581 | EXPECT_EQ(nullptr, t.tryGetExceptionObject()); |
582 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>()); |
583 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>()); |
584 | } |
585 | |
586 | { |
587 | auto t = Try<void>(exception_wrapper(epexn, *exn)); |
588 | EXPECT_EQ(exn, t.tryGetExceptionObject()); |
589 | EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>()); |
590 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>()); |
591 | } |
592 | |
593 | { |
594 | auto t = Try<void>(exception_wrapper(epnum, *num)); |
595 | EXPECT_EQ(nullptr, t.tryGetExceptionObject()); |
596 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>()); |
597 | EXPECT_EQ(num, t.tryGetExceptionObject<int>()); |
598 | } |
599 | |
600 | { |
601 | auto const t = Try<bool>(true); |
602 | EXPECT_EQ(nullptr, t.tryGetExceptionObject()); |
603 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>()); |
604 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>()); |
605 | } |
606 | |
607 | { |
608 | auto const t = Try<bool>(exception_wrapper(epexn, *exn)); |
609 | EXPECT_EQ(exn, t.tryGetExceptionObject()); |
610 | EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>()); |
611 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>()); |
612 | } |
613 | |
614 | { |
615 | auto const t = Try<bool>(exception_wrapper(epnum, *num)); |
616 | EXPECT_EQ(nullptr, t.tryGetExceptionObject()); |
617 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>()); |
618 | EXPECT_EQ(num, t.tryGetExceptionObject<int>()); |
619 | } |
620 | |
621 | { |
622 | auto const t = Try<void>(); |
623 | EXPECT_EQ(nullptr, t.tryGetExceptionObject()); |
624 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>()); |
625 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>()); |
626 | } |
627 | |
628 | { |
629 | auto const t = Try<void>(exception_wrapper(epexn, *exn)); |
630 | EXPECT_EQ(exn, t.tryGetExceptionObject()); |
631 | EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>()); |
632 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>()); |
633 | } |
634 | |
635 | { |
636 | auto const t = Try<void>(exception_wrapper(epnum, *num)); |
637 | EXPECT_EQ(nullptr, t.tryGetExceptionObject()); |
638 | EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>()); |
639 | EXPECT_EQ(num, t.tryGetExceptionObject<int>()); |
640 | } |
641 | } |
642 | |
643 | TEST(Try, withException) { |
644 | auto ew = make_exception_wrapper<std::range_error>("oops" ); |
645 | |
646 | { |
647 | auto t = Try<bool>(true); |
648 | EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {})); |
649 | EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {})); |
650 | EXPECT_FALSE(t.withException([](std::runtime_error&) {})); |
651 | EXPECT_FALSE(t.withException([](std::logic_error&) {})); |
652 | } |
653 | |
654 | { |
655 | auto t = Try<bool>(ew); |
656 | EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {})); |
657 | EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {})); |
658 | EXPECT_TRUE(t.withException([](std::runtime_error&) {})); |
659 | EXPECT_FALSE(t.withException([](std::logic_error&) {})); |
660 | } |
661 | |
662 | { |
663 | auto t = Try<void>(); |
664 | EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {})); |
665 | EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {})); |
666 | EXPECT_FALSE(t.withException([](std::runtime_error&) {})); |
667 | EXPECT_FALSE(t.withException([](std::logic_error&) {})); |
668 | } |
669 | |
670 | { |
671 | auto t = Try<void>(ew); |
672 | EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {})); |
673 | EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {})); |
674 | EXPECT_TRUE(t.withException([](std::runtime_error&) {})); |
675 | EXPECT_FALSE(t.withException([](std::logic_error&) {})); |
676 | } |
677 | |
678 | { |
679 | auto const t = Try<bool>(true); |
680 | EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {})); |
681 | EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {})); |
682 | EXPECT_FALSE(t.withException([](std::runtime_error const&) {})); |
683 | EXPECT_FALSE(t.withException([](std::logic_error const&) {})); |
684 | } |
685 | |
686 | { |
687 | auto const t = Try<bool>(ew); |
688 | EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {})); |
689 | EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {})); |
690 | EXPECT_TRUE(t.withException([](std::runtime_error const&) {})); |
691 | EXPECT_FALSE(t.withException([](std::logic_error const&) {})); |
692 | } |
693 | |
694 | { |
695 | auto const t = Try<void>(); |
696 | EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {})); |
697 | EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {})); |
698 | EXPECT_FALSE(t.withException([](std::runtime_error const&) {})); |
699 | EXPECT_FALSE(t.withException([](std::logic_error const&) {})); |
700 | } |
701 | |
702 | { |
703 | auto const t = Try<void>(ew); |
704 | EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {})); |
705 | EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {})); |
706 | EXPECT_TRUE(t.withException([](std::runtime_error const&) {})); |
707 | EXPECT_FALSE(t.withException([](std::logic_error const&) {})); |
708 | } |
709 | } |
710 | |
711 | TEST(Try, TestUnwrapTuple) { |
712 | auto original = std::make_tuple(Try<int>{1}, Try<int>{2}); |
713 | EXPECT_EQ(std::make_tuple(1, 2), unwrapTryTuple(original)); |
714 | EXPECT_EQ(std::make_tuple(1, 2), unwrapTryTuple(folly::copy(original))); |
715 | EXPECT_EQ(std::make_tuple(1, 2), unwrapTryTuple(folly::as_const(original))); |
716 | } |
717 | |
718 | TEST(Try, TestUnwrapPair) { |
719 | auto original = std::make_pair(Try<int>{1}, Try<int>{2}); |
720 | EXPECT_EQ(std::make_pair(1, 2), unwrapTryTuple(original)); |
721 | EXPECT_EQ(std::make_pair(1, 2), unwrapTryTuple(folly::copy(original))); |
722 | EXPECT_EQ(std::make_pair(1, 2), unwrapTryTuple(folly::as_const(original))); |
723 | } |
724 | |
725 | TEST(Try, TestUnwrapForward) { |
726 | using UPtr_t = std::unique_ptr<int>; |
727 | auto original = std::make_tuple(Try<UPtr_t>{std::make_unique<int>(1)}); |
728 | auto unwrapped = unwrapTryTuple(std::move(original)); |
729 | EXPECT_EQ(*std::get<0>(unwrapped), 1); |
730 | } |
731 | |