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