annotate src/capnproto-git-20161025/c++/src/kj/debug-test.c++ @ 169:223a55898ab9 tip default

Add null config files
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 02 Mar 2020 14:03:47 +0000
parents 1ac99bfc383d
children
rev   line source
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