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/ExceptionWrapper.h>
20 #include <folly/Conv.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) {}
34 int getInt() const override { return i_; }
35 const char* what() const noexcept override {
36 what_ = folly::to<std::string>("int == ", i_);
42 mutable std::string what_;
45 const static std::string kExceptionClassName =
46 demangle(typeid(std::exception)).toStdString();
47 const static std::string kRuntimeErrorClassName =
48 demangle(typeid(std::runtime_error)).toStdString();
49 const static std::string kIntExceptionClassName =
50 demangle(typeid(IntException)).toStdString();
51 const static std::string kIntClassName = demangle(typeid(int)).toStdString();
54 T& from_eptr(std::exception_ptr& eptr) {
56 std::rethrow_exception(eptr);
60 throw std::logic_error("impossible");
64 // Tests that when we call throw_exception, the proper type is thrown (derived)
65 TEST(ExceptionWrapper, throw_test) {
66 std::runtime_error e("payload");
67 auto ew = make_exception_wrapper<std::runtime_error>(e);
69 std::vector<exception_wrapper> container;
70 container.push_back(ew);
73 container[0].throw_exception();
74 } catch (std::runtime_error& err) {
75 std::string expected = "payload";
76 std::string actual = err.what();
77 EXPECT_EQ(expected, actual);
81 TEST(ExceptionWrapper, members) {
82 auto ew = exception_wrapper();
83 EXPECT_FALSE(bool(ew));
84 EXPECT_EQ(ew.what(), "");
85 EXPECT_EQ(ew.class_name(), "");
86 ew = make_exception_wrapper<std::runtime_error>("payload");
87 EXPECT_TRUE(bool(ew));
88 EXPECT_EQ(ew.what(), kRuntimeErrorClassName + ": payload");
89 EXPECT_EQ(ew.class_name(), kRuntimeErrorClassName);
92 TEST(ExceptionWrapper, try_and_catch_test) {
93 std::string expected = "payload";
95 // Catch rightmost matching exception type
96 exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
98 throw std::runtime_error(expected);
100 EXPECT_TRUE(bool(ew));
101 EXPECT_EQ(ew.what(), kRuntimeErrorClassName + ": payload");
102 EXPECT_EQ(ew.class_name(), kRuntimeErrorClassName);
103 auto rep = ew.is_compatible_with<std::runtime_error>();
106 // Changing order is like catching in wrong order. Beware of this in your
108 auto ew2 = try_and_catch<std::runtime_error, std::exception>([=]() {
109 throw std::runtime_error(expected);
111 EXPECT_TRUE(bool(ew2));
112 // We are catching a std::exception, not std::runtime_error.
113 // But, we can still get the actual type if we want it.
114 rep = ew2.is_compatible_with<std::runtime_error>();
117 // Catches even if not rightmost.
118 auto ew3 = try_and_catch<std::exception, std::runtime_error>([]() {
119 throw std::exception();
121 EXPECT_TRUE(bool(ew3));
122 EXPECT_EQ(ew3.what(), kExceptionClassName + ": std::exception");
123 EXPECT_EQ(ew3.class_name(), kExceptionClassName);
124 rep = ew3.is_compatible_with<std::runtime_error>();
127 // If does not catch, throws.
129 try_and_catch<std::runtime_error>([]() {
130 throw std::exception();
135 TEST(ExceptionWrapper, with_exception_test) {
138 // This works, and doesn't slice.
139 exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
141 throw IntException(expected);
143 EXPECT_TRUE(bool(ew));
144 EXPECT_EQ(ew.what(), kIntExceptionClassName + ": int == 23");
145 EXPECT_EQ(ew.class_name(), kIntExceptionClassName);
146 EXPECT_TRUE(ew.with_exception(
147 [&](const IntException& ie) { EXPECT_EQ(ie.getInt(), expected); }));
149 // I can try_and_catch a non-copyable base class. This will use
150 // std::exception_ptr internally.
151 exception_wrapper ew2 = try_and_catch<AbstractIntException>(
153 throw IntException(expected);
155 EXPECT_TRUE(bool(ew2));
156 EXPECT_EQ(ew2.what(), kIntExceptionClassName + ": int == 23");
157 EXPECT_EQ(ew2.class_name(), kIntExceptionClassName);
158 bool res = ew2.with_exception([&](AbstractIntException& ie) {
159 EXPECT_EQ(ie.getInt(), expected);
160 EXPECT_TRUE(dynamic_cast<IntException*>(&ie));
164 // Test with const this. If this compiles and does not crash due to
165 // infinite loop when it runs, it succeeds.
166 const exception_wrapper& cew = ew;
168 cew.with_exception([&](const IntException& /* ie */) { SUCCEED(); }));
170 // Test with empty ew.
171 exception_wrapper empty_ew;
173 empty_ew.with_exception([&](const std::exception& /* ie */) { FAIL(); }));
175 // Testing with const exception_wrapper; sanity check first:
176 EXPECT_FALSE(cew.with_exception([&](const std::runtime_error&) {}));
177 EXPECT_FALSE(cew.with_exception([&](const int&) {}));
178 // This won't even compile. You can't use a function which takes a
179 // non-const reference with a const exception_wrapper.
181 EXPECT_FALSE(cew.with_exception([&](std::runtime_error&) {}));
182 EXPECT_FALSE(cew.with_exception([&](int&) {}));
186 TEST(ExceptionWrapper, get_or_make_exception_ptr_test) {
189 // This works, and doesn't slice.
190 exception_wrapper ew = try_and_catch<std::exception, std::runtime_error>(
191 [=]() { throw IntException(expected); });
192 std::exception_ptr eptr = ew.to_exception_ptr();
193 EXPECT_THROW(std::rethrow_exception(eptr), IntException);
195 // I can try_and_catch a non-copyable base class. This will use
196 // std::exception_ptr internally.
197 exception_wrapper ew2 = try_and_catch<AbstractIntException>(
198 [=]() { throw IntException(expected); });
199 eptr = ew2.to_exception_ptr();
200 EXPECT_THROW(std::rethrow_exception(eptr), IntException);
202 // Test with const this.
203 const exception_wrapper& cew = ew;
204 eptr = cew.to_exception_ptr();
205 EXPECT_THROW(std::rethrow_exception(eptr), IntException);
207 // Test with empty ew.
208 exception_wrapper empty_ew;
209 eptr = empty_ew.to_exception_ptr();
213 TEST(ExceptionWrapper, with_exception_ptr_empty) {
214 auto ew = exception_wrapper(std::exception_ptr());
215 EXPECT_EQ(exception_wrapper::none(), ew.type());
216 EXPECT_FALSE(bool(ew));
217 EXPECT_EQ(nullptr, ew.get_exception());
218 EXPECT_EQ(nullptr, ew.get_object<std::exception>());
219 EXPECT_EQ(nullptr, ew.get_object<int>());
220 EXPECT_FALSE(ew.has_exception_ptr());
221 EXPECT_EQ(nullptr, ew.to_exception_ptr());
222 EXPECT_FALSE(ew.has_exception_ptr());
223 EXPECT_EQ("", ew.class_name());
224 EXPECT_EQ("", ew.what());
225 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
226 EXPECT_FALSE(ew.is_compatible_with<int>());
227 EXPECT_DEATH(ew.throw_exception(), "empty folly::exception_wrapper");
230 TEST(ExceptionWrapper, with_shared_ptr_test) {
231 auto ew = exception_wrapper(std::runtime_error("foo"));
232 EXPECT_TRUE(bool(ew));
233 EXPECT_EQ(typeid(std::runtime_error), ew.type());
234 EXPECT_NE(nullptr, ew.get_exception());
235 EXPECT_NE(nullptr, ew.get_object<std::exception>());
236 EXPECT_EQ(nullptr, ew.get_object<int>());
237 EXPECT_FALSE(ew.has_exception_ptr());
238 EXPECT_NE(nullptr, ew.to_exception_ptr());
239 EXPECT_TRUE(ew.has_exception_ptr());
240 EXPECT_EQ("std::runtime_error", ew.class_name());
241 EXPECT_EQ("std::runtime_error: foo", ew.what());
242 EXPECT_TRUE(ew.is_compatible_with<std::exception>());
243 EXPECT_TRUE(ew.is_compatible_with<std::runtime_error>());
244 EXPECT_FALSE(ew.is_compatible_with<int>());
245 EXPECT_THROW(ew.throw_exception(), std::runtime_error);
247 exception_wrapper(std::move(ew));
248 EXPECT_FALSE(bool(ew));
249 EXPECT_EQ(exception_wrapper::none(), ew.type());
250 EXPECT_EQ(nullptr, ew.get_exception());
251 EXPECT_EQ(nullptr, ew.get_object<std::exception>());
252 EXPECT_EQ(nullptr, ew.get_object<int>());
253 EXPECT_EQ(nullptr, ew.to_exception_ptr());
254 EXPECT_EQ("", ew.class_name());
255 EXPECT_EQ("", ew.what());
256 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
257 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
258 EXPECT_FALSE(ew.is_compatible_with<int>());
261 TEST(ExceptionWrapper, with_exception_ptr_exn_test) {
262 auto ep = std::make_exception_ptr(std::runtime_error("foo"));
263 auto ew = exception_wrapper(ep, from_eptr<std::runtime_error>(ep));
264 EXPECT_TRUE(bool(ew));
265 EXPECT_EQ(typeid(std::runtime_error), ew.type());
266 EXPECT_NE(nullptr, ew.get_exception());
267 EXPECT_NE(nullptr, ew.get_object<std::exception>());
268 EXPECT_EQ(nullptr, ew.get_object<int>());
269 EXPECT_TRUE(ew.has_exception_ptr());
270 EXPECT_EQ(ep, ew.to_exception_ptr());
271 EXPECT_TRUE(ew.has_exception_ptr());
272 EXPECT_EQ("std::runtime_error", ew.class_name());
273 EXPECT_EQ("std::runtime_error: foo", ew.what());
274 EXPECT_TRUE(ew.is_compatible_with<std::exception>());
275 EXPECT_TRUE(ew.is_compatible_with<std::runtime_error>());
276 EXPECT_FALSE(ew.is_compatible_with<int>());
277 EXPECT_THROW(ew.throw_exception(), std::runtime_error);
279 exception_wrapper(std::move(ew));
280 EXPECT_FALSE(bool(ew));
281 EXPECT_EQ(exception_wrapper::none(), ew.type());
282 EXPECT_EQ(nullptr, ew.get_exception());
283 EXPECT_EQ(nullptr, ew.get_object<std::exception>());
284 EXPECT_EQ(nullptr, ew.get_object<int>());
285 EXPECT_EQ(nullptr, ew.to_exception_ptr());
286 EXPECT_EQ("", ew.class_name());
287 EXPECT_EQ("", ew.what());
288 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
289 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
290 EXPECT_FALSE(ew.is_compatible_with<int>());
293 TEST(ExceptionWrapper, with_exception_ptr_any_test) {
294 auto ep = std::make_exception_ptr<int>(12);
295 auto ew = exception_wrapper(ep, from_eptr<int>(ep));
296 EXPECT_TRUE(bool(ew));
297 EXPECT_EQ(nullptr, ew.get_exception());
298 EXPECT_EQ(nullptr, ew.get_object<std::exception>());
299 EXPECT_NE(nullptr, ew.get_object<int>());
300 EXPECT_TRUE(ew.has_exception_ptr());
301 EXPECT_EQ(ep, ew.to_exception_ptr());
302 EXPECT_TRUE(ew.has_exception_ptr());
303 EXPECT_EQ("int", ew.class_name());
304 EXPECT_EQ("int", ew.what());
305 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
306 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
307 EXPECT_TRUE(ew.is_compatible_with<int>());
308 EXPECT_THROW(ew.throw_exception(), int);
310 exception_wrapper(std::move(ew));
311 EXPECT_FALSE(bool(ew));
312 EXPECT_EQ(nullptr, ew.get_exception());
313 EXPECT_EQ(nullptr, ew.get_object<std::exception>());
314 EXPECT_EQ(nullptr, ew.get_object<int>());
315 EXPECT_EQ(nullptr, ew.to_exception_ptr());
316 EXPECT_FALSE(ew.has_exception_ptr());
317 EXPECT_EQ("", ew.class_name());
318 EXPECT_EQ("", ew.what());
319 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
320 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
321 EXPECT_FALSE(ew.is_compatible_with<int>());
324 TEST(ExceptionWrapper, with_non_std_exception_test) {
325 auto ew = exception_wrapper(folly::in_place, 42);
326 EXPECT_TRUE(bool(ew));
327 EXPECT_EQ(nullptr, ew.get_exception());
328 EXPECT_EQ(nullptr, ew.get_object<std::exception>());
329 EXPECT_NE(nullptr, ew.get_object<int>());
330 EXPECT_FALSE(ew.has_exception_ptr());
331 EXPECT_EQ("int", ew.class_name());
332 EXPECT_EQ("int", ew.what());
333 EXPECT_NE(nullptr, ew.to_exception_ptr());
334 EXPECT_TRUE(ew.has_exception_ptr());
335 EXPECT_EQ("int", ew.class_name());
336 EXPECT_EQ("int", ew.what());
337 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
338 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
339 EXPECT_TRUE(ew.is_compatible_with<int>());
340 EXPECT_THROW(ew.throw_exception(), int);
342 exception_wrapper(std::move(ew));
343 EXPECT_FALSE(bool(ew));
344 EXPECT_EQ(nullptr, ew.get_exception());
345 EXPECT_EQ(nullptr, ew.get_object<std::exception>());
346 EXPECT_EQ(nullptr, ew.get_object<int>());
347 EXPECT_EQ(nullptr, ew.to_exception_ptr());
348 EXPECT_FALSE(ew.has_exception_ptr());
349 EXPECT_EQ("", ew.class_name());
350 EXPECT_EQ("", ew.what());
351 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
352 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
353 EXPECT_FALSE(ew.is_compatible_with<int>());
356 TEST(ExceptionWrapper, with_exception_ptr_any_nil_test) {
357 auto ep = std::make_exception_ptr<int>(12);
358 auto ew = exception_wrapper(ep); // concrete type is erased
359 EXPECT_TRUE(bool(ew));
360 EXPECT_EQ(nullptr, ew.get_exception());
361 EXPECT_EQ(nullptr, ew.get_object<std::exception>());
362 EXPECT_NE(nullptr, ew.get_object<int>());
363 EXPECT_EQ(ep, ew.to_exception_ptr());
364 EXPECT_EQ("<unknown exception>", ew.class_name()); // because concrete type is
366 EXPECT_EQ("<unknown exception>", ew.what());
367 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
368 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
369 EXPECT_TRUE(ew.is_compatible_with<int>());
370 EXPECT_THROW(ew.throw_exception(), int);
372 exception_wrapper(std::move(ew));
373 EXPECT_FALSE(bool(ew));
374 EXPECT_EQ(nullptr, ew.get_exception());
375 EXPECT_EQ(nullptr, ew.get_object<std::exception>());
376 EXPECT_EQ(nullptr, ew.get_object<int>());
377 EXPECT_EQ(nullptr, ew.to_exception_ptr());
378 EXPECT_EQ("", ew.class_name());
379 EXPECT_EQ("", ew.what());
380 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
381 EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
382 EXPECT_FALSE(ew.is_compatible_with<int>());
385 TEST(ExceptionWrapper, with_exception_deduction) {
386 auto ew = make_exception_wrapper<std::runtime_error>("hi");
387 EXPECT_TRUE(ew.with_exception([](std::runtime_error&) {}));
388 EXPECT_TRUE(ew.with_exception([](std::exception&) {}));
389 EXPECT_FALSE(ew.with_exception([](std::logic_error&) {}));
392 TEST(ExceptionWrapper, with_exception_deduction_exn_const) {
393 auto ew = make_exception_wrapper<std::runtime_error>("hi");
394 EXPECT_TRUE(ew.with_exception([](const std::runtime_error&) {}));
395 EXPECT_TRUE(ew.with_exception([](const std::exception&) {}));
396 EXPECT_FALSE(ew.with_exception([](const std::logic_error&) {}));
399 TEST(ExceptionWrapper, with_exception_deduction_wrap_const_exn_const) {
400 const auto cew = make_exception_wrapper<std::runtime_error>("hi");
401 EXPECT_TRUE(cew.with_exception([](const std::runtime_error&) {}));
402 EXPECT_TRUE(cew.with_exception([](const std::exception&) {}));
403 EXPECT_FALSE(cew.with_exception([](const std::logic_error&) {}));
406 TEST(ExceptionWrapper, with_exception_deduction_returning) {
407 auto ew = make_exception_wrapper<std::runtime_error>("hi");
408 EXPECT_TRUE(ew.with_exception([](std::runtime_error&) { return 3; }));
409 EXPECT_TRUE(ew.with_exception([](std::exception&) { return "hello"; }));
410 EXPECT_FALSE(ew.with_exception([](std::logic_error&) { return nullptr; }));
414 template <typename T>
415 T& r_to_l(T v) { return std::ref(v); }
418 TEST(ExceptionWrapper, with_exception_deduction_functor_lvalue) {
419 auto ew = make_exception_wrapper<std::runtime_error>("hi");
420 EXPECT_TRUE(ew.with_exception(r_to_l([](std::runtime_error&) {})));
421 EXPECT_TRUE(ew.with_exception(r_to_l([](std::exception&) {})));
422 EXPECT_FALSE(ew.with_exception(r_to_l([](std::logic_error&) {})));
425 TEST(ExceptionWrapper, non_std_exception_test) {
428 exception_wrapper ew = try_and_catch<std::exception, int>(
432 EXPECT_TRUE(bool(ew));
433 EXPECT_FALSE(ew.is_compatible_with<std::exception>());
434 EXPECT_TRUE(ew.is_compatible_with<int>());
435 EXPECT_EQ(ew.what(), kIntClassName);
436 EXPECT_EQ(ew.class_name(), kIntClassName);
437 // non-std::exception types are supported, but the only way to
438 // access their value is to explicity rethrow and catch it.
440 ew.throw_exception();
441 } catch /* nolint */ (int& i) {
442 EXPECT_EQ(i, expected);
447 TEST(ExceptionWrapper, exceptionStr) {
448 auto ew = make_exception_wrapper<std::runtime_error>("argh");
449 EXPECT_EQ(kRuntimeErrorClassName + ": argh", exceptionStr(ew));
452 TEST(ExceptionWrapper, throwException_noException) {
453 exception_wrapper ew;
454 ASSERT_DEATH(ew.throw_exception(), "empty folly::exception_wrapper");
458 class TestException : public std::exception { };
459 void testEW(const exception_wrapper& ew) {
460 EXPECT_THROW(ew.throw_exception(), TestException);
464 TEST(ExceptionWrapper, implicitConstruction) {
465 // Try with both lvalue and rvalue references
468 testEW(TestException());
472 struct BaseException {
473 virtual ~BaseException() {}
475 struct DerivedException : BaseException {};
476 exception_wrapper testNonStdException() {
478 throw DerivedException{};
479 } catch (const BaseException& e) {
480 return exception_wrapper{std::current_exception(), e};
485 TEST(ExceptionWrapper, base_derived_non_std_exception_test) {
486 auto ew = testNonStdException();
487 EXPECT_TRUE(ew.type() == typeid(DerivedException));
488 EXPECT_TRUE(ew.with_exception([](const DerivedException&) {}));
492 // Cannot be stored within an exception_wrapper
493 struct BigRuntimeError : std::runtime_error {
494 using std::runtime_error::runtime_error;
495 char data_[sizeof(exception_wrapper) + 1]{};
498 struct BigNonStdError {
499 char data_[sizeof(exception_wrapper) + 1]{};
503 TEST(ExceptionWrapper, handle_std_exception) {
504 auto ep = std::make_exception_ptr(std::runtime_error{"hello world"});
505 exception_wrapper const ew_eptr(ep, from_eptr<std::runtime_error>(ep));
506 exception_wrapper const ew_small(std::runtime_error{"hello world"});
507 exception_wrapper const ew_big(BigRuntimeError{"hello world"});
509 bool handled = false;
510 auto expect_runtime_error_yes_catch_all = [&](const exception_wrapper& ew) {
512 [](const std::logic_error&) { EXPECT_TRUE(false); },
513 [&](const std::runtime_error&) { handled = true; },
514 [](const std::exception&) { EXPECT_TRUE(false); },
515 [](...) { EXPECT_TRUE(false); });
518 expect_runtime_error_yes_catch_all(ew_eptr);
519 EXPECT_TRUE(handled);
521 expect_runtime_error_yes_catch_all(ew_small);
522 EXPECT_TRUE(handled);
524 expect_runtime_error_yes_catch_all(ew_big);
525 EXPECT_TRUE(handled);
528 auto expect_runtime_error_no_catch_all = [&](const exception_wrapper& ew) {
530 [](const std::logic_error&) { EXPECT_TRUE(false); },
531 [&](const std::runtime_error&) { handled = true; },
532 [](const std::exception&) { EXPECT_TRUE(false); });
535 expect_runtime_error_no_catch_all(ew_eptr);
536 EXPECT_TRUE(handled);
538 expect_runtime_error_no_catch_all(ew_small);
539 EXPECT_TRUE(handled);
541 expect_runtime_error_no_catch_all(ew_big);
542 EXPECT_TRUE(handled);
545 auto expect_runtime_error_catch_non_std = [&](const exception_wrapper& ew) {
547 [](const std::logic_error&) { EXPECT_TRUE(false); },
548 [&](const std::runtime_error&) { handled = true; },
549 [](const std::exception&) { EXPECT_TRUE(false); },
550 [](const int&) { EXPECT_TRUE(false); });
553 expect_runtime_error_catch_non_std(ew_eptr);
554 EXPECT_TRUE(handled);
556 expect_runtime_error_catch_non_std(ew_small);
557 EXPECT_TRUE(handled);
559 expect_runtime_error_catch_non_std(ew_big);
560 EXPECT_TRUE(handled);
563 // Test that an exception thrown from one handler is not caught by an
565 auto expect_runtime_error_rethrow = [&](const exception_wrapper& ew) {
567 [](const std::logic_error&) { EXPECT_TRUE(false); },
568 [&](const std::runtime_error& e) {
572 [](const std::exception&) { EXPECT_TRUE(false); });
575 EXPECT_THROW(expect_runtime_error_rethrow(ew_eptr), std::runtime_error);
576 EXPECT_TRUE(handled);
578 EXPECT_THROW(expect_runtime_error_rethrow(ew_small), std::runtime_error);
579 EXPECT_TRUE(handled);
581 EXPECT_THROW(expect_runtime_error_rethrow(ew_big), std::runtime_error);
582 EXPECT_TRUE(handled);
585 TEST(ExceptionWrapper, handle_std_exception_unhandled) {
586 auto ep = std::make_exception_ptr(std::exception{});
587 exception_wrapper const ew_eptr(ep, from_eptr<std::exception>(ep));
588 exception_wrapper const ew_small(std::exception{});
590 bool handled = false;
591 auto expect_runtime_error_yes_catch_all = [&](const exception_wrapper& ew) {
593 [](const std::logic_error&) { EXPECT_TRUE(false); },
594 [](const std::runtime_error&) { EXPECT_TRUE(false); },
595 [&](...) { handled = true; });
598 expect_runtime_error_yes_catch_all(ew_eptr);
599 EXPECT_TRUE(handled);
601 expect_runtime_error_yes_catch_all(ew_small);
602 EXPECT_TRUE(handled);
605 TEST(ExceptionWrapper, handle_non_std_exception_small) {
606 auto ep = std::make_exception_ptr(42);
607 exception_wrapper const ew_eptr1(ep);
608 exception_wrapper const ew_eptr2(ep, from_eptr<int>(ep));
609 exception_wrapper const ew_small(folly::in_place, 42);
610 bool handled = false;
612 auto expect_int_yes_catch_all = [&](const exception_wrapper& ew) {
614 [](const std::exception&) { EXPECT_TRUE(false); },
615 [&](...) { handled = true; });
618 expect_int_yes_catch_all(ew_eptr1);
619 EXPECT_TRUE(handled);
621 expect_int_yes_catch_all(ew_eptr2);
622 EXPECT_TRUE(handled);
624 expect_int_yes_catch_all(ew_small);
625 EXPECT_TRUE(handled);
628 auto expect_int_no_catch_all = [&](const exception_wrapper& ew) {
630 [](const std::exception&) { EXPECT_TRUE(false); },
631 [&](const int&) { handled = true; });
634 expect_int_no_catch_all(ew_eptr1);
635 EXPECT_TRUE(handled);
637 expect_int_no_catch_all(ew_eptr2);
638 EXPECT_TRUE(handled);
640 expect_int_no_catch_all(ew_small);
641 EXPECT_TRUE(handled);
644 auto expect_int_no_catch_all_2 = [&](const exception_wrapper& ew) {
646 [&](const int&) { handled = true; },
647 [](const std::exception&) { EXPECT_TRUE(false); });
650 expect_int_no_catch_all_2(ew_eptr1);
651 EXPECT_TRUE(handled);
653 expect_int_no_catch_all_2(ew_eptr2);
654 EXPECT_TRUE(handled);
656 expect_int_no_catch_all_2(ew_small);
657 EXPECT_TRUE(handled);
660 TEST(ExceptionWrapper, handle_non_std_exception_big) {
661 auto ep = std::make_exception_ptr(BigNonStdError{});
662 exception_wrapper const ew_eptr1(ep);
663 exception_wrapper const ew_eptr2(ep, from_eptr<BigNonStdError>(ep));
664 exception_wrapper const ew_big(folly::in_place, BigNonStdError{});
665 bool handled = false;
667 auto expect_int_yes_catch_all = [&](const exception_wrapper& ew) {
669 [](const std::exception&) { EXPECT_TRUE(false); },
670 [&](...) { handled = true; });
673 expect_int_yes_catch_all(ew_eptr1);
674 EXPECT_TRUE(handled);
676 expect_int_yes_catch_all(ew_eptr2);
677 EXPECT_TRUE(handled);
679 expect_int_yes_catch_all(ew_big);
680 EXPECT_TRUE(handled);
683 auto expect_int_no_catch_all = [&](const exception_wrapper& ew) {
685 [](const std::exception&) { EXPECT_TRUE(false); },
686 [&](const BigNonStdError&) { handled = true; });
689 expect_int_no_catch_all(ew_eptr1);
690 EXPECT_TRUE(handled);
692 expect_int_no_catch_all(ew_eptr2);
693 EXPECT_TRUE(handled);
695 expect_int_no_catch_all(ew_big);
696 EXPECT_TRUE(handled);
699 auto expect_int_no_catch_all_2 = [&](const exception_wrapper& ew) {
701 [&](const BigNonStdError&) { handled = true; },
702 [](const std::exception&) { EXPECT_TRUE(false); });
705 expect_int_no_catch_all_2(ew_eptr1);
706 EXPECT_TRUE(handled);
708 expect_int_no_catch_all_2(ew_eptr2);
709 EXPECT_TRUE(handled);
711 expect_int_no_catch_all_2(ew_big);
712 EXPECT_TRUE(handled);
716 expect_int_no_catch_all_2(exception_wrapper{folly::in_place, 42}), int);
719 TEST(ExceptionWrapper, handle_non_std_exception_rethrow_base_derived) {
720 auto ew = testNonStdException();
721 bool handled = false;
724 [&](const DerivedException& e) {
728 [](const BaseException&) { EXPECT_TRUE(false); }),
730 EXPECT_TRUE(handled);
734 [&](const DerivedException& e) {
738 [](...) { EXPECT_TRUE(false); }),
740 EXPECT_TRUE(handled);
743 TEST(ExceptionWrapper, self_swap_test) {
744 exception_wrapper ew(std::runtime_error("hello world"));
746 EXPECT_STREQ("std::runtime_error: hello world", ew.what().c_str());
748 ew = std::move(ew2); // should not crash