File: test_check_assertion.pass.cpp

package info (click to toggle)
llvm-toolchain-19 1%3A19.1.7-3~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 1,998,492 kB
  • sloc: cpp: 6,951,680; ansic: 1,486,157; asm: 913,598; python: 232,024; f90: 80,126; objc: 75,281; lisp: 37,276; pascal: 16,990; sh: 10,009; ml: 5,058; perl: 4,724; awk: 3,523; makefile: 3,167; javascript: 2,504; xml: 892; fortran: 664; cs: 573
file content (132 lines) | stat: -rw-r--r-- 4,895 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//===----------------------------------------------------------------------===//
//
// 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;
}