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