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") { ...@@ -198,18 +198,24 @@ KJ_TEST("decode all types") {
auto root = message.initRoot<TestAllTypes>(); \ auto root = message.initRoot<TestAllTypes>(); \
KJ_EXPECT_THROW_MESSAGE(errorMessage, json.decode(s, root)); \ 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"({})", root.getBoolField() == false);
CASE(R"({"unknownField":7})", root.getBoolField() == false); CASE(R"({"unknownField":7})", root.getBoolField() == false);
CASE(R"({"boolField":true})", root.getBoolField() == true); CASE(R"({"boolField":true})", root.getBoolField() == true);
CASE(R"({"int8Field":-128})", root.getInt8Field() == -128); CASE(R"({"int8Field":-128})", root.getInt8Field() == -128);
CASE(R"({"int8Field":"127"})", root.getInt8Field() == 127); CASE(R"({"int8Field":"127"})", root.getInt8Field() == 127);
CASE_THROW(R"({"int8Field":"-129"})", "Value out-of-range"); CASE_THROW_RECOVERABLE(R"({"int8Field":"-129"})", "Value out-of-range");
CASE_THROW(R"({"int8Field":128})", "Value out-of-range"); CASE_THROW_RECOVERABLE(R"({"int8Field":128})", "Value out-of-range");
CASE(R"({"int16Field":-32768})", root.getInt16Field() == -32768); CASE(R"({"int16Field":-32768})", root.getInt16Field() == -32768);
CASE(R"({"int16Field":"32767"})", root.getInt16Field() == 32767); CASE(R"({"int16Field":"32767"})", root.getInt16Field() == 32767);
CASE_THROW(R"({"int16Field":"-32769"})", "Value out-of-range"); CASE_THROW_RECOVERABLE(R"({"int16Field":"-32769"})", "Value out-of-range");
CASE_THROW(R"({"int16Field":32768})", "Value out-of-range"); CASE_THROW_RECOVERABLE(R"({"int16Field":32768})", "Value out-of-range");
CASE(R"({"int32Field":-2147483648})", root.getInt32Field() == -2147483648); CASE(R"({"int32Field":-2147483648})", root.getInt32Field() == -2147483648);
CASE(R"({"int32Field":"2147483647"})", root.getInt32Field() == 2147483647); CASE(R"({"int32Field":"2147483647"})", root.getInt32Field() == 2147483647);
CASE(R"({"int64Field":-9007199254740992})", root.getInt64Field() == -9007199254740992LL); CASE(R"({"int64Field":-9007199254740992})", root.getInt64Field() == -9007199254740992LL);
...@@ -220,16 +226,16 @@ KJ_TEST("decode all types") { ...@@ -220,16 +226,16 @@ KJ_TEST("decode all types") {
CASE_THROW(R"({"int64Field":"9223372036854775808"})", "Value out-of-range"); CASE_THROW(R"({"int64Field":"9223372036854775808"})", "Value out-of-range");
CASE(R"({"uInt8Field":255})", root.getUInt8Field() == 255); CASE(R"({"uInt8Field":255})", root.getUInt8Field() == 255);
CASE(R"({"uInt8Field":"0"})", root.getUInt8Field() == 0); CASE(R"({"uInt8Field":"0"})", root.getUInt8Field() == 0);
CASE_THROW(R"({"uInt8Field":"256"})", "Value out-of-range"); CASE_THROW_RECOVERABLE(R"({"uInt8Field":"256"})", "Value out-of-range");
CASE_THROW(R"({"uInt8Field":-1})", "Value out-of-range"); CASE_THROW_RECOVERABLE(R"({"uInt8Field":-1})", "Value out-of-range");
CASE(R"({"uInt16Field":65535})", root.getUInt16Field() == 65535); CASE(R"({"uInt16Field":65535})", root.getUInt16Field() == 65535);
CASE(R"({"uInt16Field":"0"})", root.getUInt16Field() == 0); CASE(R"({"uInt16Field":"0"})", root.getUInt16Field() == 0);
CASE_THROW(R"({"uInt16Field":"655356"})", "Value out-of-range"); CASE_THROW_RECOVERABLE(R"({"uInt16Field":"655356"})", "Value out-of-range");
CASE_THROW(R"({"uInt16Field":-1})", "Value out-of-range"); CASE_THROW_RECOVERABLE(R"({"uInt16Field":-1})", "Value out-of-range");
CASE(R"({"uInt32Field":4294967295})", root.getUInt32Field() == 4294967295); CASE(R"({"uInt32Field":4294967295})", root.getUInt32Field() == 4294967295);
CASE(R"({"uInt32Field":"0"})", root.getUInt32Field() == 0); CASE(R"({"uInt32Field":"0"})", root.getUInt32Field() == 0);
CASE_THROW(R"({"uInt32Field":"42949672956"})", "Value out-of-range"); CASE_THROW_RECOVERABLE(R"({"uInt32Field":"42949672956"})", "Value out-of-range");
CASE_THROW(R"({"uInt32Field":-1})", "Value out-of-range"); CASE_THROW_RECOVERABLE(R"({"uInt32Field":-1})", "Value out-of-range");
CASE(R"({"uInt64Field":9007199254740991})", root.getUInt64Field() == 9007199254740991ULL); CASE(R"({"uInt64Field":9007199254740991})", root.getUInt64Field() == 9007199254740991ULL);
CASE(R"({"uInt64Field":"18446744073709551615"})", root.getUInt64Field() == 18446744073709551615ULL); CASE(R"({"uInt64Field":"18446744073709551615"})", root.getUInt64Field() == 18446744073709551615ULL);
CASE(R"({"uInt64Field":"0"})", root.getUInt64Field() == 0); CASE(R"({"uInt64Field":"0"})", root.getUInt64Field() == 0);
......
...@@ -35,20 +35,6 @@ ...@@ -35,20 +35,6 @@
#include "dynamic.h" #include "dynamic.h"
#endif // !CAPNP_LITE #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. // TODO(cleanup): Auto-generate stringification functions for union discriminants.
namespace capnproto_test { namespace capnproto_test {
namespace capnp { namespace capnp {
......
...@@ -357,11 +357,6 @@ TEST(Async, SeparateFulfillerChained) { ...@@ -357,11 +357,6 @@ TEST(Async, SeparateFulfillerChained) {
EXPECT_EQ(123, pair.promise.wait(waitScope)); 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) { TEST(Async, SeparateFulfillerDiscarded) {
EventLoop loop; EventLoop loop;
WaitScope waitScope(loop); WaitScope waitScope(loop);
......
...@@ -245,13 +245,7 @@ TEST(Common, Downcast) { ...@@ -245,13 +245,7 @@ TEST(Common, Downcast) {
EXPECT_EQ(&bar, &downcast<Bar>(foo)); EXPECT_EQ(&bar, &downcast<Bar>(foo));
#if defined(KJ_DEBUG) && !KJ_NO_RTTI #if defined(KJ_DEBUG) && !KJ_NO_RTTI
#if KJ_NO_EXCEPTIONS KJ_EXPECT_THROW_MESSAGE("Value cannot be downcast", downcast<Baz>(foo));
#ifdef KJ_DEBUG
EXPECT_DEATH_IF_SUPPORTED(downcast<Baz>(foo), "Value cannot be downcast");
#endif
#else
EXPECT_ANY_THROW(downcast<Baz>(foo));
#endif
#endif #endif
#if KJ_NO_RTTI #if KJ_NO_RTTI
......
...@@ -98,8 +98,22 @@ private: ...@@ -98,8 +98,22 @@ private:
#define ADD_FAILURE() ::kj::AddFailureAdapter(__FILE__, __LINE__) #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) \ #define EXPECT_ANY_THROW(code) \
KJ_EXPECT(::kj::runCatchingExceptions([&]() { code; }) != nullptr) 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) #define TEST(x, y) KJ_TEST("legacy test: " #x "/" #y)
......
...@@ -97,11 +97,7 @@ TEST(Exception, UnwindDetector) { ...@@ -97,11 +97,7 @@ TEST(Exception, UnwindDetector) {
#if !__MINGW32__ // Inexplicably crashes when exception is thrown from constructor. #if !__MINGW32__ // Inexplicably crashes when exception is thrown from constructor.
TEST(Exception, ExceptionCallbackMustBeOnStack) { TEST(Exception, ExceptionCallbackMustBeOnStack) {
#if KJ_NO_EXCEPTIONS KJ_EXPECT_THROW_MESSAGE("must be allocated on the stack", new ExceptionCallback);
EXPECT_DEATH_IF_SUPPORTED(new ExceptionCallback, "must be allocated on the stack");
#else
EXPECT_ANY_THROW(new ExceptionCallback);
#endif
} }
#endif // !__MINGW32__ #endif // !__MINGW32__
......
...@@ -42,20 +42,6 @@ inline void delay() { Sleep(10); } ...@@ -42,20 +42,6 @@ inline void delay() { Sleep(10); }
inline void delay() { usleep(10000); } inline void delay() { usleep(10000); }
#endif #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) { TEST(Mutex, MutexGuarded) {
MutexGuarded<uint> value(123); MutexGuarded<uint> value(123);
......
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
#include <string.h> #include <string.h>
#ifndef _WIN32 #ifndef _WIN32
#include <sys/mman.h> #include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#endif #endif
namespace kj { namespace kj {
...@@ -59,7 +62,7 @@ TestCase::~TestCase() { ...@@ -59,7 +62,7 @@ TestCase::~TestCase() {
namespace _ { // private 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. // TODO(perf): This is not the best algorithm for substring matching.
if (needle.size() <= haystack.size()) { if (needle.size() <= haystack.size()) {
for (size_t i = 0; i <= haystack.size() - needle.size(); i++) { for (size_t i = 0; i <= haystack.size() - needle.size(); i++) {
...@@ -96,6 +99,74 @@ void LogExpectation::logMessage( ...@@ -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(const char* pattern): pattern(heapString(pattern)) {}
GlobFilter::GlobFilter(ArrayPtr<const char> pattern): pattern(heapString(pattern)) {} GlobFilter::GlobFilter(ArrayPtr<const char> pattern): pattern(heapString(pattern)) {}
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "debug.h" #include "debug.h"
#include "vector.h" #include "vector.h"
#include "function.h"
namespace kj { namespace kj {
...@@ -74,7 +75,7 @@ private: ...@@ -74,7 +75,7 @@ private:
if (cond); else KJ_FAIL_EXPECT("failed: expected " #cond, ##__VA_ARGS__) if (cond); else KJ_FAIL_EXPECT("failed: expected " #cond, ##__VA_ARGS__)
#endif #endif
#define KJ_EXPECT_THROW(type, code) \ #define KJ_EXPECT_THROW_RECOVERABLE(type, code) \
do { \ do { \
KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \ KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \
KJ_EXPECT(e->getType() == ::kj::Exception::Type::type, \ KJ_EXPECT(e->getType() == ::kj::Exception::Type::type, \
...@@ -84,7 +85,7 @@ private: ...@@ -84,7 +85,7 @@ private:
} \ } \
} while (false) } while (false)
#define KJ_EXPECT_THROW_MESSAGE(message, code) \ #define KJ_EXPECT_THROW_RECOVERABLE_MESSAGE(message, code) \
do { \ do { \
KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \ KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \
KJ_EXPECT(::kj::_::hasSubstring(e->getDescription(), message), \ KJ_EXPECT(::kj::_::hasSubstring(e->getDescription(), message), \
...@@ -94,6 +95,20 @@ private: ...@@ -94,6 +95,20 @@ private:
} \ } \
} while (false) } 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) \ #define KJ_EXPECT_LOG(level, substring) \
::kj::_::LogExpectation KJ_UNIQUE_NAME(_kjLogExpectation)(::kj::LogSeverity::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 // Expects that a log message with the given level and substring text will be printed within
...@@ -105,6 +120,14 @@ namespace _ { // private ...@@ -105,6 +120,14 @@ namespace _ { // private
bool hasSubstring(kj::StringPtr haystack, kj::StringPtr needle); 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 { class LogExpectation: public ExceptionCallback {
public: public:
LogExpectation(LogSeverity severity, StringPtr substring); 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