62085ff8c23d65852c438c352734dc85567e17e6
[folly.git] / folly / test / TestUtils.h
1 /*
2  * Copyright 2015-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
17 #pragma once
18
19 /*
20  * This file contains additional gtest-style check macros to use in unit tests.
21  *
22  * - SKIP(), SKIP_IF(EXPR)
23  * - EXPECT_THROW_RE(), ASSERT_THROW_RE()
24  * - EXPECT_THROW_ERRNO(), ASSERT_THROW_ERRNO()
25  * - AreWithinSecs()
26  *
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.
30  */
31
32 #include <chrono>
33 #include <regex>
34 #include <system_error>
35 #include <type_traits>
36
37 #include <folly/Conv.h>
38 #include <folly/ExceptionString.h>
39 #include <folly/Range.h>
40 #include <folly/portability/GTest.h>
41
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")
48
49 // Encapsulate conditional-skip, since it's nontrivial to get right.
50 #define SKIP_IF(expr)           \
51   GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
52   if (!(expr)) {                \
53   } else                        \
54     SKIP()
55
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)) { \
61   } else                                                     \
62     fail(gtest_result.what())
63
64 /**
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.
68  *
69  * Like other EXPECT_* and ASSERT_* macros, additional message information
70  * can be included using the << stream operator.
71  *
72  * Example usage:
73  *
74  *   EXPECT_THROW_ERRNO(readFile("notpresent.txt"), ENOENT)
75  *     << "notpresent.txt should not exist";
76  */
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_)
81
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)) { \
87   } else                                                                  \
88     fail(gtest_result.what())
89
90 /**
91  * Check that a statement throws the expected exception type, and that the
92  * exception message matches the specified regular expression.
93  *
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().)
98  *
99  * This uses ECMA-262 style regular expressions (the default behavior of
100  * std::regex).
101  *
102  * Like other EXPECT_* and ASSERT_* macros, additional message information
103  * can be included using the << stream operator.
104  *
105  * Example usage:
106  *
107  *   EXPECT_THROW_RE(badFunction(), std::runtime_error, "oh noes")
108  *     << "function did not throw the expected exception";
109  */
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_)
114
115 namespace folly {
116 namespace test {
117
118 template <typename T1, typename T2>
119 ::testing::AssertionResult
120 AreWithinSecs(T1 val1, T2 val2, std::chrono::seconds acceptableDeltaSecs) {
121   auto deltaSecs =
122       std::chrono::duration_cast<std::chrono::seconds>(val1 - val2);
123   if (deltaSecs <= acceptableDeltaSecs &&
124       deltaSecs >= -1 * acceptableDeltaSecs) {
125     return ::testing::AssertionSuccess();
126   } else {
127     return ::testing::AssertionFailure()
128         << val1.count() << " and " << val2.count() << " are not within "
129         << acceptableDeltaSecs.count() << " secs of each other";
130   }
131 }
132
133 namespace detail {
134
135 /**
136  * Helper class for implementing test macros
137  */
138 class CheckResult {
139  public:
140   explicit CheckResult(bool s) noexcept : success_(s) {}
141
142   explicit operator bool() const noexcept {
143     return success_;
144   }
145   const char* what() const noexcept {
146     return message_.c_str();
147   }
148
149   /**
150    * Support the << operator for building up the error message.
151    *
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.
156    */
157   template <typename T>
158   CheckResult& operator<<(T&& t) {
159     toAppend(std::forward<T>(t), &message_);
160     return *this;
161   }
162
163  private:
164   bool success_;
165   std::string message_;
166 };
167
168 /**
169  * Helper function for implementing EXPECT_THROW
170  */
171 template <typename Fn>
172 CheckResult checkThrowErrno(Fn&& fn, int errnoValue, const char* statementStr) {
173   try {
174     fn();
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
178     // moment.
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();
185     }
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() << ": "
191           << ex.what();
192     }
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);
199   } catch (...) {
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";
204   }
205   return CheckResult(false)
206       << "Expected: " << statementStr << " throws an exception with errno "
207       << errnoValue << " (" << std::generic_category().message(errnoValue)
208       << ")\nActual: it throws nothing";
209 }
210
211 /**
212  * Helper function for implementing EXPECT_THROW_RE
213  */
214 template <typename ExType, typename Fn>
215 CheckResult checkThrowRegex(
216     Fn&& fn,
217     const char* pattern,
218     const char* statementStr,
219     const char* excTypeStr) {
220   static_assert(
221       std::is_base_of<std::exception, ExType>::value,
222       "EXPECT_THROW_RE() exception type must derive from std::exception");
223
224   try {
225     fn();
226   } catch (const std::exception& ex) {
227     const auto* derived = dynamic_cast<const ExType*>(&ex);
228     if (!derived) {
229       return CheckResult(false)
230           << "Expected: " << statementStr << "throws a " << excTypeStr
231           << ")\nActual: it throws a different exception type: "
232           << exceptionStr(ex);
233     }
234
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();
241     }
242     return CheckResult(true);
243   } catch (...) {
244     return CheckResult(false)
245         << "Expected: " << statementStr << " throws a " << excTypeStr
246         << ")\nActual: it throws a non-exception type";
247   }
248   return CheckResult(false) << "Expected: " << statementStr << " throws a "
249                             << excTypeStr << ")\nActual: it throws nothing";
250 }
251
252 } // namespace detail
253 } // namespace test
254
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
259 // StringPiece.
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());
265 }
266
267 } // namespace folly