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
19 #include <string_view>
25 #include "test_macros.h"
26 #include "test_allocator.h"
29 # error "C++11 or greater is required to use this header"
32 struct AssertionInfoMatcher
{
33 static const int any_line
= -1;
34 static constexpr const char* any_file
= "*";
35 static constexpr const char* any_msg
= "*";
37 constexpr AssertionInfoMatcher() : is_empty_(true), msg_(any_msg
, __builtin_strlen(any_msg
)), file_(any_file
, __builtin_strlen(any_file
)), line_(any_line
) { }
38 constexpr AssertionInfoMatcher(const char* msg
, const char* file
= any_file
, int line
= any_line
)
39 : is_empty_(false), msg_(msg
, __builtin_strlen(msg
)), file_(file
, __builtin_strlen(file
)), line_(line
) {}
41 bool Matches(char const* file
, int line
, char const* message
) const {
42 assert(!empty() && "empty matcher");
44 if (CheckLineMatches(line
) && CheckFileMatches(file
) && CheckMessageMatches(message
))
46 // Write to stdout because that's the file descriptor captured by the parent
48 std::printf("Failed to match assertion info!\n%s\nVS\n%s:%d (%s)\n", ToString().data(), file
, line
, message
);
52 std::string
ToString() const {
53 std::string result
= "msg = \""; result
+= msg_
; result
+= "\"\n";
54 result
+= "line = " + (line_
== any_line
? "'*'" : std::to_string(line_
)) + "\n";
55 result
+= "file = " + (file_
== any_file
? "'*'" : std::string(file_
));
59 bool empty() const { return is_empty_
; }
61 bool CheckLineMatches(int got_line
) const {
62 if (line_
== any_line
)
64 return got_line
== line_
;
67 bool CheckFileMatches(std::string_view got_file
) const {
68 assert(!empty() && "empty matcher");
69 if (file_
== any_file
)
71 std::size_t found_at
= got_file
.find(file_
);
72 if (found_at
== std::string_view::npos
)
74 // require the match start at the beginning of the file or immediately after
75 // a directory separator.
77 char last_char
= got_file
[found_at
- 1];
78 if (last_char
!= '/' && last_char
!= '\\')
81 // require the match goes until the end of the string.
82 return got_file
.substr(found_at
) == file_
;
85 bool CheckMessageMatches(std::string_view got_msg
) const {
86 assert(!empty() && "empty matcher");
89 std::size_t found_at
= got_msg
.find(msg_
);
90 if (found_at
== std::string_view::npos
)
97 std::string_view msg_
;
98 std::string_view file_
;
102 static constexpr AssertionInfoMatcher
AnyMatcher(AssertionInfoMatcher::any_msg
);
104 inline AssertionInfoMatcher
& GlobalMatcher() {
105 static AssertionInfoMatcher GMatch
;
111 RK_DidNotDie
, RK_MatchFound
, RK_MatchFailure
, RK_Terminate
, RK_SetupFailure
, RK_Unknown
114 static const char* ResultKindToString(ResultKind RK
) {
115 #define CASE(K) case K: return #K
117 CASE(RK_MatchFailure
);
119 CASE(RK_SetupFailure
);
124 return "not a result kind";
127 static bool IsValidResultKind(int val
) {
128 return val
>= RK_DidNotDie
&& val
<= RK_Unknown
;
131 DeathTest(AssertionInfoMatcher
const& Matcher
) : matcher_(Matcher
) {}
133 template <class Func
>
134 ResultKind
Run(Func
&& f
) {
135 int pipe_res
= pipe(stdout_pipe_fd_
);
136 assert(pipe_res
!= -1 && "failed to create pipe");
137 pipe_res
= pipe(stderr_pipe_fd_
);
138 assert(pipe_res
!= -1 && "failed to create pipe");
139 pid_t child_pid
= fork();
140 assert(child_pid
!= -1 &&
141 "failed to fork a process to perform a death test");
142 child_pid_
= child_pid
;
143 if (child_pid_
== 0) {
144 RunForChild(std::forward
<Func
>(f
));
145 assert(false && "unreachable");
147 return RunForParent();
150 int getChildExitCode() const { return exit_code_
; }
151 std::string
const& getChildStdOut() const { return stdout_from_child_
; }
152 std::string
const& getChildStdErr() const { return stderr_from_child_
; }
154 template <class Func
>
155 TEST_NORETURN
void RunForChild(Func
&& f
) {
156 close(GetStdOutReadFD()); // don't need to read from the pipe in the child.
157 close(GetStdErrReadFD());
158 auto DupFD
= [](int DestFD
, int TargetFD
) {
159 int dup_result
= dup2(DestFD
, TargetFD
);
160 if (dup_result
== -1)
161 std::exit(RK_SetupFailure
);
163 DupFD(GetStdOutWriteFD(), STDOUT_FILENO
);
164 DupFD(GetStdErrWriteFD(), STDERR_FILENO
);
166 GlobalMatcher() = matcher_
;
168 std::exit(RK_DidNotDie
);
171 static std::string
ReadChildIOUntilEnd(int FD
) {
172 std::string error_msg
;
176 while ((num_read
= read(FD
, buffer
, 255)) > 0) {
177 buffer
[num_read
] = '\0';
180 } while (num_read
== -1 && errno
== EINTR
);
184 void CaptureIOFromChild() {
185 close(GetStdOutWriteFD()); // no need to write from the parent process
186 close(GetStdErrWriteFD());
187 stdout_from_child_
= ReadChildIOUntilEnd(GetStdOutReadFD());
188 stderr_from_child_
= ReadChildIOUntilEnd(GetStdErrReadFD());
189 close(GetStdOutReadFD());
190 close(GetStdErrReadFD());
193 ResultKind
RunForParent() {
194 CaptureIOFromChild();
197 pid_t result
= waitpid(child_pid_
, &status_value
, 0);
198 assert(result
!= -1 && "there is no child process to wait for");
200 if (WIFEXITED(status_value
)) {
201 exit_code_
= WEXITSTATUS(status_value
);
202 if (!IsValidResultKind(exit_code_
))
204 return static_cast<ResultKind
>(exit_code_
);
209 DeathTest(DeathTest
const&) = delete;
210 DeathTest
& operator=(DeathTest
const&) = delete;
212 int GetStdOutReadFD() const {
213 return stdout_pipe_fd_
[0];
216 int GetStdOutWriteFD() const {
217 return stdout_pipe_fd_
[1];
220 int GetStdErrReadFD() const {
221 return stderr_pipe_fd_
[0];
224 int GetStdErrWriteFD() const {
225 return stderr_pipe_fd_
[1];
228 AssertionInfoMatcher matcher_
;
229 pid_t child_pid_
= -1;
231 int stdout_pipe_fd_
[2];
232 int stderr_pipe_fd_
[2];
233 std::string stdout_from_child_
;
234 std::string stderr_from_child_
;
237 #ifdef _LIBCPP_VERSION
238 void std::__libcpp_verbose_abort(char const* format
, ...) {
239 // Extract information from the error message. This has to stay synchronized with
240 // how we format assertions in the library.
242 va_start(list
, format
);
243 char const* file
= va_arg(list
, char const*);
244 int line
= va_arg(list
, int);
245 char const* expression
= va_arg(list
, char const*); (void)expression
;
246 char const* message
= va_arg(list
, char const*);
249 if (GlobalMatcher().Matches(file
, line
, message
)) {
250 std::exit(DeathTest::RK_MatchFound
);
252 std::exit(DeathTest::RK_MatchFailure
);
254 #endif // _LIBCPP_VERSION
256 [[noreturn
]] inline void terminate_handler() {
257 std::exit(DeathTest::RK_Terminate
);
260 template <class Func
>
261 inline bool ExpectDeath(const char* stmt
, Func
&& func
, AssertionInfoMatcher Matcher
) {
262 std::set_terminate(terminate_handler
);
263 DeathTest
DT(Matcher
);
264 DeathTest::ResultKind RK
= DT
.Run(func
);
265 auto OnFailure
= [&](const char* msg
) {
266 std::fprintf(stderr
, "EXPECT_DEATH( %s ) failed! (%s)\n\n", stmt
, msg
);
267 if (RK
!= DeathTest::RK_Unknown
) {
268 std::fprintf(stderr
, "child exit code: %d\n", DT
.getChildExitCode());
270 if (!DT
.getChildStdErr().empty()) {
271 std::fprintf(stderr
, "---------- standard err ----------\n%s\n", DT
.getChildStdErr().c_str());
273 if (!DT
.getChildStdOut().empty()) {
274 std::fprintf(stderr
, "---------- standard out ----------\n%s\n", DT
.getChildStdOut().c_str());
279 case DeathTest::RK_MatchFound
:
280 case DeathTest::RK_Terminate
:
282 case DeathTest::RK_SetupFailure
:
283 return OnFailure("child failed to setup test environment");
284 case DeathTest::RK_Unknown
:
285 return OnFailure("reason unknown");
286 case DeathTest::RK_DidNotDie
:
287 return OnFailure("child did not die");
288 case DeathTest::RK_MatchFailure
:
289 return OnFailure("matcher failed");
291 assert(false && "unreachable");
294 template <class Func
>
295 inline bool ExpectDeath(const char* stmt
, Func
&& func
) {
296 return ExpectDeath(stmt
, func
, AnyMatcher
);
299 /// Assert that the specified expression throws a libc++ debug exception.
300 #define EXPECT_DEATH(...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; } )))
302 #define EXPECT_STD_TERMINATE(...) assert(ExpectDeath(#__VA_ARGS__, __VA_ARGS__))
304 #define EXPECT_DEATH_MATCHES(Matcher, ...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; }, Matcher)))
306 #define TEST_LIBCPP_ASSERT_FAILURE(expr, message) assert((ExpectDeath(#expr, [&]() { (void)(expr); }, AssertionInfoMatcher(message))))
308 #endif // TEST_SUPPORT_CHECK_ASSERTION_H