2 * Copyright 2015-present 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.
20 * This file contains additional gtest-style check macros to use in unit tests.
22 * - SKIP(), SKIP_IF(EXPR)
23 * - EXPECT_THROW_RE(), ASSERT_THROW_RE()
24 * - EXPECT_THROW_ERRNO(), ASSERT_THROW_ERRNO()
27 * Additionally, it includes a PrintTo() function for StringPiece.
28 * Including this file in your tests will ensure that StringPiece is printed
29 * nicely when used in EXPECT_EQ() or EXPECT_NE() checks.
34 #include <system_error>
35 #include <type_traits>
37 #include <folly/Conv.h>
38 #include <folly/ExceptionString.h>
39 #include <folly/Range.h>
40 #include <folly/portability/GTest.h>
42 // We use this to indicate that tests have failed because of timing
43 // or dependencies that may be flakey. Internally this is used by
44 // our test runner to retry the test. To gtest this will look like
45 // a normal test failure; there is only an effect if the test framework
46 // interprets the message.
47 #define SKIP() GTEST_FATAL_FAILURE_("Test skipped by client")
49 // Encapsulate conditional-skip, since it's nontrivial to get right.
50 #define SKIP_IF(expr) \
51 GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
56 #define TEST_THROW_ERRNO_(statement, errnoValue, fail) \
57 GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
58 if (::folly::test::detail::CheckResult gtest_result = \
59 ::folly::test::detail::checkThrowErrno( \
60 [&] { statement; }, errnoValue, #statement)) { \
62 fail(gtest_result.what())
65 * Check that a statement throws a std::system_error with the expected errno
66 * value. This is useful for checking code that uses the functions in
67 * folly/Exception.h to throw exceptions.
69 * Like other EXPECT_* and ASSERT_* macros, additional message information
70 * can be included using the << stream operator.
74 * EXPECT_THROW_ERRNO(readFile("notpresent.txt"), ENOENT)
75 * << "notpresent.txt should not exist";
77 #define EXPECT_THROW_ERRNO(statement, errnoValue) \
78 TEST_THROW_ERRNO_(statement, errnoValue, GTEST_NONFATAL_FAILURE_)
79 #define ASSERT_THROW_ERRNO(statement, errnoValue) \
80 TEST_THROW_ERRNO_(statement, errnoValue, GTEST_FATAL_FAILURE_)
82 #define TEST_THROW_RE_(statement, exceptionType, pattern, fail) \
83 GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
84 if (::folly::test::detail::CheckResult gtest_result = \
85 ::folly::test::detail::checkThrowRegex<exceptionType>( \
86 [&] { statement; }, pattern, #statement, #exceptionType)) { \
88 fail(gtest_result.what())
91 * Check that a statement throws the expected exception type, and that the
92 * exception message matches the specified regular expression.
94 * Partial matches (against just a portion of the error message) are accepted
95 * if the regular expression does not explicitly start with "^" and end with
96 * "$". (The matching is performed using std::regex_search() rather than
97 * std::regex_match().)
99 * This uses ECMA-262 style regular expressions (the default behavior of
102 * Like other EXPECT_* and ASSERT_* macros, additional message information
103 * can be included using the << stream operator.
107 * EXPECT_THROW_RE(badFunction(), std::runtime_error, "oh noes")
108 * << "function did not throw the expected exception";
110 #define EXPECT_THROW_RE(statement, exceptionType, pattern) \
111 TEST_THROW_RE_(statement, exceptionType, pattern, GTEST_NONFATAL_FAILURE_)
112 #define ASSERT_THROW_RE(statement, exceptionType, pattern) \
113 TEST_THROW_RE_(statement, exceptionType, pattern, GTEST_FATAL_FAILURE_)
118 template <typename T1, typename T2>
119 ::testing::AssertionResult
120 AreWithinSecs(T1 val1, T2 val2, std::chrono::seconds acceptableDeltaSecs) {
122 std::chrono::duration_cast<std::chrono::seconds>(val1 - val2);
123 if (deltaSecs <= acceptableDeltaSecs &&
124 deltaSecs >= -1 * acceptableDeltaSecs) {
125 return ::testing::AssertionSuccess();
127 return ::testing::AssertionFailure()
128 << val1.count() << " and " << val2.count() << " are not within "
129 << acceptableDeltaSecs.count() << " secs of each other";
136 * Helper class for implementing test macros
140 explicit CheckResult(bool s) noexcept : success_(s) {}
142 explicit operator bool() const noexcept {
145 const char* what() const noexcept {
146 return message_.c_str();
150 * Support the << operator for building up the error message.
152 * The arguments are treated as with folly::to<string>(), and we do not
153 * support iomanip parameters. The main reason we use the << operator
154 * as opposed to a variadic function like folly::to is that clang-format
155 * formats long statements using << much nicer than function call arguments.
157 template <typename T>
158 CheckResult& operator<<(T&& t) {
159 toAppend(std::forward<T>(t), &message_);
165 std::string message_;
169 * Helper function for implementing EXPECT_THROW
171 template <typename Fn>
172 CheckResult checkThrowErrno(Fn&& fn, int errnoValue, const char* statementStr) {
175 } catch (const std::system_error& ex) {
176 // TODO: POSIX errno values should really use std::generic_category(),
177 // but folly/Exception.h throws them with std::system_category() at the
179 if (ex.code().category() != std::system_category()) {
180 return CheckResult(false)
181 << "Expected: " << statementStr << " throws an exception with errno "
182 << errnoValue << " (" << std::generic_category().message(errnoValue)
183 << ")\nActual: it throws a system_error with category "
184 << ex.code().category().name() << ": " << ex.what();
186 if (ex.code().value() != errnoValue) {
187 return CheckResult(false)
188 << "Expected: " << statementStr << " throws an exception with errno "
189 << errnoValue << " (" << std::generic_category().message(errnoValue)
190 << ")\nActual: it throws errno " << ex.code().value() << ": "
193 return CheckResult(true);
194 } catch (const std::exception& ex) {
195 return CheckResult(false)
196 << "Expected: " << statementStr << " throws an exception with errno "
197 << errnoValue << " (" << std::generic_category().message(errnoValue)
198 << ")\nActual: it throws a different exception: " << exceptionStr(ex);
200 return CheckResult(false)
201 << "Expected: " << statementStr << " throws an exception with errno "
202 << errnoValue << " (" << std::generic_category().message(errnoValue)
203 << ")\nActual: it throws a non-exception type";
205 return CheckResult(false)
206 << "Expected: " << statementStr << " throws an exception with errno "
207 << errnoValue << " (" << std::generic_category().message(errnoValue)
208 << ")\nActual: it throws nothing";
212 * Helper function for implementing EXPECT_THROW_RE
214 template <typename ExType, typename Fn>
215 CheckResult checkThrowRegex(
218 const char* statementStr,
219 const char* excTypeStr) {
221 std::is_base_of<std::exception, ExType>::value,
222 "EXPECT_THROW_RE() exception type must derive from std::exception");
226 } catch (const std::exception& ex) {
227 const auto* derived = dynamic_cast<const ExType*>(&ex);
229 return CheckResult(false)
230 << "Expected: " << statementStr << "throws a " << excTypeStr
231 << ")\nActual: it throws a different exception type: "
235 std::regex re(pattern);
236 if (!std::regex_search(derived->what(), re)) {
237 return CheckResult(false)
238 << "Expected: " << statementStr << " throws a " << excTypeStr
239 << " with message matching \"" << pattern
240 << "\"\nActual: message is: " << derived->what();
242 return CheckResult(true);
244 return CheckResult(false)
245 << "Expected: " << statementStr << " throws a " << excTypeStr
246 << ")\nActual: it throws a non-exception type";
248 return CheckResult(false) << "Expected: " << statementStr << " throws a "
249 << excTypeStr << ")\nActual: it throws nothing";
252 } // namespace detail
255 // Define a PrintTo() function for StringPiece, so that gtest checks
256 // will print it as a string. Without this gtest identifies StringPiece as a
257 // container type, and therefore tries printing its elements individually,
258 // despite the fact that there is an ostream operator<<() defined for
260 inline void PrintTo(StringPiece sp, ::std::ostream* os) {
261 // gtest's PrintToString() function will quote the string and escape internal
262 // quotes and non-printable characters, the same way gtest does for the
263 // standard string types.
264 *os << ::testing::PrintToString(sp.str());