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