[MemProf] Templatize CallStackRadixTreeBuilder (NFC) (#117014)
[llvm-project.git] / libcxx / test / support / check_assertion.h
bloba279400d651b48a5a3c73c8e105eca67fdef0d8c
1 //===----------------------------------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
9 #ifndef TEST_SUPPORT_CHECK_ASSERTION_H
10 #define TEST_SUPPORT_CHECK_ASSERTION_H
12 #include <array>
13 #include <cassert>
14 #include <csignal>
15 #include <cstdarg>
16 #include <cstddef>
17 #include <cstdio>
18 #include <cstdlib>
19 #include <exception>
20 #include <functional>
21 #include <regex>
22 #include <sstream>
23 #include <string>
24 #include <string_view>
25 #include <utility>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <signal.h>
30 #include <sys/wait.h>
32 #include "test_macros.h"
33 #include "test_allocator.h"
35 #if TEST_STD_VER < 11
36 # error "C++11 or greater is required to use this header"
37 #endif
39 // When printing the assertion message to `stderr`, delimit it with a marker to make it easier to match the message
40 // later.
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
49 // library.
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);
54 assert(has_match);
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;
63 if (!result) {
64 std::stringstream matching_error;
65 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 {
88 // Valid causes
89 VerboseAbort = 1,
90 StdAbort,
91 StdTerminate,
92 Trap,
93 // Invalid causes
94 DidNotDie,
95 SetupFailure,
96 Unknown
99 bool IsValidCause(DeathCause cause) {
100 switch (cause) {
101 case DeathCause::VerboseAbort:
102 case DeathCause::StdAbort:
103 case DeathCause::StdTerminate:
104 case DeathCause::Trap:
105 return true;
106 default:
107 return false;
111 std::string ToString(DeathCause cause) {
112 switch (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:
120 return "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;
135 ss << "{";
136 for (std::size_t i = 0; i != N; ++i) {
137 ss << ToString(causes[i]);
138 if (i + 1 != N)
139 ss << ", ";
141 ss << "}";
142 return ss.str();
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);
154 enum class Outcome {
155 Success,
156 UnexpectedCause,
157 UnexpectedErrorMessage,
158 InvalidCause,
161 std::string ToString(Outcome outcome) {
162 switch (outcome) {
163 case Outcome::Success:
164 return "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 {
177 public:
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_; }
187 private:
188 Outcome outcome_ = Outcome::Success;
189 DeathCause cause_ = DeathCause::Unknown;
190 std::string failure_description_;
193 class DeathTest {
194 public:
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 {
229 std::fprintf(
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");
241 private:
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);
274 f();
275 StopChildProcess(DeathCause::DidNotDie);
278 static std::string ReadChildIOUntilEnd(int FD) {
279 std::string error_msg;
280 char buffer[256];
281 int num_read;
282 do {
283 while ((num_read = read(FD, buffer, 255)) > 0) {
284 buffer[num_read] = '\0';
285 error_msg += buffer;
287 } while (num_read == -1 && errno == EINTR);
288 return error_msg;
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();
303 int status_value;
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;
329 int exit_code_ = -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 {
338 va_list args;
339 va_start(args, format);
341 std::fprintf(stderr, "%s\n", Marker);
342 std::vfprintf(stderr, format, args);
343 std::fprintf(stderr, "%s", Marker);
345 va_end(args);
347 StopChildProcess(DeathCause::VerboseAbort);
349 #endif // _LIBCPP_VERSION
351 template <std::size_t N, class Func>
352 bool ExpectDeath(
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));
357 DeathTest test_case;
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());
381 // clang-format off
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)) ))
398 #else
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
403 // clang-format on
405 #endif // TEST_SUPPORT_CHECK_ASSERTION_H