6eb7a0b9d048324aa02012ee76ab81e5495cf581
[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()
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 #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)) { \
54   } else                                                     \
55     fail(gtest_result.what())
56
57 /**
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.
61  *
62  * Like other EXPECT_* and ASSERT_* macros, additional message information
63  * can be included using the << stream operator.
64  *
65  * Example usage:
66  *
67  *   EXPECT_THROW_ERRNO(readFile("notpresent.txt"), ENOENT)
68  *     << "notpresent.txt should not exist";
69  */
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_)
74
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)) { \
80   } else                                                                  \
81     fail(gtest_result.what())
82
83 /**
84  * Check that a statement throws the expected exception type, and that the
85  * exception message matches the specified regular expression.
86  *
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().)
91  *
92  * This uses ECMA-262 style regular expressions (the default behavior of
93  * std::regex).
94  *
95  * Like other EXPECT_* and ASSERT_* macros, additional message information
96  * can be included using the << stream operator.
97  *
98  * Example usage:
99  *
100  *   EXPECT_THROW_RE(badFunction(), std::runtime_error, "oh noes")
101  *     << "function did not throw the expected exception";
102  */
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_)
107
108 namespace folly {
109 namespace test {
110
111 template <typename T1, typename T2>
112 ::testing::AssertionResult
113 AreWithinSecs(T1 val1, T2 val2, std::chrono::seconds acceptableDeltaSecs) {
114   auto deltaSecs =
115       std::chrono::duration_cast<std::chrono::seconds>(val1 - val2);
116   if (deltaSecs <= acceptableDeltaSecs &&
117       deltaSecs >= -1 * acceptableDeltaSecs) {
118     return ::testing::AssertionSuccess();
119   } else {
120     return ::testing::AssertionFailure()
121         << val1.count() << " and " << val2.count() << " are not within "
122         << acceptableDeltaSecs.count() << " secs of each other";
123   }
124 }
125
126 namespace detail {
127
128 /**
129  * Helper class for implementing test macros
130  */
131 class CheckResult {
132  public:
133   explicit CheckResult(bool s) noexcept : success_(s) {}
134
135   explicit operator bool() const noexcept {
136     return success_;
137   }
138   const char* what() const noexcept {
139     return message_.c_str();
140   }
141
142   /**
143    * Support the << operator for building up the error message.
144    *
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.
149    */
150   template <typename T>
151   CheckResult& operator<<(T&& t) {
152     toAppend(std::forward<T>(t), &message_);
153     return *this;
154   }
155
156  private:
157   bool success_;
158   std::string message_;
159 };
160
161 /**
162  * Helper function for implementing EXPECT_THROW
163  */
164 template <typename Fn>
165 CheckResult checkThrowErrno(Fn&& fn, int errnoValue, const char* statementStr) {
166   try {
167     fn();
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
171     // moment.
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();
178     }
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() << ": "
184           << ex.what();
185     }
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);
192   } catch (...) {
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";
197   }
198   return CheckResult(false)
199       << "Expected: " << statementStr << " throws an exception with errno "
200       << errnoValue << " (" << std::generic_category().message(errnoValue)
201       << ")\nActual: it throws nothing";
202 }
203
204 /**
205  * Helper function for implementing EXPECT_THROW_RE
206  */
207 template <typename ExType, typename Fn>
208 CheckResult checkThrowRegex(
209     Fn&& fn,
210     const char* pattern,
211     const char* statementStr,
212     const char* excTypeStr) {
213   static_assert(
214       std::is_base_of<std::exception, ExType>::value,
215       "EXPECT_THROW_RE() exception type must derive from std::exception");
216
217   try {
218     fn();
219   } catch (const std::exception& ex) {
220     const auto* derived = dynamic_cast<const ExType*>(&ex);
221     if (!derived) {
222       return CheckResult(false)
223           << "Expected: " << statementStr << "throws a " << excTypeStr
224           << ")\nActual: it throws a different exception type: "
225           << exceptionStr(ex);
226     }
227
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();
234     }
235     return CheckResult(true);
236   } catch (...) {
237     return CheckResult(false)
238         << "Expected: " << statementStr << " throws a " << excTypeStr
239         << ")\nActual: it throws a non-exception type";
240   }
241   return CheckResult(false) << "Expected: " << statementStr << " throws a "
242                             << excTypeStr << ")\nActual: it throws nothing";
243 }
244
245 } // namespace detail
246 } // namespace test
247
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
252 // StringPiece.
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());
258 }
259
260 } // namespace folly