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