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.
20 * This file contains additional gtest-style check macros to use in unit tests.
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 #define TEST_THROW_ERRNO_(statement, errnoValue, fail) \
50 GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
51 if (::folly::test::detail::CheckResult gtest_result = \
52 ::folly::test::detail::checkThrowErrno( \
53 [&] { statement; }, errnoValue, #statement)) { \
55 fail(gtest_result.what())
58 * Check that a statement throws a std::system_error with the expected errno
59 * value. This is useful for checking code that uses the functions in
60 * folly/Exception.h to throw exceptions.
62 * Like other EXPECT_* and ASSERT_* macros, additional message information
63 * can be included using the << stream operator.
67 * EXPECT_THROW_ERRNO(readFile("notpresent.txt"), ENOENT)
68 * << "notpresent.txt should not exist";
70 #define EXPECT_THROW_ERRNO(statement, errnoValue) \
71 TEST_THROW_ERRNO_(statement, errnoValue, GTEST_NONFATAL_FAILURE_)
72 #define ASSERT_THROW_ERRNO(statement, errnoValue) \
73 TEST_THROW_ERRNO_(statement, errnoValue, GTEST_FATAL_FAILURE_)
75 #define TEST_THROW_RE_(statement, exceptionType, pattern, fail) \
76 GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
77 if (::folly::test::detail::CheckResult gtest_result = \
78 ::folly::test::detail::checkThrowRegex<exceptionType>( \
79 [&] { statement; }, pattern, #statement, #exceptionType)) { \
81 fail(gtest_result.what())
84 * Check that a statement throws the expected exception type, and that the
85 * exception message matches the specified regular expression.
87 * Partial matches (against just a portion of the error message) are accepted
88 * if the regular expression does not explicitly start with "^" and end with
89 * "$". (The matching is performed using std::regex_search() rather than
90 * std::regex_match().)
92 * This uses ECMA-262 style regular expressions (the default behavior of
95 * Like other EXPECT_* and ASSERT_* macros, additional message information
96 * can be included using the << stream operator.
100 * EXPECT_THROW_RE(badFunction(), std::runtime_error, "oh noes")
101 * << "function did not throw the expected exception";
103 #define EXPECT_THROW_RE(statement, exceptionType, pattern) \
104 TEST_THROW_RE_(statement, exceptionType, pattern, GTEST_NONFATAL_FAILURE_)
105 #define ASSERT_THROW_RE(statement, exceptionType, pattern) \
106 TEST_THROW_RE_(statement, exceptionType, pattern, GTEST_FATAL_FAILURE_)
111 template <typename T1, typename T2>
112 ::testing::AssertionResult
113 AreWithinSecs(T1 val1, T2 val2, std::chrono::seconds acceptableDeltaSecs) {
115 std::chrono::duration_cast<std::chrono::seconds>(val1 - val2);
116 if (deltaSecs <= acceptableDeltaSecs &&
117 deltaSecs >= -1 * acceptableDeltaSecs) {
118 return ::testing::AssertionSuccess();
120 return ::testing::AssertionFailure()
121 << val1.count() << " and " << val2.count() << " are not within "
122 << acceptableDeltaSecs.count() << " secs of each other";
129 * Helper class for implementing test macros
133 explicit CheckResult(bool s) noexcept : success_(s) {}
135 explicit operator bool() const noexcept {
138 const char* what() const noexcept {
139 return message_.c_str();
143 * Support the << operator for building up the error message.
145 * The arguments are treated as with folly::to<string>(), and we do not
146 * support iomanip parameters. The main reason we use the << operator
147 * as opposed to a variadic function like folly::to is that clang-format
148 * formats long statements using << much nicer than function call arguments.
150 template <typename T>
151 CheckResult& operator<<(T&& t) {
152 toAppend(std::forward<T>(t), &message_);
158 std::string message_;
162 * Helper function for implementing EXPECT_THROW
164 template <typename Fn>
165 CheckResult checkThrowErrno(Fn&& fn, int errnoValue, const char* statementStr) {
168 } catch (const std::system_error& ex) {
169 // TODO: POSIX errno values should really use std::generic_category(),
170 // but folly/Exception.h throws them with std::system_category() at the
172 if (ex.code().category() != std::system_category()) {
173 return CheckResult(false)
174 << "Expected: " << statementStr << " throws an exception with errno "
175 << errnoValue << " (" << std::generic_category().message(errnoValue)
176 << ")\nActual: it throws a system_error with category "
177 << ex.code().category().name() << ": " << ex.what();
179 if (ex.code().value() != errnoValue) {
180 return CheckResult(false)
181 << "Expected: " << statementStr << " throws an exception with errno "
182 << errnoValue << " (" << std::generic_category().message(errnoValue)
183 << ")\nActual: it throws errno " << ex.code().value() << ": "
186 return CheckResult(true);
187 } catch (const std::exception& ex) {
188 return CheckResult(false)
189 << "Expected: " << statementStr << " throws an exception with errno "
190 << errnoValue << " (" << std::generic_category().message(errnoValue)
191 << ")\nActual: it throws a different exception: " << exceptionStr(ex);
193 return CheckResult(false)
194 << "Expected: " << statementStr << " throws an exception with errno "
195 << errnoValue << " (" << std::generic_category().message(errnoValue)
196 << ")\nActual: it throws a non-exception type";
198 return CheckResult(false)
199 << "Expected: " << statementStr << " throws an exception with errno "
200 << errnoValue << " (" << std::generic_category().message(errnoValue)
201 << ")\nActual: it throws nothing";
205 * Helper function for implementing EXPECT_THROW_RE
207 template <typename ExType, typename Fn>
208 CheckResult checkThrowRegex(
211 const char* statementStr,
212 const char* excTypeStr) {
214 std::is_base_of<std::exception, ExType>::value,
215 "EXPECT_THROW_RE() exception type must derive from std::exception");
219 } catch (const std::exception& ex) {
220 const auto* derived = dynamic_cast<const ExType*>(&ex);
222 return CheckResult(false)
223 << "Expected: " << statementStr << "throws a " << excTypeStr
224 << ")\nActual: it throws a different exception type: "
228 std::regex re(pattern);
229 if (!std::regex_search(derived->what(), re)) {
230 return CheckResult(false)
231 << "Expected: " << statementStr << " throws a " << excTypeStr
232 << " with message matching \"" << pattern
233 << "\"\nActual: message is: " << derived->what();
235 return CheckResult(true);
237 return CheckResult(false)
238 << "Expected: " << statementStr << " throws a " << excTypeStr
239 << ")\nActual: it throws a non-exception type";
241 return CheckResult(false) << "Expected: " << statementStr << " throws a "
242 << excTypeStr << ")\nActual: it throws nothing";
245 } // namespace detail
248 // Define a PrintTo() function for StringPiece, so that gtest checks
249 // will print it as a string. Without this gtest identifies StringPiece as a
250 // container type, and therefore tries printing its elements individually,
251 // despite the fact that there is an ostream operator<<() defined for
253 inline void PrintTo(StringPiece sp, ::std::ostream* os) {
254 // gtest's PrintToString() function will quote the string and escape internal
255 // quotes and non-printable characters, the same way gtest does for the
256 // standard string types.
257 *os << ::testing::PrintToString(sp.str());