+
+TEST(ExceptionWrapper, with_exception_test) {
+ int expected = 23;
+
+ // This works, and doesn't slice.
+ exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
+ [=]() {
+ throw IntException(expected);
+ });
+ EXPECT_TRUE(bool(ew));
+ EXPECT_EQ(ew.what(), kIntExceptionClassName + ": int == 23");
+ EXPECT_EQ(ew.class_name(), kIntExceptionClassName);
+ EXPECT_TRUE(ew.with_exception(
+ [&](const IntException& ie) { EXPECT_EQ(ie.getInt(), expected); }));
+
+ // I can try_and_catch a non-copyable base class. This will use
+ // std::exception_ptr internally.
+ exception_wrapper ew2 = try_and_catch<AbstractIntException>(
+ [=]() {
+ throw IntException(expected);
+ });
+ EXPECT_TRUE(bool(ew2));
+ EXPECT_EQ(ew2.what(), kIntExceptionClassName + ": int == 23");
+ EXPECT_EQ(ew2.class_name(), kIntExceptionClassName);
+ bool res = ew2.with_exception([&](AbstractIntException& ie) {
+ EXPECT_EQ(ie.getInt(), expected);
+ EXPECT_TRUE(dynamic_cast<IntException*>(&ie));
+ });
+ EXPECT_TRUE(res);
+
+ // Test with const this. If this compiles and does not crash due to
+ // infinite loop when it runs, it succeeds.
+ const exception_wrapper& cew = ew;
+ EXPECT_TRUE(
+ cew.with_exception([&](const IntException& /* ie */) { SUCCEED(); }));
+
+ // Test with empty ew.
+ exception_wrapper empty_ew;
+ EXPECT_FALSE(
+ empty_ew.with_exception([&](const std::exception& /* ie */) { FAIL(); }));
+
+ // Testing with const exception_wrapper; sanity check first:
+ EXPECT_FALSE(cew.with_exception([&](const std::runtime_error&) {}));
+ EXPECT_FALSE(cew.with_exception([&](const int&) {}));
+ // This won't even compile. You can't use a function which takes a
+ // non-const reference with a const exception_wrapper.
+ /*
+ EXPECT_FALSE(cew.with_exception([&](std::runtime_error&) {}));
+ EXPECT_FALSE(cew.with_exception([&](int&) {}));
+ */
+}
+
+TEST(ExceptionWrapper, get_or_make_exception_ptr_test) {
+ int expected = 23;
+
+ // This works, and doesn't slice.
+ exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
+ [=]() { throw IntException(expected); });
+ std::exception_ptr eptr = ew.to_exception_ptr();
+ EXPECT_THROW(std::rethrow_exception(eptr), IntException);
+
+ // I can try_and_catch a non-copyable base class. This will use
+ // std::exception_ptr internally.
+ exception_wrapper ew2 = try_and_catch<AbstractIntException>(
+ [=]() { throw IntException(expected); });
+ eptr = ew2.to_exception_ptr();
+ EXPECT_THROW(std::rethrow_exception(eptr), IntException);
+
+ // Test with const this.
+ const exception_wrapper& cew = ew;
+ eptr = cew.to_exception_ptr();
+ EXPECT_THROW(std::rethrow_exception(eptr), IntException);
+
+ // Test with empty ew.
+ exception_wrapper empty_ew;
+ eptr = empty_ew.to_exception_ptr();
+ EXPECT_FALSE(eptr);
+}
+
+TEST(ExceptionWrapper, with_exception_ptr_empty) {
+ auto ew = exception_wrapper(std::exception_ptr());
+ EXPECT_EQ(exception_wrapper::none(), ew.type());
+ EXPECT_FALSE(bool(ew));
+ EXPECT_EQ(nullptr, ew.get_exception());
+ EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+ EXPECT_EQ(nullptr, ew.get_object<int>());
+ EXPECT_FALSE(ew.has_exception_ptr());
+ EXPECT_EQ(nullptr, ew.to_exception_ptr());
+ EXPECT_FALSE(ew.has_exception_ptr());
+ EXPECT_EQ("", ew.class_name());
+ EXPECT_EQ("", ew.what());
+ EXPECT_FALSE(ew.is_compatible_with<std::exception>());
+ EXPECT_FALSE(ew.is_compatible_with<int>());
+ EXPECT_DEATH(ew.throw_exception(), "empty folly::exception_wrapper");
+}
+
+TEST(ExceptionWrapper, with_shared_ptr_test) {
+ auto ew = exception_wrapper(std::runtime_error("foo"));
+ EXPECT_TRUE(bool(ew));
+ EXPECT_EQ(typeid(std::runtime_error), ew.type());
+ EXPECT_NE(nullptr, ew.get_exception());
+ EXPECT_NE(nullptr, ew.get_object<std::exception>());
+ EXPECT_EQ(nullptr, ew.get_object<int>());
+ EXPECT_FALSE(ew.has_exception_ptr());
+ EXPECT_NE(nullptr, ew.to_exception_ptr());
+ EXPECT_TRUE(ew.has_exception_ptr());
+ EXPECT_EQ("std::runtime_error", ew.class_name());
+ EXPECT_EQ("std::runtime_error: foo", ew.what());
+ EXPECT_TRUE(ew.is_compatible_with<std::exception>());
+ EXPECT_TRUE(ew.is_compatible_with<std::runtime_error>());
+ EXPECT_FALSE(ew.is_compatible_with<int>());
+ EXPECT_THROW(ew.throw_exception(), std::runtime_error);
+
+ exception_wrapper(std::move(ew));
+ EXPECT_FALSE(bool(ew));
+ EXPECT_EQ(exception_wrapper::none(), ew.type());
+ EXPECT_EQ(nullptr, ew.get_exception());
+ EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+ EXPECT_EQ(nullptr, ew.get_object<int>());
+ EXPECT_EQ(nullptr, ew.to_exception_ptr());
+ EXPECT_EQ("", ew.class_name());
+ EXPECT_EQ("", ew.what());
+ EXPECT_FALSE(ew.is_compatible_with<std::exception>());
+ EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
+ EXPECT_FALSE(ew.is_compatible_with<int>());
+}
+
+TEST(ExceptionWrapper, with_exception_ptr_exn_test) {
+ auto ep = std::make_exception_ptr(std::runtime_error("foo"));
+ auto ew = exception_wrapper(ep, from_eptr<std::runtime_error>(ep));
+ EXPECT_TRUE(bool(ew));
+ EXPECT_EQ(typeid(std::runtime_error), ew.type());
+ EXPECT_NE(nullptr, ew.get_exception());
+ EXPECT_NE(nullptr, ew.get_object<std::exception>());
+ EXPECT_EQ(nullptr, ew.get_object<int>());
+ EXPECT_TRUE(ew.has_exception_ptr());
+ EXPECT_EQ(ep, ew.to_exception_ptr());
+ EXPECT_TRUE(ew.has_exception_ptr());
+ EXPECT_EQ("std::runtime_error", ew.class_name());
+ EXPECT_EQ("std::runtime_error: foo", ew.what());
+ EXPECT_TRUE(ew.is_compatible_with<std::exception>());
+ EXPECT_TRUE(ew.is_compatible_with<std::runtime_error>());
+ EXPECT_FALSE(ew.is_compatible_with<int>());
+ EXPECT_THROW(ew.throw_exception(), std::runtime_error);
+
+ exception_wrapper(std::move(ew));
+ EXPECT_FALSE(bool(ew));
+ EXPECT_EQ(exception_wrapper::none(), ew.type());
+ EXPECT_EQ(nullptr, ew.get_exception());
+ EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+ EXPECT_EQ(nullptr, ew.get_object<int>());
+ EXPECT_EQ(nullptr, ew.to_exception_ptr());
+ EXPECT_EQ("", ew.class_name());
+ EXPECT_EQ("", ew.what());
+ EXPECT_FALSE(ew.is_compatible_with<std::exception>());
+ EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
+ EXPECT_FALSE(ew.is_compatible_with<int>());
+}
+
+TEST(ExceptionWrapper, with_exception_ptr_any_test) {
+ auto ep = std::make_exception_ptr<int>(12);
+ auto ew = exception_wrapper(ep, from_eptr<int>(ep));
+ EXPECT_TRUE(bool(ew));
+ EXPECT_EQ(nullptr, ew.get_exception());
+ EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+ EXPECT_NE(nullptr, ew.get_object<int>());
+ EXPECT_TRUE(ew.has_exception_ptr());
+ EXPECT_EQ(ep, ew.to_exception_ptr());
+ EXPECT_TRUE(ew.has_exception_ptr());
+ EXPECT_EQ("int", ew.class_name());
+ EXPECT_EQ("int", ew.what());
+ EXPECT_FALSE(ew.is_compatible_with<std::exception>());
+ EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
+ EXPECT_TRUE(ew.is_compatible_with<int>());
+ EXPECT_THROW(ew.throw_exception(), int);
+
+ exception_wrapper(std::move(ew));
+ EXPECT_FALSE(bool(ew));
+ EXPECT_EQ(nullptr, ew.get_exception());
+ EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+ EXPECT_EQ(nullptr, ew.get_object<int>());
+ EXPECT_EQ(nullptr, ew.to_exception_ptr());
+ EXPECT_FALSE(ew.has_exception_ptr());
+ EXPECT_EQ("", ew.class_name());
+ EXPECT_EQ("", ew.what());
+ EXPECT_FALSE(ew.is_compatible_with<std::exception>());
+ EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
+ EXPECT_FALSE(ew.is_compatible_with<int>());
+}
+
+TEST(ExceptionWrapper, with_non_std_exception_test) {
+ auto ew = exception_wrapper(folly::in_place, 42);
+ EXPECT_TRUE(bool(ew));
+ EXPECT_EQ(nullptr, ew.get_exception());
+ EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+ EXPECT_NE(nullptr, ew.get_object<int>());
+ EXPECT_FALSE(ew.has_exception_ptr());
+ EXPECT_EQ("int", ew.class_name());
+ EXPECT_EQ("int", ew.what());
+ EXPECT_NE(nullptr, ew.to_exception_ptr());
+ EXPECT_TRUE(ew.has_exception_ptr());
+ EXPECT_EQ("int", ew.class_name());
+ EXPECT_EQ("int", ew.what());
+ EXPECT_FALSE(ew.is_compatible_with<std::exception>());
+ EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
+ EXPECT_TRUE(ew.is_compatible_with<int>());
+ EXPECT_THROW(ew.throw_exception(), int);
+
+ exception_wrapper(std::move(ew));
+ EXPECT_FALSE(bool(ew));
+ EXPECT_EQ(nullptr, ew.get_exception());
+ EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+ EXPECT_EQ(nullptr, ew.get_object<int>());
+ EXPECT_EQ(nullptr, ew.to_exception_ptr());
+ EXPECT_FALSE(ew.has_exception_ptr());
+ EXPECT_EQ("", ew.class_name());
+ EXPECT_EQ("", ew.what());
+ EXPECT_FALSE(ew.is_compatible_with<std::exception>());
+ EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
+ EXPECT_FALSE(ew.is_compatible_with<int>());
+}
+
+TEST(ExceptionWrapper, with_exception_ptr_any_nil_test) {
+ auto ep = std::make_exception_ptr<int>(12);
+ auto ew = exception_wrapper(ep); // concrete type is erased
+ EXPECT_TRUE(bool(ew));
+ EXPECT_EQ(nullptr, ew.get_exception());
+ EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+ EXPECT_NE(nullptr, ew.get_object<int>());
+ EXPECT_EQ(ep, ew.to_exception_ptr());
+ EXPECT_EQ("<unknown exception>", ew.class_name()); // because concrete type is
+ // erased
+ EXPECT_EQ("<unknown exception>", ew.what());
+ EXPECT_FALSE(ew.is_compatible_with<std::exception>());
+ EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
+ EXPECT_TRUE(ew.is_compatible_with<int>());
+ EXPECT_THROW(ew.throw_exception(), int);
+
+ exception_wrapper(std::move(ew));
+ EXPECT_FALSE(bool(ew));
+ EXPECT_EQ(nullptr, ew.get_exception());
+ EXPECT_EQ(nullptr, ew.get_object<std::exception>());
+ EXPECT_EQ(nullptr, ew.get_object<int>());
+ EXPECT_EQ(nullptr, ew.to_exception_ptr());
+ EXPECT_EQ("", ew.class_name());
+ EXPECT_EQ("", ew.what());
+ EXPECT_FALSE(ew.is_compatible_with<std::exception>());
+ EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
+ EXPECT_FALSE(ew.is_compatible_with<int>());
+}
+
+TEST(ExceptionWrapper, with_exception_deduction) {
+ auto ew = make_exception_wrapper<std::runtime_error>("hi");
+ EXPECT_TRUE(ew.with_exception([](std::runtime_error&) {}));
+ EXPECT_TRUE(ew.with_exception([](std::exception&) {}));
+ EXPECT_FALSE(ew.with_exception([](std::logic_error&) {}));
+}
+
+TEST(ExceptionWrapper, with_exception_deduction_exn_const) {
+ auto ew = make_exception_wrapper<std::runtime_error>("hi");
+ EXPECT_TRUE(ew.with_exception([](const std::runtime_error&) {}));
+ EXPECT_TRUE(ew.with_exception([](const std::exception&) {}));
+ EXPECT_FALSE(ew.with_exception([](const std::logic_error&) {}));
+}
+
+TEST(ExceptionWrapper, with_exception_deduction_wrap_const_exn_const) {
+ const auto cew = make_exception_wrapper<std::runtime_error>("hi");
+ EXPECT_TRUE(cew.with_exception([](const std::runtime_error&) {}));
+ EXPECT_TRUE(cew.with_exception([](const std::exception&) {}));
+ EXPECT_FALSE(cew.with_exception([](const std::logic_error&) {}));
+}
+
+TEST(ExceptionWrapper, with_exception_deduction_returning) {
+ auto ew = make_exception_wrapper<std::runtime_error>("hi");
+ EXPECT_TRUE(ew.with_exception([](std::runtime_error&) { return 3; }));
+ EXPECT_TRUE(ew.with_exception([](std::exception&) { return "hello"; }));
+ EXPECT_FALSE(ew.with_exception([](std::logic_error&) { return nullptr; }));
+}
+
+namespace {
+template <typename T>
+T& r_to_l(T v) { return std::ref(v); }
+}
+
+TEST(ExceptionWrapper, with_exception_deduction_functor_lvalue) {
+ auto ew = make_exception_wrapper<std::runtime_error>("hi");
+ EXPECT_TRUE(ew.with_exception(r_to_l([](std::runtime_error&) {})));
+ EXPECT_TRUE(ew.with_exception(r_to_l([](std::exception&) {})));
+ EXPECT_FALSE(ew.with_exception(r_to_l([](std::logic_error&) {})));
+}
+
+TEST(ExceptionWrapper, non_std_exception_test) {
+ int expected = 17;
+
+ exception_wrapper ew = try_and_catch<std::exception, int>(
+ [=]() {
+ throw expected;
+ });
+ EXPECT_TRUE(bool(ew));
+ EXPECT_FALSE(ew.is_compatible_with<std::exception>());
+ EXPECT_TRUE(ew.is_compatible_with<int>());
+ EXPECT_EQ(ew.what(), kIntClassName);
+ EXPECT_EQ(ew.class_name(), kIntClassName);
+ // non-std::exception types are supported, but the only way to
+ // access their value is to explicity rethrow and catch it.
+ try {
+ ew.throw_exception();
+ } catch /* nolint */ (int& i) {
+ EXPECT_EQ(i, expected);
+ }
+}
+
+
+TEST(ExceptionWrapper, exceptionStr) {
+ auto ew = make_exception_wrapper<std::runtime_error>("argh");
+ EXPECT_EQ(kRuntimeErrorClassName + ": argh", exceptionStr(ew));
+}
+
+TEST(ExceptionWrapper, throwException_noException) {
+ exception_wrapper ew;
+ ASSERT_DEATH(ew.throw_exception(), "empty folly::exception_wrapper");
+}
+
+namespace {
+class TestException : public std::exception { };
+void testEW(const exception_wrapper& ew) {
+ EXPECT_THROW(ew.throw_exception(), TestException);
+}
+} // namespace
+
+TEST(ExceptionWrapper, implicitConstruction) {
+ // Try with both lvalue and rvalue references
+ TestException e;
+ testEW(e);
+ testEW(TestException());
+}
+
+namespace {
+struct BaseException {
+ virtual ~BaseException() {}
+};
+struct DerivedException : BaseException {};
+exception_wrapper testNonStdException() {
+ try {
+ throw DerivedException{};
+ } catch (const BaseException& e) {
+ return exception_wrapper{std::current_exception(), e};
+ }
+}
+}
+
+TEST(ExceptionWrapper, base_derived_non_std_exception_test) {
+ auto ew = testNonStdException();
+ EXPECT_TRUE(ew.type() == typeid(DerivedException));
+ EXPECT_TRUE(ew.with_exception([](const DerivedException&) {}));
+}
+
+namespace {
+// Cannot be stored within an exception_wrapper
+struct BigRuntimeError : std::runtime_error {
+ using std::runtime_error::runtime_error;
+ char data_[sizeof(exception_wrapper) + 1]{};
+};
+
+struct BigNonStdError {
+ char data_[sizeof(exception_wrapper) + 1]{};
+};
+}
+
+TEST(ExceptionWrapper, handle_std_exception) {
+ auto ep = std::make_exception_ptr(std::runtime_error{"hello world"});
+ exception_wrapper const ew_eptr(ep, from_eptr<std::runtime_error>(ep));
+ exception_wrapper const ew_small(std::runtime_error{"hello world"});
+ exception_wrapper const ew_big(BigRuntimeError{"hello world"});
+
+ bool handled = false;
+ auto expect_runtime_error_yes_catch_all = [&](const exception_wrapper& ew) {
+ ew.handle(
+ [](const std::logic_error&) { EXPECT_TRUE(false); },
+ [&](const std::runtime_error&) { handled = true; },
+ [](const std::exception&) { EXPECT_TRUE(false); },
+ [](...) { EXPECT_TRUE(false); });
+ };
+
+ expect_runtime_error_yes_catch_all(ew_eptr);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_runtime_error_yes_catch_all(ew_small);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_runtime_error_yes_catch_all(ew_big);
+ EXPECT_TRUE(handled);
+ handled = false;
+
+ auto expect_runtime_error_no_catch_all = [&](const exception_wrapper& ew) {
+ ew.handle(
+ [](const std::logic_error&) { EXPECT_TRUE(false); },
+ [&](const std::runtime_error&) { handled = true; },
+ [](const std::exception&) { EXPECT_TRUE(false); });
+ };
+
+ expect_runtime_error_no_catch_all(ew_eptr);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_runtime_error_no_catch_all(ew_small);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_runtime_error_no_catch_all(ew_big);
+ EXPECT_TRUE(handled);
+ handled = false;
+
+ auto expect_runtime_error_catch_non_std = [&](const exception_wrapper& ew) {
+ ew.handle(
+ [](const std::logic_error&) { EXPECT_TRUE(false); },
+ [&](const std::runtime_error&) { handled = true; },
+ [](const std::exception&) { EXPECT_TRUE(false); },
+ [](const int&) { EXPECT_TRUE(false); });
+ };
+
+ expect_runtime_error_catch_non_std(ew_eptr);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_runtime_error_catch_non_std(ew_small);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_runtime_error_catch_non_std(ew_big);
+ EXPECT_TRUE(handled);
+ handled = false;
+
+ // Test that an exception thrown from one handler is not caught by an
+ // outer handler:
+ auto expect_runtime_error_rethrow = [&](const exception_wrapper& ew) {
+ ew.handle(
+ [](const std::logic_error&) { EXPECT_TRUE(false); },
+ [&](const std::runtime_error& e) {
+ handled = true;
+ throw e;
+ },
+ [](const std::exception&) { EXPECT_TRUE(false); });
+ };
+
+ EXPECT_THROW(expect_runtime_error_rethrow(ew_eptr), std::runtime_error);
+ EXPECT_TRUE(handled);
+ handled = false;
+ EXPECT_THROW(expect_runtime_error_rethrow(ew_small), std::runtime_error);
+ EXPECT_TRUE(handled);
+ handled = false;
+ EXPECT_THROW(expect_runtime_error_rethrow(ew_big), std::runtime_error);
+ EXPECT_TRUE(handled);
+}
+
+TEST(ExceptionWrapper, handle_std_exception_unhandled) {
+ auto ep = std::make_exception_ptr(std::exception{});
+ exception_wrapper const ew_eptr(ep, from_eptr<std::exception>(ep));
+ exception_wrapper const ew_small(std::exception{});
+
+ bool handled = false;
+ auto expect_runtime_error_yes_catch_all = [&](const exception_wrapper& ew) {
+ ew.handle(
+ [](const std::logic_error&) { EXPECT_TRUE(false); },
+ [](const std::runtime_error&) { EXPECT_TRUE(false); },
+ [&](...) { handled = true; });
+ };
+
+ expect_runtime_error_yes_catch_all(ew_eptr);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_runtime_error_yes_catch_all(ew_small);
+ EXPECT_TRUE(handled);
+}
+
+TEST(ExceptionWrapper, handle_non_std_exception_small) {
+ auto ep = std::make_exception_ptr(42);
+ exception_wrapper const ew_eptr1(ep);
+ exception_wrapper const ew_eptr2(ep, from_eptr<int>(ep));
+ exception_wrapper const ew_small(folly::in_place, 42);
+ bool handled = false;
+
+ auto expect_int_yes_catch_all = [&](const exception_wrapper& ew) {
+ ew.handle(
+ [](const std::exception&) { EXPECT_TRUE(false); },
+ [&](...) { handled = true; });
+ };
+
+ expect_int_yes_catch_all(ew_eptr1);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_int_yes_catch_all(ew_eptr2);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_int_yes_catch_all(ew_small);
+ EXPECT_TRUE(handled);
+ handled = false;
+
+ auto expect_int_no_catch_all = [&](const exception_wrapper& ew) {
+ ew.handle(
+ [](const std::exception&) { EXPECT_TRUE(false); },
+ [&](const int&) { handled = true; });
+ };
+
+ expect_int_no_catch_all(ew_eptr1);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_int_no_catch_all(ew_eptr2);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_int_no_catch_all(ew_small);
+ EXPECT_TRUE(handled);
+ handled = false;
+
+ auto expect_int_no_catch_all_2 = [&](const exception_wrapper& ew) {
+ ew.handle(
+ [&](const int&) { handled = true; },
+ [](const std::exception&) { EXPECT_TRUE(false); });
+ };
+
+ expect_int_no_catch_all_2(ew_eptr1);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_int_no_catch_all_2(ew_eptr2);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_int_no_catch_all_2(ew_small);
+ EXPECT_TRUE(handled);
+}
+
+TEST(ExceptionWrapper, handle_non_std_exception_big) {
+ auto ep = std::make_exception_ptr(BigNonStdError{});
+ exception_wrapper const ew_eptr1(ep);
+ exception_wrapper const ew_eptr2(ep, from_eptr<BigNonStdError>(ep));
+ exception_wrapper const ew_big(folly::in_place, BigNonStdError{});
+ bool handled = false;
+
+ auto expect_int_yes_catch_all = [&](const exception_wrapper& ew) {
+ ew.handle(
+ [](const std::exception&) { EXPECT_TRUE(false); },
+ [&](...) { handled = true; });
+ };
+
+ expect_int_yes_catch_all(ew_eptr1);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_int_yes_catch_all(ew_eptr2);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_int_yes_catch_all(ew_big);
+ EXPECT_TRUE(handled);
+ handled = false;
+
+ auto expect_int_no_catch_all = [&](const exception_wrapper& ew) {
+ ew.handle(
+ [](const std::exception&) { EXPECT_TRUE(false); },
+ [&](const BigNonStdError&) { handled = true; });
+ };
+
+ expect_int_no_catch_all(ew_eptr1);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_int_no_catch_all(ew_eptr2);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_int_no_catch_all(ew_big);
+ EXPECT_TRUE(handled);
+ handled = false;
+
+ auto expect_int_no_catch_all_2 = [&](const exception_wrapper& ew) {
+ ew.handle(
+ [&](const BigNonStdError&) { handled = true; },
+ [](const std::exception&) { EXPECT_TRUE(false); });
+ };
+
+ expect_int_no_catch_all_2(ew_eptr1);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_int_no_catch_all_2(ew_eptr2);
+ EXPECT_TRUE(handled);
+ handled = false;
+ expect_int_no_catch_all_2(ew_big);
+ EXPECT_TRUE(handled);
+ handled = false;
+
+ EXPECT_THROW(
+ expect_int_no_catch_all_2(exception_wrapper{folly::in_place, 42}), int);
+}
+
+TEST(ExceptionWrapper, handle_non_std_exception_rethrow_base_derived) {
+ auto ew = testNonStdException();
+ bool handled = false;
+ EXPECT_THROW(
+ ew.handle(
+ [&](const DerivedException& e) {
+ handled = true;
+ throw e;
+ },
+ [](const BaseException&) { EXPECT_TRUE(false); }),
+ DerivedException);
+ EXPECT_TRUE(handled);
+ handled = false;
+ EXPECT_THROW(
+ ew.handle(
+ [&](const DerivedException& e) {
+ handled = true;
+ throw e;
+ },
+ [](...) { EXPECT_TRUE(false); }),
+ DerivedException);
+ EXPECT_TRUE(handled);
+}
+
+TEST(ExceptionWrapper, self_swap_test) {
+ exception_wrapper ew(std::runtime_error("hello world"));
+ folly::swap(ew, ew);
+ EXPECT_STREQ("std::runtime_error: hello world", ew.what().c_str());
+ auto& ew2 = ew;
+ ew = std::move(ew2); // should not crash
+}