Rename exception_wrapper::get_object to get_exception
[folly.git] / folly / test / ExceptionWrapperTest.cpp
1 /*
2  * Copyright 2017 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 <stdexcept>
18
19 #include <folly/ExceptionWrapper.h>
20 #include <folly/Conv.h>
21 #include <folly/portability/GTest.h>
22
23 using namespace folly;
24
25 class AbstractIntException : public std::exception {
26  public:
27   virtual int getInt() const = 0;
28 };
29
30 class IntException : public AbstractIntException {
31  public:
32   explicit IntException(int i) : i_(i) {}
33
34   int getInt() const override { return i_; }
35   const char* what() const noexcept override {
36     what_ = folly::to<std::string>("int == ", i_);
37     return what_.c_str();
38   }
39
40  private:
41   int i_;
42   mutable std::string what_;
43 };
44
45 const static std::string kExceptionClassName =
46     demangle(typeid(std::exception)).toStdString();
47 const static std::string kRuntimeErrorClassName =
48     demangle(typeid(std::runtime_error)).toStdString();
49 const static std::string kIntExceptionClassName =
50     demangle(typeid(IntException)).toStdString();
51 const static std::string kIntClassName = demangle(typeid(int)).toStdString();
52
53 template <typename T>
54 T& from_eptr(std::exception_ptr& eptr) {
55   try {
56     std::rethrow_exception(eptr);
57   } catch (T& e) {
58     return e;
59   } catch (...) {
60     throw std::logic_error("impossible");
61   }
62 }
63
64 // Tests that when we call throw_exception, the proper type is thrown (derived)
65 TEST(ExceptionWrapper, throw_test) {
66   std::runtime_error e("payload");
67   auto ew = make_exception_wrapper<std::runtime_error>(e);
68
69   std::vector<exception_wrapper> container;
70   container.push_back(ew);
71
72   try {
73     container[0].throw_exception();
74   } catch (std::runtime_error& err) {
75     std::string expected = "payload";
76     std::string actual = err.what();
77     EXPECT_EQ(expected, actual);
78   }
79 }
80
81 TEST(ExceptionWrapper, members) {
82   auto ew = exception_wrapper();
83   EXPECT_FALSE(bool(ew));
84   EXPECT_EQ(ew.what(), "");
85   EXPECT_EQ(ew.class_name(), "");
86   ew = make_exception_wrapper<std::runtime_error>("payload");
87   EXPECT_TRUE(bool(ew));
88   EXPECT_EQ(ew.what(), kRuntimeErrorClassName + ": payload");
89   EXPECT_EQ(ew.class_name(), kRuntimeErrorClassName);
90 }
91
92 TEST(ExceptionWrapper, try_and_catch_test) {
93   std::string expected = "payload";
94
95   // Catch rightmost matching exception type
96   exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
97     [=]() {
98       throw std::runtime_error(expected);
99     });
100   EXPECT_TRUE(bool(ew));
101   EXPECT_EQ(ew.what(), kRuntimeErrorClassName + ": payload");
102   EXPECT_EQ(ew.class_name(), kRuntimeErrorClassName);
103   auto rep = ew.is_compatible_with<std::runtime_error>();
104   EXPECT_TRUE(rep);
105
106   // Changing order is like catching in wrong order. Beware of this in your
107   // code.
108   auto ew2 = try_and_catch<std::runtime_error, std::exception>([=]() {
109     throw std::runtime_error(expected);
110   });
111   EXPECT_TRUE(bool(ew2));
112   // We are catching a std::exception, not std::runtime_error.
113   // But, we can still get the actual type if we want it.
114   rep = ew2.is_compatible_with<std::runtime_error>();
115   EXPECT_TRUE(rep);
116
117   // Catches even if not rightmost.
118   auto ew3 = try_and_catch<std::exception, std::runtime_error>([]() {
119     throw std::exception();
120   });
121   EXPECT_TRUE(bool(ew3));
122   EXPECT_EQ(ew3.what(), kExceptionClassName + ": std::exception");
123   EXPECT_EQ(ew3.class_name(), kExceptionClassName);
124   rep = ew3.is_compatible_with<std::runtime_error>();
125   EXPECT_FALSE(rep);
126
127   // If does not catch, throws.
128   EXPECT_THROW(
129     try_and_catch<std::runtime_error>([]() {
130       throw std::exception();
131     }),
132     std::exception);
133 }
134
135 TEST(ExceptionWrapper, with_exception_test) {
136   int expected = 23;
137
138   // This works, and doesn't slice.
139   exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
140     [=]() {
141       throw IntException(expected);
142     });
143   EXPECT_TRUE(bool(ew));
144   EXPECT_EQ(ew.what(), kIntExceptionClassName + ": int == 23");
145   EXPECT_EQ(ew.class_name(), kIntExceptionClassName);
146   EXPECT_TRUE(ew.with_exception(
147       [&](const IntException& ie) { EXPECT_EQ(ie.getInt(), expected); }));
148
149   // I can try_and_catch a non-copyable base class.  This will use
150   // std::exception_ptr internally.
151   exception_wrapper ew2 = try_and_catch<AbstractIntException>(
152     [=]() {
153       throw IntException(expected);
154     });
155   EXPECT_TRUE(bool(ew2));
156   EXPECT_EQ(ew2.what(), kIntExceptionClassName + ": int == 23");
157   EXPECT_EQ(ew2.class_name(), kIntExceptionClassName);
158   bool res = ew2.with_exception([&](AbstractIntException& ie) {
159     EXPECT_EQ(ie.getInt(), expected);
160     EXPECT_TRUE(dynamic_cast<IntException*>(&ie));
161   });
162   EXPECT_TRUE(res);
163
164   // Test with const this.  If this compiles and does not crash due to
165   // infinite loop when it runs, it succeeds.
166   const exception_wrapper& cew = ew;
167   EXPECT_TRUE(
168       cew.with_exception([&](const IntException& /* ie */) { SUCCEED(); }));
169
170   // Test with empty ew.
171   exception_wrapper empty_ew;
172   EXPECT_FALSE(
173       empty_ew.with_exception([&](const std::exception& /* ie */) { FAIL(); }));
174
175   // Testing with const exception_wrapper; sanity check first:
176   EXPECT_FALSE(cew.with_exception([&](const std::runtime_error&) {}));
177   EXPECT_FALSE(cew.with_exception([&](const int&) {}));
178   // This won't even compile.  You can't use a function which takes a
179   // non-const reference with a const exception_wrapper.
180   /*
181   EXPECT_FALSE(cew.with_exception([&](std::runtime_error&) {}));
182   EXPECT_FALSE(cew.with_exception([&](int&) {}));
183   */
184 }
185
186 TEST(ExceptionWrapper, get_or_make_exception_ptr_test) {
187   int expected = 23;
188
189   // This works, and doesn't slice.
190   exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
191       [=]() { throw IntException(expected); });
192   std::exception_ptr eptr = ew.to_exception_ptr();
193   EXPECT_THROW(std::rethrow_exception(eptr), IntException);
194
195   // I can try_and_catch a non-copyable base class.  This will use
196   // std::exception_ptr internally.
197   exception_wrapper ew2 = try_and_catch<AbstractIntException>(
198       [=]() { throw IntException(expected); });
199   eptr = ew2.to_exception_ptr();
200   EXPECT_THROW(std::rethrow_exception(eptr), IntException);
201
202   // Test with const this.
203   const exception_wrapper& cew = ew;
204   eptr = cew.to_exception_ptr();
205   EXPECT_THROW(std::rethrow_exception(eptr), IntException);
206
207   // Test with empty ew.
208   exception_wrapper empty_ew;
209   eptr = empty_ew.to_exception_ptr();
210   EXPECT_FALSE(eptr);
211 }
212
213 TEST(ExceptionWrapper, with_exception_ptr_empty) {
214   auto ew = exception_wrapper(std::exception_ptr());
215   EXPECT_EQ(exception_wrapper::none(), ew.type());
216   EXPECT_FALSE(bool(ew));
217   EXPECT_EQ(nullptr, ew.get_exception());
218   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
219   EXPECT_EQ(nullptr, ew.get_exception<int>());
220   EXPECT_FALSE(ew.has_exception_ptr());
221   EXPECT_EQ(nullptr, ew.to_exception_ptr());
222   EXPECT_FALSE(ew.has_exception_ptr());
223   EXPECT_EQ("", ew.class_name());
224   EXPECT_EQ("", ew.what());
225   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
226   EXPECT_FALSE(ew.is_compatible_with<int>());
227   EXPECT_DEATH(ew.throw_exception(), "empty folly::exception_wrapper");
228 }
229
230 TEST(ExceptionWrapper, with_shared_ptr_test) {
231   auto ew = exception_wrapper(std::runtime_error("foo"));
232   EXPECT_TRUE(bool(ew));
233   EXPECT_EQ(typeid(std::runtime_error), ew.type());
234   EXPECT_NE(nullptr, ew.get_exception());
235   EXPECT_NE(nullptr, ew.get_exception<std::exception>());
236   EXPECT_EQ(nullptr, ew.get_exception<int>());
237   EXPECT_FALSE(ew.has_exception_ptr());
238   EXPECT_NE(nullptr, ew.to_exception_ptr());
239   EXPECT_TRUE(ew.has_exception_ptr());
240   EXPECT_EQ("std::runtime_error", ew.class_name());
241   EXPECT_EQ("std::runtime_error: foo", ew.what());
242   EXPECT_TRUE(ew.is_compatible_with<std::exception>());
243   EXPECT_TRUE(ew.is_compatible_with<std::runtime_error>());
244   EXPECT_FALSE(ew.is_compatible_with<int>());
245   EXPECT_THROW(ew.throw_exception(), std::runtime_error);
246
247   exception_wrapper(std::move(ew));
248   EXPECT_FALSE(bool(ew));
249   EXPECT_EQ(exception_wrapper::none(), ew.type());
250   EXPECT_EQ(nullptr, ew.get_exception());
251   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
252   EXPECT_EQ(nullptr, ew.get_exception<int>());
253   EXPECT_EQ(nullptr, ew.to_exception_ptr());
254   EXPECT_EQ("", ew.class_name());
255   EXPECT_EQ("", ew.what());
256   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
257   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
258   EXPECT_FALSE(ew.is_compatible_with<int>());
259 }
260
261 TEST(ExceptionWrapper, with_exception_ptr_exn_test) {
262   auto ep = std::make_exception_ptr(std::runtime_error("foo"));
263   auto ew = exception_wrapper(ep, from_eptr<std::runtime_error>(ep));
264   EXPECT_TRUE(bool(ew));
265   EXPECT_EQ(typeid(std::runtime_error), ew.type());
266   EXPECT_NE(nullptr, ew.get_exception());
267   EXPECT_NE(nullptr, ew.get_exception<std::exception>());
268   EXPECT_EQ(nullptr, ew.get_exception<int>());
269   EXPECT_TRUE(ew.has_exception_ptr());
270   EXPECT_EQ(ep, ew.to_exception_ptr());
271   EXPECT_TRUE(ew.has_exception_ptr());
272   EXPECT_EQ("std::runtime_error", ew.class_name());
273   EXPECT_EQ("std::runtime_error: foo", ew.what());
274   EXPECT_TRUE(ew.is_compatible_with<std::exception>());
275   EXPECT_TRUE(ew.is_compatible_with<std::runtime_error>());
276   EXPECT_FALSE(ew.is_compatible_with<int>());
277   EXPECT_THROW(ew.throw_exception(), std::runtime_error);
278
279   exception_wrapper(std::move(ew));
280   EXPECT_FALSE(bool(ew));
281   EXPECT_EQ(exception_wrapper::none(), ew.type());
282   EXPECT_EQ(nullptr, ew.get_exception());
283   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
284   EXPECT_EQ(nullptr, ew.get_exception<int>());
285   EXPECT_EQ(nullptr, ew.to_exception_ptr());
286   EXPECT_EQ("", ew.class_name());
287   EXPECT_EQ("", ew.what());
288   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
289   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
290   EXPECT_FALSE(ew.is_compatible_with<int>());
291 }
292
293 TEST(ExceptionWrapper, with_exception_ptr_any_test) {
294   auto ep = std::make_exception_ptr<int>(12);
295   auto ew = exception_wrapper(ep, from_eptr<int>(ep));
296   EXPECT_TRUE(bool(ew));
297   EXPECT_EQ(nullptr, ew.get_exception());
298   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
299   EXPECT_NE(nullptr, ew.get_exception<int>());
300   EXPECT_TRUE(ew.has_exception_ptr());
301   EXPECT_EQ(ep, ew.to_exception_ptr());
302   EXPECT_TRUE(ew.has_exception_ptr());
303   EXPECT_EQ("int", ew.class_name());
304   EXPECT_EQ("int", ew.what());
305   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
306   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
307   EXPECT_TRUE(ew.is_compatible_with<int>());
308   EXPECT_THROW(ew.throw_exception(), int);
309
310   exception_wrapper(std::move(ew));
311   EXPECT_FALSE(bool(ew));
312   EXPECT_EQ(nullptr, ew.get_exception());
313   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
314   EXPECT_EQ(nullptr, ew.get_exception<int>());
315   EXPECT_EQ(nullptr, ew.to_exception_ptr());
316   EXPECT_FALSE(ew.has_exception_ptr());
317   EXPECT_EQ("", ew.class_name());
318   EXPECT_EQ("", ew.what());
319   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
320   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
321   EXPECT_FALSE(ew.is_compatible_with<int>());
322 }
323
324 TEST(ExceptionWrapper, with_non_std_exception_test) {
325   auto ew = exception_wrapper(folly::in_place, 42);
326   EXPECT_TRUE(bool(ew));
327   EXPECT_EQ(nullptr, ew.get_exception());
328   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
329   EXPECT_NE(nullptr, ew.get_exception<int>());
330   EXPECT_FALSE(ew.has_exception_ptr());
331   EXPECT_EQ("int", ew.class_name());
332   EXPECT_EQ("int", ew.what());
333   EXPECT_NE(nullptr, ew.to_exception_ptr());
334   EXPECT_TRUE(ew.has_exception_ptr());
335   EXPECT_EQ("int", ew.class_name());
336   EXPECT_EQ("int", ew.what());
337   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
338   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
339   EXPECT_TRUE(ew.is_compatible_with<int>());
340   EXPECT_THROW(ew.throw_exception(), int);
341
342   exception_wrapper(std::move(ew));
343   EXPECT_FALSE(bool(ew));
344   EXPECT_EQ(nullptr, ew.get_exception());
345   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
346   EXPECT_EQ(nullptr, ew.get_exception<int>());
347   EXPECT_EQ(nullptr, ew.to_exception_ptr());
348   EXPECT_FALSE(ew.has_exception_ptr());
349   EXPECT_EQ("", ew.class_name());
350   EXPECT_EQ("", ew.what());
351   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
352   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
353   EXPECT_FALSE(ew.is_compatible_with<int>());
354 }
355
356 TEST(ExceptionWrapper, with_exception_ptr_any_nil_test) {
357   auto ep = std::make_exception_ptr<int>(12);
358   auto ew = exception_wrapper(ep); // concrete type is erased
359   EXPECT_TRUE(bool(ew));
360   EXPECT_EQ(nullptr, ew.get_exception());
361   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
362   EXPECT_NE(nullptr, ew.get_exception<int>());
363   EXPECT_EQ(ep, ew.to_exception_ptr());
364   EXPECT_EQ("<unknown exception>", ew.class_name()); // because concrete type is
365   // erased
366   EXPECT_EQ("<unknown exception>", ew.what());
367   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
368   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
369   EXPECT_TRUE(ew.is_compatible_with<int>());
370   EXPECT_THROW(ew.throw_exception(), int);
371
372   exception_wrapper(std::move(ew));
373   EXPECT_FALSE(bool(ew));
374   EXPECT_EQ(nullptr, ew.get_exception());
375   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
376   EXPECT_EQ(nullptr, ew.get_exception<int>());
377   EXPECT_EQ(nullptr, ew.to_exception_ptr());
378   EXPECT_EQ("", ew.class_name());
379   EXPECT_EQ("", ew.what());
380   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
381   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
382   EXPECT_FALSE(ew.is_compatible_with<int>());
383 }
384
385 TEST(ExceptionWrapper, with_exception_deduction) {
386   auto ew = make_exception_wrapper<std::runtime_error>("hi");
387   EXPECT_TRUE(ew.with_exception([](std::runtime_error&) {}));
388   EXPECT_TRUE(ew.with_exception([](std::exception&) {}));
389   EXPECT_FALSE(ew.with_exception([](std::logic_error&) {}));
390 }
391
392 TEST(ExceptionWrapper, with_exception_deduction_exn_const) {
393   auto ew = make_exception_wrapper<std::runtime_error>("hi");
394   EXPECT_TRUE(ew.with_exception([](const std::runtime_error&) {}));
395   EXPECT_TRUE(ew.with_exception([](const std::exception&) {}));
396   EXPECT_FALSE(ew.with_exception([](const std::logic_error&) {}));
397 }
398
399 TEST(ExceptionWrapper, with_exception_deduction_wrap_const_exn_const) {
400   const auto cew = make_exception_wrapper<std::runtime_error>("hi");
401   EXPECT_TRUE(cew.with_exception([](const std::runtime_error&) {}));
402   EXPECT_TRUE(cew.with_exception([](const std::exception&) {}));
403   EXPECT_FALSE(cew.with_exception([](const std::logic_error&) {}));
404 }
405
406 TEST(ExceptionWrapper, with_exception_deduction_returning) {
407   auto ew = make_exception_wrapper<std::runtime_error>("hi");
408   EXPECT_TRUE(ew.with_exception([](std::runtime_error&) { return 3; }));
409   EXPECT_TRUE(ew.with_exception([](std::exception&) { return "hello"; }));
410   EXPECT_FALSE(ew.with_exception([](std::logic_error&) { return nullptr; }));
411 }
412
413 namespace {
414 template <typename T>
415 T& r_to_l(T v) { return std::ref(v); }
416 }
417
418 TEST(ExceptionWrapper, with_exception_deduction_functor_lvalue) {
419   auto ew = make_exception_wrapper<std::runtime_error>("hi");
420   EXPECT_TRUE(ew.with_exception(r_to_l([](std::runtime_error&) {})));
421   EXPECT_TRUE(ew.with_exception(r_to_l([](std::exception&) {})));
422   EXPECT_FALSE(ew.with_exception(r_to_l([](std::logic_error&) {})));
423 }
424
425 TEST(ExceptionWrapper, non_std_exception_test) {
426   int expected = 17;
427
428   exception_wrapper ew = try_and_catch<std::exception, int>(
429     [=]() {
430       throw expected;
431     });
432   EXPECT_TRUE(bool(ew));
433   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
434   EXPECT_TRUE(ew.is_compatible_with<int>());
435   EXPECT_EQ(ew.what(), kIntClassName);
436   EXPECT_EQ(ew.class_name(), kIntClassName);
437   // non-std::exception types are supported, but the only way to
438   // access their value is to explicity rethrow and catch it.
439   try {
440     ew.throw_exception();
441   } catch /* nolint */ (int& i) {
442     EXPECT_EQ(i, expected);
443   }
444 }
445
446
447 TEST(ExceptionWrapper, exceptionStr) {
448   auto ew = make_exception_wrapper<std::runtime_error>("argh");
449   EXPECT_EQ(kRuntimeErrorClassName + ": argh", exceptionStr(ew));
450 }
451
452 TEST(ExceptionWrapper, throwException_noException) {
453   exception_wrapper ew;
454   ASSERT_DEATH(ew.throw_exception(), "empty folly::exception_wrapper");
455 }
456
457 namespace {
458 class TestException : public std::exception { };
459 void testEW(const exception_wrapper& ew) {
460   EXPECT_THROW(ew.throw_exception(), TestException);
461 }
462 }  // namespace
463
464 TEST(ExceptionWrapper, implicitConstruction) {
465   // Try with both lvalue and rvalue references
466   TestException e;
467   testEW(e);
468   testEW(TestException());
469 }
470
471 namespace {
472 struct BaseException {
473   virtual ~BaseException() {}
474 };
475 struct DerivedException : BaseException {};
476 exception_wrapper testNonStdException() {
477   try {
478     throw DerivedException{};
479   } catch (const BaseException& e) {
480     return exception_wrapper{std::current_exception(), e};
481   }
482 }
483 }
484
485 TEST(ExceptionWrapper, base_derived_non_std_exception_test) {
486   auto ew = testNonStdException();
487   EXPECT_TRUE(ew.type() == typeid(DerivedException));
488   EXPECT_TRUE(ew.with_exception([](const DerivedException&) {}));
489 }
490
491 namespace {
492 // Cannot be stored within an exception_wrapper
493 struct BigRuntimeError : std::runtime_error {
494   using std::runtime_error::runtime_error;
495   char data_[sizeof(exception_wrapper) + 1]{};
496 };
497
498 struct BigNonStdError {
499   char data_[sizeof(exception_wrapper) + 1]{};
500 };
501 }
502
503 TEST(ExceptionWrapper, handle_std_exception) {
504   auto ep = std::make_exception_ptr(std::runtime_error{"hello world"});
505   exception_wrapper const ew_eptr(ep, from_eptr<std::runtime_error>(ep));
506   exception_wrapper const ew_small(std::runtime_error{"hello world"});
507   exception_wrapper const ew_big(BigRuntimeError{"hello world"});
508
509   bool handled = false;
510   auto expect_runtime_error_yes_catch_all = [&](const exception_wrapper& ew) {
511     ew.handle(
512         [](const std::logic_error&) { EXPECT_TRUE(false); },
513         [&](const std::runtime_error&) { handled = true; },
514         [](const std::exception&) { EXPECT_TRUE(false); },
515         [](...) { EXPECT_TRUE(false); });
516   };
517
518   expect_runtime_error_yes_catch_all(ew_eptr);
519   EXPECT_TRUE(handled);
520   handled = false;
521   expect_runtime_error_yes_catch_all(ew_small);
522   EXPECT_TRUE(handled);
523   handled = false;
524   expect_runtime_error_yes_catch_all(ew_big);
525   EXPECT_TRUE(handled);
526   handled = false;
527
528   auto expect_runtime_error_no_catch_all = [&](const exception_wrapper& ew) {
529     ew.handle(
530         [](const std::logic_error&) { EXPECT_TRUE(false); },
531         [&](const std::runtime_error&) { handled = true; },
532         [](const std::exception&) { EXPECT_TRUE(false); });
533   };
534
535   expect_runtime_error_no_catch_all(ew_eptr);
536   EXPECT_TRUE(handled);
537   handled = false;
538   expect_runtime_error_no_catch_all(ew_small);
539   EXPECT_TRUE(handled);
540   handled = false;
541   expect_runtime_error_no_catch_all(ew_big);
542   EXPECT_TRUE(handled);
543   handled = false;
544
545   auto expect_runtime_error_catch_non_std = [&](const exception_wrapper& ew) {
546     ew.handle(
547         [](const std::logic_error&) { EXPECT_TRUE(false); },
548         [&](const std::runtime_error&) { handled = true; },
549         [](const std::exception&) { EXPECT_TRUE(false); },
550         [](const int&) { EXPECT_TRUE(false); });
551   };
552
553   expect_runtime_error_catch_non_std(ew_eptr);
554   EXPECT_TRUE(handled);
555   handled = false;
556   expect_runtime_error_catch_non_std(ew_small);
557   EXPECT_TRUE(handled);
558   handled = false;
559   expect_runtime_error_catch_non_std(ew_big);
560   EXPECT_TRUE(handled);
561   handled = false;
562
563   // Test that an exception thrown from one handler is not caught by an
564   // outer handler:
565   auto expect_runtime_error_rethrow = [&](const exception_wrapper& ew) {
566     ew.handle(
567         [](const std::logic_error&) { EXPECT_TRUE(false); },
568         [&](const std::runtime_error& e) {
569           handled = true;
570           throw e;
571         },
572         [](const std::exception&) { EXPECT_TRUE(false); });
573   };
574
575   EXPECT_THROW(expect_runtime_error_rethrow(ew_eptr), std::runtime_error);
576   EXPECT_TRUE(handled);
577   handled = false;
578   EXPECT_THROW(expect_runtime_error_rethrow(ew_small), std::runtime_error);
579   EXPECT_TRUE(handled);
580   handled = false;
581   EXPECT_THROW(expect_runtime_error_rethrow(ew_big), std::runtime_error);
582   EXPECT_TRUE(handled);
583 }
584
585 TEST(ExceptionWrapper, handle_std_exception_unhandled) {
586   auto ep = std::make_exception_ptr(std::exception{});
587   exception_wrapper const ew_eptr(ep, from_eptr<std::exception>(ep));
588   exception_wrapper const ew_small(std::exception{});
589
590   bool handled = false;
591   auto expect_runtime_error_yes_catch_all = [&](const exception_wrapper& ew) {
592     ew.handle(
593         [](const std::logic_error&) { EXPECT_TRUE(false); },
594         [](const std::runtime_error&) { EXPECT_TRUE(false); },
595         [&](...) { handled = true; });
596   };
597
598   expect_runtime_error_yes_catch_all(ew_eptr);
599   EXPECT_TRUE(handled);
600   handled = false;
601   expect_runtime_error_yes_catch_all(ew_small);
602   EXPECT_TRUE(handled);
603 }
604
605 TEST(ExceptionWrapper, handle_non_std_exception_small) {
606   auto ep = std::make_exception_ptr(42);
607   exception_wrapper const ew_eptr1(ep);
608   exception_wrapper const ew_eptr2(ep, from_eptr<int>(ep));
609   exception_wrapper const ew_small(folly::in_place, 42);
610   bool handled = false;
611
612   auto expect_int_yes_catch_all = [&](const exception_wrapper& ew) {
613     ew.handle(
614         [](const std::exception&) { EXPECT_TRUE(false); },
615         [&](...) { handled = true; });
616   };
617
618   expect_int_yes_catch_all(ew_eptr1);
619   EXPECT_TRUE(handled);
620   handled = false;
621   expect_int_yes_catch_all(ew_eptr2);
622   EXPECT_TRUE(handled);
623   handled = false;
624   expect_int_yes_catch_all(ew_small);
625   EXPECT_TRUE(handled);
626   handled = false;
627
628   auto expect_int_no_catch_all = [&](const exception_wrapper& ew) {
629     ew.handle(
630         [](const std::exception&) { EXPECT_TRUE(false); },
631         [&](const int&) { handled = true; });
632   };
633
634   expect_int_no_catch_all(ew_eptr1);
635   EXPECT_TRUE(handled);
636   handled = false;
637   expect_int_no_catch_all(ew_eptr2);
638   EXPECT_TRUE(handled);
639   handled = false;
640   expect_int_no_catch_all(ew_small);
641   EXPECT_TRUE(handled);
642   handled = false;
643
644   auto expect_int_no_catch_all_2 = [&](const exception_wrapper& ew) {
645     ew.handle(
646         [&](const int&) { handled = true; },
647         [](const std::exception&) { EXPECT_TRUE(false); });
648   };
649
650   expect_int_no_catch_all_2(ew_eptr1);
651   EXPECT_TRUE(handled);
652   handled = false;
653   expect_int_no_catch_all_2(ew_eptr2);
654   EXPECT_TRUE(handled);
655   handled = false;
656   expect_int_no_catch_all_2(ew_small);
657   EXPECT_TRUE(handled);
658 }
659
660 TEST(ExceptionWrapper, handle_non_std_exception_big) {
661   auto ep = std::make_exception_ptr(BigNonStdError{});
662   exception_wrapper const ew_eptr1(ep);
663   exception_wrapper const ew_eptr2(ep, from_eptr<BigNonStdError>(ep));
664   exception_wrapper const ew_big(folly::in_place, BigNonStdError{});
665   bool handled = false;
666
667   auto expect_int_yes_catch_all = [&](const exception_wrapper& ew) {
668     ew.handle(
669         [](const std::exception&) { EXPECT_TRUE(false); },
670         [&](...) { handled = true; });
671   };
672
673   expect_int_yes_catch_all(ew_eptr1);
674   EXPECT_TRUE(handled);
675   handled = false;
676   expect_int_yes_catch_all(ew_eptr2);
677   EXPECT_TRUE(handled);
678   handled = false;
679   expect_int_yes_catch_all(ew_big);
680   EXPECT_TRUE(handled);
681   handled = false;
682
683   auto expect_int_no_catch_all = [&](const exception_wrapper& ew) {
684     ew.handle(
685         [](const std::exception&) { EXPECT_TRUE(false); },
686         [&](const BigNonStdError&) { handled = true; });
687   };
688
689   expect_int_no_catch_all(ew_eptr1);
690   EXPECT_TRUE(handled);
691   handled = false;
692   expect_int_no_catch_all(ew_eptr2);
693   EXPECT_TRUE(handled);
694   handled = false;
695   expect_int_no_catch_all(ew_big);
696   EXPECT_TRUE(handled);
697   handled = false;
698
699   auto expect_int_no_catch_all_2 = [&](const exception_wrapper& ew) {
700     ew.handle(
701         [&](const BigNonStdError&) { handled = true; },
702         [](const std::exception&) { EXPECT_TRUE(false); });
703   };
704
705   expect_int_no_catch_all_2(ew_eptr1);
706   EXPECT_TRUE(handled);
707   handled = false;
708   expect_int_no_catch_all_2(ew_eptr2);
709   EXPECT_TRUE(handled);
710   handled = false;
711   expect_int_no_catch_all_2(ew_big);
712   EXPECT_TRUE(handled);
713   handled = false;
714
715   EXPECT_THROW(
716       expect_int_no_catch_all_2(exception_wrapper{folly::in_place, 42}), int);
717 }
718
719 TEST(ExceptionWrapper, handle_non_std_exception_rethrow_base_derived) {
720   auto ew = testNonStdException();
721   bool handled = false;
722   EXPECT_THROW(
723       ew.handle(
724           [&](const DerivedException& e) {
725             handled = true;
726             throw e;
727           },
728           [](const BaseException&) { EXPECT_TRUE(false); }),
729       DerivedException);
730   EXPECT_TRUE(handled);
731   handled = false;
732   EXPECT_THROW(
733       ew.handle(
734           [&](const DerivedException& e) {
735             handled = true;
736             throw e;
737           },
738           [](...) { EXPECT_TRUE(false); }),
739       DerivedException);
740   EXPECT_TRUE(handled);
741 }
742
743 TEST(ExceptionWrapper, self_swap_test) {
744   exception_wrapper ew(std::runtime_error("hello world"));
745   folly::swap(ew, ew);
746   EXPECT_STREQ("std::runtime_error: hello world", ew.what().c_str());
747   auto& ew2 = ew;
748   ew = std::move(ew2); // should not crash
749 }