//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-hardening-mode=none
// XFAIL: availability-verbose_abort-missing
#include <cassert>
#include <cstdio>
#include <string>
#include "check_assertion.h"
template <class Func>
bool TestDeathTest(
Outcome expected_outcome, DeathCause expected_cause, const char* stmt, Func&& func, const Matcher& matcher) {
auto get_matcher = [&] {
#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
return matcher;
#else
(void)matcher;
return MakeAnyMatcher();
#endif
};
DeathTest test_case;
DeathTestResult test_result = test_case.Run(std::array<DeathCause, 1>{expected_cause}, func, get_matcher());
std::string maybe_failure_description;
Outcome outcome = test_result.outcome();
if (expected_outcome != outcome) {
maybe_failure_description +=
std::string("Test outcome was different from expected; expected ") + ToString(expected_outcome) +
", got: " + ToString(outcome);
}
DeathCause cause = test_result.cause();
if (expected_cause != cause) {
auto failure_description =
std::string("Cause of death was different from expected; expected ") + ToString(expected_cause) +
", got: " + ToString(cause);
if (maybe_failure_description.empty()) {
maybe_failure_description = failure_description;
} else {
maybe_failure_description += std::string("; ") + failure_description;
}
}
if (!maybe_failure_description.empty()) {
test_case.PrintFailureDetails(maybe_failure_description, stmt, test_result.cause());
return false;
}
return true;
}
// clang-format off
#define TEST_DEATH_TEST(outcome, cause, ...) \
assert(( TestDeathTest(outcome, cause, #__VA_ARGS__, [&]() { __VA_ARGS__; }, MakeAnyMatcher()) ))
#define TEST_DEATH_TEST_MATCHES(outcome, cause, matcher, ...) \
assert(( TestDeathTest(outcome, cause, #__VA_ARGS__, [&]() { __VA_ARGS__; }, matcher) ))
// clang-format on
#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
DeathCause assertion_death_cause = DeathCause::VerboseAbort;
#else
DeathCause assertion_death_cause = DeathCause::Trap;
#endif
int main(int, char**) {
auto fail_assert = [] { _LIBCPP_ASSERT(false, "Some message"); };
Matcher good_matcher = MakeAssertionMessageMatcher("Some message");
Matcher bad_matcher = MakeAssertionMessageMatcher("Bad expected message");
// Test the implementation of death tests. We're bypassing the assertions added by the actual `EXPECT_DEATH` macros
// which allows us to test failure cases (where the assertion would fail) as well.
{
// Success -- `std::terminate`.
TEST_DEATH_TEST(Outcome::Success, DeathCause::StdTerminate, std::terminate());
// Success -- trapping.
TEST_DEATH_TEST(Outcome::Success, DeathCause::Trap, __builtin_trap());
// Success -- assertion failure with any matcher.
TEST_DEATH_TEST_MATCHES(Outcome::Success, assertion_death_cause, MakeAnyMatcher(), fail_assert());
// Success -- assertion failure with a specific matcher.
TEST_DEATH_TEST_MATCHES(Outcome::Success, assertion_death_cause, good_matcher, fail_assert());
#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
// Failure -- error message doesn't match.
TEST_DEATH_TEST_MATCHES(Outcome::UnexpectedErrorMessage, assertion_death_cause, bad_matcher, fail_assert());
#endif
// Invalid cause -- child did not die.
TEST_DEATH_TEST(Outcome::InvalidCause, DeathCause::DidNotDie, ((void)0));
// Invalid cause -- unknown.
TEST_DEATH_TEST(Outcome::InvalidCause, DeathCause::Unknown, std::exit(13));
}
// Test the `EXPECT_DEATH` macros themselves. Since they assert success, we can only test successful cases.
{
auto invoke_verbose_abort = [] { _LIBCPP_VERBOSE_ABORT("contains some message"); };
auto invoke_abort = [] { std::abort(); };
auto simple_matcher = [](const std::string& text) {
bool success = text.find("some") != std::string::npos;
return MatchResult(success, "");
};
EXPECT_ANY_DEATH(_LIBCPP_VERBOSE_ABORT(""));
EXPECT_ANY_DEATH(std::abort());
EXPECT_ANY_DEATH(std::terminate());
EXPECT_DEATH(invoke_verbose_abort());
EXPECT_DEATH_MATCHES(MakeAnyMatcher(), invoke_verbose_abort());
EXPECT_DEATH_MATCHES(simple_matcher, invoke_verbose_abort());
EXPECT_STD_ABORT(invoke_abort());
EXPECT_STD_TERMINATE([] { std::terminate(); });
TEST_LIBCPP_ASSERT_FAILURE(fail_assert(), "Some message");
}
return 0;
}