summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibTest/Macros.h
blob: 9c084e46a330b65dcab9071453700c5e42decdcc (plain)
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
/*
 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
 * Copyright (c) 2021, Andrew Kaster <akaster@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/Assertions.h>
#include <AK/CheckedFormatString.h>
#include <AK/Math.h>
#include <LibTest/CrashTest.h>

namespace AK {
template<typename... Parameters>
void warnln(CheckedFormatString<Parameters...>&& fmtstr, const Parameters&...);
}

namespace Test {
// Declare a helper so that we can call it from VERIFY in included headers
void current_test_case_did_fail();
}

#undef VERIFY
#define VERIFY(x)                                                                                    \
    do {                                                                                             \
        if (!(x)) {                                                                                  \
            ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: VERIFY({}) failed", __FILE__, __LINE__, #x); \
            ::Test::current_test_case_did_fail();                                                    \
        }                                                                                            \
    } while (false)

#undef VERIFY_NOT_REACHED
#define VERIFY_NOT_REACHED()                                                                           \
    do {                                                                                               \
        ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: VERIFY_NOT_REACHED() called", __FILE__, __LINE__); \
        ::abort();                                                                                     \
    } while (false)

#undef TODO
#define TODO()                                                                           \
    do {                                                                                 \
        ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: TODO() called", __FILE__, __LINE__); \
        ::abort();                                                                       \
    } while (false)

#define EXPECT_EQ(a, b)                                                                                                                                                                      \
    do {                                                                                                                                                                                     \
        auto lhs = (a);                                                                                                                                                                      \
        auto rhs = (b);                                                                                                                                                                      \
        if (lhs != rhs) {                                                                                                                                                                    \
            ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: EXPECT_EQ({}, {}) failed with lhs={} and rhs={}", __FILE__, __LINE__, #a, #b, FormatIfSupported { lhs }, FormatIfSupported { rhs }); \
            ::Test::current_test_case_did_fail();                                                                                                                                            \
        }                                                                                                                                                                                    \
    } while (false)

// If you're stuck and `EXPECT_EQ` seems to refuse to print anything useful,
// try this: It'll spit out a nice compiler error telling you why it doesn't print.
#define EXPECT_EQ_FORCE(a, b)                                                                                                                    \
    do {                                                                                                                                         \
        auto lhs = (a);                                                                                                                          \
        auto rhs = (b);                                                                                                                          \
        if (lhs != rhs) {                                                                                                                        \
            ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: EXPECT_EQ({}, {}) failed with lhs={} and rhs={}", __FILE__, __LINE__, #a, #b, lhs, rhs); \
            ::Test::current_test_case_did_fail();                                                                                                \
        }                                                                                                                                        \
    } while (false)

#define EXPECT_NE(a, b)                                                                                                                                                                      \
    do {                                                                                                                                                                                     \
        auto lhs = (a);                                                                                                                                                                      \
        auto rhs = (b);                                                                                                                                                                      \
        if (lhs == rhs) {                                                                                                                                                                    \
            ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: EXPECT_NE({}, {}) failed with lhs={} and rhs={}", __FILE__, __LINE__, #a, #b, FormatIfSupported { lhs }, FormatIfSupported { rhs }); \
            ::Test::current_test_case_did_fail();                                                                                                                                            \
        }                                                                                                                                                                                    \
    } while (false)

#define EXPECT(x)                                                                                    \
    do {                                                                                             \
        if (!(x)) {                                                                                  \
            ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: EXPECT({}) failed", __FILE__, __LINE__, #x); \
            ::Test::current_test_case_did_fail();                                                    \
        }                                                                                            \
    } while (false)

#define EXPECT_APPROXIMATE(a, b)                                                                                \
    do {                                                                                                        \
        auto expect_close_lhs = a;                                                                              \
        auto expect_close_rhs = b;                                                                              \
        auto expect_close_diff = static_cast<double>(expect_close_lhs) - static_cast<double>(expect_close_rhs); \
        if (AK::fabs(expect_close_diff) > 0.0000005) {                                                          \
            ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: EXPECT_APPROXIMATE({}, {})"                             \
                         " failed with lhs={}, rhs={}, (lhs-rhs)={}",                                           \
                __FILE__, __LINE__, #a, #b, expect_close_lhs, expect_close_rhs, expect_close_diff);             \
            ::Test::current_test_case_did_fail();                                                               \
        }                                                                                                       \
    } while (false)

#define FAIL(message)                                                                  \
    do {                                                                               \
        ::AK::warnln("\033[31;1mFAIL\033[0m: {}:{}: {}", __FILE__, __LINE__, message); \
        ::Test::current_test_case_did_fail();                                          \
    } while (false)

// To use, specify the lambda to execute in a sub process and verify it exits:
//  EXPECT_CRASH("This should fail", []{
//      return Test::Crash::Failure::DidNotCrash;
//  });
#define EXPECT_CRASH(test_message, test_func)       \
    do {                                            \
        Test::Crash crash(test_message, test_func); \
        if (!crash.run())                           \
            ::Test::current_test_case_did_fail();   \
    } while (false)