1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef TEST_SUPPORT_CHECK_ASSERTION_H
10 #define TEST_SUPPORT_CHECK_ASSERTION_H
24 #include <string_view>
32 #include "test_macros.h"
33 #include "test_allocator.h"
36 # error "C++11 or greater is required to use this header"
39 // When printing the assertion message to `stderr`, delimit it with a marker to make it easier to match the message
41 static constexpr const char* Marker
= "###";
43 // (success, error-message-if-failed)
44 using MatchResult
= std::pair
<bool, std::string
>;
45 using Matcher
= std::function
<MatchResult(const std::string
& /*text*/)>;
47 MatchResult
MatchAssertionMessage(const std::string
& text
, std::string_view expected_message
) {
48 // Extract information from the error message. This has to stay synchronized with how we format assertions in the
50 std::regex
assertion_format(".*###\\n(.*):(\\d+): assertion (.*) failed: (.*)\\n###");
52 std::smatch match_result
;
53 bool has_match
= std::regex_match(text
, match_result
, assertion_format
);
55 assert(match_result
.size() == 5);
57 const std::string
& file
= match_result
[1];
58 int line
= std::stoi(match_result
[2]);
59 // Omitting `expression` in `match_result[3]`
60 const std::string
& assertion_message
= match_result
[4];
62 bool result
= assertion_message
== expected_message
;
64 std::stringstream matching_error
;
66 << "Expected message: '" << expected_message
.data() << "'\n" //
67 << "Actual message: '" << assertion_message
.c_str() << "'\n" //
68 << "Source location: " << file
<< ":" << std::to_string(line
) << "\n";
69 return MatchResult(/*success=*/false, matching_error
.str());
72 return MatchResult(/*success=*/true, /*maybe_error=*/"");
75 Matcher
MakeAssertionMessageMatcher(std::string_view assertion_message
) {
76 return [=](const std::string
& text
) { //
77 return MatchAssertionMessage(text
, assertion_message
);
81 Matcher
MakeAnyMatcher() {
82 return [](const std::string
&) { //
83 return MatchResult(/*success=*/true, /*maybe_error=*/"");
87 enum class DeathCause
{
99 bool IsValidCause(DeathCause cause
) {
101 case DeathCause::VerboseAbort
:
102 case DeathCause::StdAbort
:
103 case DeathCause::StdTerminate
:
104 case DeathCause::Trap
:
111 std::string
ToString(DeathCause cause
) {
113 case DeathCause::VerboseAbort
:
114 return "verbose abort";
115 case DeathCause::StdAbort
:
116 return "`std::abort`";
117 case DeathCause::StdTerminate
:
118 return "`std::terminate`";
119 case DeathCause::Trap
:
121 case DeathCause::DidNotDie
:
122 return "<invalid cause (child did not die)>";
123 case DeathCause::SetupFailure
:
124 return "<invalid cause (child failed to set up test environment)>";
125 case DeathCause::Unknown
:
126 return "<invalid cause (cause unknown)>";
129 assert(false && "Unreachable");
132 template <std::size_t N
>
133 std::string
ToString(std::array
<DeathCause
, N
> const& causes
) {
134 std::stringstream ss
;
136 for (std::size_t i
= 0; i
!= N
; ++i
) {
137 ss
<< ToString(causes
[i
]);
145 [[noreturn
]] void StopChildProcess(DeathCause cause
) { std::exit(static_cast<int>(cause
)); }
147 DeathCause
ConvertToDeathCause(int val
) {
148 if (val
< static_cast<int>(DeathCause::VerboseAbort
) || val
> static_cast<int>(DeathCause::Unknown
)) {
149 return DeathCause::Unknown
;
151 return static_cast<DeathCause
>(val
);
157 UnexpectedErrorMessage
,
161 std::string
ToString(Outcome outcome
) {
163 case Outcome::Success
:
165 case Outcome::UnexpectedCause
:
166 return "unexpected death cause";
167 case Outcome::UnexpectedErrorMessage
:
168 return "unexpected error message";
169 case Outcome::InvalidCause
:
170 return "invalid death cause";
173 assert(false && "Unreachable");
176 class DeathTestResult
{
178 DeathTestResult() = default;
179 DeathTestResult(Outcome set_outcome
, DeathCause set_cause
, const std::string
& set_failure_description
= "")
180 : outcome_(set_outcome
), cause_(set_cause
), failure_description_(set_failure_description
) {}
182 bool success() const { return outcome() == Outcome::Success
; }
183 Outcome
outcome() const { return outcome_
; }
184 DeathCause
cause() const { return cause_
; }
185 const std::string
& failure_description() const { return failure_description_
; }
188 Outcome outcome_
= Outcome::Success
;
189 DeathCause cause_
= DeathCause::Unknown
;
190 std::string failure_description_
;
195 DeathTest() = default;
196 DeathTest(DeathTest
const&) = delete;
197 DeathTest
& operator=(DeathTest
const&) = delete;
199 template <std::size_t N
, class Func
>
200 DeathTestResult
Run(const std::array
<DeathCause
, N
>& expected_causes
, Func
&& func
, const Matcher
& matcher
) {
201 std::signal(SIGABRT
, [](int) { StopChildProcess(DeathCause::StdAbort
); });
202 std::set_terminate([] { StopChildProcess(DeathCause::StdTerminate
); });
204 DeathCause cause
= Run(func
);
206 if (!IsValidCause(cause
)) {
207 return DeathTestResult(Outcome::InvalidCause
, cause
, ToString(cause
));
210 if (std::find(expected_causes
.begin(), expected_causes
.end(), cause
) == expected_causes
.end()) {
211 std::stringstream failure_description
;
212 failure_description
//
213 << "Child died, but with a different death cause\n" //
214 << "Expected cause(s): " << ToString(expected_causes
) << "\n" //
215 << "Actual cause: " << ToString(cause
) << "\n";
216 return DeathTestResult(Outcome::UnexpectedCause
, cause
, failure_description
.str());
219 MatchResult match_result
= matcher(GetChildStdErr());
220 if (!match_result
.first
) {
221 auto failure_description
= std::string("Child died, but with a different error message\n") + match_result
.second
;
222 return DeathTestResult(Outcome::UnexpectedErrorMessage
, cause
, failure_description
);
225 return DeathTestResult(Outcome::Success
, cause
);
228 void PrintFailureDetails(std::string_view failure_description
, std::string_view stmt
, DeathCause cause
) const {
230 stderr
, "Failure: EXPECT_DEATH( %s ) failed!\n(reason: %s)\n\n", stmt
.data(), failure_description
.data());
232 if (cause
!= DeathCause::Unknown
) {
233 std::fprintf(stderr
, "child exit code: %d\n", GetChildExitCode());
235 std::fprintf(stderr
, "---------- standard err ----------\n%s", GetChildStdErr().c_str());
236 std::fprintf(stderr
, "\n----------------------------------\n");
237 std::fprintf(stderr
, "---------- standard out ----------\n%s", GetChildStdOut().c_str());
238 std::fprintf(stderr
, "\n----------------------------------\n");
242 int GetChildExitCode() const { return exit_code_
; }
243 std::string
const& GetChildStdOut() const { return stdout_from_child_
; }
244 std::string
const& GetChildStdErr() const { return stderr_from_child_
; }
246 template <class Func
>
247 DeathCause
Run(Func
&& f
) {
248 int pipe_res
= pipe(stdout_pipe_fd_
);
249 assert(pipe_res
!= -1 && "failed to create pipe");
250 pipe_res
= pipe(stderr_pipe_fd_
);
251 assert(pipe_res
!= -1 && "failed to create pipe");
252 pid_t child_pid
= fork();
253 assert(child_pid
!= -1 && "failed to fork a process to perform a death test");
254 child_pid_
= child_pid
;
255 if (child_pid_
== 0) {
256 RunForChild(std::forward
<Func
>(f
));
257 assert(false && "unreachable");
259 return RunForParent();
262 template <class Func
>
263 [[noreturn
]] void RunForChild(Func
&& f
) {
264 close(GetStdOutReadFD()); // don't need to read from the pipe in the child.
265 close(GetStdErrReadFD());
266 auto DupFD
= [](int DestFD
, int TargetFD
) {
267 int dup_result
= dup2(DestFD
, TargetFD
);
268 if (dup_result
== -1)
269 StopChildProcess(DeathCause::SetupFailure
);
271 DupFD(GetStdOutWriteFD(), STDOUT_FILENO
);
272 DupFD(GetStdErrWriteFD(), STDERR_FILENO
);
275 StopChildProcess(DeathCause::DidNotDie
);
278 static std::string
ReadChildIOUntilEnd(int FD
) {
279 std::string error_msg
;
283 while ((num_read
= read(FD
, buffer
, 255)) > 0) {
284 buffer
[num_read
] = '\0';
287 } while (num_read
== -1 && errno
== EINTR
);
291 void CaptureIOFromChild() {
292 close(GetStdOutWriteFD()); // no need to write from the parent process
293 close(GetStdErrWriteFD());
294 stdout_from_child_
= ReadChildIOUntilEnd(GetStdOutReadFD());
295 stderr_from_child_
= ReadChildIOUntilEnd(GetStdErrReadFD());
296 close(GetStdOutReadFD());
297 close(GetStdErrReadFD());
300 DeathCause
RunForParent() {
301 CaptureIOFromChild();
304 pid_t result
= waitpid(child_pid_
, &status_value
, 0);
305 assert(result
!= -1 && "there is no child process to wait for");
307 if (WIFEXITED(status_value
)) {
308 exit_code_
= WEXITSTATUS(status_value
);
309 return ConvertToDeathCause(exit_code_
);
312 if (WIFSIGNALED(status_value
)) {
313 exit_code_
= WTERMSIG(status_value
);
314 // `__builtin_trap` generqtes `SIGILL` on x86 and `SIGTRAP` on ARM.
315 if (exit_code_
== SIGILL
|| exit_code_
== SIGTRAP
) {
316 return DeathCause::Trap
;
320 return DeathCause::Unknown
;
323 int GetStdOutReadFD() const { return stdout_pipe_fd_
[0]; }
324 int GetStdOutWriteFD() const { return stdout_pipe_fd_
[1]; }
325 int GetStdErrReadFD() const { return stderr_pipe_fd_
[0]; }
326 int GetStdErrWriteFD() const { return stderr_pipe_fd_
[1]; }
328 pid_t child_pid_
= -1;
330 int stdout_pipe_fd_
[2];
331 int stderr_pipe_fd_
[2];
332 std::string stdout_from_child_
;
333 std::string stderr_from_child_
;
336 #ifdef _LIBCPP_VERSION
337 void std::__libcpp_verbose_abort(char const* format
, ...) noexcept
{
339 va_start(args
, format
);
341 std::fprintf(stderr
, "%s\n", Marker
);
342 std::vfprintf(stderr
, format
, args
);
343 std::fprintf(stderr
, "%s", Marker
);
347 StopChildProcess(DeathCause::VerboseAbort
);
349 #endif // _LIBCPP_VERSION
351 template <std::size_t N
, class Func
>
353 const std::array
<DeathCause
, N
>& expected_causes
, const char* stmt
, Func
&& func
, const Matcher
& matcher
) {
354 for (auto cause
: expected_causes
)
355 assert(IsValidCause(cause
));
358 DeathTestResult test_result
= test_case
.Run(expected_causes
, func
, matcher
);
359 if (!test_result
.success()) {
360 test_case
.PrintFailureDetails(test_result
.failure_description(), stmt
, test_result
.cause());
363 return test_result
.success();
366 template <class Func
>
367 bool ExpectDeath(DeathCause expected_cause
, const char* stmt
, Func
&& func
, const Matcher
& matcher
) {
368 return ExpectDeath(std::array
<DeathCause
, 1>{expected_cause
}, stmt
, func
, matcher
);
371 template <std::size_t N
, class Func
>
372 bool ExpectDeath(const std::array
<DeathCause
, N
>& expected_causes
, const char* stmt
, Func
&& func
) {
373 return ExpectDeath(expected_causes
, stmt
, func
, MakeAnyMatcher());
376 template <class Func
>
377 bool ExpectDeath(DeathCause expected_cause
, const char* stmt
, Func
&& func
) {
378 return ExpectDeath(std::array
<DeathCause
, 1>{expected_cause
}, stmt
, func
, MakeAnyMatcher());
383 /// Assert that the specified expression aborts with the expected cause and, optionally, error message.
384 #define EXPECT_ANY_DEATH(...) \
385 assert(( ExpectDeath(std::array<DeathCause, 4>{DeathCause::VerboseAbort, DeathCause::StdAbort, DeathCause::StdTerminate, DeathCause::Trap}, #__VA_ARGS__, [&]() { __VA_ARGS__; } ) ))
386 #define EXPECT_DEATH(...) \
387 assert(( ExpectDeath(DeathCause::VerboseAbort, #__VA_ARGS__, [&]() { __VA_ARGS__; } ) ))
388 #define EXPECT_DEATH_MATCHES(matcher, ...) \
389 assert(( ExpectDeath(DeathCause::VerboseAbort, #__VA_ARGS__, [&]() { __VA_ARGS__; }, matcher) ))
390 #define EXPECT_STD_ABORT(...) \
391 assert( ExpectDeath(DeathCause::StdAbort, #__VA_ARGS__, [&]() { __VA_ARGS__; }) )
392 #define EXPECT_STD_TERMINATE(...) \
393 assert( ExpectDeath(DeathCause::StdTerminate, #__VA_ARGS__, __VA_ARGS__) )
395 #if defined(_LIBCPP_HARDENING_MODE) && _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
396 #define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \
397 assert(( ExpectDeath(DeathCause::VerboseAbort, #expr, [&]() { (void)(expr); }, MakeAssertionMessageMatcher(message)) ))
399 #define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \
400 assert(( ExpectDeath(DeathCause::Trap, #expr, [&]() { (void)(expr); }) ))
401 #endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
405 #endif // TEST_SUPPORT_CHECK_ASSERTION_H