Commit 9aabfdbe authored by Kenton Varda's avatar Kenton Varda

Update tests to work with -fno-exceptions.

parent dec6bafa
......@@ -198,18 +198,24 @@ KJ_TEST("decode all types") {
auto root = message.initRoot<TestAllTypes>(); \
KJ_EXPECT_THROW_MESSAGE(errorMessage, json.decode(s, root)); \
}
#define CASE_THROW_RECOVERABLE(s, errorMessage) \
{ \
MallocMessageBuilder message; \
auto root = message.initRoot<TestAllTypes>(); \
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE(errorMessage, json.decode(s, root)); \
}
CASE(R"({})", root.getBoolField() == false);
CASE(R"({"unknownField":7})", root.getBoolField() == false);
CASE(R"({"boolField":true})", root.getBoolField() == true);
CASE(R"({"int8Field":-128})", root.getInt8Field() == -128);
CASE(R"({"int8Field":"127"})", root.getInt8Field() == 127);
CASE_THROW(R"({"int8Field":"-129"})", "Value out-of-range");
CASE_THROW(R"({"int8Field":128})", "Value out-of-range");
CASE_THROW_RECOVERABLE(R"({"int8Field":"-129"})", "Value out-of-range");
CASE_THROW_RECOVERABLE(R"({"int8Field":128})", "Value out-of-range");
CASE(R"({"int16Field":-32768})", root.getInt16Field() == -32768);
CASE(R"({"int16Field":"32767"})", root.getInt16Field() == 32767);
CASE_THROW(R"({"int16Field":"-32769"})", "Value out-of-range");
CASE_THROW(R"({"int16Field":32768})", "Value out-of-range");
CASE_THROW_RECOVERABLE(R"({"int16Field":"-32769"})", "Value out-of-range");
CASE_THROW_RECOVERABLE(R"({"int16Field":32768})", "Value out-of-range");
CASE(R"({"int32Field":-2147483648})", root.getInt32Field() == -2147483648);
CASE(R"({"int32Field":"2147483647"})", root.getInt32Field() == 2147483647);
CASE(R"({"int64Field":-9007199254740992})", root.getInt64Field() == -9007199254740992LL);
......@@ -220,16 +226,16 @@ KJ_TEST("decode all types") {
CASE_THROW(R"({"int64Field":"9223372036854775808"})", "Value out-of-range");
CASE(R"({"uInt8Field":255})", root.getUInt8Field() == 255);
CASE(R"({"uInt8Field":"0"})", root.getUInt8Field() == 0);
CASE_THROW(R"({"uInt8Field":"256"})", "Value out-of-range");
CASE_THROW(R"({"uInt8Field":-1})", "Value out-of-range");
CASE_THROW_RECOVERABLE(R"({"uInt8Field":"256"})", "Value out-of-range");
CASE_THROW_RECOVERABLE(R"({"uInt8Field":-1})", "Value out-of-range");
CASE(R"({"uInt16Field":65535})", root.getUInt16Field() == 65535);
CASE(R"({"uInt16Field":"0"})", root.getUInt16Field() == 0);
CASE_THROW(R"({"uInt16Field":"655356"})", "Value out-of-range");
CASE_THROW(R"({"uInt16Field":-1})", "Value out-of-range");
CASE_THROW_RECOVERABLE(R"({"uInt16Field":"655356"})", "Value out-of-range");
CASE_THROW_RECOVERABLE(R"({"uInt16Field":-1})", "Value out-of-range");
CASE(R"({"uInt32Field":4294967295})", root.getUInt32Field() == 4294967295);
CASE(R"({"uInt32Field":"0"})", root.getUInt32Field() == 0);
CASE_THROW(R"({"uInt32Field":"42949672956"})", "Value out-of-range");
CASE_THROW(R"({"uInt32Field":-1})", "Value out-of-range");
CASE_THROW_RECOVERABLE(R"({"uInt32Field":"42949672956"})", "Value out-of-range");
CASE_THROW_RECOVERABLE(R"({"uInt32Field":-1})", "Value out-of-range");
CASE(R"({"uInt64Field":9007199254740991})", root.getUInt64Field() == 9007199254740991ULL);
CASE(R"({"uInt64Field":"18446744073709551615"})", root.getUInt64Field() == 18446744073709551615ULL);
CASE(R"({"uInt64Field":"0"})", root.getUInt64Field() == 0);
......
......@@ -35,20 +35,6 @@
#include "dynamic.h"
#endif // !CAPNP_LITE
#if KJ_NO_EXCEPTIONS
#undef EXPECT_ANY_THROW
#define EXPECT_ANY_THROW(code) EXPECT_DEATH(code, ".")
#endif
#define EXPECT_NONFATAL_FAILURE(code) \
EXPECT_TRUE(kj::runCatchingExceptions([&]() { code; }) != nullptr);
#ifdef KJ_DEBUG
#define EXPECT_DEBUG_ANY_THROW EXPECT_ANY_THROW
#else
#define EXPECT_DEBUG_ANY_THROW(EXP)
#endif
// TODO(cleanup): Auto-generate stringification functions for union discriminants.
namespace capnproto_test {
namespace capnp {
......
......@@ -357,11 +357,6 @@ TEST(Async, SeparateFulfillerChained) {
EXPECT_EQ(123, pair.promise.wait(waitScope));
}
#if KJ_NO_EXCEPTIONS
#undef EXPECT_ANY_THROW
#define EXPECT_ANY_THROW(code) EXPECT_DEATH(code, ".")
#endif
TEST(Async, SeparateFulfillerDiscarded) {
EventLoop loop;
WaitScope waitScope(loop);
......
......@@ -245,13 +245,7 @@ TEST(Common, Downcast) {
EXPECT_EQ(&bar, &downcast<Bar>(foo));
#if defined(KJ_DEBUG) && !KJ_NO_RTTI
#if KJ_NO_EXCEPTIONS
#ifdef KJ_DEBUG
EXPECT_DEATH_IF_SUPPORTED(downcast<Baz>(foo), "Value cannot be downcast");
#endif
#else
EXPECT_ANY_THROW(downcast<Baz>(foo));
#endif
KJ_EXPECT_THROW_MESSAGE("Value cannot be downcast", downcast<Baz>(foo));
#endif
#if KJ_NO_RTTI
......
......@@ -98,8 +98,22 @@ private:
#define ADD_FAILURE() ::kj::AddFailureAdapter(__FILE__, __LINE__)
#if KJ_NO_EXCEPTIONS
#define EXPECT_ANY_THROW(code) \
KJ_EXPECT(::kj::_::expectFatalThrow(nullptr, nullptr, [&]() { code; }))
#else
#define EXPECT_ANY_THROW(code) \
KJ_EXPECT(::kj::runCatchingExceptions([&]() { code; }) != nullptr)
#endif
#define EXPECT_NONFATAL_FAILURE(code) \
EXPECT_TRUE(kj::runCatchingExceptions([&]() { code; }) != nullptr);
#ifdef KJ_DEBUG
#define EXPECT_DEBUG_ANY_THROW EXPECT_ANY_THROW
#else
#define EXPECT_DEBUG_ANY_THROW(EXP)
#endif
#define TEST(x, y) KJ_TEST("legacy test: " #x "/" #y)
......
......@@ -97,11 +97,7 @@ TEST(Exception, UnwindDetector) {
#if !__MINGW32__ // Inexplicably crashes when exception is thrown from constructor.
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
KJ_EXPECT_THROW_MESSAGE("must be allocated on the stack", new ExceptionCallback);
}
#endif // !__MINGW32__
......
......@@ -42,20 +42,6 @@ inline void delay() { Sleep(10); }
inline void delay() { usleep(10000); }
#endif
#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 KJ_DEBUG
#define EXPECT_DEBUG_ANY_THROW EXPECT_ANY_THROW
#else
#define EXPECT_DEBUG_ANY_THROW(EXP)
#endif
TEST(Mutex, MutexGuarded) {
MutexGuarded<uint> value(123);
......
......@@ -28,6 +28,9 @@
#include <string.h>
#ifndef _WIN32
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#endif
namespace kj {
......@@ -59,7 +62,7 @@ TestCase::~TestCase() {
namespace _ { // private
bool hasSubstring(kj::StringPtr haystack, kj::StringPtr needle) {
bool hasSubstring(StringPtr haystack, StringPtr needle) {
// TODO(perf): This is not the best algorithm for substring matching.
if (needle.size() <= haystack.size()) {
for (size_t i = 0; i <= haystack.size() - needle.size(); i++) {
......@@ -96,6 +99,74 @@ void LogExpectation::logMessage(
// =======================================================================================
namespace {
class FatalThrowExpectation: public ExceptionCallback {
public:
FatalThrowExpectation(Maybe<Exception::Type> type,
Maybe<StringPtr> message)
: type(type), message(message) {}
virtual void onFatalException(Exception&& exception) {
KJ_IF_MAYBE(expectedType, type) {
if (exception.getType() != *expectedType) {
KJ_LOG(ERROR, "threw exception of wrong type", exception, *expectedType);
_exit(1);
}
}
KJ_IF_MAYBE(expectedSubstring, message) {
if (!hasSubstring(exception.getDescription(), *expectedSubstring)) {
KJ_LOG(ERROR, "threw exception with wrong message", exception, *expectedSubstring);
_exit(1);
}
}
_exit(0);
}
private:
Maybe<Exception::Type> type;
Maybe<StringPtr> message;
};
} // namespace
bool expectFatalThrow(kj::Maybe<Exception::Type> type, kj::Maybe<StringPtr> message,
Function<void()> code) {
#if _WIN32
// We don't support death tests on Windows due to lack of efficient fork.
return true;
#else
pid_t child;
KJ_SYSCALL(child = fork());
if (child == 0) {
KJ_DEFER(_exit(1));
FatalThrowExpectation expectation(type, message);
KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() {
code();
})) {
KJ_LOG(ERROR, "a non-fatal exception was thrown, but we expected fatal", *e);
} else {
KJ_LOG(ERROR, "no fatal exception was thrown");
}
}
int status;
KJ_SYSCALL(waitpid(child, &status, 0));
if (WIFEXITED(status)) {
return WEXITSTATUS(status) == 0;
} else if (WIFSIGNALED(status)) {
KJ_FAIL_EXPECT("subprocess crashed without throwing exception", WTERMSIG(status));
return false;
} else {
KJ_FAIL_EXPECT("subprocess neiter excited nor crashed?", status);
return false;
}
#endif
}
// =======================================================================================
GlobFilter::GlobFilter(const char* pattern): pattern(heapString(pattern)) {}
GlobFilter::GlobFilter(ArrayPtr<const char> pattern): pattern(heapString(pattern)) {}
......
......@@ -28,6 +28,7 @@
#include "debug.h"
#include "vector.h"
#include "function.h"
namespace kj {
......@@ -74,7 +75,7 @@ private:
if (cond); else KJ_FAIL_EXPECT("failed: expected " #cond, ##__VA_ARGS__)
#endif
#define KJ_EXPECT_THROW(type, code) \
#define KJ_EXPECT_THROW_RECOVERABLE(type, code) \
do { \
KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \
KJ_EXPECT(e->getType() == ::kj::Exception::Type::type, \
......@@ -84,7 +85,7 @@ private:
} \
} while (false)
#define KJ_EXPECT_THROW_MESSAGE(message, code) \
#define KJ_EXPECT_THROW_RECOVERABLE_MESSAGE(message, code) \
do { \
KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \
KJ_EXPECT(::kj::_::hasSubstring(e->getDescription(), message), \
......@@ -94,6 +95,20 @@ private:
} \
} while (false)
#if KJ_NO_EXCEPTIONS
#define KJ_EXPECT_THROW(type, code) \
do { \
KJ_EXPECT(::kj::_::expectFatalThrow(type, nullptr, [&]() { code; })); \
} while (false)
#define KJ_EXPECT_THROW_MESSAGE(message, code) \
do { \
KJ_EXPECT(::kj::_::expectFatalThrow(nullptr, kj::StringPtr(message), [&]() { code; })); \
} while (false)
#else
#define KJ_EXPECT_THROW KJ_EXPECT_THROW_RECOVERABLE
#define KJ_EXPECT_THROW_MESSAGE KJ_EXPECT_THROW_RECOVERABLE_MESSAGE
#endif
#define KJ_EXPECT_LOG(level, substring) \
::kj::_::LogExpectation KJ_UNIQUE_NAME(_kjLogExpectation)(::kj::LogSeverity::level, substring)
// Expects that a log message with the given level and substring text will be printed within
......@@ -105,6 +120,14 @@ namespace _ { // private
bool hasSubstring(kj::StringPtr haystack, kj::StringPtr needle);
#if KJ_NO_EXCEPTIONS
bool expectFatalThrow(Maybe<Exception::Type> type, Maybe<StringPtr> message,
Function<void()> code);
// Expects that the given code will throw a fatal exception matching the given type and/or message.
// Since exceptions are disabled, the test will fork() and run in a subprocess. On Windows, where
// fork() is not available, this always returns true.
#endif
class LogExpectation: public ExceptionCallback {
public:
LogExpectation(LogSeverity severity, StringPtr substring);
......
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