Commit 1ac3accc authored by Kenton Varda's avatar Kenton Varda

Make tests pass with -fno-rtti and -fno-exceptions.

parent 77abb6e6
......@@ -316,6 +316,12 @@ TEST(DynamicApi, UnionsWrite) {
EXPECT_EQ(1234567890123456789ll, reader.getUnion3().getU3f0s64());
}
#if KJ_NO_EXCEPTIONS
#undef EXPECT_ANY_THROW
// All exceptions should be non-fatal, so when exceptions are disabled the code should return.
#define EXPECT_ANY_THROW(code) code
#endif
TEST(DynamicApi, ConversionFailures) {
MallocMessageBuilder builder;
auto root = builder.initRoot<DynamicStruct>(Schema::from<TestAllTypes>());
......
......@@ -1444,12 +1444,16 @@ HANDLE_NUMERIC_TYPE(double, kj::implicitCast, kj::implicitCast, kj::implicitCast
#define HANDLE_TYPE(name, discrim, typeName) \
ReaderFor<typeName> DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
KJ_REQUIRE(reader.type == discrim, \
"Type mismatch when using DynamicValue::Reader::as()."); \
"Type mismatch when using DynamicValue::Reader::as().") { \
return ReaderFor<typeName>(); \
} \
return reader.name##Value; \
} \
BuilderFor<typeName> DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
KJ_REQUIRE(builder.type == discrim, \
"Type mismatch when using DynamicValue::Builder::as()."); \
"Type mismatch when using DynamicValue::Builder::as().") { \
return BuilderFor<typeName>(); \
} \
return builder.name##Value; \
}
......
......@@ -212,6 +212,14 @@ TEST(Encoding, GenericObjects) {
}
}
#if KJ_NO_EXCEPTIONS
#undef EXPECT_ANY_THROW
#define EXPECT_ANY_THROW(code) EXPECT_DEATH(code, ".")
#define EXPECT_NONFATAL_FAILURE(code) code
#else
#define EXPECT_NONFATAL_FAILURE EXPECT_ANY_THROW
#endif
#ifdef NDEBUG
#define EXPECT_DEBUG_ANY_THROW(EXP)
#else
......@@ -947,12 +955,12 @@ TEST(Encoding, UpgradeListInBuilder) {
root.setObjectField<List<Void>>({Void::VOID, Void::VOID, Void::VOID, Void::VOID});
checkList(root.getObjectField<List<Void>>(), {Void::VOID, Void::VOID, Void::VOID, Void::VOID});
EXPECT_ANY_THROW(root.getObjectField<List<bool>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint8_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint16_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint32_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint64_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<Text>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<bool>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint8_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint16_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint32_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint64_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<Text>>());
checkUpgradedList(root, {0, 0, 0, 0}, {"", "", "", ""});
// -----------------------------------------------------------------
......@@ -962,11 +970,11 @@ TEST(Encoding, UpgradeListInBuilder) {
auto orig = root.asReader().getObjectField<List<bool>>();
checkList(root.getObjectField<List<Void>>(), {Void::VOID, Void::VOID, Void::VOID, Void::VOID});
checkList(root.getObjectField<List<bool>>(), {true, false, true, true});
EXPECT_ANY_THROW(root.getObjectField<List<uint8_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint16_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint32_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint64_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<Text>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint8_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint16_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint32_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint64_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<Text>>());
checkList(orig, {true, false, true, true});
checkUpgradedList(root, {1, 0, 1, 1}, {"", "", "", ""});
......@@ -981,10 +989,10 @@ TEST(Encoding, UpgradeListInBuilder) {
checkList(root.getObjectField<List<Void>>(), {Void::VOID, Void::VOID, Void::VOID, Void::VOID});
checkList(root.getObjectField<List<bool>>(), {false, true, true, false});
checkList(root.getObjectField<List<uint8_t>>(), {0x12, 0x23, 0x33, 0x44});
EXPECT_ANY_THROW(root.getObjectField<List<uint16_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint32_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint64_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<Text>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint16_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint32_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint64_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<Text>>());
checkList(orig, {0x12, 0x23, 0x33, 0x44});
checkUpgradedList(root, {0x12, 0x23, 0x33, 0x44}, {"", "", "", ""});
......@@ -1000,9 +1008,9 @@ TEST(Encoding, UpgradeListInBuilder) {
checkList(root.getObjectField<List<bool>>(), {false, true, true, false});
checkList(root.getObjectField<List<uint8_t>>(), {0x12, 0x23, 0x33, 0x44});
checkList(root.getObjectField<List<uint16_t>>(), {0x5612, 0x7823, 0xab33, 0xcd44});
EXPECT_ANY_THROW(root.getObjectField<List<uint32_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint64_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<Text>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint32_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint64_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<Text>>());
checkList(orig, {0x5612, 0x7823, 0xab33, 0xcd44});
checkUpgradedList(root, {0x5612, 0x7823, 0xab33, 0xcd44}, {"", "", "", ""});
......@@ -1019,8 +1027,8 @@ TEST(Encoding, UpgradeListInBuilder) {
checkList(root.getObjectField<List<uint8_t>>(), {0x12, 0x23, 0x32, 0x45});
checkList(root.getObjectField<List<uint16_t>>(), {0x5612, 0x7823, 0xab32, 0xcd45});
checkList(root.getObjectField<List<uint32_t>>(), {0x17595612u, 0x29347823u, 0x5923ab32u, 0x1a39cd45u});
EXPECT_ANY_THROW(root.getObjectField<List<uint64_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<Text>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint64_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<Text>>());
checkList(orig, {0x17595612u, 0x29347823u, 0x5923ab32u, 0x1a39cd45u});
checkUpgradedList(root, {0x17595612, 0x29347823, 0x5923ab32, 0x1a39cd45}, {"", "", "", ""});
......@@ -1038,7 +1046,7 @@ TEST(Encoding, UpgradeListInBuilder) {
checkList(root.getObjectField<List<uint16_t>>(), {0xfe21, 0xaf36});
checkList(root.getObjectField<List<uint32_t>>(), {0x8735fe21u, 0x1923af36u});
checkList(root.getObjectField<List<uint64_t>>(), {0x1234abcd8735fe21ull, 0x7173bc0e1923af36ull});
EXPECT_ANY_THROW(root.getObjectField<List<Text>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<Text>>());
checkList(orig, {0x1234abcd8735fe21ull, 0x7173bc0e1923af36ull});
checkUpgradedList(root, {0x1234abcd8735fe21ull, 0x7173bc0e1923af36ull}, {"", ""});
......@@ -1051,11 +1059,11 @@ TEST(Encoding, UpgradeListInBuilder) {
root.setObjectField<List<Text>>({"foo", "bar", "baz"});
auto orig = root.asReader().getObjectField<List<Text>>();
checkList(root.getObjectField<List<Void>>(), {Void::VOID, Void::VOID, Void::VOID});
EXPECT_ANY_THROW(root.getObjectField<List<bool>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint8_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint16_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint32_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint64_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<bool>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint8_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint16_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint32_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint64_t>>());
checkList(root.getObjectField<List<Text>>(), {"foo", "bar", "baz"});
checkList(orig, {"foo", "bar", "baz"});
......@@ -1117,9 +1125,9 @@ TEST(Encoding, UpgradeListInBuilder) {
}
checkList(root.getObjectField<List<bool>>(), {true, true, false, false});
checkList(root.getObjectField<List<uint16_t>>(), {12573u, 3251u, 9238u, 5832u});
EXPECT_ANY_THROW(root.getObjectField<List<uint32_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint64_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<Text>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint32_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint64_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<Text>>());
// Upgrade from multi-byte, sub-word data.
root.setObjectField<List<uint16_t>>({12u, 34u, 56u, 78u});
......@@ -1143,8 +1151,8 @@ TEST(Encoding, UpgradeListInBuilder) {
checkList(root.getObjectField<List<uint16_t>>(), {0x1235u, 0x2879u, 0x3082u, 0x8948u});
checkList(root.getObjectField<List<uint32_t>>(),
{0x65ac1235u, 0x13f12879u, 0x33423082u, 0x12988948u});
EXPECT_ANY_THROW(root.getObjectField<List<uint64_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<Text>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint64_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<Text>>());
// Upgrade from void -> data struct
root.setObjectField<List<Void>>({Void::VOID, Void::VOID, Void::VOID, Void::VOID});
......@@ -1162,9 +1170,9 @@ TEST(Encoding, UpgradeListInBuilder) {
}
checkList(root.getObjectField<List<bool>>(), {true, true, false, false});
checkList(root.getObjectField<List<uint16_t>>(), {12573u, 3251u, 9238u, 5832u});
EXPECT_ANY_THROW(root.getObjectField<List<uint32_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint64_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<Text>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint32_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint64_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<Text>>());
// Upgrade from void -> pointer struct
root.setObjectField<List<Void>>({Void::VOID, Void::VOID, Void::VOID, Void::VOID});
......@@ -1180,18 +1188,18 @@ TEST(Encoding, UpgradeListInBuilder) {
l[2].setF("baz");
l[3].setF("qux");
}
EXPECT_ANY_THROW(root.getObjectField<List<bool>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint16_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint32_t>>());
EXPECT_ANY_THROW(root.getObjectField<List<uint64_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<bool>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint16_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint32_t>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<uint64_t>>());
checkList(root.getObjectField<List<Text>>(), {"foo", "bar", "baz", "qux"});
// Verify that we cannot "side-grade" a pointer list to a data struct list, or a data list to
// a pointer struct list.
root.setObjectField<List<Text>>({"foo", "bar", "baz", "qux"});
EXPECT_ANY_THROW(root.getObjectField<List<test::TestLists::Struct32>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<test::TestLists::Struct32>>());
root.setObjectField<List<uint32_t>>({12, 34, 56, 78});
EXPECT_ANY_THROW(root.getObjectField<List<Text>>());
EXPECT_NONFATAL_FAILURE(root.getObjectField<List<Text>>());
}
// =======================================================================================
......
......@@ -56,6 +56,14 @@ TEST(SchemaLoader, Load) {
EXPECT_EQ(0u, struct16Schema.getProto().getBody().getStructNode().getMembers().size());
}
#if KJ_NO_EXCEPTIONS
#undef EXPECT_ANY_THROW
#define EXPECT_ANY_THROW(code) EXPECT_DEATH(code, ".")
#define EXPECT_NONFATAL_FAILURE(code) code
#else
#define EXPECT_NONFATAL_FAILURE EXPECT_ANY_THROW
#endif
TEST(SchemaLoader, Use) {
SchemaLoader loader;
......@@ -196,7 +204,7 @@ TEST(SchemaLoader, Downgrade) {
TEST(SchemaLoader, Incompatible) {
SchemaLoader loader;
loader.loadCompiledTypeAndDependencies<test::TestListDefaults>();
EXPECT_ANY_THROW(
EXPECT_NONFATAL_FAILURE(
loadUnderAlternateTypeId<test::TestAllTypes>(loader, typeId<test::TestListDefaults>()));
}
......
......@@ -52,6 +52,11 @@ namespace capnp {
namespace _ { // private
namespace {
#if KJ_NO_EXCEPTIONS
#undef EXPECT_ANY_THROW
#define EXPECT_ANY_THROW(code) EXPECT_DEATH(code, ".")
#endif
TEST(Schema, Structs) {
StructSchema schema = Schema::from<TestAllTypes>();
......
......@@ -124,6 +124,7 @@ TEST(Array, ComplexConstructor) {
EXPECT_EQ(0, TestObject::count);
}
#if !KJ_NO_EXCEPTIONS
TEST(Array, ThrowingConstructor) {
TestObject::count = 0;
TestObject::throwAt = 16;
......@@ -145,6 +146,7 @@ TEST(Array, ThrowingDestructor) {
EXPECT_ANY_THROW(array = nullptr);
EXPECT_EQ(0, TestObject::count);
}
#endif // !KJ_NO_EXCEPTIONS
TEST(Array, AraryBuilder) {
TestObject::count = 0;
......@@ -260,6 +262,7 @@ TEST(Array, AraryBuilderAddAll) {
EXPECT_EQ(0, TestObject::count);
EXPECT_EQ(0, TestObject::copiedCount);
#if !KJ_NO_EXCEPTIONS
{
// Complex case, exceptions occur.
TestObject::count = 0;
......@@ -283,6 +286,7 @@ TEST(Array, AraryBuilderAddAll) {
}
EXPECT_EQ(0, TestObject::count);
EXPECT_EQ(0, TestObject::copiedCount);
#endif // !KJ_NO_EXCEPTIONS
}
TEST(Array, HeapCopy) {
......
......@@ -204,8 +204,14 @@ TEST(Common, Downcast) {
EXPECT_EQ(&bar, &downcast<Bar>(foo));
#if !defined(NDEBUG) && !KJ_NO_RTTI
#if KJ_NO_EXCEPTIONS
#ifndef NDEBUG
EXPECT_DEATH_IF_SUPPORTED(downcast<Baz>(foo), "Value cannot be downcast");
#endif
#else
EXPECT_ANY_THROW(downcast<Baz>(foo));
#endif
#endif
#if KJ_NO_RTTI
EXPECT_TRUE(dynamicDowncastIfAvailable<Bar>(foo) == nullptr);
......
......@@ -27,6 +27,7 @@
#include <string>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <exception>
......@@ -43,6 +44,83 @@ public:
std::string text;
int outputPipe = -1;
bool forkForDeathTest() {
// This is called when exceptions are disabled. We fork the process instead and then expect
// the child to die.
int pipeFds[2];
pipe(pipeFds);
pid_t child = fork();
if (child == 0) {
// This is the child!
close(pipeFds[0]);
outputPipe = pipeFds[1];
return true;
} else {
close(pipeFds[1]);
// Read child error messages into our local buffer.
char buf[1024];
for (;;) {
ssize_t n = read(pipeFds[0], buf, sizeof(buf));
if (n < 0) {
if (errno == EINTR) {
continue;
} else {
break;
}
} else if (n == 0) {
break;
} else {
text.append(buf, n);
}
}
close(pipeFds[0]);
// Get exit status.
int status;
do {
if (waitpid(child, &status, 0) < 0) {
if (errno == EINTR) {
continue;
} else {
ADD_FAILURE() << "waidpid: " << strerror(errno);
return false;
}
}
} while (false);
EXPECT_TRUE(WIFEXITED(status));
EXPECT_EQ(74, WEXITSTATUS(status));
return false;
}
}
void flush() {
if (outputPipe != -1) {
const char* pos = &*text.begin();
const char* end = pos + text.size();
while (pos < end) {
ssize_t n = write(outputPipe, pos, end - pos);
if (n < 0) {
if (errno == EINTR) {
continue;
} else {
break; // Give up on error.
}
}
pos += n;
}
text.clear();
}
}
void onRecoverableException(Exception&& exception) override {
text += "recoverable exception: ";
auto what = str(exception);
......@@ -54,6 +132,7 @@ public:
text.append(what.cStr(), end);
}
text += '\n';
flush();
}
void onFatalException(Exception&& exception) override {
......@@ -67,7 +146,17 @@ public:
text.append(what.cStr(), end);
}
text += '\n';
flush();
#if KJ_NO_EXCEPTIONS
if (outputPipe >= 0) {
// This is a child process. We got what we want, now exit quickly without writing any
// additional messages, with a status code that the parent will interpret as "exited in the
// way we expected".
_exit(74);
}
#else
throw MockException();
#endif
}
void logMessage(const char* file, int line, int contextDepth, String&& text) override {
......@@ -77,6 +166,12 @@ public:
}
};
#if KJ_NO_EXCEPTIONS
#define EXPECT_FATAL(code) if (mockCallback.forkForDeathTest()) { code; abort(); }
#else
#define EXPECT_FATAL(code) EXPECT_THROW(code, MockException);
#endif
std::string fileLine(std::string file, int line) {
file += ':';
char buffer[32];
......@@ -123,7 +218,7 @@ TEST(Debug, Log) {
Debug::setLogLevel(Debug::Severity::WARNING);
KJ_ASSERT(1 == 1);
EXPECT_THROW(KJ_ASSERT(1 == 2), MockException); line = __LINE__;
EXPECT_FATAL(KJ_ASSERT(1 == 2)); line = __LINE__;
EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": bug in code: expected "
"1 == 2\n", mockCallback.text);
mockCallback.text.clear();
......@@ -140,17 +235,17 @@ TEST(Debug, Log) {
EXPECT_TRUE(recovered);
mockCallback.text.clear();
EXPECT_THROW(KJ_ASSERT(1 == 2, i, "hi", str), MockException); line = __LINE__;
EXPECT_FATAL(KJ_ASSERT(1 == 2, i, "hi", str)); line = __LINE__;
EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": bug in code: expected "
"1 == 2; i = 123; hi; str = foo\n", mockCallback.text);
mockCallback.text.clear();
EXPECT_THROW(KJ_REQUIRE(1 == 2, i, "hi", str), MockException); line = __LINE__;
EXPECT_FATAL(KJ_REQUIRE(1 == 2, i, "hi", str)); line = __LINE__;
EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": requirement not met: expected "
"1 == 2; i = 123; hi; str = foo\n", mockCallback.text);
mockCallback.text.clear();
EXPECT_THROW(KJ_FAIL_ASSERT("foo"), MockException); line = __LINE__;
EXPECT_FATAL(KJ_FAIL_ASSERT("foo")); line = __LINE__;
EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": bug in code: foo\n",
mockCallback.text);
mockCallback.text.clear();
......@@ -159,28 +254,47 @@ TEST(Debug, Log) {
TEST(Debug, Catch) {
int line;
// Catch as kj::Exception.
Maybe<Exception> exception = kj::runCatchingExceptions([&](){
line = __LINE__; KJ_FAIL_ASSERT("foo");
});
KJ_IF_MAYBE(e, exception) {
String what = str(*e);
std::string text(what.cStr(), strchr(what.cStr(), '\n') - what.cStr());
EXPECT_EQ(fileLine(__FILE__, line) + ": bug in code: foo", text);
} else {
ADD_FAILURE() << "Expected exception.";
{
// Catch recoverable as kj::Exception.
Maybe<Exception> exception = kj::runCatchingExceptions([&](){
line = __LINE__; KJ_FAIL_ASSERT("foo") { break; }
});
KJ_IF_MAYBE(e, exception) {
String what = str(*e);
std::string text(what.cStr(), strchr(what.cStr(), '\n') - what.cStr());
EXPECT_EQ(fileLine(__FILE__, line) + ": bug in code: foo", text);
} else {
ADD_FAILURE() << "Expected exception.";
}
}
#if !KJ_NO_EXCEPTIONS
// Catch as std::exception.
try {
line = __LINE__; KJ_FAIL_ASSERT("foo");
ADD_FAILURE() << "Expected exception.";
} catch (const std::exception& e) {
const char* what = e.what();
std::string text(what, strchr(what, '\n') - what);
EXPECT_EQ(fileLine(__FILE__, line) + ": bug in code: foo", text);
{
// Catch fatal as kj::Exception.
Maybe<Exception> exception = kj::runCatchingExceptions([&](){
line = __LINE__; KJ_FAIL_ASSERT("foo");
});
KJ_IF_MAYBE(e, exception) {
String what = str(*e);
std::string text(what.cStr(), strchr(what.cStr(), '\n') - what.cStr());
EXPECT_EQ(fileLine(__FILE__, line) + ": bug in code: foo", text);
} else {
ADD_FAILURE() << "Expected exception.";
}
}
{
// Catch as std::exception.
try {
line = __LINE__; KJ_FAIL_ASSERT("foo");
ADD_FAILURE() << "Expected exception.";
} catch (const std::exception& e) {
const char* what = e.what();
std::string text(what, strchr(what, '\n') - what);
EXPECT_EQ(fileLine(__FILE__, line) + ": bug in code: foo", text);
}
}
#endif
}
......@@ -195,7 +309,7 @@ TEST(Debug, Syscall) {
int fd;
KJ_SYSCALL(fd = dup(STDIN_FILENO));
KJ_SYSCALL(close(fd));
EXPECT_THROW(KJ_SYSCALL(close(fd), i, "bar", str), MockException); line = __LINE__;
EXPECT_FATAL(KJ_SYSCALL(close(fd), i, "bar", str)); line = __LINE__;
EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": error from OS: close(fd): "
+ strerror(EBADF) + "; i = 123; bar; str = foo\n", mockCallback.text);
mockCallback.text.clear();
......@@ -221,7 +335,7 @@ TEST(Debug, Context) {
mockCallback.text);
mockCallback.text.clear();
EXPECT_THROW(KJ_FAIL_ASSERT("bar"), MockException); line = __LINE__;
EXPECT_FATAL(KJ_FAIL_ASSERT("bar")); line = __LINE__;
EXPECT_EQ("fatal exception: " + fileLine(__FILE__, cline) + ": context: foo\n"
+ fileLine(__FILE__, line) + ": bug in code: bar\n",
mockCallback.text);
......@@ -231,7 +345,7 @@ TEST(Debug, Context) {
int i = 123;
const char* str = "qux";
KJ_CONTEXT("baz", i, "corge", str); int cline2 = __LINE__;
EXPECT_THROW(KJ_FAIL_ASSERT("bar"), MockException); line = __LINE__;
EXPECT_FATAL(KJ_FAIL_ASSERT("bar")); line = __LINE__;
EXPECT_EQ("fatal exception: " + fileLine(__FILE__, cline) + ": context: foo\n"
+ fileLine(__FILE__, cline2) + ": context: baz; i = 123; corge; str = qux\n"
......@@ -242,7 +356,7 @@ TEST(Debug, Context) {
{
KJ_CONTEXT("grault"); int cline2 = __LINE__;
EXPECT_THROW(KJ_FAIL_ASSERT("bar"), MockException); line = __LINE__;
EXPECT_FATAL(KJ_FAIL_ASSERT("bar")); line = __LINE__;
EXPECT_EQ("fatal exception: " + fileLine(__FILE__, cline) + ": context: foo\n"
+ fileLine(__FILE__, cline2) + ": context: grault\n"
......
......@@ -88,7 +88,11 @@ TEST(Exception, UnwindDetector) {
}
TEST(Exception, ExceptionCallbackMustBeOnStack) {
#if KJ_NO_EXCEPTIONS
EXPECT_DEATH_IF_SUPPORTED(new ExceptionCallback, "must be allocated on the stack");
#else
EXPECT_ANY_THROW(new ExceptionCallback);
#endif
}
} // namespace
......
......@@ -348,7 +348,7 @@ private:
getExceptionCallback().logMessage(e.getFile(), e.getLine(), 0, str(
e.getNature(), e.getDurability() == Exception::Durability::TEMPORARY ? " (temporary)" : "",
e.getDescription() == nullptr ? "" : ": ", e.getDescription(),
"\nstack: ", strArray(e.getStackTrace(), " ")));
"\nstack: ", strArray(e.getStackTrace(), " "), "\n"));
}
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment