xref: /llvm-project/libcxx/test/support/check_assertion.h (revision 954836634abb446f18719b14120c386a929a42d1)
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