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