1f6fd1c14SLouis Dionne //===----------------------------------------------------------------------===// 2f6fd1c14SLouis Dionne // 3f6fd1c14SLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4f6fd1c14SLouis Dionne // See https://llvm.org/LICENSE.txt for license information. 5f6fd1c14SLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f6fd1c14SLouis Dionne // 7f6fd1c14SLouis Dionne //===----------------------------------------------------------------------===// 8f6fd1c14SLouis Dionne 9f6fd1c14SLouis Dionne #ifndef TEST_SUPPORT_CHECK_ASSERTION_H 10f6fd1c14SLouis Dionne #define TEST_SUPPORT_CHECK_ASSERTION_H 11f6fd1c14SLouis Dionne 1231452655SLouis Dionne #include <array> 13f6fd1c14SLouis Dionne #include <cassert> 1431452655SLouis Dionne #include <csignal> 157de5aca8SLouis Dionne #include <cstdarg> 16f6fd1c14SLouis Dionne #include <cstddef> 17f6fd1c14SLouis Dionne #include <cstdio> 18f6fd1c14SLouis Dionne #include <cstdlib> 19aade7467SNikolas Klauser #include <exception> 2058780b81SKonstantin Varlamov #include <functional> 218dfc67d6SKonstantin Varlamov #include <regex> 2258780b81SKonstantin Varlamov #include <sstream> 23f6fd1c14SLouis Dionne #include <string> 24f6fd1c14SLouis Dionne #include <string_view> 25f6fd1c14SLouis Dionne #include <utility> 26f6fd1c14SLouis Dionne 27f6fd1c14SLouis Dionne #include <unistd.h> 28f6fd1c14SLouis Dionne #include <errno.h> 2907b5829fSHristo Hristov #include <signal.h> 30f6fd1c14SLouis Dionne #include <sys/wait.h> 3107b5829fSHristo Hristov 32f6fd1c14SLouis Dionne #include "test_macros.h" 33f6fd1c14SLouis Dionne #include "test_allocator.h" 34f6fd1c14SLouis Dionne 35f6fd1c14SLouis Dionne #if TEST_STD_VER < 11 36f6fd1c14SLouis Dionne # error "C++11 or greater is required to use this header" 37f6fd1c14SLouis Dionne #endif 38f6fd1c14SLouis Dionne 3958780b81SKonstantin Varlamov // When printing the assertion message to `stderr`, delimit it with a marker to make it easier to match the message 4058780b81SKonstantin Varlamov // later. 4158780b81SKonstantin Varlamov static constexpr const char* Marker = "###"; 42f6fd1c14SLouis Dionne 4358780b81SKonstantin Varlamov // (success, error-message-if-failed) 4458780b81SKonstantin Varlamov using MatchResult = std::pair<bool, std::string>; 4558780b81SKonstantin Varlamov using Matcher = std::function<MatchResult(const std::string& /*text*/)>; 46f6fd1c14SLouis Dionne 4758780b81SKonstantin Varlamov MatchResult MatchAssertionMessage(const std::string& text, std::string_view expected_message) { 4858780b81SKonstantin Varlamov // Extract information from the error message. This has to stay synchronized with how we format assertions in the 4958780b81SKonstantin Varlamov // library. 5058780b81SKonstantin Varlamov std::regex assertion_format(".*###\\n(.*):(\\d+): assertion (.*) failed: (.*)\\n###"); 51f6fd1c14SLouis Dionne 5258780b81SKonstantin Varlamov std::smatch match_result; 5358780b81SKonstantin Varlamov bool has_match = std::regex_match(text, match_result, assertion_format); 5458780b81SKonstantin Varlamov assert(has_match); 5558780b81SKonstantin Varlamov assert(match_result.size() == 5); 5658780b81SKonstantin Varlamov 5758780b81SKonstantin Varlamov const std::string& file = match_result[1]; 5858780b81SKonstantin Varlamov int line = std::stoi(match_result[2]); 5958780b81SKonstantin Varlamov // Omitting `expression` in `match_result[3]` 6058780b81SKonstantin Varlamov const std::string& assertion_message = match_result[4]; 6158780b81SKonstantin Varlamov 6258780b81SKonstantin Varlamov bool result = assertion_message == expected_message; 6358780b81SKonstantin Varlamov if (!result) { 6458780b81SKonstantin Varlamov std::stringstream matching_error; 6558780b81SKonstantin Varlamov matching_error // 6658780b81SKonstantin Varlamov << "Expected message: '" << expected_message.data() << "'\n" // 6758780b81SKonstantin Varlamov << "Actual message: '" << assertion_message.c_str() << "'\n" // 6858780b81SKonstantin Varlamov << "Source location: " << file << ":" << std::to_string(line) << "\n"; 6958780b81SKonstantin Varlamov return MatchResult(/*success=*/false, matching_error.str()); 70f6fd1c14SLouis Dionne } 71f6fd1c14SLouis Dionne 7258780b81SKonstantin Varlamov return MatchResult(/*success=*/true, /*maybe_error=*/""); 73f6fd1c14SLouis Dionne } 74f6fd1c14SLouis Dionne 7558780b81SKonstantin Varlamov Matcher MakeAssertionMessageMatcher(std::string_view assertion_message) { 7658780b81SKonstantin Varlamov return [=](const std::string& text) { // 7758780b81SKonstantin Varlamov return MatchAssertionMessage(text, assertion_message); 7858780b81SKonstantin Varlamov }; 79f6fd1c14SLouis Dionne } 80f6fd1c14SLouis Dionne 8158780b81SKonstantin Varlamov Matcher MakeAnyMatcher() { 8258780b81SKonstantin Varlamov return [](const std::string&) { // 8358780b81SKonstantin Varlamov return MatchResult(/*success=*/true, /*maybe_error=*/""); 8458780b81SKonstantin Varlamov }; 85f6fd1c14SLouis Dionne } 86f6fd1c14SLouis Dionne 8758780b81SKonstantin Varlamov enum class DeathCause { 8858780b81SKonstantin Varlamov // Valid causes 8958780b81SKonstantin Varlamov VerboseAbort = 1, 9031452655SLouis Dionne StdAbort, 9158780b81SKonstantin Varlamov StdTerminate, 9258780b81SKonstantin Varlamov Trap, 9358780b81SKonstantin Varlamov // Invalid causes 9458780b81SKonstantin Varlamov DidNotDie, 9558780b81SKonstantin Varlamov SetupFailure, 9658780b81SKonstantin Varlamov Unknown 97f6fd1c14SLouis Dionne }; 98f6fd1c14SLouis Dionne 9958780b81SKonstantin Varlamov bool IsValidCause(DeathCause cause) { 10058780b81SKonstantin Varlamov switch (cause) { 10158780b81SKonstantin Varlamov case DeathCause::VerboseAbort: 10231452655SLouis Dionne case DeathCause::StdAbort: 10358780b81SKonstantin Varlamov case DeathCause::StdTerminate: 10458780b81SKonstantin Varlamov case DeathCause::Trap: 10558780b81SKonstantin Varlamov return true; 10658780b81SKonstantin Varlamov default: 10758780b81SKonstantin Varlamov return false; 10858780b81SKonstantin Varlamov } 109f6fd1c14SLouis Dionne } 110f6fd1c14SLouis Dionne 11158780b81SKonstantin Varlamov std::string ToString(DeathCause cause) { 11258780b81SKonstantin Varlamov switch (cause) { 11358780b81SKonstantin Varlamov case DeathCause::VerboseAbort: 11458780b81SKonstantin Varlamov return "verbose abort"; 11531452655SLouis Dionne case DeathCause::StdAbort: 11631452655SLouis Dionne return "`std::abort`"; 11758780b81SKonstantin Varlamov case DeathCause::StdTerminate: 11858780b81SKonstantin Varlamov return "`std::terminate`"; 11958780b81SKonstantin Varlamov case DeathCause::Trap: 12058780b81SKonstantin Varlamov return "trap"; 12158780b81SKonstantin Varlamov case DeathCause::DidNotDie: 12258780b81SKonstantin Varlamov return "<invalid cause (child did not die)>"; 12358780b81SKonstantin Varlamov case DeathCause::SetupFailure: 12458780b81SKonstantin Varlamov return "<invalid cause (child failed to set up test environment)>"; 12558780b81SKonstantin Varlamov case DeathCause::Unknown: 12658780b81SKonstantin Varlamov return "<invalid cause (cause unknown)>"; 12758780b81SKonstantin Varlamov } 12858780b81SKonstantin Varlamov 12958780b81SKonstantin Varlamov assert(false && "Unreachable"); 13058780b81SKonstantin Varlamov } 13158780b81SKonstantin Varlamov 13231452655SLouis Dionne template <std::size_t N> 13331452655SLouis Dionne std::string ToString(std::array<DeathCause, N> const& causes) { 13431452655SLouis Dionne std::stringstream ss; 13531452655SLouis Dionne ss << "{"; 13631452655SLouis Dionne for (std::size_t i = 0; i != N; ++i) { 13731452655SLouis Dionne ss << ToString(causes[i]); 13831452655SLouis Dionne if (i + 1 != N) 13931452655SLouis Dionne ss << ", "; 14031452655SLouis Dionne } 14131452655SLouis Dionne ss << "}"; 14231452655SLouis Dionne return ss.str(); 14331452655SLouis Dionne } 14431452655SLouis Dionne 145748023dcSNikolas Klauser [[noreturn]] void StopChildProcess(DeathCause cause) { std::exit(static_cast<int>(cause)); } 14658780b81SKonstantin Varlamov 14758780b81SKonstantin Varlamov DeathCause ConvertToDeathCause(int val) { 14858780b81SKonstantin Varlamov if (val < static_cast<int>(DeathCause::VerboseAbort) || val > static_cast<int>(DeathCause::Unknown)) { 14958780b81SKonstantin Varlamov return DeathCause::Unknown; 15058780b81SKonstantin Varlamov } 15158780b81SKonstantin Varlamov return static_cast<DeathCause>(val); 15258780b81SKonstantin Varlamov } 15358780b81SKonstantin Varlamov 15458780b81SKonstantin Varlamov enum class Outcome { 15558780b81SKonstantin Varlamov Success, 15658780b81SKonstantin Varlamov UnexpectedCause, 15758780b81SKonstantin Varlamov UnexpectedErrorMessage, 15858780b81SKonstantin Varlamov InvalidCause, 159f6fd1c14SLouis Dionne }; 160f6fd1c14SLouis Dionne 16158780b81SKonstantin Varlamov std::string ToString(Outcome outcome) { 16258780b81SKonstantin Varlamov switch (outcome) { 16358780b81SKonstantin Varlamov case Outcome::Success: 16458780b81SKonstantin Varlamov return "success"; 16558780b81SKonstantin Varlamov case Outcome::UnexpectedCause: 16658780b81SKonstantin Varlamov return "unexpected death cause"; 16758780b81SKonstantin Varlamov case Outcome::UnexpectedErrorMessage: 16858780b81SKonstantin Varlamov return "unexpected error message"; 16958780b81SKonstantin Varlamov case Outcome::InvalidCause: 17058780b81SKonstantin Varlamov return "invalid death cause"; 171f6fd1c14SLouis Dionne } 172f6fd1c14SLouis Dionne 17358780b81SKonstantin Varlamov assert(false && "Unreachable"); 174f6fd1c14SLouis Dionne } 175f6fd1c14SLouis Dionne 17658780b81SKonstantin Varlamov class DeathTestResult { 17758780b81SKonstantin Varlamov public: 17858780b81SKonstantin Varlamov DeathTestResult() = default; 17958780b81SKonstantin Varlamov DeathTestResult(Outcome set_outcome, DeathCause set_cause, const std::string& set_failure_description = "") 18058780b81SKonstantin Varlamov : outcome_(set_outcome), cause_(set_cause), failure_description_(set_failure_description) {} 18158780b81SKonstantin Varlamov 18258780b81SKonstantin Varlamov bool success() const { return outcome() == Outcome::Success; } 18358780b81SKonstantin Varlamov Outcome outcome() const { return outcome_; } 18458780b81SKonstantin Varlamov DeathCause cause() const { return cause_; } 18558780b81SKonstantin Varlamov const std::string& failure_description() const { return failure_description_; } 18658780b81SKonstantin Varlamov 18758780b81SKonstantin Varlamov private: 18858780b81SKonstantin Varlamov Outcome outcome_ = Outcome::Success; 18958780b81SKonstantin Varlamov DeathCause cause_ = DeathCause::Unknown; 19058780b81SKonstantin Varlamov std::string failure_description_; 19158780b81SKonstantin Varlamov }; 19258780b81SKonstantin Varlamov 19358780b81SKonstantin Varlamov class DeathTest { 19458780b81SKonstantin Varlamov public: 19558780b81SKonstantin Varlamov DeathTest() = default; 19658780b81SKonstantin Varlamov DeathTest(DeathTest const&) = delete; 19758780b81SKonstantin Varlamov DeathTest& operator=(DeathTest const&) = delete; 198f6fd1c14SLouis Dionne 19931452655SLouis Dionne template <std::size_t N, class Func> 20031452655SLouis Dionne DeathTestResult Run(const std::array<DeathCause, N>& expected_causes, Func&& func, const Matcher& matcher) { 20131452655SLouis Dionne std::signal(SIGABRT, [](int) { StopChildProcess(DeathCause::StdAbort); }); 20258780b81SKonstantin Varlamov std::set_terminate([] { StopChildProcess(DeathCause::StdTerminate); }); 20358780b81SKonstantin Varlamov 20458780b81SKonstantin Varlamov DeathCause cause = Run(func); 20558780b81SKonstantin Varlamov 20658780b81SKonstantin Varlamov if (!IsValidCause(cause)) { 20758780b81SKonstantin Varlamov return DeathTestResult(Outcome::InvalidCause, cause, ToString(cause)); 20858780b81SKonstantin Varlamov } 20958780b81SKonstantin Varlamov 21031452655SLouis Dionne if (std::find(expected_causes.begin(), expected_causes.end(), cause) == expected_causes.end()) { 21158780b81SKonstantin Varlamov std::stringstream failure_description; 21258780b81SKonstantin Varlamov failure_description // 21358780b81SKonstantin Varlamov << "Child died, but with a different death cause\n" // 21431452655SLouis Dionne << "Expected cause(s): " << ToString(expected_causes) << "\n" // 21558780b81SKonstantin Varlamov << "Actual cause: " << ToString(cause) << "\n"; 21658780b81SKonstantin Varlamov return DeathTestResult(Outcome::UnexpectedCause, cause, failure_description.str()); 21758780b81SKonstantin Varlamov } 21858780b81SKonstantin Varlamov 21958780b81SKonstantin Varlamov MatchResult match_result = matcher(GetChildStdErr()); 22058780b81SKonstantin Varlamov if (!match_result.first) { 22158780b81SKonstantin Varlamov auto failure_description = std::string("Child died, but with a different error message\n") + match_result.second; 22258780b81SKonstantin Varlamov return DeathTestResult(Outcome::UnexpectedErrorMessage, cause, failure_description); 22358780b81SKonstantin Varlamov } 22458780b81SKonstantin Varlamov 22558780b81SKonstantin Varlamov return DeathTestResult(Outcome::Success, cause); 22658780b81SKonstantin Varlamov } 22758780b81SKonstantin Varlamov 22858780b81SKonstantin Varlamov void PrintFailureDetails(std::string_view failure_description, std::string_view stmt, DeathCause cause) const { 22958780b81SKonstantin Varlamov std::fprintf( 23058780b81SKonstantin Varlamov stderr, "Failure: EXPECT_DEATH( %s ) failed!\n(reason: %s)\n\n", stmt.data(), failure_description.data()); 23158780b81SKonstantin Varlamov 23258780b81SKonstantin Varlamov if (cause != DeathCause::Unknown) { 23358780b81SKonstantin Varlamov std::fprintf(stderr, "child exit code: %d\n", GetChildExitCode()); 23458780b81SKonstantin Varlamov } 23558780b81SKonstantin Varlamov std::fprintf(stderr, "---------- standard err ----------\n%s", GetChildStdErr().c_str()); 23658780b81SKonstantin Varlamov std::fprintf(stderr, "\n----------------------------------\n"); 23758780b81SKonstantin Varlamov std::fprintf(stderr, "---------- standard out ----------\n%s", GetChildStdOut().c_str()); 23858780b81SKonstantin Varlamov std::fprintf(stderr, "\n----------------------------------\n"); 23958780b81SKonstantin Varlamov }; 24058780b81SKonstantin Varlamov 24158780b81SKonstantin Varlamov private: 24258780b81SKonstantin Varlamov int GetChildExitCode() const { return exit_code_; } 24358780b81SKonstantin Varlamov std::string const& GetChildStdOut() const { return stdout_from_child_; } 24458780b81SKonstantin Varlamov std::string const& GetChildStdErr() const { return stderr_from_child_; } 24558780b81SKonstantin Varlamov 24658780b81SKonstantin Varlamov template <class Func> 24758780b81SKonstantin Varlamov DeathCause Run(Func&& f) { 248f6fd1c14SLouis Dionne int pipe_res = pipe(stdout_pipe_fd_); 249f6fd1c14SLouis Dionne assert(pipe_res != -1 && "failed to create pipe"); 250f6fd1c14SLouis Dionne pipe_res = pipe(stderr_pipe_fd_); 251f6fd1c14SLouis Dionne assert(pipe_res != -1 && "failed to create pipe"); 252f6fd1c14SLouis Dionne pid_t child_pid = fork(); 25358780b81SKonstantin Varlamov assert(child_pid != -1 && "failed to fork a process to perform a death test"); 254f6fd1c14SLouis Dionne child_pid_ = child_pid; 255f6fd1c14SLouis Dionne if (child_pid_ == 0) { 256f6fd1c14SLouis Dionne RunForChild(std::forward<Func>(f)); 257f6fd1c14SLouis Dionne assert(false && "unreachable"); 258f6fd1c14SLouis Dionne } 259f6fd1c14SLouis Dionne return RunForParent(); 260f6fd1c14SLouis Dionne } 261f6fd1c14SLouis Dionne 262f6fd1c14SLouis Dionne template <class Func> 263748023dcSNikolas Klauser [[noreturn]] void RunForChild(Func&& f) { 264f6fd1c14SLouis Dionne close(GetStdOutReadFD()); // don't need to read from the pipe in the child. 265f6fd1c14SLouis Dionne close(GetStdErrReadFD()); 266f6fd1c14SLouis Dionne auto DupFD = [](int DestFD, int TargetFD) { 267f6fd1c14SLouis Dionne int dup_result = dup2(DestFD, TargetFD); 268f6fd1c14SLouis Dionne if (dup_result == -1) 26958780b81SKonstantin Varlamov StopChildProcess(DeathCause::SetupFailure); 270f6fd1c14SLouis Dionne }; 271f6fd1c14SLouis Dionne DupFD(GetStdOutWriteFD(), STDOUT_FILENO); 272f6fd1c14SLouis Dionne DupFD(GetStdErrWriteFD(), STDERR_FILENO); 273f6fd1c14SLouis Dionne 274f6fd1c14SLouis Dionne f(); 27558780b81SKonstantin Varlamov StopChildProcess(DeathCause::DidNotDie); 276f6fd1c14SLouis Dionne } 277f6fd1c14SLouis Dionne 278f6fd1c14SLouis Dionne static std::string ReadChildIOUntilEnd(int FD) { 279f6fd1c14SLouis Dionne std::string error_msg; 280f6fd1c14SLouis Dionne char buffer[256]; 281f6fd1c14SLouis Dionne int num_read; 282f6fd1c14SLouis Dionne do { 283f6fd1c14SLouis Dionne while ((num_read = read(FD, buffer, 255)) > 0) { 284f6fd1c14SLouis Dionne buffer[num_read] = '\0'; 285f6fd1c14SLouis Dionne error_msg += buffer; 286f6fd1c14SLouis Dionne } 287f6fd1c14SLouis Dionne } while (num_read == -1 && errno == EINTR); 288f6fd1c14SLouis Dionne return error_msg; 289f6fd1c14SLouis Dionne } 290f6fd1c14SLouis Dionne 291f6fd1c14SLouis Dionne void CaptureIOFromChild() { 292f6fd1c14SLouis Dionne close(GetStdOutWriteFD()); // no need to write from the parent process 293f6fd1c14SLouis Dionne close(GetStdErrWriteFD()); 294f6fd1c14SLouis Dionne stdout_from_child_ = ReadChildIOUntilEnd(GetStdOutReadFD()); 295f6fd1c14SLouis Dionne stderr_from_child_ = ReadChildIOUntilEnd(GetStdErrReadFD()); 296f6fd1c14SLouis Dionne close(GetStdOutReadFD()); 297f6fd1c14SLouis Dionne close(GetStdErrReadFD()); 298f6fd1c14SLouis Dionne } 299f6fd1c14SLouis Dionne 30058780b81SKonstantin Varlamov DeathCause RunForParent() { 301f6fd1c14SLouis Dionne CaptureIOFromChild(); 302f6fd1c14SLouis Dionne 303f6fd1c14SLouis Dionne int status_value; 304f6fd1c14SLouis Dionne pid_t result = waitpid(child_pid_, &status_value, 0); 305f6fd1c14SLouis Dionne assert(result != -1 && "there is no child process to wait for"); 306f6fd1c14SLouis Dionne 307f6fd1c14SLouis Dionne if (WIFEXITED(status_value)) { 308f6fd1c14SLouis Dionne exit_code_ = WEXITSTATUS(status_value); 30958780b81SKonstantin Varlamov return ConvertToDeathCause(exit_code_); 310f6fd1c14SLouis Dionne } 311f6fd1c14SLouis Dionne 31258780b81SKonstantin Varlamov if (WIFSIGNALED(status_value)) { 31358780b81SKonstantin Varlamov exit_code_ = WTERMSIG(status_value); 31458780b81SKonstantin Varlamov // `__builtin_trap` generqtes `SIGILL` on x86 and `SIGTRAP` on ARM. 31558780b81SKonstantin Varlamov if (exit_code_ == SIGILL || exit_code_ == SIGTRAP) { 31658780b81SKonstantin Varlamov return DeathCause::Trap; 31758780b81SKonstantin Varlamov } 318f6fd1c14SLouis Dionne } 319f6fd1c14SLouis Dionne 32058780b81SKonstantin Varlamov return DeathCause::Unknown; 321f6fd1c14SLouis Dionne } 322f6fd1c14SLouis Dionne 32358780b81SKonstantin Varlamov int GetStdOutReadFD() const { return stdout_pipe_fd_[0]; } 32458780b81SKonstantin Varlamov int GetStdOutWriteFD() const { return stdout_pipe_fd_[1]; } 32558780b81SKonstantin Varlamov int GetStdErrReadFD() const { return stderr_pipe_fd_[0]; } 32658780b81SKonstantin Varlamov int GetStdErrWriteFD() const { return stderr_pipe_fd_[1]; } 327f6fd1c14SLouis Dionne 328f6fd1c14SLouis Dionne pid_t child_pid_ = -1; 329f6fd1c14SLouis Dionne int exit_code_ = -1; 330f6fd1c14SLouis Dionne int stdout_pipe_fd_[2]; 331f6fd1c14SLouis Dionne int stderr_pipe_fd_[2]; 332f6fd1c14SLouis Dionne std::string stdout_from_child_; 333f6fd1c14SLouis Dionne std::string stderr_from_child_; 334f6fd1c14SLouis Dionne }; 335f6fd1c14SLouis Dionne 336aade7467SNikolas Klauser #ifdef _LIBCPP_VERSION 337*95483663SDoug Wyatt void std::__libcpp_verbose_abort(char const* format, ...) noexcept { 3388dfc67d6SKonstantin Varlamov va_list args; 33958780b81SKonstantin Varlamov va_start(args, format); 3407de5aca8SLouis Dionne 34158780b81SKonstantin Varlamov std::fprintf(stderr, "%s\n", Marker); 34258780b81SKonstantin Varlamov std::vfprintf(stderr, format, args); 34358780b81SKonstantin Varlamov std::fprintf(stderr, "%s", Marker); 3448dfc67d6SKonstantin Varlamov 34558780b81SKonstantin Varlamov va_end(args); 3468dfc67d6SKonstantin Varlamov 34758780b81SKonstantin Varlamov StopChildProcess(DeathCause::VerboseAbort); 348b0fd9497SLouis Dionne } 349aade7467SNikolas Klauser #endif // _LIBCPP_VERSION 350aade7467SNikolas Klauser 35131452655SLouis Dionne template <std::size_t N, class Func> 352888f2a58SLouis Dionne bool ExpectDeath( 353888f2a58SLouis Dionne const std::array<DeathCause, N>& expected_causes, const char* stmt, Func&& func, const Matcher& matcher) { 35431452655SLouis Dionne for (auto cause : expected_causes) 35531452655SLouis Dionne assert(IsValidCause(cause)); 35658780b81SKonstantin Varlamov 35758780b81SKonstantin Varlamov DeathTest test_case; 35831452655SLouis Dionne DeathTestResult test_result = test_case.Run(expected_causes, func, matcher); 35958780b81SKonstantin Varlamov if (!test_result.success()) { 36058780b81SKonstantin Varlamov test_case.PrintFailureDetails(test_result.failure_description(), stmt, test_result.cause()); 36158780b81SKonstantin Varlamov } 36258780b81SKonstantin Varlamov 36358780b81SKonstantin Varlamov return test_result.success(); 364aade7467SNikolas Klauser } 365b0fd9497SLouis Dionne 366f6fd1c14SLouis Dionne template <class Func> 36731452655SLouis Dionne bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func, const Matcher& matcher) { 36831452655SLouis Dionne return ExpectDeath(std::array<DeathCause, 1>{expected_cause}, stmt, func, matcher); 36931452655SLouis Dionne } 37031452655SLouis Dionne 37131452655SLouis Dionne template <std::size_t N, class Func> 37231452655SLouis Dionne bool ExpectDeath(const std::array<DeathCause, N>& expected_causes, const char* stmt, Func&& func) { 37331452655SLouis Dionne return ExpectDeath(expected_causes, stmt, func, MakeAnyMatcher()); 37431452655SLouis Dionne } 37531452655SLouis Dionne 37631452655SLouis Dionne template <class Func> 37758780b81SKonstantin Varlamov bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func) { 37831452655SLouis Dionne return ExpectDeath(std::array<DeathCause, 1>{expected_cause}, stmt, func, MakeAnyMatcher()); 379f6fd1c14SLouis Dionne } 380f6fd1c14SLouis Dionne 38158780b81SKonstantin Varlamov // clang-format off 382f6fd1c14SLouis Dionne 38358780b81SKonstantin Varlamov /// Assert that the specified expression aborts with the expected cause and, optionally, error message. 38431452655SLouis Dionne #define EXPECT_ANY_DEATH(...) \ 38531452655SLouis Dionne assert(( ExpectDeath(std::array<DeathCause, 4>{DeathCause::VerboseAbort, DeathCause::StdAbort, DeathCause::StdTerminate, DeathCause::Trap}, #__VA_ARGS__, [&]() { __VA_ARGS__; } ) )) 38658780b81SKonstantin Varlamov #define EXPECT_DEATH(...) \ 38758780b81SKonstantin Varlamov assert(( ExpectDeath(DeathCause::VerboseAbort, #__VA_ARGS__, [&]() { __VA_ARGS__; } ) )) 38858780b81SKonstantin Varlamov #define EXPECT_DEATH_MATCHES(matcher, ...) \ 38958780b81SKonstantin Varlamov assert(( ExpectDeath(DeathCause::VerboseAbort, #__VA_ARGS__, [&]() { __VA_ARGS__; }, matcher) )) 39031452655SLouis Dionne #define EXPECT_STD_ABORT(...) \ 39131452655SLouis Dionne assert( ExpectDeath(DeathCause::StdAbort, #__VA_ARGS__, [&]() { __VA_ARGS__; }) ) 39258780b81SKonstantin Varlamov #define EXPECT_STD_TERMINATE(...) \ 39358780b81SKonstantin Varlamov assert( ExpectDeath(DeathCause::StdTerminate, #__VA_ARGS__, __VA_ARGS__) ) 394f6fd1c14SLouis Dionne 3957918e624SLouis Dionne #if defined(_LIBCPP_HARDENING_MODE) && _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG 39658780b81SKonstantin Varlamov #define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \ 39758780b81SKonstantin Varlamov assert(( ExpectDeath(DeathCause::VerboseAbort, #expr, [&]() { (void)(expr); }, MakeAssertionMessageMatcher(message)) )) 39858780b81SKonstantin Varlamov #else 39958780b81SKonstantin Varlamov #define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \ 40058780b81SKonstantin Varlamov assert(( ExpectDeath(DeathCause::Trap, #expr, [&]() { (void)(expr); }) )) 40158780b81SKonstantin Varlamov #endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG 402aade7467SNikolas Klauser 40358780b81SKonstantin Varlamov // clang-format on 404f6fd1c14SLouis Dionne 405f6fd1c14SLouis Dionne #endif // TEST_SUPPORT_CHECK_ASSERTION_H 406