Commit ca7304b5 authored by Kenton Varda's avatar Kenton Varda

Move a couple things from libkj-test into libkj proper.

This allows functions which use KJ_EXPECT and other test macros to be built without linking libkj-test, which pulls in a possibly-unwanted main() function.

In particular, afl-testcase.c++ could not link in -fno-exceptions mode without this change.
parent 31d0ec7e
......@@ -223,6 +223,7 @@ libkj_la_SOURCES= \
src/kj/io.c++ \
src/kj/mutex.c++ \
src/kj/thread.c++ \
src/kj/test-helpers.c++ \
src/kj/main.c++ \
src/kj/parse/char.c++
......
......@@ -13,6 +13,7 @@ set(kj_sources_lite
thread.c++
main.c++
arena.c++
test-helpers.c++
)
set(kj_sources_heavy
units.c++
......
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "test.h"
#ifndef _WIN32
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#endif
namespace kj {
namespace _ { // private
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++) {
if (haystack.slice(i).startsWith(needle)) {
return true;
}
}
}
return false;
}
LogExpectation::LogExpectation(LogSeverity severity, StringPtr substring)
: severity(severity), substring(substring), seen(false) {}
LogExpectation::~LogExpectation() {
if (!unwindDetector.isUnwinding()) {
KJ_ASSERT(seen, "expected log message not seen", severity, substring);
}
}
void LogExpectation::logMessage(
LogSeverity severity, const char* file, int line, int contextDepth,
String&& text) {
if (!seen && severity == this->severity) {
if (hasSubstring(text, substring)) {
// Match. Ignore it.
seen = true;
return;
}
}
// Pass up the chain.
ExceptionCallback::logMessage(severity, file, line, contextDepth, kj::mv(text));
}
// =======================================================================================
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
}
} // namespace _ (private)
} // namespace kj
......@@ -28,9 +28,6 @@
#include <string.h>
#ifndef _WIN32
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#endif
namespace kj {
......@@ -62,111 +59,6 @@ TestCase::~TestCase() {
namespace _ { // private
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++) {
if (haystack.slice(i).startsWith(needle)) {
return true;
}
}
}
return false;
}
LogExpectation::LogExpectation(LogSeverity severity, StringPtr substring)
: severity(severity), substring(substring), seen(false) {}
LogExpectation::~LogExpectation() {
if (!unwindDetector.isUnwinding()) {
KJ_ASSERT(seen, "expected log message not seen", severity, substring);
}
}
void LogExpectation::logMessage(
LogSeverity severity, const char* file, int line, int contextDepth,
String&& text) {
if (!seen && severity == this->severity) {
if (hasSubstring(text, substring)) {
// Match. Ignore it.
seen = true;
return;
}
}
// Pass up the chain.
ExceptionCallback::logMessage(severity, file, line, contextDepth, kj::mv(text));
}
// =======================================================================================
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)) {}
......
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