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.
17 #include <folly/Conv.h>
18 #include <folly/UncaughtExceptions.h>
19 #include <folly/portability/GTest.h>
20 #include <glog/logging.h>
23 * Test helper class, when goes out of scope it validaes that
24 * folly::uncaught_exceptions() returns the specified
29 Validator(int expectedCount, const std::string& msg)
30 : expectedCount_(expectedCount), msg_(msg) {}
32 // Automatic validation during destruction.
37 // Invoke to validate explicitly.
39 LOG(INFO) << msg_ << ", expected " << expectedCount_ << ", is "
40 << folly::uncaught_exceptions();
41 EXPECT_EQ(expectedCount_, folly::uncaught_exceptions()) << msg_;
45 const int32_t expectedCount_;
46 const std::string msg_;
49 TEST(UncaughtExceptions, no_exception) {
50 Validator validator(0, "no_exception");
53 TEST(UncaughtExceptions, no_uncaught_exception) {
54 Validator validator(0, "no_uncaught_exception");
56 throw std::runtime_error("exception");
57 } catch (const std::runtime_error& e) {
62 TEST(UncaughtExceptions, one_uncaught_exception) {
64 Validator validator(1, "one_uncaught_exception");
65 throw std::runtime_error("exception");
66 } catch (const std::runtime_error& e) {
70 TEST(UncaughtExceptions, catch_rethrow) {
72 Validator validatorOuter(1, "catch_rethrow_outer");
74 Validator validatorInner(1, "catch_rethrow_inner");
75 throw std::runtime_error("exception");
76 } catch (const std::runtime_error& e) {
77 EXPECT_EQ(0, folly::uncaught_exceptions());
78 Validator validatorRethrow(1, "catch_rethrow");
81 } catch (const std::runtime_error& e) {
82 EXPECT_EQ(0, folly::uncaught_exceptions());
86 [[noreturn]] void throwingFunction() {
87 Validator validator(1, "one_uncaught_exception_in_function");
88 throw std::runtime_error("exception");
91 TEST(UncaughtExceptions, one_uncaught_exception_in_function) {
92 EXPECT_THROW({ throwingFunction(); }, std::runtime_error);
96 * Test helper class. Generates N wrapped classes/objects.
97 * The destructor N of the most outer class creates the N-1
98 * object, and N - 1 object destructor creating the N-2 object,
99 * and so on. Each destructor throws an exception after creating
100 * the inner object on the stack, thus the number of exceptions
101 * accumulates while the stack is unwinding. It's used to test
102 * the folly::uncaught_exceptions() with value >= 2.
104 template <size_t N, size_t I = N>
105 struct ThrowInDestructor {
106 using InnerThrowInDestructor = ThrowInDestructor<N, I - 1>;
107 ThrowInDestructor() {}
109 ~ThrowInDestructor() {
111 InnerThrowInDestructor stackObjectThrowingOnUnwind;
113 N - I + 1, "validating in " + folly::to<std::string>(I));
114 LOG(INFO) << "throwing in ~ThrowInDestructor " << I;
115 throw std::logic_error("inner");
116 } catch (const std::logic_error& e) {
117 LOG(INFO) << "catching in ~ThrowInDestructor " << I << " expecting "
118 << N - I << ", it is " << folly::uncaught_exceptions();
119 EXPECT_EQ(N - I, folly::uncaught_exceptions());
125 * Terminate recursion
128 struct ThrowInDestructor<N, 0> {
129 ThrowInDestructor() = default;
130 ~ThrowInDestructor() = default;
133 TEST(UncaughtExceptions, two_uncaught_exceptions) {
134 ThrowInDestructor<2> twoUncaughtExceptions;
137 TEST(UncaughtExceptions, ten_uncaught_exceptions) {
138 ThrowInDestructor<10> twoUncaughtExceptions;
141 struct ThrowingConstructor {
142 [[noreturn]] ThrowingConstructor() noexcept(false) {
143 throw std::runtime_error("exception");
147 struct InheritsThrowingConstructor : public Validator,
148 public ThrowingConstructor {
149 InheritsThrowingConstructor() try
150 : Validator(1, "one_exception_in_ctor_initializer_expression"),
151 ThrowingConstructor() {
153 // This is being re-thrown once the catch block ends, so I guess
154 // it's similar to a catch/throw; (re-throw) behavior and thus the value
156 EXPECT_EQ(0, folly::uncaught_exceptions());
160 TEST(UncaughtExceptions, one_exception_in_ctor_initializer_expression) {
162 { InheritsThrowingConstructor inheritsThrowingConstructor; },