"test/vscode:/vscode.git/clone" did not exist on "8b4c69c5be967176e580484fcc33cb13dfad004c"
test.hpp 6.54 KB
Newer Older
Paul's avatar
Paul committed
1
2
3
4
5

#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <iostream>
Paul's avatar
Paul committed
6
7
#include <unordered_map>
#include <vector>
Paul's avatar
Paul committed
8

Paul's avatar
Paul committed
9
10
#ifndef MIGRAPH_GUARD_TEST_TEST_HPP
#define MIGRAPH_GUARD_TEST_TEST_HPP
Paul's avatar
Paul committed
11

Paul's avatar
Paul committed
12
13
namespace test {
// NOLINTNEXTLINE
Paul's avatar
Paul committed
14
15
16
#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
17
18

// NOLINTNEXTLINE
Paul's avatar
Paul committed
19
20
21
22
23
24
25
26
27
28
#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
29

Paul's avatar
Paul committed
30
31
TEST_FOREACH_OPERATOR(TEST_EACH_OPERATOR_OBJECT)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Paul's avatar
Paul committed
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
using string_map = std::unordered_map<std::string, std::vector<std::string>>;

template <class Keyword>
string_map parse(std::vector<std::string> as, Keyword keyword)
{
    string_map result;

    std::string flag;
    for(auto&& x : as)
    {
        auto f = keyword(x);
        if(f.empty())
        {
            result[flag].push_back(x);
        }
        else
        {
            flag = f.front();
            result[flag]; // Ensure the flag exists
        }
    }
    return result;
}

inline auto& get_test_cases()
{
    static std::vector<std::pair<std::string, std::function<void()>>> cases;
    return cases;
}

inline void add_test_case(std::string name, std::function<void()> f)
{
    get_test_cases().emplace_back(name, f);
}

struct auto_register
{
Paul's avatar
Paul committed
196
197
198
199
    auto_register(std::string name, std::function<void()> f)
    {
        add_test_case(name, f);
    }
Paul's avatar
Paul committed
200
201
202
};

inline void run_test_case(std::string name, std::function<void()> f)
Paul's avatar
Paul committed
203
{
Paul's avatar
Paul committed
204
205
206
207
208
209
210
211
212
    std::cout << "[   RUN    ] " << name << std::endl;
    f();
    std::cout << "[ COMPLETE ] " << name << std::endl;
}

inline void run(int argc, const char* argv[])
{
    std::vector<std::string> as(argv + 1, argv + argc);

Paul's avatar
Paul committed
213
214
215
    auto args = parse(as, [](auto&&) -> std::vector<std::string> {
        return {};
    });
Paul's avatar
Paul committed
216
217
218
    auto cases = args[""];
    if(cases.empty())
    {
Paul's avatar
Paul committed
219
        for(auto&& tc:get_test_cases())
Paul's avatar
Paul committed
220
221
222
223
            run_test_case(tc.first, tc.second);
    }
    else
    {
Paul's avatar
Paul committed
224
225
        std::unordered_map<std::string, std::function<void()>> m(get_test_cases().begin(), get_test_cases().end());
        for(auto&& name:cases)
Paul's avatar
Paul committed
226
227
            run_test_case(name, m[name]);
    }
Paul's avatar
Paul committed
228
229
}

Paul's avatar
Paul committed
230
231
232
} // namespace test

// NOLINTNEXTLINE
Paul's avatar
Paul committed
233
234
235
236
#define CHECK(...)                                                                                 \
    test::failed(                                                                                  \
        test::capture{}->*__VA_ARGS__, #__VA_ARGS__, __PRETTY_FUNCTION__, __FILE__, __LINE__, [] { \
        })
Paul's avatar
Paul committed
237
// NOLINTNEXTLINE
Paul's avatar
Paul committed
238
239
240
241
242
243
244
#define EXPECT(...)                             \
    test::failed(test::capture{}->*__VA_ARGS__, \
                 #__VA_ARGS__,                  \
                 __PRETTY_FUNCTION__,           \
                 __FILE__,                      \
                 __LINE__,                      \
                 &std::abort)
Paul's avatar
Paul committed
245
246
247
// NOLINTNEXTLINE
#define STATUS(...) EXPECT((__VA_ARGS__) == 0)

Paul's avatar
Paul committed
248
249
250
251
252
// NOLINTNEXTLINE
#define TEST_CASE(...) \
    void __VA_ARGS__ (); \
    static test::auto_register __VA_ARGS__ ## _register = test::auto_register(#__VA_ARGS__, &__VA_ARGS__); \
    void __VA_ARGS__ ()
Paul's avatar
Paul committed
253
254
255
256
257
258

#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wglobal-constructors"
#endif

Paul's avatar
Paul committed
259
#endif