Fix a few exception_wrapper tests under MSVC
[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), 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, with_exception_ptr_empty) {
213   auto ew = exception_wrapper(std::exception_ptr());
214   EXPECT_EQ(exception_wrapper::none(), ew.type());
215   EXPECT_FALSE(bool(ew));
216   EXPECT_EQ(nullptr, ew.get_exception());
217   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
218   EXPECT_EQ(nullptr, ew.get_exception<int>());
219   EXPECT_FALSE(ew.has_exception_ptr());
220   EXPECT_EQ(nullptr, ew.to_exception_ptr());
221   EXPECT_FALSE(ew.has_exception_ptr());
222   EXPECT_EQ("", ew.class_name());
223   EXPECT_EQ("", ew.what());
224   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
225   EXPECT_FALSE(ew.is_compatible_with<int>());
226   EXPECT_DEATH(ew.throw_exception(), "empty folly::exception_wrapper");
227 }
228
229 TEST(ExceptionWrapper, with_shared_ptr_test) {
230   auto ew = exception_wrapper(std::runtime_error("foo"));
231   EXPECT_TRUE(bool(ew));
232   EXPECT_EQ(typeid(std::runtime_error), ew.type());
233   EXPECT_NE(nullptr, ew.get_exception());
234   EXPECT_NE(nullptr, ew.get_exception<std::exception>());
235   EXPECT_EQ(nullptr, ew.get_exception<int>());
236   EXPECT_FALSE(ew.has_exception_ptr());
237   EXPECT_NE(nullptr, ew.to_exception_ptr());
238   EXPECT_TRUE(ew.has_exception_ptr());
239   EXPECT_EQ(kRuntimeErrorClassName, ew.class_name());
240   EXPECT_EQ(kRuntimeErrorClassName + ": foo", ew.what());
241   EXPECT_TRUE(ew.is_compatible_with<std::exception>());
242   EXPECT_TRUE(ew.is_compatible_with<std::runtime_error>());
243   EXPECT_FALSE(ew.is_compatible_with<int>());
244   EXPECT_THROW(ew.throw_exception(), std::runtime_error);
245
246   exception_wrapper(std::move(ew));
247   EXPECT_FALSE(bool(ew));
248   EXPECT_EQ(exception_wrapper::none(), ew.type());
249   EXPECT_EQ(nullptr, ew.get_exception());
250   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
251   EXPECT_EQ(nullptr, ew.get_exception<int>());
252   EXPECT_EQ(nullptr, ew.to_exception_ptr());
253   EXPECT_EQ("", ew.class_name());
254   EXPECT_EQ("", ew.what());
255   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
256   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
257   EXPECT_FALSE(ew.is_compatible_with<int>());
258 }
259
260 TEST(ExceptionWrapper, with_exception_ptr_exn_test) {
261   auto ep = std::make_exception_ptr(std::runtime_error("foo"));
262   auto ew = exception_wrapper(ep, from_eptr<std::runtime_error>(ep));
263   EXPECT_TRUE(bool(ew));
264   EXPECT_EQ(typeid(std::runtime_error), ew.type());
265   EXPECT_NE(nullptr, ew.get_exception());
266   EXPECT_NE(nullptr, ew.get_exception<std::exception>());
267   EXPECT_EQ(nullptr, ew.get_exception<int>());
268   EXPECT_TRUE(ew.has_exception_ptr());
269   EXPECT_EQ(ep, ew.to_exception_ptr());
270   EXPECT_TRUE(ew.has_exception_ptr());
271   EXPECT_EQ(kRuntimeErrorClassName, ew.class_name());
272   EXPECT_EQ(kRuntimeErrorClassName + ": foo", ew.what());
273   EXPECT_TRUE(ew.is_compatible_with<std::exception>());
274   EXPECT_TRUE(ew.is_compatible_with<std::runtime_error>());
275   EXPECT_FALSE(ew.is_compatible_with<int>());
276   EXPECT_THROW(ew.throw_exception(), std::runtime_error);
277
278   exception_wrapper(std::move(ew));
279   EXPECT_FALSE(bool(ew));
280   EXPECT_EQ(exception_wrapper::none(), ew.type());
281   EXPECT_EQ(nullptr, ew.get_exception());
282   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
283   EXPECT_EQ(nullptr, ew.get_exception<int>());
284   EXPECT_EQ(nullptr, ew.to_exception_ptr());
285   EXPECT_EQ("", ew.class_name());
286   EXPECT_EQ("", ew.what());
287   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
288   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
289   EXPECT_FALSE(ew.is_compatible_with<int>());
290 }
291
292 TEST(ExceptionWrapper, with_exception_ptr_any_test) {
293   auto ep = std::make_exception_ptr<int>(12);
294   auto ew = exception_wrapper(ep, from_eptr<int>(ep));
295   EXPECT_TRUE(bool(ew));
296   EXPECT_EQ(nullptr, ew.get_exception());
297   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
298   EXPECT_NE(nullptr, ew.get_exception<int>());
299   EXPECT_TRUE(ew.has_exception_ptr());
300   EXPECT_EQ(ep, ew.to_exception_ptr());
301   EXPECT_TRUE(ew.has_exception_ptr());
302   EXPECT_EQ("int", ew.class_name());
303   EXPECT_EQ("int", ew.what());
304   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
305   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
306   EXPECT_TRUE(ew.is_compatible_with<int>());
307   EXPECT_THROW(ew.throw_exception(), int);
308
309   exception_wrapper(std::move(ew));
310   EXPECT_FALSE(bool(ew));
311   EXPECT_EQ(nullptr, ew.get_exception());
312   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
313   EXPECT_EQ(nullptr, ew.get_exception<int>());
314   EXPECT_EQ(nullptr, ew.to_exception_ptr());
315   EXPECT_FALSE(ew.has_exception_ptr());
316   EXPECT_EQ("", ew.class_name());
317   EXPECT_EQ("", ew.what());
318   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
319   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
320   EXPECT_FALSE(ew.is_compatible_with<int>());
321 }
322
323 TEST(ExceptionWrapper, with_non_std_exception_test) {
324   auto ew = exception_wrapper(folly::in_place, 42);
325   EXPECT_TRUE(bool(ew));
326   EXPECT_EQ(nullptr, ew.get_exception());
327   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
328   EXPECT_NE(nullptr, ew.get_exception<int>());
329   EXPECT_FALSE(ew.has_exception_ptr());
330   EXPECT_EQ("int", ew.class_name());
331   EXPECT_EQ("int", ew.what());
332   EXPECT_NE(nullptr, ew.to_exception_ptr());
333   EXPECT_TRUE(ew.has_exception_ptr());
334   EXPECT_EQ("int", ew.class_name());
335   EXPECT_EQ("int", ew.what());
336   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
337   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
338   EXPECT_TRUE(ew.is_compatible_with<int>());
339   EXPECT_THROW(ew.throw_exception(), int);
340
341   exception_wrapper(std::move(ew));
342   EXPECT_FALSE(bool(ew));
343   EXPECT_EQ(nullptr, ew.get_exception());
344   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
345   EXPECT_EQ(nullptr, ew.get_exception<int>());
346   EXPECT_EQ(nullptr, ew.to_exception_ptr());
347   EXPECT_FALSE(ew.has_exception_ptr());
348   EXPECT_EQ("", ew.class_name());
349   EXPECT_EQ("", ew.what());
350   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
351   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
352   EXPECT_FALSE(ew.is_compatible_with<int>());
353 }
354
355 TEST(ExceptionWrapper, with_exception_ptr_any_nil_test) {
356   auto ep = std::make_exception_ptr<int>(12);
357   auto ew = exception_wrapper(ep); // concrete type is erased
358   EXPECT_TRUE(bool(ew));
359   EXPECT_EQ(nullptr, ew.get_exception());
360   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
361   EXPECT_NE(nullptr, ew.get_exception<int>());
362   EXPECT_EQ(ep, ew.to_exception_ptr());
363   EXPECT_EQ("<unknown exception>", ew.class_name()); // because concrete type is
364   // erased
365   EXPECT_EQ("<unknown exception>", ew.what());
366   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
367   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
368   EXPECT_TRUE(ew.is_compatible_with<int>());
369   EXPECT_THROW(ew.throw_exception(), int);
370
371   exception_wrapper(std::move(ew));
372   EXPECT_FALSE(bool(ew));
373   EXPECT_EQ(nullptr, ew.get_exception());
374   EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
375   EXPECT_EQ(nullptr, ew.get_exception<int>());
376   EXPECT_EQ(nullptr, ew.to_exception_ptr());
377   EXPECT_EQ("", ew.class_name());
378   EXPECT_EQ("", ew.what());
379   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
380   EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
381   EXPECT_FALSE(ew.is_compatible_with<int>());
382 }
383
384 TEST(ExceptionWrapper, with_exception_deduction) {
385   auto ew = make_exception_wrapper<std::runtime_error>("hi");
386   EXPECT_TRUE(ew.with_exception([](std::runtime_error&) {}));
387   EXPECT_TRUE(ew.with_exception([](std::exception&) {}));
388   EXPECT_FALSE(ew.with_exception([](std::logic_error&) {}));
389 }
390
391 TEST(ExceptionWrapper, with_exception_deduction_exn_const) {
392   auto ew = make_exception_wrapper<std::runtime_error>("hi");
393   EXPECT_TRUE(ew.with_exception([](const std::runtime_error&) {}));
394   EXPECT_TRUE(ew.with_exception([](const std::exception&) {}));
395   EXPECT_FALSE(ew.with_exception([](const std::logic_error&) {}));
396 }
397
398 TEST(ExceptionWrapper, with_exception_deduction_wrap_const_exn_const) {
399   const auto cew = make_exception_wrapper<std::runtime_error>("hi");
400   EXPECT_TRUE(cew.with_exception([](const std::runtime_error&) {}));
401   EXPECT_TRUE(cew.with_exception([](const std::exception&) {}));
402   EXPECT_FALSE(cew.with_exception([](const std::logic_error&) {}));
403 }
404
405 TEST(ExceptionWrapper, with_exception_deduction_returning) {
406   auto ew = make_exception_wrapper<std::runtime_error>("hi");
407   EXPECT_TRUE(ew.with_exception([](std::runtime_error&) { return 3; }));
408   EXPECT_TRUE(ew.with_exception([](std::exception&) { return "hello"; }));
409   EXPECT_FALSE(ew.with_exception([](std::logic_error&) { return nullptr; }));
410 }
411
412 namespace {
413 template <typename T>
414 T& r_to_l(T v) { return std::ref(v); }
415 }
416
417 TEST(ExceptionWrapper, with_exception_deduction_functor_lvalue) {
418   auto ew = make_exception_wrapper<std::runtime_error>("hi");
419   EXPECT_TRUE(ew.with_exception(r_to_l([](std::runtime_error&) {})));
420   EXPECT_TRUE(ew.with_exception(r_to_l([](std::exception&) {})));
421   EXPECT_FALSE(ew.with_exception(r_to_l([](std::logic_error&) {})));
422 }
423
424 TEST(ExceptionWrapper, non_std_exception_test) {
425   int expected = 17;
426
427   exception_wrapper ew = try_and_catch<std::exception, int>(
428     [=]() {
429       throw expected;
430     });
431   EXPECT_TRUE(bool(ew));
432   EXPECT_FALSE(ew.is_compatible_with<std::exception>());
433   EXPECT_TRUE(ew.is_compatible_with<int>());
434   EXPECT_EQ(ew.what(), kIntClassName);
435   EXPECT_EQ(ew.class_name(), kIntClassName);
436   // non-std::exception types are supported, but the only way to
437   // access their value is to explicity rethrow and catch it.
438   try {
439     ew.throw_exception();
440   } catch /* nolint */ (int& i) {
441     EXPECT_EQ(i, expected);
442   }
443 }
444
445
446 TEST(ExceptionWrapper, exceptionStr) {
447   auto ew = make_exception_wrapper<std::runtime_error>("argh");
448   EXPECT_EQ(kRuntimeErrorClassName + ": argh", exceptionStr(ew));
449 }
450
451 TEST(ExceptionWrapper, throwException_noException) {
452   exception_wrapper ew;
453   ASSERT_DEATH(ew.throw_exception(), "empty folly::exception_wrapper");
454 }
455
456 namespace {
457 class TestException : public std::exception { };
458 void testEW(const exception_wrapper& ew) {
459   EXPECT_THROW(ew.throw_exception(), TestException);
460 }
461 }  // namespace
462
463 TEST(ExceptionWrapper, implicitConstruction) {
464   // Try with both lvalue and rvalue references
465   TestException e;
466   testEW(e);
467   testEW(TestException());
468 }
469
470 namespace {
471 struct BaseException {
472   virtual ~BaseException() {}
473 };
474 struct DerivedException : BaseException {};
475 exception_wrapper testNonStdException() {
476   try {
477     throw DerivedException{};
478   } catch (const BaseException& e) {
479     return exception_wrapper{std::current_exception(), e};
480   }
481 }
482 }
483
484 TEST(ExceptionWrapper, base_derived_non_std_exception_test) {
485   auto ew = testNonStdException();
486   EXPECT_TRUE(ew.type() == typeid(DerivedException));
487   EXPECT_TRUE(ew.with_exception([](const DerivedException&) {}));
488 }
489
490 namespace {
491 // Cannot be stored within an exception_wrapper
492 struct BigRuntimeError : std::runtime_error {
493   using std::runtime_error::runtime_error;
494   char data_[sizeof(exception_wrapper) + 1]{};
495 };
496
497 struct BigNonStdError {
498   char data_[sizeof(exception_wrapper) + 1]{};
499 };
500 }
501
502 TEST(ExceptionWrapper, handle_std_exception) {
503   auto ep = std::make_exception_ptr(std::runtime_error{"hello world"});
504   exception_wrapper const ew_eptr(ep, from_eptr<std::runtime_error>(ep));
505   exception_wrapper const ew_small(std::runtime_error{"hello world"});
506   exception_wrapper const ew_big(BigRuntimeError{"hello world"});
507
508   bool handled = false;
509   auto expect_runtime_error_yes_catch_all = [&](const exception_wrapper& ew) {
510     ew.handle(
511         [](const std::logic_error&) { EXPECT_TRUE(false); },
512         [&](const std::runtime_error&) { handled = true; },
513         [](const std::exception&) { EXPECT_TRUE(false); },
514         [](...) { EXPECT_TRUE(false); });
515   };
516
517   expect_runtime_error_yes_catch_all(ew_eptr);
518   EXPECT_TRUE(handled);
519   handled = false;
520   expect_runtime_error_yes_catch_all(ew_small);
521   EXPECT_TRUE(handled);
522   handled = false;
523   expect_runtime_error_yes_catch_all(ew_big);
524   EXPECT_TRUE(handled);
525   handled = false;
526
527   auto expect_runtime_error_no_catch_all = [&](const exception_wrapper& ew) {
528     ew.handle(
529         [](const std::logic_error&) { EXPECT_TRUE(false); },
530         [&](const std::runtime_error&) { handled = true; },
531         [](const std::exception&) { EXPECT_TRUE(false); });
532   };
533
534   expect_runtime_error_no_catch_all(ew_eptr);
535   EXPECT_TRUE(handled);
536   handled = false;
537   expect_runtime_error_no_catch_all(ew_small);
538   EXPECT_TRUE(handled);
539   handled = false;
540   expect_runtime_error_no_catch_all(ew_big);
541   EXPECT_TRUE(handled);
542   handled = false;
543
544   auto expect_runtime_error_catch_non_std = [&](const exception_wrapper& ew) {
545     ew.handle(
546         [](const std::logic_error&) { EXPECT_TRUE(false); },
547         [&](const std::runtime_error&) { handled = true; },
548         [](const std::exception&) { EXPECT_TRUE(false); },
549         [](const int&) { EXPECT_TRUE(false); });
550   };
551
552   expect_runtime_error_catch_non_std(ew_eptr);
553   EXPECT_TRUE(handled);
554   handled = false;
555   expect_runtime_error_catch_non_std(ew_small);
556   EXPECT_TRUE(handled);
557   handled = false;
558   expect_runtime_error_catch_non_std(ew_big);
559   EXPECT_TRUE(handled);
560   handled = false;
561
562   // Test that an exception thrown from one handler is not caught by an
563   // outer handler:
564   auto expect_runtime_error_rethrow = [&](const exception_wrapper& ew) {
565     ew.handle(
566         [](const std::logic_error&) { EXPECT_TRUE(false); },
567         [&](const std::runtime_error& e) {
568           handled = true;
569           throw e;
570         },
571         [](const std::exception&) { EXPECT_TRUE(false); });
572   };
573
574   EXPECT_THROW(expect_runtime_error_rethrow(ew_eptr), std::runtime_error);
575   EXPECT_TRUE(handled);
576   handled = false;
577   EXPECT_THROW(expect_runtime_error_rethrow(ew_small), std::runtime_error);
578   EXPECT_TRUE(handled);
579   handled = false;
580   EXPECT_THROW(expect_runtime_error_rethrow(ew_big), std::runtime_error);
581   EXPECT_TRUE(handled);
582 }
583
584 TEST(ExceptionWrapper, handle_std_exception_unhandled) {
585   auto ep = std::make_exception_ptr(std::exception{});
586   exception_wrapper const ew_eptr(ep, from_eptr<std::exception>(ep));
587   exception_wrapper const ew_small(std::exception{});
588
589   bool handled = false;
590   auto expect_runtime_error_yes_catch_all = [&](const exception_wrapper& ew) {
591     ew.handle(
592         [](const std::logic_error&) { EXPECT_TRUE(false); },
593         [](const std::runtime_error&) { EXPECT_TRUE(false); },
594         [&](...) { handled = true; });
595   };
596
597   expect_runtime_error_yes_catch_all(ew_eptr);
598   EXPECT_TRUE(handled);
599   handled = false;
600   expect_runtime_error_yes_catch_all(ew_small);
601   EXPECT_TRUE(handled);
602 }
603
604 TEST(ExceptionWrapper, handle_non_std_exception_small) {
605   auto ep = std::make_exception_ptr(42);
606   exception_wrapper const ew_eptr1(ep);
607   exception_wrapper const ew_eptr2(ep, from_eptr<int>(ep));
608   exception_wrapper const ew_small(folly::in_place, 42);
609   bool handled = false;
610
611   auto expect_int_yes_catch_all = [&](const exception_wrapper& ew) {
612     ew.handle(
613         [](const std::exception&) { EXPECT_TRUE(false); },
614         [&](...) { handled = true; });
615   };
616
617   expect_int_yes_catch_all(ew_eptr1);
618   EXPECT_TRUE(handled);
619   handled = false;
620   expect_int_yes_catch_all(ew_eptr2);
621   EXPECT_TRUE(handled);
622   handled = false;
623   expect_int_yes_catch_all(ew_small);
624   EXPECT_TRUE(handled);
625   handled = false;
626
627   auto expect_int_no_catch_all = [&](const exception_wrapper& ew) {
628     ew.handle(
629         [](const std::exception&) { EXPECT_TRUE(false); },
630         [&](const int&) { handled = true; });
631   };
632
633   expect_int_no_catch_all(ew_eptr1);
634   EXPECT_TRUE(handled);
635   handled = false;
636   expect_int_no_catch_all(ew_eptr2);
637   EXPECT_TRUE(handled);
638   handled = false;
639   expect_int_no_catch_all(ew_small);
640   EXPECT_TRUE(handled);
641   handled = false;
642
643   auto expect_int_no_catch_all_2 = [&](const exception_wrapper& ew) {
644     ew.handle(
645         [&](const int&) { handled = true; },
646         [](const std::exception&) { EXPECT_TRUE(false); });
647   };
648
649   expect_int_no_catch_all_2(ew_eptr1);
650   EXPECT_TRUE(handled);
651   handled = false;
652   expect_int_no_catch_all_2(ew_eptr2);
653   EXPECT_TRUE(handled);
654   handled = false;
655   expect_int_no_catch_all_2(ew_small);
656   EXPECT_TRUE(handled);
657 }
658
659 TEST(ExceptionWrapper, handle_non_std_exception_big) {
660   auto ep = std::make_exception_ptr(BigNonStdError{});
661   exception_wrapper const ew_eptr1(ep);
662   exception_wrapper const ew_eptr2(ep, from_eptr<BigNonStdError>(ep));
663   exception_wrapper const ew_big(folly::in_place, BigNonStdError{});
664   bool handled = false;
665
666   auto expect_int_yes_catch_all = [&](const exception_wrapper& ew) {
667     ew.handle(
668         [](const std::exception&) { EXPECT_TRUE(false); },
669         [&](...) { handled = true; });
670   };
671
672   expect_int_yes_catch_all(ew_eptr1);
673   EXPECT_TRUE(handled);
674   handled = false;
675   expect_int_yes_catch_all(ew_eptr2);
676   EXPECT_TRUE(handled);
677   handled = false;
678   expect_int_yes_catch_all(ew_big);
679   EXPECT_TRUE(handled);
680   handled = false;
681
682   auto expect_int_no_catch_all = [&](const exception_wrapper& ew) {
683     ew.handle(
684         [](const std::exception&) { EXPECT_TRUE(false); },
685         [&](const BigNonStdError&) { handled = true; });
686   };
687
688   expect_int_no_catch_all(ew_eptr1);
689   EXPECT_TRUE(handled);
690   handled = false;
691   expect_int_no_catch_all(ew_eptr2);
692   EXPECT_TRUE(handled);
693   handled = false;
694   expect_int_no_catch_all(ew_big);
695   EXPECT_TRUE(handled);
696   handled = false;
697
698   auto expect_int_no_catch_all_2 = [&](const exception_wrapper& ew) {
699     ew.handle(
700         [&](const BigNonStdError&) { handled = true; },
701         [](const std::exception&) { EXPECT_TRUE(false); });
702   };
703
704   expect_int_no_catch_all_2(ew_eptr1);
705   EXPECT_TRUE(handled);
706   handled = false;
707   expect_int_no_catch_all_2(ew_eptr2);
708   EXPECT_TRUE(handled);
709   handled = false;
710   expect_int_no_catch_all_2(ew_big);
711   EXPECT_TRUE(handled);
712   handled = false;
713
714   EXPECT_THROW(
715       expect_int_no_catch_all_2(exception_wrapper{folly::in_place, 42}), int);
716 }
717
718 TEST(ExceptionWrapper, handle_non_std_exception_rethrow_base_derived) {
719   auto ew = testNonStdException();
720   bool handled = false;
721   EXPECT_THROW(
722       ew.handle(
723           [&](const DerivedException& e) {
724             handled = true;
725             throw e;
726           },
727           [](const BaseException&) { EXPECT_TRUE(false); }),
728       DerivedException);
729   EXPECT_TRUE(handled);
730   handled = false;
731   EXPECT_THROW(
732       ew.handle(
733           [&](const DerivedException& e) {
734             handled = true;
735             throw e;
736           },
737           [](...) { EXPECT_TRUE(false); }),
738       DerivedException);
739   EXPECT_TRUE(handled);
740 }
741
742 TEST(ExceptionWrapper, self_swap_test) {
743   exception_wrapper ew(std::runtime_error("hello world"));
744   folly::swap(ew, ew);
745   EXPECT_EQ(kRuntimeErrorClassName + ": hello world", ew.what());
746   auto& ew2 = ew;
747   ew = std::move(ew2); // should not crash
748 }