test.hpp 4.66 KB
Newer Older
Paul's avatar
Paul committed
1
2
3
4
5
6

#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <iostream>

Paul's avatar
Paul committed
7
8
#ifndef MIGRAPH_GUARD_TEST_TEST_HPP
#define MIGRAPH_GUARD_TEST_TEST_HPP
Paul's avatar
Paul committed
9

Paul's avatar
Paul committed
10
11
namespace test {
// NOLINTNEXTLINE
Paul's avatar
Paul committed
12
13
14
#define TEST_FOREACH_OPERATOR(m)                                                                   \
    m(==, equal) m(!=, not_equal) m(<=, less_than_equal) m(>=, greater_than_equal) m(<, less_than) \
        m(>, greater_than)
Paul's avatar
Paul committed
15
16

// NOLINTNEXTLINE
Paul's avatar
Paul committed
17
18
19
20
21
22
23
24
25
26
#define TEST_EACH_OPERATOR_OBJECT(op, name)            \
    struct name                                        \
    {                                                  \
        static std::string as_string() { return #op; } \
        template <class T, class U>                    \
        static decltype(auto) call(T&& x, U&& y)       \
        {                                              \
            return x op y;                             \
        }                                              \
    };
Paul's avatar
Paul committed
27

Paul's avatar
Paul committed
28
29
TEST_FOREACH_OPERATOR(TEST_EACH_OPERATOR_OBJECT)

Paul's avatar
Paul committed
30
31
32
33
34
35
inline std::ostream& operator<<(std::ostream& s, std::nullptr_t)
{
    s << "nullptr";
    return s;
}

Paul's avatar
Paul committed
36
template <class T, class U, class Operator>
Paul's avatar
Paul committed
37
struct expression
Paul's avatar
Paul committed
38
{
Paul's avatar
Paul committed
39
40
41
42
    T lhs;
    U rhs;

    friend std::ostream& operator<<(std::ostream& s, const expression& self)
Paul's avatar
Paul committed
43
    {
Paul's avatar
Paul committed
44
45
        s << " [ " << self.lhs << " " << Operator::as_string() << " " << self.rhs << " ]";
        return s;
Paul's avatar
Paul committed
46
    }
Paul's avatar
Paul committed
47

Paul's avatar
Paul committed
48
49
50
    decltype(auto) value() const { return Operator::call(lhs, rhs); };
};

Paul's avatar
Paul committed
51
// TODO: Remove rvalue references
Paul's avatar
Paul committed
52
template <class T, class U, class Operator>
Paul's avatar
Paul committed
53
expression<T, U, Operator> make_expression(T&& rhs, U&& lhs, Operator)
Paul's avatar
Paul committed
54
{
Paul's avatar
Paul committed
55
    return {std::forward<T>(rhs), std::forward<U>(lhs)};
Paul's avatar
Paul committed
56
}
Paul's avatar
Paul committed
57

Paul's avatar
Paul committed
58
template <class T>
Paul's avatar
Paul committed
59
60
struct lhs_expression;

Paul's avatar
Paul committed
61
// TODO: Remove rvalue reference
Paul's avatar
Paul committed
62
template <class T>
Paul's avatar
Paul committed
63
lhs_expression<T> make_lhs_expression(T&& lhs)
Paul's avatar
Paul committed
64
{
Paul's avatar
Paul committed
65
    return lhs_expression<T>{std::forward<T>(lhs)};
Paul's avatar
Paul committed
66
67
}

Paul's avatar
Paul committed
68
template <class T>
Paul's avatar
Paul committed
69
70
71
struct lhs_expression
{
    T lhs;
Paul's avatar
Paul committed
72
    explicit lhs_expression(T e) : lhs(e) {}
Paul's avatar
Paul committed
73
74
75
76
77
78
79

