| 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 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | // REQUIRES: has-unix-headers |
| 10 | // UNSUPPORTED: c++03 |
| 11 | // UNSUPPORTED: libcpp-hardening-mode=none |
| 12 | // XFAIL: availability-verbose_abort-missing |
| 13 | |
| 14 | #include <cassert> |
| 15 | #include <cstdio> |
| 16 | #include <string> |
| 17 | |
| 18 | #include "check_assertion.h" |
| 19 | |
| 20 | template <class Func> |
| 21 | bool TestDeathTest( |
| 22 | Outcome expected_outcome, DeathCause expected_cause, const char* stmt, Func&& func, const Matcher& matcher) { |
| 23 | auto get_matcher = [&] { |
| 24 | #if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG |
| 25 | return matcher; |
| 26 | #else |
| 27 | (void)matcher; |
| 28 | return MakeAnyMatcher(); |
| 29 | #endif |
| 30 | }; |
| 31 | |
| 32 | DeathTest test_case; |
| 33 | DeathTestResult test_result = test_case.Run(std::array<DeathCause, 1>{expected_cause}, func, get_matcher()); |
| 34 | std::string maybe_failure_description; |
| 35 | |
| 36 | Outcome outcome = test_result.outcome(); |
| 37 | if (expected_outcome != outcome) { |
| 38 | maybe_failure_description += |
| 39 | std::string("Test outcome was different from expected; expected " ) + ToString(expected_outcome) + |
| 40 | ", got: " + ToString(outcome); |
| 41 | } |
| 42 | |
| 43 | DeathCause cause = test_result.cause(); |
| 44 | if (expected_cause != cause) { |
| 45 | auto failure_description = |
| 46 | std::string("Cause of death was different from expected; expected " ) + ToString(expected_cause) + |
| 47 | ", got: " + ToString(cause); |
| 48 | if (maybe_failure_description.empty()) { |
| 49 | maybe_failure_description = failure_description; |
| 50 | } else { |
| 51 | maybe_failure_description += std::string("; " ) + failure_description; |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | if (!maybe_failure_description.empty()) { |
| 56 | test_case.PrintFailureDetails(maybe_failure_description, stmt, test_result.cause()); |
| 57 | return false; |
| 58 | } |
| 59 | |
| 60 | return true; |
| 61 | } |
| 62 | |
| 63 | // clang-format off |
| 64 | |
| 65 | #define TEST_DEATH_TEST(outcome, cause, ...) \ |
| 66 | assert(( TestDeathTest(outcome, cause, #__VA_ARGS__, [&]() { __VA_ARGS__; }, MakeAnyMatcher()) )) |
| 67 | #define TEST_DEATH_TEST_MATCHES(outcome, cause, matcher, ...) \ |
| 68 | assert(( TestDeathTest(outcome, cause, #__VA_ARGS__, [&]() { __VA_ARGS__; }, matcher) )) |
| 69 | |
| 70 | // clang-format on |
| 71 | |
| 72 | #if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG |
| 73 | DeathCause assertion_death_cause = DeathCause::VerboseAbort; |
| 74 | #else |
| 75 | DeathCause assertion_death_cause = DeathCause::Trap; |
| 76 | #endif |
| 77 | |
| 78 | int main(int, char**) { |
| 79 | auto fail_assert = [] { _LIBCPP_ASSERT(false, "Some message" ); }; |
| 80 | Matcher good_matcher = MakeAssertionMessageMatcher("Some message" ); |
| 81 | Matcher bad_matcher = MakeAssertionMessageMatcher("Bad expected message" ); |
| 82 | |
| 83 | // Test the implementation of death tests. We're bypassing the assertions added by the actual `EXPECT_DEATH` macros |
| 84 | // which allows us to test failure cases (where the assertion would fail) as well. |
| 85 | { |
| 86 | // Success -- `std::terminate`. |
| 87 | TEST_DEATH_TEST(Outcome::Success, DeathCause::StdTerminate, std::terminate()); |
| 88 | |
| 89 | // Success -- trapping. |
| 90 | TEST_DEATH_TEST(Outcome::Success, DeathCause::Trap, __builtin_trap()); |
| 91 | |
| 92 | // Success -- assertion failure with any matcher. |
| 93 | TEST_DEATH_TEST_MATCHES(Outcome::Success, assertion_death_cause, MakeAnyMatcher(), fail_assert()); |
| 94 | |
| 95 | // Success -- assertion failure with a specific matcher. |
| 96 | TEST_DEATH_TEST_MATCHES(Outcome::Success, assertion_death_cause, good_matcher, fail_assert()); |
| 97 | |
| 98 | #if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG |
| 99 | // Failure -- error message doesn't match. |
| 100 | TEST_DEATH_TEST_MATCHES(Outcome::UnexpectedErrorMessage, assertion_death_cause, bad_matcher, fail_assert()); |
| 101 | #endif |
| 102 | |
| 103 | // Invalid cause -- child did not die. |
| 104 | TEST_DEATH_TEST(Outcome::InvalidCause, DeathCause::DidNotDie, ((void)0)); |
| 105 | |
| 106 | // Invalid cause -- unknown. |
| 107 | TEST_DEATH_TEST(Outcome::InvalidCause, DeathCause::Unknown, std::exit(13)); |
| 108 | } |
| 109 | |
| 110 | // Test the `EXPECT_DEATH` macros themselves. Since they assert success, we can only test successful cases. |
| 111 | { |
| 112 | auto invoke_verbose_abort = [] { _LIBCPP_VERBOSE_ABORT("contains some message" ); }; |
| 113 | auto invoke_abort = [] { std::abort(); }; |
| 114 | |
| 115 | auto simple_matcher = [](const std::string& text) { |
| 116 | bool success = text.find(s: "some" ) != std::string::npos; |
| 117 | return MatchResult(success, "" ); |
| 118 | }; |
| 119 | |
| 120 | EXPECT_ANY_DEATH(_LIBCPP_VERBOSE_ABORT("" )); |
| 121 | EXPECT_ANY_DEATH(std::abort()); |
| 122 | EXPECT_ANY_DEATH(std::terminate()); |
| 123 | EXPECT_DEATH(invoke_verbose_abort()); |
| 124 | EXPECT_DEATH_MATCHES(MakeAnyMatcher(), invoke_verbose_abort()); |
| 125 | EXPECT_DEATH_MATCHES(simple_matcher, invoke_verbose_abort()); |
| 126 | EXPECT_STD_ABORT(invoke_abort()); |
| 127 | EXPECT_STD_TERMINATE([] { std::terminate(); }); |
| 128 | TEST_LIBCPP_ASSERT_FAILURE(fail_assert(), "Some message" ); |
| 129 | } |
| 130 | |
| 131 | return 0; |
| 132 | } |
| 133 | |