Mercurial > repos > rliterman > csp2
comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/include/kj/test.h @ 69:33d812a61356
planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author | jpayne |
---|---|
date | Tue, 18 Mar 2025 17:55:14 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
67:0e9998148a16 | 69:33d812a61356 |
---|---|
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 KJ_LOG(ERROR, ##__VA_ARGS__); | |
90 #define KJ_EXPECT(cond, ...) \ | |
91 if (auto _kjCondition = ::kj::_::MAGIC_ASSERT << cond); \ | |
92 else KJ_FAIL_EXPECT("failed: expected " #cond, _kjCondition, ##__VA_ARGS__) | |
93 #endif | |
94 | |
95 #if _MSC_VER && !defined(__clang__) | |
96 #define KJ_EXPECT_THROW_RECOVERABLE(type, code, ...) \ | |
97 do { \ | |
98 KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \ | |
99 KJ_INDIRECT_EXPAND(KJ_EXPECT, (e->getType() == ::kj::Exception::Type::type, \ | |
100 "code threw wrong exception type: " #code, *e, __VA_ARGS__)); \ | |
101 } else { \ | |
102 KJ_INDIRECT_EXPAND(KJ_FAIL_EXPECT, ("code did not throw: " #code, __VA_ARGS__)); \ | |
103 } \ | |
104 } while (false) | |
105 | |
106 #define KJ_EXPECT_THROW_RECOVERABLE_MESSAGE(message, code, ...) \ | |
107 do { \ | |
108 KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \ | |
109 KJ_INDIRECT_EXPAND(KJ_EXPECT, (::kj::_::hasSubstring(e->getDescription(), message), \ | |
110 "exception description didn't contain expected substring", *e, __VA_ARGS__)); \ | |
111 } else { \ | |
112 KJ_INDIRECT_EXPAND(KJ_FAIL_EXPECT, ("code did not throw: " #code, __VA_ARGS__)); \ | |
113 } \ | |
114 } while (false) | |
115 #else | |
116 #define KJ_EXPECT_THROW_RECOVERABLE(type, code, ...) \ | |
117 do { \ | |
118 KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \ | |
119 KJ_EXPECT(e->getType() == ::kj::Exception::Type::type, \ | |
120 "code threw wrong exception type: " #code, *e, ##__VA_ARGS__); \ | |
121 } else { \ | |
122 KJ_FAIL_EXPECT("code did not throw: " #code, ##__VA_ARGS__); \ | |
123 } \ | |
124 } while (false) | |
125 | |
126 #define KJ_EXPECT_THROW_RECOVERABLE_MESSAGE(message, code, ...) \ | |
127 do { \ | |
128 KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \ | |
129 KJ_EXPECT(::kj::_::hasSubstring(e->getDescription(), message), \ | |
130 "exception description didn't contain expected substring", *e, ##__VA_ARGS__); \ | |
131 } else { \ | |
132 KJ_FAIL_EXPECT("code did not throw: " #code, ##__VA_ARGS__); \ | |
133 } \ | |
134 } while (false) | |
135 #endif | |
136 | |
137 #if KJ_NO_EXCEPTIONS | |
138 #define KJ_EXPECT_THROW(type, code, ...) \ | |
139 do { \ | |
140 KJ_EXPECT(::kj::_::expectFatalThrow(::kj::Exception::Type::type, nullptr, [&]() { code; })); \ | |
141 } while (false) | |
142 #define KJ_EXPECT_THROW_MESSAGE(message, code, ...) \ | |
143 do { \ | |
144 KJ_EXPECT(::kj::_::expectFatalThrow(nullptr, kj::StringPtr(message), [&]() { code; })); \ | |
145 } while (false) | |
146 #else | |
147 #define KJ_EXPECT_THROW KJ_EXPECT_THROW_RECOVERABLE | |
148 #define KJ_EXPECT_THROW_MESSAGE KJ_EXPECT_THROW_RECOVERABLE_MESSAGE | |
149 #endif | |
150 | |
151 #define KJ_EXPECT_EXIT(statusCode, code) \ | |
152 do { \ | |
153 KJ_EXPECT(::kj::_::expectExit(statusCode, [&]() { code; })); \ | |
154 } while (false) | |
155 // Forks the code and expects it to exit with a given code. | |
156 | |
157 #define KJ_EXPECT_SIGNAL(signal, code) \ | |
158 do { \ | |
159 KJ_EXPECT(::kj::_::expectSignal(signal, [&]() { code; })); \ | |
160 } while (false) | |
161 // Forks the code and expects it to trigger a signal. | |
162 // In the child resets all signal handlers as printStackTraceOnCrash sets. | |
163 | |
164 #define KJ_EXPECT_LOG(level, substring) \ | |
165 ::kj::_::LogExpectation KJ_UNIQUE_NAME(_kjLogExpectation)(::kj::LogSeverity::level, substring) | |
166 // Expects that a log message with the given level and substring text will be printed within | |
167 // the current scope. This message will not cause the test to fail, even if it is an error. | |
168 | |
169 // ======================================================================================= | |
170 | |
171 namespace _ { // private | |
172 | |
173 bool hasSubstring(kj::StringPtr haystack, kj::StringPtr needle); | |
174 | |
175 #if KJ_NO_EXCEPTIONS | |
176 bool expectFatalThrow(Maybe<Exception::Type> type, Maybe<StringPtr> message, | |
177 Function<void()> code); | |
178 // Expects that the given code will throw a fatal exception matching the given type and/or message. | |
179 // Since exceptions are disabled, the test will fork() and run in a subprocess. On Windows, where | |
180 // fork() is not available, this always returns true. | |
181 #endif | |
182 | |
183 bool expectExit(Maybe<int> statusCode, FunctionParam<void()> code) noexcept; | |
184 // Expects that the given code will exit with a given statusCode. | |
185 // The test will fork() and run in a subprocess. On Windows, where fork() is not available, | |
186 // this always returns true. | |
187 | |
188 bool expectSignal(Maybe<int> signal, FunctionParam<void()> code) noexcept; | |
189 // Expects that the given code will trigger a signal. | |
190 // The test will fork() and run in a subprocess. On Windows, where fork() is not available, | |
191 // this always returns true. | |
192 // Resets signal handlers to default prior to running the code in the child process. | |
193 | |
194 class LogExpectation: public ExceptionCallback { | |
195 public: | |
196 LogExpectation(LogSeverity severity, StringPtr substring); | |
197 ~LogExpectation(); | |
198 | |
199 void logMessage(LogSeverity severity, const char* file, int line, int contextDepth, | |
200 String&& text) override; | |
201 | |
202 private: | |
203 LogSeverity severity; | |
204 StringPtr substring; | |
205 bool seen; | |
206 UnwindDetector unwindDetector; | |
207 }; | |
208 | |
209 class GlobFilter { | |
210 // Implements glob filters for the --filter flag. | |
211 // | |
212 // Exposed in header only for testing. | |
213 | |
214 public: | |
215 explicit GlobFilter(const char* pattern); | |
216 explicit GlobFilter(ArrayPtr<const char> pattern); | |
217 | |
218 bool matches(StringPtr name); | |
219 | |
220 private: | |
221 String pattern; | |
222 Vector<uint> states; | |
223 | |
224 void applyState(char c, int state); | |
225 }; | |
226 | |
227 } // namespace _ (private) | |
228 } // namespace kj | |
229 | |
230 KJ_END_HEADER |