    friend std::ostream& operator<<(std::ostream& s, const lhs_expression& self)
    {
        s << self.lhs;
        return s;
    }

Paul's avatar
Paul committed
80
    T value() const { return lhs; }
Paul's avatar
Paul committed
81
// NOLINTNEXTLINE
Paul's avatar
Paul committed
82
83
84
85
#define TEST_LHS_OPERATOR(op, name)                            \
    template <class U>                                         \
    auto operator op(const U& rhs) const                       \
    {                                                          \
Paul's avatar
Paul committed
86
        return make_expression(lhs, rhs, name{}); /* NOLINT */ \
Paul's avatar
Paul committed
87
    }
Paul's avatar
Paul committed
88
89

    TEST_FOREACH_OPERATOR(TEST_LHS_OPERATOR)
Paul's avatar
Paul committed
90
// NOLINTNEXTLINE
Paul's avatar
Paul committed
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#define TEST_LHS_REOPERATOR(op)                 \
    template <class U>                          \
    auto operator op(const U& rhs) const        \
    {                                           \
        return make_lhs_expression(lhs op rhs); \
    }
    TEST_LHS_REOPERATOR(+)
    TEST_LHS_REOPERATOR(-)
    TEST_LHS_REOPERATOR(*)
    TEST_LHS_REOPERATOR(/)
    TEST_LHS_REOPERATOR(%)
    TEST_LHS_REOPERATOR(&)
    TEST_LHS_REOPERATOR(|)
    TEST_LHS_REOPERATOR(&&)
    TEST_LHS_REOPERATOR(||)
Paul's avatar
Paul committed
106
107
};

Paul's avatar
Paul committed
108
struct capture
Paul's avatar
Paul committed
109
{
Paul's avatar
Paul committed
110
111
112
113
114
    template <class T>
    auto operator->*(const T& x)
    {
        return make_lhs_expression(x);
    }
Paul's avatar
Paul committed
115
116
};

Paul's avatar
Paul committed
117
template <class T, class F>
Paul's avatar
Paul committed
118
void failed(T x, const char* msg, const char* func, const char* file, int line, F f)
Paul's avatar
Paul committed
119
{
Paul's avatar
Paul committed
120
    if(!x.value())
Paul's avatar
Paul committed
121
    {
Paul's avatar
Paul committed
122
        std::cout << func << std::endl;
Paul's avatar
Paul committed
123
124
125
126
127
        std::cout << file << ":" << line << ":" << std::endl;
        std::cout << "    FAILED: " << msg << " " << x << std::endl;
        f();
    }
}
Paul's avatar
Paul committed
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

template <class F>
bool throws(F f)
{
    try
    {
        f();
        return false;
    }
    catch(...)
    {
        return true;
    }
}

Khalique's avatar
Khalique committed
143
template <class Exception, class F>
Paul's avatar
Paul committed
144
bool throws(F f, const std::string& msg = "")
Paul's avatar
Paul committed
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
{
    try
    {
        f();
        return false;
    }
    catch(const Exception& ex)
    {
        return std::string(ex.what()).find(msg) != std::string::npos;
    }
}

template <class T>
void run_test()
{
    T t = {};
    t.run();
}

Paul's avatar
Paul committed
164
165
166
} // namespace test

// NOLINTNEXTLINE
Paul's avatar
Paul committed
167
168
169
170
#define CHECK(...)                                                                                 \
    test::failed(                                                                                  \
        test::capture{}->*__VA_ARGS__, #__VA_ARGS__, __PRETTY_FUNCTION__, __FILE__, __LINE__, [] { \
        })
Paul's avatar
Paul committed
171
// NOLINTNEXTLINE
Paul's avatar
Paul committed
172
173
174
175
176
177
178
#define EXPECT(...)                             \
    test::failed(test::capture{}->*__VA_ARGS__, \
                 #__VA_ARGS__,                  \
                 __PRETTY_FUNCTION__,           \
                 __FILE__,                      \
                 __LINE__,                      \
                 &std::abort)
Paul's avatar
Paul committed
179
180
181
// NOLINTNEXTLINE
#define STATUS(...) EXPECT((__VA_ARGS__) == 0)

Paul's avatar
Paul committed
182
#endif