/src/capnproto/c++/src/kj/test.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors |
2 | | // Licensed under the MIT License: |
3 | | // |
4 | | // Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | | // of this software and associated documentation files (the "Software"), to deal |
6 | | // in the Software without restriction, including without limitation the rights |
7 | | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
8 | | // copies of the Software, and to permit persons to whom the Software is |
9 | | // furnished to do so, subject to the following conditions: |
10 | | // |
11 | | // The above copyright notice and this permission notice shall be included in |
12 | | // all copies or substantial portions of the Software. |
13 | | // |
14 | | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
19 | | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
20 | | // THE SOFTWARE. |
21 | | |
22 | | #pragma once |
23 | | |
24 | | #include "debug.h" |
25 | | #include "vector.h" |
26 | | #include "function.h" |
27 | | #include "windows-sanity.h" // work-around macro conflict with `ERROR` |
28 | | |
29 | | KJ_BEGIN_HEADER |
30 | | |
31 | | namespace kj { |
32 | | |
33 | | class TestRunner; |
34 | | |
35 | | class TestCase { |
36 | | public: |
37 | | TestCase(const char* file, uint line, const char* description); |
38 | | ~TestCase(); |
39 | | |
40 | | virtual void run() = 0; |
41 | | |
42 | | protected: |
43 | | template <typename Func> |
44 | | void doBenchmark(Func&& func) { |
45 | | // Perform a benchmark with configurable iterations. func() will be called N times, where N |
46 | | // is set by the --benchmark CLI flag. This defaults to 1, so that when --benchmark is not |
47 | | // specified, we only test that the benchmark works. |
48 | | // |
49 | | // In the future, this could adaptively choose iteration count by running a few iterations to |
50 | | // find out how fast the benchmark is, then scaling. |
51 | | |
52 | | for (size_t i = iterCount(); i-- > 0;) { |
53 | | func(); |
54 | | } |
55 | | } |
56 | | |
57 | | private: |
58 | | const char* file; |
59 | | uint line; |
60 | | const char* description; |
61 | | TestCase* next; |
62 | | TestCase** prev; |
63 | | bool matchedFilter; |
64 | | |
65 | | static size_t iterCount(); |
66 | | |
67 | | friend class TestRunner; |
68 | | }; |
69 | | |
70 | | #define KJ_TEST(description) \ |
71 | | /* Make sure the linker fails if tests are not in anonymous namespaces. */ \ |
72 | | extern int KJ_CONCAT(YouMustWrapTestsInAnonymousNamespace, __COUNTER__) KJ_UNUSED; \ |
73 | | class KJ_UNIQUE_NAME(TestCase): public ::kj::TestCase { \ |
74 | | public: \ |
75 | | KJ_UNIQUE_NAME(TestCase)(): ::kj::TestCase(__FILE__, __LINE__, description) {} \ |
76 | | void run() override; \ |
77 | | } KJ_UNIQUE_NAME(testCase); \ |
78 | | void KJ_UNIQUE_NAME(TestCase)::run() |
79 | | |
80 | | #if KJ_MSVC_TRADITIONAL_CPP |
81 | | #define KJ_INDIRECT_EXPAND(m, vargs) m vargs |
82 | | #define KJ_FAIL_EXPECT(...) \ |
83 | | KJ_INDIRECT_EXPAND(KJ_LOG, (ERROR , __VA_ARGS__)); |
84 | | #define KJ_EXPECT(cond, ...) \ |
85 | | if (auto _kjCondition = ::kj::_::MAGIC_ASSERT << cond); \ |
86 | | else KJ_INDIRECT_EXPAND(KJ_FAIL_EXPECT, ("failed: expected " #cond , _kjCondition, __VA_ARGS__)) |
87 | | #else |
88 | | #define KJ_FAIL_EXPECT(...) \ |
89 | 193k | KJ_LOG(ERROR, ##__VA_ARGS__); |
90 | | #define KJ_EXPECT(cond, ...) \ |
91 | 205k | if (auto _kjCondition = ::kj::_::MAGIC_ASSERT << cond); \ |
92 | 205k | else KJ_FAIL_EXPECT("failed: expected " #cond, _kjCondition, ##__VA_ARGS__) |
93 | | #endif |
94 | | |
95 | | // TODO(msvc): cast results to void like non-MSVC versions do |
96 | | #if _MSC_VER && !defined(__clang__) |
97 | | #define KJ_EXPECT_THROW_RECOVERABLE(type, code, ...) \ |
98 | | do { \ |
99 | | KJ_IF_SOME(e, ::kj::runCatchingExceptions([&]() { code; })) { \ |
100 | | KJ_INDIRECT_EXPAND(KJ_EXPECT, (e.getType() == ::kj::Exception::Type::type, \ |
101 | | "code threw wrong exception type: " #code, e, __VA_ARGS__)); \ |
102 | | } else { \ |
103 | | KJ_INDIRECT_EXPAND(KJ_FAIL_EXPECT, ("code did not throw: " #code, __VA_ARGS__)); \ |
104 | | } \ |
105 | | } while (false) |
106 | | |
107 | | #define KJ_EXPECT_THROW_RECOVERABLE_MESSAGE(message, code, ...) \ |
108 | | do { \ |
109 | | KJ_IF_SOME(e, ::kj::runCatchingExceptions([&]() { code; })) { \ |
110 | | KJ_INDIRECT_EXPAND(KJ_EXPECT, (e.getDescription().contains(message), \ |
111 | | "exception description didn't contain expected substring", e, __VA_ARGS__)); \ |
112 | | } else { \ |
113 | | KJ_INDIRECT_EXPAND(KJ_FAIL_EXPECT, ("code did not throw: " #code, __VA_ARGS__)); \ |
114 | | } \ |
115 | | } while (false) |
116 | | #else |
117 | | #define KJ_EXPECT_THROW_RECOVERABLE(type, code, ...) \ |
118 | | do { \ |
119 | | KJ_IF_SOME(e, ::kj::runCatchingExceptions([&]() { (void)({code;}); })) { \ |
120 | | KJ_EXPECT(e.getType() == ::kj::Exception::Type::type, \ |
121 | | "code threw wrong exception type: " #code, e, ##__VA_ARGS__); \ |
122 | | } else { \ |
123 | | KJ_FAIL_EXPECT("code did not throw: " #code, ##__VA_ARGS__); \ |
124 | | } \ |
125 | | } while (false) |
126 | | |
127 | | #define KJ_EXPECT_THROW_RECOVERABLE_MESSAGE(message, code, ...) \ |
128 | | do { \ |
129 | | KJ_IF_SOME(e, ::kj::runCatchingExceptions([&]() { (void)({code;}); })) { \ |
130 | | KJ_EXPECT(e.getDescription().contains(message), \ |
131 | | "exception description didn't contain expected substring", e, ##__VA_ARGS__); \ |
132 | | } else { \ |
133 | | KJ_FAIL_EXPECT("code did not throw: " #code, ##__VA_ARGS__); \ |
134 | | } \ |
135 | | } while (false) |
136 | | #endif |
137 | | |
138 | | #define KJ_EXPECT_THROW KJ_EXPECT_THROW_RECOVERABLE |
139 | | #define KJ_EXPECT_THROW_MESSAGE KJ_EXPECT_THROW_RECOVERABLE_MESSAGE |
140 | | |
141 | | #define KJ_EXPECT_EXIT(statusCode, code) \ |
142 | | do { \ |
143 | | KJ_EXPECT(::kj::_::expectExit(statusCode, [&]() { code; })); \ |
144 | | } while (false) |
145 | | // Forks the code and expects it to exit with a given code. |
146 | | |
147 | | #define KJ_EXPECT_SIGNAL(signal, code) \ |
148 | | do { \ |
149 | | KJ_EXPECT(::kj::_::expectSignal(signal, [&]() { code; })); \ |
150 | | } while (false) |
151 | | // Forks the code and expects it to trigger a signal. |
152 | | // In the child resets all signal handlers as printStackTraceOnCrash sets. |
153 | | |
154 | | #define KJ_EXPECT_LOG(level, substring) \ |
155 | | ::kj::_::LogExpectation KJ_UNIQUE_NAME(_kjLogExpectation)(::kj::LogSeverity::level, substring) |
156 | | // Expects that a log message with the given level and substring text will be printed within |
157 | | // the current scope. This message will not cause the test to fail, even if it is an error. |
158 | | |
159 | | // ======================================================================================= |
160 | | |
161 | | namespace _ { // private |
162 | | |
163 | | bool expectExit(Maybe<int> statusCode, FunctionParam<void()> code) noexcept; |
164 | | // Expects that the given code will exit with a given statusCode. |
165 | | // The test will fork() and run in a subprocess. On Windows, where fork() is not available, |
166 | | // this always returns true. |
167 | | |
168 | | bool expectSignal(Maybe<int> signal, FunctionParam<void()> code) noexcept; |
169 | | // Expects that the given code will trigger a signal. |
170 | | // The test will fork() and run in a subprocess. On Windows, where fork() is not available, |
171 | | // this always returns true. |
172 | | // Resets signal handlers to default prior to running the code in the child process. |
173 | | |
174 | | class LogExpectation: public ExceptionCallback { |
175 | | public: |
176 | | LogExpectation(LogSeverity severity, StringPtr substring); |
177 | | ~LogExpectation(); |
178 | | |
179 | | void logMessage(LogSeverity severity, const char* file, int line, int contextDepth, |
180 | | String&& text) override; |
181 | | |
182 | | private: |
183 | | LogSeverity severity; |
184 | | StringPtr substring; |
185 | | bool seen; |
186 | | UnwindDetector unwindDetector; |
187 | | }; |
188 | | |
189 | | class GlobFilter { |
190 | | // Implements glob filters for the --filter flag. |
191 | | // |
192 | | // Exposed in header only for testing. |
193 | | |
194 | | public: |
195 | | explicit GlobFilter(const char* pattern); |
196 | | explicit GlobFilter(ArrayPtr<const char> pattern); |
197 | | |
198 | | bool matches(StringPtr name); |
199 | | |
200 | | private: |
201 | | String pattern; |
202 | | Vector<uint> states; |
203 | | |
204 | | void applyState(char c, int state); |
205 | | }; |
206 | | |
207 | | } // namespace _ (private) |
208 | | } // namespace kj |
209 | | |
210 | | KJ_END_HEADER |