cannam@133
|
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
cannam@133
|
2 // Licensed under the MIT License:
|
cannam@133
|
3 //
|
cannam@133
|
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
cannam@133
|
5 // of this software and associated documentation files (the "Software"), to deal
|
cannam@133
|
6 // in the Software without restriction, including without limitation the rights
|
cannam@133
|
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
cannam@133
|
8 // copies of the Software, and to permit persons to whom the Software is
|
cannam@133
|
9 // furnished to do so, subject to the following conditions:
|
cannam@133
|
10 //
|
cannam@133
|
11 // The above copyright notice and this permission notice shall be included in
|
cannam@133
|
12 // all copies or substantial portions of the Software.
|
cannam@133
|
13 //
|
cannam@133
|
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
cannam@133
|
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
cannam@133
|
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
cannam@133
|
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
cannam@133
|
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
cannam@133
|
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
cannam@133
|
20 // THE SOFTWARE.
|
cannam@133
|
21
|
cannam@133
|
22 #include "debug.h"
|
cannam@133
|
23 #include "exception.h"
|
cannam@133
|
24 #include <kj/compat/gtest.h>
|
cannam@133
|
25 #include <string>
|
cannam@133
|
26 #include <stdio.h>
|
cannam@133
|
27 #include <signal.h>
|
cannam@133
|
28 #include <errno.h>
|
cannam@133
|
29 #include <string.h>
|
cannam@133
|
30 #include <exception>
|
cannam@133
|
31
|
cannam@133
|
32 #include "miniposix.h"
|
cannam@133
|
33
|
cannam@133
|
34 #if !_WIN32
|
cannam@133
|
35 #include <sys/wait.h>
|
cannam@133
|
36 #endif
|
cannam@133
|
37
|
cannam@133
|
38 #if _MSC_VER
|
cannam@133
|
39 #pragma warning(disable: 4996)
|
cannam@133
|
40 // Warns that sprintf() is buffer-overrunny. Yeah, I know, it's cool.
|
cannam@133
|
41 #endif
|
cannam@133
|
42
|
cannam@133
|
43 namespace kj {
|
cannam@133
|
44 namespace _ { // private
|
cannam@133
|
45 namespace {
|
cannam@133
|
46
|
cannam@133
|
47 class MockException {};
|
cannam@133
|
48
|
cannam@133
|
49 class MockExceptionCallback: public ExceptionCallback {
|
cannam@133
|
50 public:
|
cannam@133
|
51 ~MockExceptionCallback() {}
|
cannam@133
|
52
|
cannam@133
|
53 std::string text;
|
cannam@133
|
54
|
cannam@133
|
55 int outputPipe = -1;
|
cannam@133
|
56
|
cannam@133
|
57 bool forkForDeathTest() {
|
cannam@133
|
58 // This is called when exceptions are disabled. We fork the process instead and then expect
|
cannam@133
|
59 // the child to die.
|
cannam@133
|
60
|
cannam@133
|
61 #if _WIN32
|
cannam@133
|
62 // Windows doesn't support fork() or anything like it. Just skip the test.
|
cannam@133
|
63 return false;
|
cannam@133
|
64
|
cannam@133
|
65 #else
|
cannam@133
|
66 int pipeFds[2];
|
cannam@133
|
67 KJ_SYSCALL(pipe(pipeFds));
|
cannam@133
|
68 pid_t child = fork();
|
cannam@133
|
69 if (child == 0) {
|
cannam@133
|
70 // This is the child!
|
cannam@133
|
71 close(pipeFds[0]);
|
cannam@133
|
72 outputPipe = pipeFds[1];
|
cannam@133
|
73 return true;
|
cannam@133
|
74 } else {
|
cannam@133
|
75 close(pipeFds[1]);
|
cannam@133
|
76
|
cannam@133
|
77 // Read child error messages into our local buffer.
|
cannam@133
|
78 char buf[1024];
|
cannam@133
|
79 for (;;) {
|
cannam@133
|
80 ssize_t n = read(pipeFds[0], buf, sizeof(buf));
|
cannam@133
|
81 if (n < 0) {
|
cannam@133
|
82 if (errno == EINTR) {
|
cannam@133
|
83 continue;
|
cannam@133
|
84 } else {
|
cannam@133
|
85 break;
|
cannam@133
|
86 }
|
cannam@133
|
87 } else if (n == 0) {
|
cannam@133
|
88 break;
|
cannam@133
|
89 } else {
|
cannam@133
|
90 text.append(buf, n);
|
cannam@133
|
91 }
|
cannam@133
|
92 }
|
cannam@133
|
93
|
cannam@133
|
94 close(pipeFds[0]);
|
cannam@133
|
95
|
cannam@133
|
96 // Get exit status.
|
cannam@133
|
97 int status;
|
cannam@133
|
98 KJ_SYSCALL(waitpid(child, &status, 0));
|
cannam@133
|
99
|
cannam@133
|
100 EXPECT_TRUE(WIFEXITED(status));
|
cannam@133
|
101 EXPECT_EQ(74, WEXITSTATUS(status));
|
cannam@133
|
102
|
cannam@133
|
103 return false;
|
cannam@133
|
104 }
|
cannam@133
|
105 #endif // _WIN32, else
|
cannam@133
|
106 }
|
cannam@133
|
107
|
cannam@133
|
108 void flush() {
|
cannam@133
|
109 if (outputPipe != -1) {
|
cannam@133
|
110 const char* pos = &*text.begin();
|
cannam@133
|
111 const char* end = pos + text.size();
|
cannam@133
|
112
|
cannam@133
|
113 while (pos < end) {
|
cannam@133
|
114 miniposix::ssize_t n = miniposix::write(outputPipe, pos, end - pos);
|
cannam@133
|
115 if (n < 0) {
|
cannam@133
|
116 if (errno == EINTR) {
|
cannam@133
|
117 continue;
|
cannam@133
|
118 } else {
|
cannam@133
|
119 break; // Give up on error.
|
cannam@133
|
120 }
|
cannam@133
|
121 }
|
cannam@133
|
122 pos += n;
|
cannam@133
|
123 }
|
cannam@133
|
124
|
cannam@133
|
125 text.clear();
|
cannam@133
|
126 }
|
cannam@133
|
127 }
|
cannam@133
|
128
|
cannam@133
|
129 void onRecoverableException(Exception&& exception) override {
|
cannam@133
|
130 text += "recoverable exception: ";
|
cannam@133
|
131 auto what = str(exception);
|
cannam@133
|
132 // Discard the stack trace.
|
cannam@133
|
133 const char* end = strstr(what.cStr(), "\nstack: ");
|
cannam@133
|
134 if (end == nullptr) {
|
cannam@133
|
135 text += what.cStr();
|
cannam@133
|
136 } else {
|
cannam@133
|
137 text.append(what.cStr(), end);
|
cannam@133
|
138 }
|
cannam@133
|
139 text += '\n';
|
cannam@133
|
140 flush();
|
cannam@133
|
141 }
|
cannam@133
|
142
|
cannam@133
|
143 void onFatalException(Exception&& exception) override {
|
cannam@133
|
144 text += "fatal exception: ";
|
cannam@133
|
145 auto what = str(exception);
|
cannam@133
|
146 // Discard the stack trace.
|
cannam@133
|
147 const char* end = strstr(what.cStr(), "\nstack: ");
|
cannam@133
|
148 if (end == nullptr) {
|
cannam@133
|
149 text += what.cStr();
|
cannam@133
|
150 } else {
|
cannam@133
|
151 text.append(what.cStr(), end);
|
cannam@133
|
152 }
|
cannam@133
|
153 text += '\n';
|
cannam@133
|
154 flush();
|
cannam@133
|
155 #if KJ_NO_EXCEPTIONS
|
cannam@133
|
156 if (outputPipe >= 0) {
|
cannam@133
|
157 // This is a child process. We got what we want, now exit quickly without writing any
|
cannam@133
|
158 // additional messages, with a status code that the parent will interpret as "exited in the
|
cannam@133
|
159 // way we expected".
|
cannam@133
|
160 _exit(74);
|
cannam@133
|
161 }
|
cannam@133
|
162 #else
|
cannam@133
|
163 throw MockException();
|
cannam@133
|
164 #endif
|
cannam@133
|
165 }
|
cannam@133
|
166
|
cannam@133
|
167 void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
|
cannam@133
|
168 String&& text) override {
|
cannam@133
|
169 this->text += "log message: ";
|
cannam@133
|
170 text = str(file, ":", line, ":+", contextDepth, ": ", severity, ": ", mv(text));
|
cannam@133
|
171 this->text.append(text.begin(), text.end());
|
cannam@133
|
172 }
|
cannam@133
|
173 };
|
cannam@133
|
174
|
cannam@133
|
175 #if KJ_NO_EXCEPTIONS
|
cannam@133
|
176 #define EXPECT_FATAL(code) if (mockCallback.forkForDeathTest()) { code; abort(); }
|
cannam@133
|
177 #else
|
cannam@133
|
178 #define EXPECT_FATAL(code) \
|
cannam@133
|
179 try { code; KJ_FAIL_EXPECT("expected exception"); } \
|
cannam@133
|
180 catch (MockException e) {} \
|
cannam@133
|
181 catch (...) { KJ_FAIL_EXPECT("wrong exception"); }
|
cannam@133
|
182 #endif
|
cannam@133
|
183
|
cannam@133
|
184 std::string fileLine(std::string file, int line) {
|
cannam@133
|
185 file = trimSourceFilename(file.c_str()).cStr();
|
cannam@133
|
186
|
cannam@133
|
187 file += ':';
|
cannam@133
|
188 char buffer[32];
|
cannam@133
|
189 sprintf(buffer, "%d", line);
|
cannam@133
|
190 file += buffer;
|
cannam@133
|
191 return file;
|
cannam@133
|
192 }
|
cannam@133
|
193
|
cannam@133
|
194 TEST(Debug, Log) {
|
cannam@133
|
195 MockExceptionCallback mockCallback;
|
cannam@133
|
196 int line;
|
cannam@133
|
197
|
cannam@133
|
198 KJ_LOG(WARNING, "Hello world!"); line = __LINE__;
|
cannam@133
|
199 EXPECT_EQ("log message: " + fileLine(__FILE__, line) + ":+0: warning: Hello world!\n",
|
cannam@133
|
200 mockCallback.text);
|
cannam@133
|
201 mockCallback.text.clear();
|
cannam@133
|
202
|
cannam@133
|
203 int i = 123;
|
cannam@133
|
204 const char* str = "foo";
|
cannam@133
|
205
|
cannam@133
|
206 KJ_LOG(ERROR, i, str); line = __LINE__;
|
cannam@133
|
207 EXPECT_EQ("log message: " + fileLine(__FILE__, line) + ":+0: error: i = 123; str = foo\n",
|
cannam@133
|
208 mockCallback.text);
|
cannam@133
|
209 mockCallback.text.clear();
|
cannam@133
|
210
|
cannam@133
|
211 KJ_DBG("Some debug text."); line = __LINE__;
|
cannam@133
|
212 EXPECT_EQ("log message: " + fileLine(__FILE__, line) + ":+0: debug: Some debug text.\n",
|
cannam@133
|
213 mockCallback.text);
|
cannam@133
|
214 mockCallback.text.clear();
|
cannam@133
|
215
|
cannam@133
|
216 // INFO logging is disabled by default.
|
cannam@133
|
217 KJ_LOG(INFO, "Info."); line = __LINE__;
|
cannam@133
|
218 EXPECT_EQ("", mockCallback.text);
|
cannam@133
|
219 mockCallback.text.clear();
|
cannam@133
|
220
|
cannam@133
|
221 // Enable it.
|
cannam@133
|
222 Debug::setLogLevel(Debug::Severity::INFO);
|
cannam@133
|
223 KJ_LOG(INFO, "Some text."); line = __LINE__;
|
cannam@133
|
224 EXPECT_EQ("log message: " + fileLine(__FILE__, line) + ":+0: info: Some text.\n",
|
cannam@133
|
225 mockCallback.text);
|
cannam@133
|
226 mockCallback.text.clear();
|
cannam@133
|
227
|
cannam@133
|
228 // Back to default.
|
cannam@133
|
229 Debug::setLogLevel(Debug::Severity::WARNING);
|
cannam@133
|
230
|
cannam@133
|
231 KJ_ASSERT(1 == 1);
|
cannam@133
|
232 EXPECT_FATAL(KJ_ASSERT(1 == 2)); line = __LINE__;
|
cannam@133
|
233 EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": failed: expected "
|
cannam@133
|
234 "1 == 2\n", mockCallback.text);
|
cannam@133
|
235 mockCallback.text.clear();
|
cannam@133
|
236
|
cannam@133
|
237 KJ_ASSERT(1 == 1) {
|
cannam@133
|
238 ADD_FAILURE() << "Shouldn't call recovery code when check passes.";
|
cannam@133
|
239 break;
|
cannam@133
|
240 };
|
cannam@133
|
241
|
cannam@133
|
242 bool recovered = false;
|
cannam@133
|
243 KJ_ASSERT(1 == 2, "1 is not 2") { recovered = true; break; } line = __LINE__;
|
cannam@133
|
244 EXPECT_EQ("recoverable exception: " + fileLine(__FILE__, line) + ": failed: expected "
|
cannam@133
|
245 "1 == 2; 1 is not 2\n", mockCallback.text);
|
cannam@133
|
246 EXPECT_TRUE(recovered);
|
cannam@133
|
247 mockCallback.text.clear();
|
cannam@133
|
248
|
cannam@133
|
249 EXPECT_FATAL(KJ_ASSERT(1 == 2, i, "hi", str)); line = __LINE__;
|
cannam@133
|
250 EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": failed: expected "
|
cannam@133
|
251 "1 == 2; i = 123; hi; str = foo\n", mockCallback.text);
|
cannam@133
|
252 mockCallback.text.clear();
|
cannam@133
|
253
|
cannam@133
|
254 EXPECT_FATAL(KJ_REQUIRE(1 == 2, i, "hi", str)); line = __LINE__;
|
cannam@133
|
255 EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": failed: expected "
|
cannam@133
|
256 "1 == 2; i = 123; hi; str = foo\n", mockCallback.text);
|
cannam@133
|
257 mockCallback.text.clear();
|
cannam@133
|
258
|
cannam@133
|
259 EXPECT_FATAL(KJ_FAIL_ASSERT("foo")); line = __LINE__;
|
cannam@133
|
260 EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": failed: foo\n",
|
cannam@133
|
261 mockCallback.text);
|
cannam@133
|
262 mockCallback.text.clear();
|
cannam@133
|
263 }
|
cannam@133
|
264
|
cannam@133
|
265 TEST(Debug, Exception) {
|
cannam@133
|
266 int i = 123;
|
cannam@133
|
267
|
cannam@133
|
268 int line = __LINE__; Exception exception = KJ_EXCEPTION(DISCONNECTED, "foo", i);
|
cannam@133
|
269
|
cannam@133
|
270 EXPECT_EQ(Exception::Type::DISCONNECTED, exception.getType());
|
cannam@133
|
271 EXPECT_TRUE(kj::StringPtr(__FILE__).endsWith(exception.getFile()));
|
cannam@133
|
272 EXPECT_EQ(line, exception.getLine());
|
cannam@133
|
273 EXPECT_EQ("foo; i = 123", exception.getDescription());
|
cannam@133
|
274 }
|
cannam@133
|
275
|
cannam@133
|
276 TEST(Debug, Catch) {
|
cannam@133
|
277 int line;
|
cannam@133
|
278
|
cannam@133
|
279 {
|
cannam@133
|
280 // Catch recoverable as kj::Exception.
|
cannam@133
|
281 Maybe<Exception> exception = kj::runCatchingExceptions([&](){
|
cannam@133
|
282 line = __LINE__; KJ_FAIL_ASSERT("foo") { break; }
|
cannam@133
|
283 });
|
cannam@133
|
284
|
cannam@133
|
285 KJ_IF_MAYBE(e, exception) {
|
cannam@133
|
286 String what = str(*e);
|
cannam@133
|
287 KJ_IF_MAYBE(eol, what.findFirst('\n')) {
|
cannam@133
|
288 what = kj::str(what.slice(0, *eol));
|
cannam@133
|
289 }
|
cannam@133
|
290 std::string text(what.cStr());
|
cannam@133
|
291 EXPECT_EQ(fileLine(__FILE__, line) + ": failed: foo", text);
|
cannam@133
|
292 } else {
|
cannam@133
|
293 ADD_FAILURE() << "Expected exception.";
|
cannam@133
|
294 }
|
cannam@133
|
295 }
|
cannam@133
|
296
|
cannam@133
|
297 #if !KJ_NO_EXCEPTIONS
|
cannam@133
|
298 {
|
cannam@133
|
299 // Catch fatal as kj::Exception.
|
cannam@133
|
300 Maybe<Exception> exception = kj::runCatchingExceptions([&](){
|
cannam@133
|
301 line = __LINE__; KJ_FAIL_ASSERT("foo");
|
cannam@133
|
302 });
|
cannam@133
|
303
|
cannam@133
|
304 KJ_IF_MAYBE(e, exception) {
|
cannam@133
|
305 String what = str(*e);
|
cannam@133
|
306 KJ_IF_MAYBE(eol, what.findFirst('\n')) {
|
cannam@133
|
307 what = kj::str(what.slice(0, *eol));
|
cannam@133
|
308 }
|
cannam@133
|
309 std::string text(what.cStr());
|
cannam@133
|
310 EXPECT_EQ(fileLine(__FILE__, line) + ": failed: foo", text);
|
cannam@133
|
311 } else {
|
cannam@133
|
312 ADD_FAILURE() << "Expected exception.";
|
cannam@133
|
313 }
|
cannam@133
|
314 }
|
cannam@133
|
315
|
cannam@133
|
316 {
|
cannam@133
|
317 // Catch as std::exception.
|
cannam@133
|
318 try {
|
cannam@133
|
319 line = __LINE__; KJ_FAIL_ASSERT("foo");
|
cannam@133
|
320 ADD_FAILURE() << "Expected exception.";
|
cannam@133
|
321 } catch (const std::exception& e) {
|
cannam@133
|
322 kj::StringPtr what = e.what();
|
cannam@133
|
323 std::string text;
|
cannam@133
|
324 KJ_IF_MAYBE(eol, what.findFirst('\n')) {
|
cannam@133
|
325 text.assign(what.cStr(), *eol);
|
cannam@133
|
326 } else {
|
cannam@133
|
327 text.assign(what.cStr());
|
cannam@133
|
328 }
|
cannam@133
|
329 EXPECT_EQ(fileLine(__FILE__, line) + ": failed: foo", text);
|
cannam@133
|
330 }
|
cannam@133
|
331 }
|
cannam@133
|
332 #endif
|
cannam@133
|
333 }
|
cannam@133
|
334
|
cannam@133
|
335 int mockSyscall(int i, int error = 0) {
|
cannam@133
|
336 errno = error;
|
cannam@133
|
337 return i;
|
cannam@133
|
338 }
|
cannam@133
|
339
|
cannam@133
|
340 TEST(Debug, Syscall) {
|
cannam@133
|
341 MockExceptionCallback mockCallback;
|
cannam@133
|
342 int line;
|
cannam@133
|
343
|
cannam@133
|
344 int i = 123;
|
cannam@133
|
345 const char* str = "foo";
|
cannam@133
|
346
|
cannam@133
|
347 KJ_SYSCALL(mockSyscall(0));
|
cannam@133
|
348 KJ_SYSCALL(mockSyscall(1));
|
cannam@133
|
349
|
cannam@133
|
350 EXPECT_FATAL(KJ_SYSCALL(mockSyscall(-1, EBADF), i, "bar", str)); line = __LINE__;
|
cannam@133
|
351 EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) +
|
cannam@133
|
352 ": failed: mockSyscall(-1, EBADF): " + strerror(EBADF) +
|
cannam@133
|
353 "; i = 123; bar; str = foo\n", mockCallback.text);
|
cannam@133
|
354 mockCallback.text.clear();
|
cannam@133
|
355
|
cannam@133
|
356 EXPECT_FATAL(KJ_SYSCALL(mockSyscall(-1, ECONNRESET), i, "bar", str)); line = __LINE__;
|
cannam@133
|
357 EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) +
|
cannam@133
|
358 ": disconnected: mockSyscall(-1, ECONNRESET): " + strerror(ECONNRESET) +
|
cannam@133
|
359 "; i = 123; bar; str = foo\n", mockCallback.text);
|
cannam@133
|
360 mockCallback.text.clear();
|
cannam@133
|
361
|
cannam@133
|
362 EXPECT_FATAL(KJ_SYSCALL(mockSyscall(-1, ENOMEM), i, "bar", str)); line = __LINE__;
|
cannam@133
|
363 EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) +
|
cannam@133
|
364 ": overloaded: mockSyscall(-1, ENOMEM): " + strerror(ENOMEM) +
|
cannam@133
|
365 "; i = 123; bar; str = foo\n", mockCallback.text);
|
cannam@133
|
366 mockCallback.text.clear();
|
cannam@133
|
367
|
cannam@133
|
368 EXPECT_FATAL(KJ_SYSCALL(mockSyscall(-1, ENOSYS), i, "bar", str)); line = __LINE__;
|
cannam@133
|
369 EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) +
|
cannam@133
|
370 ": unimplemented: mockSyscall(-1, ENOSYS): " + strerror(ENOSYS) +
|
cannam@133
|
371 "; i = 123; bar; str = foo\n", mockCallback.text);
|
cannam@133
|
372 mockCallback.text.clear();
|
cannam@133
|
373
|
cannam@133
|
374 int result = 0;
|
cannam@133
|
375 bool recovered = false;
|
cannam@133
|
376 KJ_SYSCALL(result = mockSyscall(-2, EBADF), i, "bar", str) { recovered = true; break; } line = __LINE__;
|
cannam@133
|
377 EXPECT_EQ("recoverable exception: " + fileLine(__FILE__, line) +
|
cannam@133
|
378 ": failed: mockSyscall(-2, EBADF): " + strerror(EBADF) +
|
cannam@133
|
379 "; i = 123; bar; str = foo\n", mockCallback.text);
|
cannam@133
|
380 EXPECT_EQ(-2, result);
|
cannam@133
|
381 EXPECT_TRUE(recovered);
|
cannam@133
|
382 }
|
cannam@133
|
383
|
cannam@133
|
384 TEST(Debug, Context) {
|
cannam@133
|
385 MockExceptionCallback mockCallback;
|
cannam@133
|
386
|
cannam@133
|
387 {
|
cannam@133
|
388 KJ_CONTEXT("foo"); int cline = __LINE__;
|
cannam@133
|
389
|
cannam@133
|
390 KJ_LOG(WARNING, "blah"); int line = __LINE__;
|
cannam@133
|
391 EXPECT_EQ("log message: " + fileLine(__FILE__, cline) + ":+0: context: foo\n"
|
cannam@133
|
392 "log message: " + fileLine(__FILE__, line) + ":+1: warning: blah\n",
|
cannam@133
|
393 mockCallback.text);
|
cannam@133
|
394 mockCallback.text.clear();
|
cannam@133
|
395
|
cannam@133
|
396 EXPECT_FATAL(KJ_FAIL_ASSERT("bar")); line = __LINE__;
|
cannam@133
|
397 EXPECT_EQ("fatal exception: " + fileLine(__FILE__, cline) + ": context: foo\n"
|
cannam@133
|
398 + fileLine(__FILE__, line) + ": failed: bar\n",
|
cannam@133
|
399 mockCallback.text);
|
cannam@133
|
400 mockCallback.text.clear();
|
cannam@133
|
401
|
cannam@133
|
402 {
|
cannam@133
|
403 int i = 123;
|
cannam@133
|
404 const char* str = "qux";
|
cannam@133
|
405 KJ_CONTEXT("baz", i, "corge", str); int cline2 = __LINE__;
|
cannam@133
|
406 EXPECT_FATAL(KJ_FAIL_ASSERT("bar")); line = __LINE__;
|
cannam@133
|
407
|
cannam@133
|
408 EXPECT_EQ("fatal exception: " + fileLine(__FILE__, cline) + ": context: foo\n"
|
cannam@133
|
409 + fileLine(__FILE__, cline2) + ": context: baz; i = 123; corge; str = qux\n"
|
cannam@133
|
410 + fileLine(__FILE__, line) + ": failed: bar\n",
|
cannam@133
|
411 mockCallback.text);
|
cannam@133
|
412 mockCallback.text.clear();
|
cannam@133
|
413 }
|
cannam@133
|
414
|
cannam@133
|
415 {
|
cannam@133
|
416 KJ_CONTEXT("grault"); int cline2 = __LINE__;
|
cannam@133
|
417 EXPECT_FATAL(KJ_FAIL_ASSERT("bar")); line = __LINE__;
|
cannam@133
|
418
|
cannam@133
|
419 EXPECT_EQ("fatal exception: " + fileLine(__FILE__, cline) + ": context: foo\n"
|
cannam@133
|
420 + fileLine(__FILE__, cline2) + ": context: grault\n"
|
cannam@133
|
421 + fileLine(__FILE__, line) + ": failed: bar\n",
|
cannam@133
|
422 mockCallback.text);
|
cannam@133
|
423 mockCallback.text.clear();
|
cannam@133
|
424 }
|
cannam@133
|
425 }
|
cannam@133
|
426 }
|
cannam@133
|
427
|
cannam@133
|
428 } // namespace
|
cannam@133
|
429 } // namespace _ (private)
|
cannam@133
|
430 } // namespace kj
|