test.hpp 4.65 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>
Paul's avatar
Paul committed
54
make_expression(T&& rhs, U&& lhs, Operator)
Paul's avatar
Paul committed
55
{
Paul's avatar
Paul committed
56
    return {std::forward<T>(rhs), std::forward<U>(lhs)};
Paul's avatar
Paul committed
57
}
Paul's avatar
Paul committed
58

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

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

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

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

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

    TEST_FOREACH_OPERATOR(TEST_LHS_OPERATOR)
Paul's avatar
Paul committed
91
// NOLINTNEXTLINE
Paul's avatar
Paul committed
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#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
107
108
};

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

Paul's avatar
Paul committed
118
template <class T, class F>
Paul's avatar
Paul committed
119
void failed(T x, const char* msg, const char* func, const char* file, int line, F f)
Paul's avatar
Paul committed
120
{
Paul's avatar
Paul committed
121
    if(!x.value())
Paul's avatar
Paul committed
122
    {
Paul's avatar
Paul committed
123
        std::cout << func << std::endl;
Paul's avatar
Paul committed
124
125
126
127
128
        std::cout << file << ":" << line << ":" << std::endl;
        std::cout << "    FAILED: " << msg << " " << x << std::endl;
        f();
    }
}
Paul's avatar
Paul committed
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

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

template <class F, class Exception>
bool throws(F f, std::string msg = "")
{
    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
165
166
167
} // namespace test

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

Paul's avatar
Paul committed
183
#endif