2 * Copyright 2014-present Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <folly/Conv.h>
20 #include <folly/ExceptionWrapper.h>
21 #include <folly/portability/GTest.h>
23 using namespace folly;
25 class AbstractIntException : public std::exception {
27 virtual int getInt() const = 0;
30 class IntException : public AbstractIntException {
32 explicit IntException(int i) : i_(i), what_(to<std::string>("int == ", i_)) {}
34 int getInt() const override { return i_; }
35 const char* what() const noexcept override {
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();
53 T& from_eptr(std::exception_ptr& eptr) {
55 std::rethrow_exception(eptr);
59 throw std::logic_error("impossible");
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);
68 std::vector<exception_wrapper> container;
69 container.push_back(ew);
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);
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);
91 TEST(ExceptionWrapper, try_and_catch_test) {
92 std::string expected = "payload";
94 // Catch rightmost matching exception type
95 exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
97 throw std::runtime_error(expected);
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>();
105 // Changing order is like catching in wrong order. Beware of this in your
107 auto ew2 = try_and_catch<std::runtime_error, std::exception>([=]() {
108 throw std::runtime_error(expected);
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>();
116 // Catches even if not rightmost.
117 auto ew3 = try_and_catch<std::exception, std::runtime_error>([]() {
118 throw std::exception();
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>();
126 // If does not catch, throws.
128 try_and_catch<std::runtime_error>([]() {
129 throw std::exception();
134 TEST(ExceptionWrapper, with_exception_test) {
137 // This works, and doesn't slice.
138 exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
140 throw IntException(expected);
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); }));
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>(
152 throw IntException(expected);
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));
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;
167 cew.with_exception([&](const IntException& /* ie */) { SUCCEED(); }));
169 // Test with empty ew.
170 exception_wrapper empty_ew;
172 empty_ew.with_exception([&](const std::exception& /* ie */) { FAIL(); }));
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.
180 EXPECT_FALSE(cew.with_exception([&](std::runtime_error&) {}));
181 EXPECT_FALSE(cew.with_exception([&](int&) {}));
185 TEST(ExceptionWrapper, get_or_make_exception_ptr_test) {
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);
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);
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);
206 // Test with empty ew.
207 exception_wrapper empty_ew;
208 eptr = empty_ew.to_exception_ptr();
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));
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>());
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>());
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");
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);
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>());
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);
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>());
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);
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>());
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);
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>());
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
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);
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>());
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&) {}));
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&) {}));
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&) {}));
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; }));
440 template <typename T>
441 T& r_to_l(T v) { return std::ref(v); }
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&) {})));
451 TEST(ExceptionWrapper, non_std_exception_test) {
454 exception_wrapper ew = try_and_catch<std::exception, int>(
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.
466 ew.throw_exception();
467 } catch /* nolint */ (int& i) {
468 EXPECT_EQ(i, expected);
473 TEST(ExceptionWrapper, exceptionStr) {
474 auto ew = make_exception_wrapper<std::runtime_error>("argh");
475 EXPECT_EQ(kRuntimeErrorClassName + ": argh", exceptionStr(ew));
478 TEST(ExceptionWrapper, throwException_noException) {
479 exception_wrapper ew;
480 ASSERT_DEATH(ew.throw_exception(), "empty folly::exception_wrapper");
484 class TestException : public std::exception { };
485 void testEW(const exception_wrapper& ew) {
486 EXPECT_THROW(ew.throw_exception(), TestException);
490 TEST(ExceptionWrapper, implicitConstruction) {
491 // Try with both lvalue and rvalue references
494 testEW(TestException());
498 struct BaseException {
499 virtual ~BaseException() {}
501 struct DerivedException : BaseException {};
502 exception_wrapper testNonStdException() {
504 throw DerivedException{};
505 } catch (const BaseException& e) {
506 return exception_wrapper{std::current_exception(), e};
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&) {}));
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]{};
524 struct BigNonStdError {
525 char data_[sizeof(exception_wrapper) + 1]{};
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"});
535 bool handled = false;
536 auto expect_runtime_error_yes_catch_all = [&](const exception_wrapper& ew) {
538 [](const std::logic_error&) { ADD_FAILURE(); },
539 [&](const std::runtime_error&) { handled = true; },
540 [](const std::exception&) { ADD_FAILURE(); },
541 [](...) { ADD_FAILURE(); });
544 expect_runtime_error_yes_catch_all(ew_eptr);
545 EXPECT_TRUE(handled);
547 expect_runtime_error_yes_catch_all(ew_small);
548 EXPECT_TRUE(handled);
550 expect_runtime_error_yes_catch_all(ew_big);
551 EXPECT_TRUE(handled);
554 auto expect_runtime_error_no_catch_all = [&](const exception_wrapper& ew) {
556 [](const std::logic_error&) { ADD_FAILURE(); },
557 [&](const std::runtime_error&) { handled = true; },
558 [](const std::exception&) { ADD_FAILURE(); });
561 expect_runtime_error_no_catch_all(ew_eptr);
562 EXPECT_TRUE(handled);
564 expect_runtime_error_no_catch_all(ew_small);
565 EXPECT_TRUE(handled);
567 expect_runtime_error_no_catch_all(ew_big);
568 EXPECT_TRUE(handled);
571 auto expect_runtime_error_catch_non_std = [&](const exception_wrapper& ew) {
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(); });
579 expect_runtime_error_catch_non_std(ew_eptr);
580 EXPECT_TRUE(handled);
582 expect_runtime_error_catch_non_std(ew_small);
583 EXPECT_TRUE(handled);
585 expect_runtime_error_catch_non_std(ew_big);
586 EXPECT_TRUE(handled);
589 // Test that an exception thrown from one handler is not caught by an
591 auto expect_runtime_error_rethrow = [&](const exception_wrapper& ew) {
593 [](const std::logic_error&) { ADD_FAILURE(); },
594 [&](const std::runtime_error& e) {
598 [](const std::exception&) { ADD_FAILURE(); });
601 EXPECT_THROW(expect_runtime_error_rethrow(ew_eptr), std::runtime_error);
602 EXPECT_TRUE(handled);
604 EXPECT_THROW(expect_runtime_error_rethrow(ew_small), std::runtime_error);
605 EXPECT_TRUE(handled);
607 EXPECT_THROW(expect_runtime_error_rethrow(ew_big), std::runtime_error);
608 EXPECT_TRUE(handled);
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{});
616 bool handled = false;
617 auto expect_runtime_error_yes_catch_all = [&](const exception_wrapper& ew) {
619 [](const std::logic_error&) { ADD_FAILURE(); },
620 [](const std::runtime_error&) { ADD_FAILURE(); },
621 [&](...) { handled = true; });
624 expect_runtime_error_yes_catch_all(ew_eptr);
625 EXPECT_TRUE(handled);
627 expect_runtime_error_yes_catch_all(ew_small);
628 EXPECT_TRUE(handled);
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;
638 auto expect_int_yes_catch_all = [&](const exception_wrapper& ew) {
640 [](const std::exception&) { ADD_FAILURE(); },
641 [&](...) { handled = true; });
644 expect_int_yes_catch_all(ew_eptr1);
645 EXPECT_TRUE(handled);
647 expect_int_yes_catch_all(ew_eptr2);
648 EXPECT_TRUE(handled);
650 expect_int_yes_catch_all(ew_small);
651 EXPECT_TRUE(handled);
654 auto expect_int_no_catch_all = [&](const exception_wrapper& ew) {
656 [](const std::exception&) { ADD_FAILURE(); },
657 [&](const int&) { handled = true; });
660 expect_int_no_catch_all(ew_eptr1);
661 EXPECT_TRUE(handled);
663 expect_int_no_catch_all(ew_eptr2);
664 EXPECT_TRUE(handled);
666 expect_int_no_catch_all(ew_small);
667 EXPECT_TRUE(handled);
670 auto expect_int_no_catch_all_2 = [&](const exception_wrapper& ew) {
672 [&](const int&) { handled = true; },
673 [](const std::exception&) { ADD_FAILURE(); });
676 expect_int_no_catch_all_2(ew_eptr1);
677 EXPECT_TRUE(handled);
679 expect_int_no_catch_all_2(ew_eptr2);
680 EXPECT_TRUE(handled);
682 expect_int_no_catch_all_2(ew_small);
683 EXPECT_TRUE(handled);
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;
693 auto expect_int_yes_catch_all = [&](const exception_wrapper& ew) {
695 [](const std::exception&) { ADD_FAILURE(); },
696 [&](...) { handled = true; });
699 expect_int_yes_catch_all(ew_eptr1);
700 EXPECT_TRUE(handled);
702 expect_int_yes_catch_all(ew_eptr2);
703 EXPECT_TRUE(handled);
705 expect_int_yes_catch_all(ew_big);
706 EXPECT_TRUE(handled);
709 auto expect_int_no_catch_all = [&](const exception_wrapper& ew) {
711 [](const std::exception&) { ADD_FAILURE(); },
712 [&](const BigNonStdError&) { handled = true; });
715 expect_int_no_catch_all(ew_eptr1);
716 EXPECT_TRUE(handled);
718 expect_int_no_catch_all(ew_eptr2);
719 EXPECT_TRUE(handled);
721 expect_int_no_catch_all(ew_big);
722 EXPECT_TRUE(handled);
725 auto expect_int_no_catch_all_2 = [&](const exception_wrapper& ew) {
727 [&](const BigNonStdError&) { handled = true; },
728 [](const std::exception&) { ADD_FAILURE(); });
731 expect_int_no_catch_all_2(ew_eptr1);
732 EXPECT_TRUE(handled);
734 expect_int_no_catch_all_2(ew_eptr2);
735 EXPECT_TRUE(handled);
737 expect_int_no_catch_all_2(ew_big);
738 EXPECT_TRUE(handled);
742 expect_int_no_catch_all_2(exception_wrapper{folly::in_place, 42}), int);
745 TEST(ExceptionWrapper, handle_non_std_exception_rethrow_base_derived) {
746 auto ew = testNonStdException();
747 bool handled = false;
750 [&](const DerivedException& e) {
754 [](const BaseException&) { ADD_FAILURE(); }),
756 EXPECT_TRUE(handled);
760 [&](const DerivedException& e) {
764 [](...) { ADD_FAILURE(); }),
766 EXPECT_TRUE(handled);
769 TEST(ExceptionWrapper, self_swap_test) {
770 exception_wrapper ew(std::runtime_error("hello world"));
772 EXPECT_EQ(kRuntimeErrorClassName + ": hello world", ew.what());
774 ew = std::move(ew2); // should not crash