libcryfs/test/cpp-utils/assert/backtrace_test.cpp

236 lines
6.1 KiB
C++
Raw Normal View History

2018-05-17 07:31:43 +02:00
#include <gmock/gmock.h>
#include <csignal>
2018-05-17 07:31:43 +02:00
#include "cpp-utils/assert/backtrace.h"
#include "cpp-utils/process/subprocess.h"
#include <boost/filesystem.hpp>
#include "my-gtest-main.h"
2018-05-17 07:31:43 +02:00
using std::string;
using testing::HasSubstr;
namespace bf = boost::filesystem;
2018-05-17 07:31:43 +02:00
namespace
{
std::string call_process_exiting_with(const std::string &kind, const std::string &signal = "")
{
#if defined(_MSC_VER)
auto executable = bf::canonical(get_executable().parent_path()) / "cpp-utils-test_exit_signal.exe";
#else
auto executable = bf::canonical(get_executable().parent_path()) / "cpp-utils-test_exit_signal";
#endif
if (!bf::exists(executable))
{
throw std::runtime_error(executable.string() + " not found.");
}
auto result = cpputils::Subprocess::call(executable, {kind, signal}, "");
return result.output_stderr;
}
}
#if !(defined(_MSC_VER) && defined(NDEBUG))
TEST(BacktraceTest, ContainsTopLevelLine)
{
const string backtrace = cpputils::backtrace();
EXPECT_THAT(backtrace, HasSubstr("BacktraceTest"));
EXPECT_THAT(backtrace, HasSubstr("ContainsTopLevelLine"));
2018-05-17 07:31:43 +02:00
}
#endif
namespace
{
2023-06-22 05:33:00 +02:00
#if !(defined(__clang__) && defined(NDEBUG))
std::string call_process_exiting_with_nullptr_violation()
{
return call_process_exiting_with("nullptr");
}
2023-06-22 05:33:00 +02:00
#endif
std::string call_process_exiting_with_exception(const std::string &message)
{
return call_process_exiting_with("exception", message);
2018-07-09 04:34:08 +02:00
}
}
2018-07-09 04:34:08 +02:00
#if defined(_MSC_VER)
#include <Windows.h>
namespace
{
std::string call_process_exiting_with_sigsegv()
{
return call_process_exiting_with("signal", std::to_string(EXCEPTION_ACCESS_VIOLATION));
2018-07-09 04:34:08 +02:00
}
std::string call_process_exiting_with_sigill()
{
return call_process_exiting_with("signal", std::to_string(EXCEPTION_ILLEGAL_INSTRUCTION));
2018-07-09 04:34:08 +02:00
}
std::string call_process_exiting_with_code(DWORD code)
{
return call_process_exiting_with("signal", std::to_string(code));
2018-07-09 04:34:08 +02:00
}
}
2018-07-09 04:34:08 +02:00
#else
namespace
{
std::string call_process_exiting_with_sigsegv()
{
return call_process_exiting_with("signal", std::to_string(SIGSEGV));
2018-07-09 04:34:08 +02:00
}
std::string call_process_exiting_with_sigabrt()
{
return call_process_exiting_with("signal", std::to_string(SIGABRT));
2018-07-09 04:34:08 +02:00
}
std::string call_process_exiting_with_sigill()
{
return call_process_exiting_with("signal", std::to_string(SIGILL));
2018-07-09 04:34:08 +02:00
}
}
2018-07-09 04:34:08 +02:00
#endif
TEST(BacktraceTest, DoesntCrashOnCaughtException)
{
// This is needed to make sure we don't use some kind of vectored exception handler on Windows
// that ignores the call stack and always jumps on when an exception happens.
cpputils::showBacktraceOnCrash();
try
{
throw std::logic_error("exception");
}
catch (const std::logic_error &e)
{
// intentionally empty
}
}
#if !(defined(_MSC_VER) && defined(NDEBUG))
TEST(BacktraceTest, ContainsBacktrace)
{
const string backtrace = cpputils::backtrace();
#if defined(_MSC_VER)
EXPECT_THAT(backtrace, HasSubstr("testing::Test::Run"));
#else
EXPECT_THAT(backtrace, HasSubstr("BacktraceTest_ContainsBacktrace_Test::TestBody"));
#endif
}
#if !(defined(__clang__))
// TODO Can we also make this work on clang?
TEST(BacktraceTest, ShowBacktraceOnNullptrAccess)
{
auto output = call_process_exiting_with_nullptr_violation();
#if defined(_MSC_VER)
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
#else
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
#endif
}
2023-06-22 05:33:00 +02:00
#endif
TEST(BacktraceTest, ShowBacktraceOnSigSegv)
{
auto output = call_process_exiting_with_sigsegv();
#if defined(_MSC_VER)
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
#else
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
#endif
}
TEST(BacktraceTest, ShowBacktraceOnUnhandledException)
{
auto output = call_process_exiting_with_exception("my_exception_message");
#if defined(_MSC_VER)
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
#else
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
#endif
}
TEST(BacktraceTest, ShowBacktraceOnSigIll)
{
auto output = call_process_exiting_with_sigill();
#if defined(_MSC_VER)
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
#else
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
#endif
2018-07-09 04:34:08 +02:00
}
#else
TEST(BacktraceTest, ContainsBacktrace)
{
string backtrace = cpputils::backtrace();
EXPECT_THAT(backtrace, HasSubstr("#0"));
}
TEST(BacktraceTest, ShowBacktraceOnNullptrAccess)
{
auto output = call_process_exiting_with_nullptr_violation();
EXPECT_THAT(output, HasSubstr("#1"));
}
TEST(BacktraceTest, ShowBacktraceOnSigSegv)
{
auto output = call_process_exiting_with_sigsegv();
EXPECT_THAT(output, HasSubstr("#1"));
}
TEST(BacktraceTest, ShowBacktraceOnUnhandledException)
{
auto output = call_process_exiting_with_exception("my_exception_message");
EXPECT_THAT(output, HasSubstr("#1"));
}
TEST(BacktraceTest, ShowBacktraceOnSigIll)
{
auto output = call_process_exiting_with_sigill();
EXPECT_THAT(output, HasSubstr("#1"));
}
#endif
2018-07-09 04:34:08 +02:00
#if !defined(_MSC_VER)
TEST(BacktraceTest, ShowBacktraceOnSigAbrt)
{
auto output = call_process_exiting_with_sigabrt();
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
}
TEST(BacktraceTest, ShowBacktraceOnSigAbrt_ShowsCorrectSignalName)
{
auto output = call_process_exiting_with_sigabrt();
EXPECT_THAT(output, HasSubstr("SIGABRT"));
}
2018-07-09 04:34:08 +02:00
#endif
#if !defined(_MSC_VER)
constexpr const char *sigsegv_message = "SIGSEGV";
constexpr const char *sigill_message = "SIGILL";
2018-07-09 04:34:08 +02:00
#else
constexpr const char *sigsegv_message = "EXCEPTION_ACCESS_VIOLATION";
constexpr const char *sigill_message = "EXCEPTION_ILLEGAL_INSTRUCTION";
2018-07-09 04:34:08 +02:00
#endif
TEST(BacktraceTest, ShowBacktraceOnSigSegv_ShowsCorrectSignalName)
{
auto output = call_process_exiting_with_sigsegv();
EXPECT_THAT(output, HasSubstr(sigsegv_message));
}
TEST(BacktraceTest, ShowBacktraceOnSigIll_ShowsCorrectSignalName)
{
auto output = call_process_exiting_with_sigill();
EXPECT_THAT(output, HasSubstr(sigill_message));
}
#if !defined(_MSC_VER)
TEST(BacktraceTest, ShowBacktraceOnUnhandledException_ShowsCorrectExceptionMessage)
{
auto output = call_process_exiting_with_exception("my_exception_message");
EXPECT_THAT(output, HasSubstr("my_exception_message"));
}
#endif
2018-07-09 04:34:08 +02:00
#if defined(_MSC_VER)
TEST(BacktraceTest, UnknownCode_ShowsCorrectSignalName)
{
2018-09-19 12:01:31 +02:00
auto output = call_process_exiting_with_code(0x1234567);
EXPECT_THAT(output, HasSubstr("UNKNOWN_CODE(0x1234567)"));
}
2018-07-09 04:34:08 +02:00
#endif