proxygen
UncaughtExceptionsTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2016-present Facebook, Inc.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
18 #include <folly/Conv.h>
20 #include <glog/logging.h>
21 
22 /*
23  * Test helper class, when goes out of scope it validaes that
24  * folly::uncaught_exceptions() returns the specified
25  * value.
26  */
27 class Validator {
28  public:
29  Validator(int expectedCount, const std::string& msg)
30  : expectedCount_(expectedCount), msg_(msg) {}
31 
32  // Automatic validation during destruction.
34  validate();
35  }
36 
37  // Invoke to validate explicitly.
38  void validate() {
39  LOG(INFO) << msg_ << ", expected " << expectedCount_ << ", is "
41  EXPECT_EQ(expectedCount_, folly::uncaught_exceptions()) << msg_;
42  }
43 
44  private:
47 };
48 
49 TEST(UncaughtExceptions, no_exception) {
50  Validator validator(0, "no_exception");
51 }
52 
53 TEST(UncaughtExceptions, no_uncaught_exception) {
54  Validator validator(0, "no_uncaught_exception");
55  try {
56  throw std::runtime_error("exception");
57  } catch (const std::runtime_error& e) {
58  validator.validate();
59  }
60 }
61 
62 TEST(UncaughtExceptions, one_uncaught_exception) {
63  try {
64  Validator validator(1, "one_uncaught_exception");
65  throw std::runtime_error("exception");
66  } catch (const std::runtime_error& e) {
67  }
68 }
69 
70 TEST(UncaughtExceptions, catch_rethrow) {
71  try {
72  Validator validatorOuter(1, "catch_rethrow_outer");
73  try {
74  Validator validatorInner(1, "catch_rethrow_inner");
75  throw std::runtime_error("exception");
76  } catch (const std::runtime_error& e) {
78  Validator validatorRethrow(1, "catch_rethrow");
79  throw;
80  }
81  } catch (const std::runtime_error& e) {
83  }
84 }
85 
86 [[noreturn]] void throwingFunction() {
87  Validator validator(1, "one_uncaught_exception_in_function");
88  throw std::runtime_error("exception");
89 }
90 
91 TEST(UncaughtExceptions, one_uncaught_exception_in_function) {
92  EXPECT_THROW({ throwingFunction(); }, std::runtime_error);
93 }
94 
95 /*
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.
103  */
104 template <size_t N, size_t I = N>
108 
110  try {
111  InnerThrowInDestructor stackObjectThrowingOnUnwind;
112  (void)stackObjectThrowingOnUnwind;
113  Validator validator(
114  N - I + 1, "validating in " + folly::to<std::string>(I));
115  LOG(INFO) << "throwing in ~ThrowInDestructor " << I;
116  throw std::logic_error("inner");
117  } catch (const std::logic_error& e) {
118  LOG(INFO) << "catching in ~ThrowInDestructor " << I << " expecting "
119  << N - I << ", it is " << folly::uncaught_exceptions();
120  EXPECT_EQ(N - I, folly::uncaught_exceptions());
121  }
122  }
123 };
124 
125 /*
126  * Terminate recursion
127  */
128 template <size_t N>
129 struct ThrowInDestructor<N, 0> {
130  ThrowInDestructor() = default;
131  ~ThrowInDestructor() = default;
132 };
133 
134 TEST(UncaughtExceptions, two_uncaught_exceptions) {
135  ThrowInDestructor<2> twoUncaughtExceptions;
136 }
137 
138 TEST(UncaughtExceptions, ten_uncaught_exceptions) {
139  ThrowInDestructor<10> twoUncaughtExceptions;
140 }
141 
143  [[noreturn]] ThrowingConstructor() noexcept(false) {
144  throw std::runtime_error("exception");
145  }
146 };
147 
149  public ThrowingConstructor {
151  : Validator(1, "one_exception_in_ctor_initializer_expression"),
153  } catch (...) {
154  // This is being re-thrown once the catch block ends, so I guess
155  // it's similar to a catch/throw; (re-throw) behavior and thus the value
156  // is 0.
158  }
159 };
160 
161 TEST(UncaughtExceptions, one_exception_in_ctor_initializer_expression) {
162  EXPECT_THROW(
163  { InheritsThrowingConstructor inheritsThrowingConstructor; },
164  std::runtime_error);
165 }
void throwingFunction()
Validator(int expectedCount, const std::string &msg)
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
requires E e noexcept(noexcept(s.error(std::move(e))))
int uncaught_exceptions() noexcept
const std::string msg_
const int32_t expectedCount_
const char * string
Definition: Conv.cpp:212
TEST(UncaughtExceptions, no_exception)
ThrowingConstructor() noexcept(false)