aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/testing/gtest_extensions/assertions.h
blob: e8ea07b5df300082611582525f6bcd2bb9a89b4a (plain) (blame)
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
#pragma once

#include <util/generic/string.h>

#include <gtest/gtest.h>
#include <gmock/gmock.h>

/**
 * Check that the given statement throws an exception of the given type,
 * and that the thrown exception message contains the given substring.
 */
#define EXPECT_THROW_MESSAGE_HAS_SUBSTR(statement, expectedException, substring) \
    _Y_GTEST_EXPECT_THROW_MESSAGE_HAS_SUBSTR_IMPL_(statement, expectedException, substring, GTEST_NONFATAL_FAILURE_)

/**
 * Check that the given statement throws an exception of the given type,
 * and that the thrown exception message contains the given substring.
 */
#define ASSERT_THROW_MESSAGE_HAS_SUBSTR(statement, expectedException, substring) \
    _Y_GTEST_EXPECT_THROW_MESSAGE_HAS_SUBSTR_IMPL_(statement, expectedException, substring, GTEST_FATAL_FAILURE_)


// Improve default macros. New implementation shows better exception messages.
// See https://github.com/google/googletest/issues/2878

#undef EXPECT_THROW
#define EXPECT_THROW(statement, expectedException) \
    _Y_GTEST_EXPECT_THROW_IMPL_(statement, expectedException, GTEST_NONFATAL_FAILURE_)

#undef ASSERT_THROW
#define ASSERT_THROW(statement, expectedException) \
    _Y_GTEST_EXPECT_THROW_IMPL_(statement, expectedException, GTEST_FATAL_FAILURE_)

#undef EXPECT_NO_THROW
#define EXPECT_NO_THROW(statement) \
    _Y_GTEST_EXPECT_NO_THROW_IMPL_(statement, GTEST_NONFATAL_FAILURE_)

#undef ASSERT_NO_THROW
#define ASSERT_NO_THROW(statement) \
    _Y_GTEST_EXPECT_NO_THROW_IMPL_(statement, GTEST_FATAL_FAILURE_)


// Implementation details

namespace NGTest::NInternal {
    TString FormatErrorWrongException(const char* statement, const char* type);
    TString FormatErrorWrongException(const char* statement, const char* type, TString contains);
    TString FormatErrorUnexpectedException(const char* statement);
    bool ExceptionMessageContains(const std::exception& err, TString contains);
}

#define _Y_GTEST_EXPECT_THROW_IMPL_(statement, expectedException, fail)                                             \
    GTEST_AMBIGUOUS_ELSE_BLOCKER_                                                                                   \
    if (::TString gtestMsg = ""; ::testing::internal::AlwaysTrue()) {                                               \
        bool gtestCaughtExpected = false;                                                                           \
        try {                                                                                                       \
            GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement);                                              \
        } catch (expectedException const&) {                                                                        \
            gtestCaughtExpected = true;                                                                             \
        } catch (...) {                                                                                             \
            gtestMsg = ::NGTest::NInternal::FormatErrorWrongException(                                              \
                #statement, #expectedException);                                                                    \
            goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__);                                             \
        } if (!gtestCaughtExpected) {                                                                               \
            gtestMsg = ::NGTest::NInternal::FormatErrorWrongException(                                              \
                #statement, #expectedException);                                                                    \
            goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__);                                             \
        }                                                                                                           \
    } else                                                                                                          \
        GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__):                                                      \
            fail(gtestMsg.c_str())

#define _Y_GTEST_EXPECT_THROW_MESSAGE_HAS_SUBSTR_IMPL_(statement, expectedException, substring, fail)               \
    GTEST_AMBIGUOUS_ELSE_BLOCKER_                                                                                   \
    if (::TString gtestMsg = ""; ::testing::internal::AlwaysTrue()) {                                               \
        bool gtestCaughtExpected = false;                                                                           \
        ::TString gtestSubstring{substring};                                                                        \
        try {                                                                                                       \
            GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement);                                              \
        } catch (expectedException const& gtestError) {                                                             \
            if (!::NGTest::NInternal::ExceptionMessageContains(gtestError, gtestSubstring)) {                       \
                gtestMsg = ::NGTest::NInternal::FormatErrorWrongException(                                          \
                    #statement, #expectedException, gtestSubstring);                                                \
                goto GTEST_CONCAT_TOKEN_(gtest_label_testthrowsubstr_, __LINE__);                                   \
            }                                                                                                       \
            gtestCaughtExpected = true;                                                                             \
        } catch (...) {                                                                                             \
            gtestMsg = ::NGTest::NInternal::FormatErrorWrongException(                                              \
                #statement, #expectedException, gtestSubstring);                                                    \
            goto GTEST_CONCAT_TOKEN_(gtest_label_testthrowsubstr_, __LINE__);                                       \
        } if (!gtestCaughtExpected) {                                                                               \
            gtestMsg = ::NGTest::NInternal::FormatErrorWrongException(                                              \
                #statement, #expectedException, gtestSubstring);                                                    \
            goto GTEST_CONCAT_TOKEN_(gtest_label_testthrowsubstr_, __LINE__);                                       \
        }                                                                                                           \
    } else                                                                                                          \
        GTEST_CONCAT_TOKEN_(gtest_label_testthrowsubstr_, __LINE__):                                                \
            fail(gtestMsg.c_str())

#define _Y_GTEST_EXPECT_NO_THROW_IMPL_(statement, fail)                                                             \
    GTEST_AMBIGUOUS_ELSE_BLOCKER_                                                                                   \
    if (::TString gtestMsg = ""; ::testing::internal::AlwaysTrue()) {                                               \
        try {                                                                                                       \
            GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement);                                              \
        } catch (...) {                                                                                             \
            gtestMsg = ::NGTest::NInternal::FormatErrorUnexpectedException(#statement);                             \
            goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__);                                           \
        }                                                                                                           \
    } else                                                                                                          \
        GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__):                                                    \
            fail(gtestMsg.c_str())