2 * Copyright 2017 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_EQ(nullptr, ew.get_exception<int>());
258 EXPECT_FALSE(ew.has_exception_ptr());
259 EXPECT_NE(nullptr, ew.to_exception_ptr());
260 EXPECT_TRUE(ew.has_exception_ptr());
261 EXPECT_EQ(kRuntimeErrorClassName, ew.class_name());
262 EXPECT_EQ(kRuntimeErrorClassName + ": foo", ew.what());
263 EXPECT_TRUE(ew.is_compatible_with<std::exception>());
264 EXPECT_TRUE(ew.is_compatible_with<std::runtime_error>());
265 EXPECT_FALSE(ew.is_compatible_with<int>());
266 EXPECT_THROW(ew.throw_exception(), std::runtime_error);
268 exception_wrapper(std::move(ew));
269 EXPECT_FALSE(bool(ew));
270 EXPECT_EQ(exception_wrapper::none(), ew.type());
271 EXPECT_EQ(nullptr, ew.get_exception());
272 EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
273 EXPECT_EQ(nullptr, ew.get_exception<int>());
274 EXPECT_EQ(nullptr, ew.to_exception_ptr());
275 EXPECT_EQ("", ew.class_name());
276 EXPECT_EQ("", ew.what());
277 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
278 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
279 EXPECT_FALSE(ew.is_compatible_with<int>());
282 TEST(ExceptionWrapper, with_exception_ptr_exn_test) {
283 auto ep = std::make_exception_ptr(std::runtime_error("foo"));
284 auto ew = exception_wrapper(ep, from_eptr<std::runtime_error>(ep));
285 EXPECT_TRUE(bool(ew));
286 EXPECT_EQ(typeid(std::runtime_error), ew.type());
287 EXPECT_NE(nullptr, ew.get_exception());
288 EXPECT_NE(nullptr, ew.get_exception<std::exception>());
289 EXPECT_EQ(nullptr, ew.get_exception<int>());
290 EXPECT_TRUE(ew.has_exception_ptr());
291 EXPECT_EQ(ep, ew.to_exception_ptr());
292 EXPECT_TRUE(ew.has_exception_ptr());
293 EXPECT_EQ(kRuntimeErrorClassName, ew.class_name());
294 EXPECT_EQ(kRuntimeErrorClassName + ": foo", ew.what());
295 EXPECT_TRUE(ew.is_compatible_with<std::exception>());
296 EXPECT_TRUE(ew.is_compatible_with<std::runtime_error>());
297 EXPECT_FALSE(ew.is_compatible_with<int>());
298 EXPECT_THROW(ew.throw_exception(), std::runtime_error);
300 exception_wrapper(std::move(ew));
301 EXPECT_FALSE(bool(ew));
302 EXPECT_EQ(exception_wrapper::none(), ew.type());
303 EXPECT_EQ(nullptr, ew.get_exception());
304 EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
305 EXPECT_EQ(nullptr, ew.get_exception<int>());
306 EXPECT_EQ(nullptr, ew.to_exception_ptr());
307 EXPECT_EQ("", ew.class_name());
308 EXPECT_EQ("", ew.what());
309 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
310 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
311 EXPECT_FALSE(ew.is_compatible_with<int>());
314 TEST(ExceptionWrapper, with_exception_ptr_any_test) {
315 auto ep = std::make_exception_ptr<int>(12);
316 auto ew = exception_wrapper(ep, from_eptr<int>(ep));
317 EXPECT_TRUE(bool(ew));
318 EXPECT_EQ(nullptr, ew.get_exception());
319 EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
320 EXPECT_NE(nullptr, ew.get_exception<int>());
321 EXPECT_TRUE(ew.has_exception_ptr());
322 EXPECT_EQ(ep, ew.to_exception_ptr());
323 EXPECT_TRUE(ew.has_exception_ptr());
324 EXPECT_EQ("int", ew.class_name());
325 EXPECT_EQ("int", ew.what());
326 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
327 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
328 EXPECT_TRUE(ew.is_compatible_with<int>());
329 EXPECT_THROW(ew.throw_exception(), int);
331 exception_wrapper(std::move(ew));
332 EXPECT_FALSE(bool(ew));
333 EXPECT_EQ(nullptr, ew.get_exception());
334 EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
335 EXPECT_EQ(nullptr, ew.get_exception<int>());
336 EXPECT_EQ(nullptr, ew.to_exception_ptr());
337 EXPECT_FALSE(ew.has_exception_ptr());
338 EXPECT_EQ("", ew.class_name());
339 EXPECT_EQ("", ew.what());
340 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
341 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
342 EXPECT_FALSE(ew.is_compatible_with<int>());
345 TEST(ExceptionWrapper, with_non_std_exception_test) {
346 auto ew = exception_wrapper(folly::in_place, 42);
347 EXPECT_TRUE(bool(ew));
348 EXPECT_EQ(nullptr, ew.get_exception());
349 EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
350 EXPECT_NE(nullptr, ew.get_exception<int>());
351 EXPECT_FALSE(ew.has_exception_ptr());
352 EXPECT_EQ("int", ew.class_name());
353 EXPECT_EQ("int", ew.what());
354 EXPECT_NE(nullptr, ew.to_exception_ptr());
355 EXPECT_TRUE(ew.has_exception_ptr());
356 EXPECT_EQ("int", ew.class_name());
357 EXPECT_EQ("int", ew.what());
358 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
359 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
360 EXPECT_TRUE(ew.is_compatible_with<int>());
361 EXPECT_THROW(ew.throw_exception(), int);
363 exception_wrapper(std::move(ew));
364 EXPECT_FALSE(bool(ew));
365 EXPECT_EQ(nullptr, ew.get_exception());
366 EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
367 EXPECT_EQ(nullptr, ew.get_exception<int>());
368 EXPECT_EQ(nullptr, ew.to_exception_ptr());
369 EXPECT_FALSE(ew.has_exception_ptr());
370 EXPECT_EQ("", ew.class_name());
371 EXPECT_EQ("", ew.what());
372 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
373 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
374 EXPECT_FALSE(ew.is_compatible_with<int>());
377 TEST(ExceptionWrapper, with_exception_ptr_any_nil_test) {
378 auto ep = std::make_exception_ptr<int>(12);
379 auto ew = exception_wrapper(ep); // concrete type is erased
380 EXPECT_TRUE(bool(ew));
381 EXPECT_EQ(nullptr, ew.get_exception());
382 EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
383 EXPECT_NE(nullptr, ew.get_exception<int>());
384 EXPECT_EQ(ep, ew.to_exception_ptr());
385 EXPECT_EQ("<unknown exception>", ew.class_name()); // because concrete type is
387 EXPECT_EQ("<unknown exception>", ew.what());
388 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
389 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
390 EXPECT_TRUE(ew.is_compatible_with<int>());
391 EXPECT_THROW(ew.throw_exception(), int);
393 exception_wrapper(std::move(ew));
394 EXPECT_FALSE(bool(ew));
395 EXPECT_EQ(nullptr, ew.get_exception());
396 EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
397 EXPECT_EQ(nullptr, ew.get_exception<int>());
398 EXPECT_EQ(nullptr, ew.to_exception_ptr());
399 EXPECT_EQ("", ew.class_name());
400 EXPECT_EQ("", ew.what());
401 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
402 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
403 EXPECT_FALSE(ew.is_compatible_with<int>());
406 TEST(ExceptionWrapper, with_exception_deduction) {
407 auto ew = make_exception_wrapper<std::runtime_error>("hi");
408 EXPECT_TRUE(ew.with_exception([](std::runtime_error&) {}));
409 EXPECT_TRUE(ew.with_exception([](std::exception&) {}));
410 EXPECT_FALSE(ew.with_exception([](std::logic_error&) {}));
413 TEST(ExceptionWrapper, with_exception_deduction_exn_const) {
414 auto ew = make_exception_wrapper<std::runtime_error>("hi");
415 EXPECT_TRUE(ew.with_exception([](const std::runtime_error&) {}));
416 EXPECT_TRUE(ew.with_exception([](const std::exception&) {}));
417 EXPECT_FALSE(ew.with_exception([](const std::logic_error&) {}));
420 TEST(ExceptionWrapper, with_exception_deduction_wrap_const_exn_const) {
421 const auto cew = make_exception_wrapper<std::runtime_error>("hi");
422 EXPECT_TRUE(cew.with_exception([](const std::runtime_error&) {}));
423 EXPECT_TRUE(cew.with_exception([](const std::exception&) {}));
424 EXPECT_FALSE(cew.with_exception([](const std::logic_error&) {}));
427 TEST(ExceptionWrapper, with_exception_deduction_returning) {
428 auto ew = make_exception_wrapper<std::runtime_error>("hi");
429 EXPECT_TRUE(ew.with_exception([](std::runtime_error&) { return 3; }));
430 EXPECT_TRUE(ew.with_exception([](std::exception&) { return "hello"; }));
431 EXPECT_FALSE(ew.with_exception([](std::logic_error&) { return nullptr; }));
435 template <typename T>
436 T& r_to_l(T v) { return std::ref(v); }
439 TEST(ExceptionWrapper, with_exception_deduction_functor_lvalue) {
440 auto ew = make_exception_wrapper<std::runtime_error>("hi");
441 EXPECT_TRUE(ew.with_exception(r_to_l([](std::runtime_error&) {})));
442 EXPECT_TRUE(ew.with_exception(r_to_l([](std::exception&) {})));
443 EXPECT_FALSE(ew.with_exception(r_to_l([](std::logic_error&) {})));
446 TEST(ExceptionWrapper, non_std_exception_test) {
449 exception_wrapper ew = try_and_catch<std::exception, int>(
453 EXPECT_TRUE(bool(ew));
454 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
455 EXPECT_TRUE(ew.is_compatible_with<int>());
456 EXPECT_EQ(ew.what(), kIntClassName);
457 EXPECT_EQ(ew.class_name(), kIntClassName);
458 // non-std::exception types are supported, but the only way to
459 // access their value is to explicity rethrow and catch it.
461 ew.throw_exception();
462 } catch /* nolint */ (int& i) {
463 EXPECT_EQ(i, expected);
468 TEST(ExceptionWrapper, exceptionStr) {
469 auto ew = make_exception_wrapper<std::runtime_error>("argh");
470 EXPECT_EQ(kRuntimeErrorClassName + ": argh", exceptionStr(ew));
473 TEST(ExceptionWrapper, throwException_noException) {
474 exception_wrapper ew;
475 ASSERT_DEATH(ew.throw_exception(), "empty folly::exception_wrapper");
479 class TestException : public std::exception { };
480 void testEW(const exception_wrapper& ew) {
481 EXPECT_THROW(ew.throw_exception(), TestException);
485 TEST(ExceptionWrapper, implicitConstruction) {
486 // Try with both lvalue and rvalue references
489 testEW(TestException());
493 struct BaseException {
494 virtual ~BaseException() {}
496 struct DerivedException : BaseException {};
497 exception_wrapper testNonStdException() {
499 throw DerivedException{};
500 } catch (const BaseException& e) {
501 return exception_wrapper{std::current_exception(), e};
506 TEST(ExceptionWrapper, base_derived_non_std_exception_test) {
507 auto ew = testNonStdException();
508 EXPECT_TRUE(ew.type() == typeid(DerivedException));
509 EXPECT_TRUE(ew.with_exception([](const DerivedException&) {}));
513 // Cannot be stored within an exception_wrapper
514 struct BigRuntimeError : std::runtime_error {
515 using std::runtime_error::runtime_error;
516 char data_[sizeof(exception_wrapper) + 1]{};
519 struct BigNonStdError {
520 char data_[sizeof(exception_wrapper) + 1]{};
524 TEST(ExceptionWrapper, handle_std_exception) {
525 auto ep = std::make_exception_ptr(std::runtime_error{"hello world"});
526 exception_wrapper const ew_eptr(ep, from_eptr<std::runtime_error>(ep));
527 exception_wrapper const ew_small(std::runtime_error{"hello world"});
528 exception_wrapper const ew_big(BigRuntimeError{"hello world"});
530 bool handled = false;
531 auto expect_runtime_error_yes_catch_all = [&](const exception_wrapper& ew) {
533 [](const std::logic_error&) { ADD_FAILURE(); },
534 [&](const std::runtime_error&) { handled = true; },
535 [](const std::exception&) { ADD_FAILURE(); },
536 [](...) { ADD_FAILURE(); });
539 expect_runtime_error_yes_catch_all(ew_eptr);
540 EXPECT_TRUE(handled);
542 expect_runtime_error_yes_catch_all(ew_small);
543 EXPECT_TRUE(handled);
545 expect_runtime_error_yes_catch_all(ew_big);
546 EXPECT_TRUE(handled);
549 auto expect_runtime_error_no_catch_all = [&](const exception_wrapper& ew) {
551 [](const std::logic_error&) { ADD_FAILURE(); },
552 [&](const std::runtime_error&) { handled = true; },
553 [](const std::exception&) { ADD_FAILURE(); });
556 expect_runtime_error_no_catch_all(ew_eptr);
557 EXPECT_TRUE(handled);
559 expect_runtime_error_no_catch_all(ew_small);
560 EXPECT_TRUE(handled);
562 expect_runtime_error_no_catch_all(ew_big);
563 EXPECT_TRUE(handled);
566 auto expect_runtime_error_catch_non_std = [&](const exception_wrapper& ew) {
568 [](const std::logic_error&) { ADD_FAILURE(); },
569 [&](const std::runtime_error&) { handled = true; },
570 [](const std::exception&) { ADD_FAILURE(); },
571 [](const int&) { ADD_FAILURE(); });
574 expect_runtime_error_catch_non_std(ew_eptr);
575 EXPECT_TRUE(handled);
577 expect_runtime_error_catch_non_std(ew_small);
578 EXPECT_TRUE(handled);
580 expect_runtime_error_catch_non_std(ew_big);
581 EXPECT_TRUE(handled);
584 // Test that an exception thrown from one handler is not caught by an
586 auto expect_runtime_error_rethrow = [&](const exception_wrapper& ew) {
588 [](const std::logic_error&) { ADD_FAILURE(); },
589 [&](const std::runtime_error& e) {
593 [](const std::exception&) { ADD_FAILURE(); });
596 EXPECT_THROW(expect_runtime_error_rethrow(ew_eptr), std::runtime_error);
597 EXPECT_TRUE(handled);
599 EXPECT_THROW(expect_runtime_error_rethrow(ew_small), std::runtime_error);
600 EXPECT_TRUE(handled);
602 EXPECT_THROW(expect_runtime_error_rethrow(ew_big), std::runtime_error);
603 EXPECT_TRUE(handled);
606 TEST(ExceptionWrapper, handle_std_exception_unhandled) {
607 auto ep = std::make_exception_ptr(std::exception{});
608 exception_wrapper const ew_eptr(ep, from_eptr<std::exception>(ep));
609 exception_wrapper const ew_small(std::exception{});
611 bool handled = false;
612 auto expect_runtime_error_yes_catch_all = [&](const exception_wrapper& ew) {
614 [](const std::logic_error&) { ADD_FAILURE(); },
615 [](const std::runtime_error&) { ADD_FAILURE(); },
616 [&](...) { handled = true; });
619 expect_runtime_error_yes_catch_all(ew_eptr);
620 EXPECT_TRUE(handled);
622 expect_runtime_error_yes_catch_all(ew_small);
623 EXPECT_TRUE(handled);
626 TEST(ExceptionWrapper, handle_non_std_exception_small) {
627 auto ep = std::make_exception_ptr(42);
628 exception_wrapper const ew_eptr1(ep);
629 exception_wrapper const ew_eptr2(ep, from_eptr<int>(ep));
630 exception_wrapper const ew_small(folly::in_place, 42);
631 bool handled = false;
633 auto expect_int_yes_catch_all = [&](const exception_wrapper& ew) {
635 [](const std::exception&) { ADD_FAILURE(); },
636 [&](...) { handled = true; });
639 expect_int_yes_catch_all(ew_eptr1);
640 EXPECT_TRUE(handled);
642 expect_int_yes_catch_all(ew_eptr2);
643 EXPECT_TRUE(handled);
645 expect_int_yes_catch_all(ew_small);
646 EXPECT_TRUE(handled);
649 auto expect_int_no_catch_all = [&](const exception_wrapper& ew) {
651 [](const std::exception&) { ADD_FAILURE(); },
652 [&](const int&) { handled = true; });
655 expect_int_no_catch_all(ew_eptr1);
656 EXPECT_TRUE(handled);
658 expect_int_no_catch_all(ew_eptr2);
659 EXPECT_TRUE(handled);
661 expect_int_no_catch_all(ew_small);
662 EXPECT_TRUE(handled);
665 auto expect_int_no_catch_all_2 = [&](const exception_wrapper& ew) {
667 [&](const int&) { handled = true; },
668 [](const std::exception&) { ADD_FAILURE(); });
671 expect_int_no_catch_all_2(ew_eptr1);
672 EXPECT_TRUE(handled);
674 expect_int_no_catch_all_2(ew_eptr2);
675 EXPECT_TRUE(handled);
677 expect_int_no_catch_all_2(ew_small);
678 EXPECT_TRUE(handled);
681 TEST(ExceptionWrapper, handle_non_std_exception_big) {
682 auto ep = std::make_exception_ptr(BigNonStdError{});
683 exception_wrapper const ew_eptr1(ep);
684 exception_wrapper const ew_eptr2(ep, from_eptr<BigNonStdError>(ep));
685 exception_wrapper const ew_big(folly::in_place, BigNonStdError{});
686 bool handled = false;
688 auto expect_int_yes_catch_all = [&](const exception_wrapper& ew) {
690 [](const std::exception&) { ADD_FAILURE(); },
691 [&](...) { handled = true; });
694 expect_int_yes_catch_all(ew_eptr1);
695 EXPECT_TRUE(handled);
697 expect_int_yes_catch_all(ew_eptr2);
698 EXPECT_TRUE(handled);
700 expect_int_yes_catch_all(ew_big);
701 EXPECT_TRUE(handled);
704 auto expect_int_no_catch_all = [&](const exception_wrapper& ew) {
706 [](const std::exception&) { ADD_FAILURE(); },
707 [&](const BigNonStdError&) { handled = true; });
710 expect_int_no_catch_all(ew_eptr1);
711 EXPECT_TRUE(handled);
713 expect_int_no_catch_all(ew_eptr2);
714 EXPECT_TRUE(handled);
716 expect_int_no_catch_all(ew_big);
717 EXPECT_TRUE(handled);
720 auto expect_int_no_catch_all_2 = [&](const exception_wrapper& ew) {
722 [&](const BigNonStdError&) { handled = true; },
723 [](const std::exception&) { ADD_FAILURE(); });
726 expect_int_no_catch_all_2(ew_eptr1);
727 EXPECT_TRUE(handled);
729 expect_int_no_catch_all_2(ew_eptr2);
730 EXPECT_TRUE(handled);
732 expect_int_no_catch_all_2(ew_big);
733 EXPECT_TRUE(handled);
737 expect_int_no_catch_all_2(exception_wrapper{folly::in_place, 42}), int);
740 TEST(ExceptionWrapper, handle_non_std_exception_rethrow_base_derived) {
741 auto ew = testNonStdException();
742 bool handled = false;
745 [&](const DerivedException& e) {
749 [](const BaseException&) { ADD_FAILURE(); }),
751 EXPECT_TRUE(handled);
755 [&](const DerivedException& e) {
759 [](...) { ADD_FAILURE(); }),
761 EXPECT_TRUE(handled);
764 TEST(ExceptionWrapper, self_swap_test) {
765 exception_wrapper ew(std::runtime_error("hello world"));
767 EXPECT_EQ(kRuntimeErrorClassName + ": hello world", ew.what());
769 ew = std::move(ew2); // should not crash