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