Last active
June 9, 2022 20:57
-
-
Save m-pilia/6cb686b0fe0ab22a4f6feebdd177bdf8 to your computer and use it in GitHub Desktop.
Catch2 death test (fork)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <catch2/catch_test_macros.hpp> | |
#include "abnormal_termination.hpp" | |
TEST_CASE("Example test", "[example]" ) { | |
CHECK(abnormalTermination([]() { | |
std::cout << "hallo\n"; | |
std::abort(); | |
})); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <functional> | |
#include <unistd.h> | |
#include <sys/wait.h> | |
#include "default_signal_handling_guard.hpp" | |
/** | |
* Execute a callable in a child process, and retur true if execution of | |
* the callbale terminates abnormally due to a signal being raised. | |
* | |
* NOTE: This function ignores signal handlers set before its call. | |
*/ | |
bool abnormalTermination(const std::function<void(void)>& callable) { | |
constexpr auto forkFailure = -1; | |
constexpr auto childProcess = 0; | |
int exitStatus{}; | |
switch (fork()) { | |
case forkFailure: | |
throw std::runtime_error("Failed to spawn child process"); | |
case childProcess: | |
{ | |
DefaultSignalHandlingGuard guard{}; | |
callable(); | |
} | |
std::exit(EXIT_SUCCESS); | |
default: | |
break; | |
} | |
wait(&exitStatus); | |
return WIFSIGNALED(exitStatus) != 0; | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 3.5) | |
set(CMAKE_CXX_STANDARD 17) | |
project(catch2_death_test_example LANGUAGES CXX VERSION 0.0.1) | |
include(FetchContent) | |
FetchContent_Declare( | |
Catch2 | |
GIT_REPOSITORY https://github.com/catchorg/Catch2.git | |
GIT_TAG v3.0.1 | |
) | |
FetchContent_MakeAvailable(Catch2) | |
add_executable(example_test_suite _death_test.cpp) | |
target_link_libraries(example_test_suite PRIVATE Catch2::Catch2WithMain) | |
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras) | |
include(CTest) | |
include(Catch) | |
catch_discover_tests(example_test_suite) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <array> | |
#include <csignal> | |
#include <iostream> | |
#include <map> | |
/** | |
* Restore default signal handlers for the standard signals under the lifetime of the guard. | |
*/ | |
class DefaultSignalHandlingGuard { | |
public: | |
DefaultSignalHandlingGuard() { | |
for (const auto signalId : _signalIds) { | |
const auto previousHandler = std::signal(signalId, SIG_DFL); | |
if (previousHandler == SIG_ERR) { | |
throw std::runtime_error("Failed to set signal handler for signal id " + std::to_string(signalId)); | |
} | |
_previousHandlers[signalId] = previousHandler; | |
} | |
} | |
~DefaultSignalHandlingGuard() { | |
for (const auto [signalId, previousHandler] : _previousHandlers) { | |
const auto result = std::signal(signalId, previousHandler); | |
if (result == SIG_ERR) { | |
std::cerr << "Failed to restore signal handler for signal id " << signalId; | |
} | |
} | |
} | |
private: | |
using SignalId = decltype(SIGINT); | |
using SignalHandler = void(*)(SignalId); | |
static constexpr std::array _signalIds{ | |
SIGINT, | |
SIGILL, | |
SIGFPE, | |
SIGSEGV, | |
SIGTERM, | |
SIGABRT, | |
}; | |
std::map<SignalId, SignalHandler> _previousHandlers{}; | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment