test.hpp 4.06 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
#ifndef RTG_GUARD_TEST_TEST_HPP
Paul's avatar
Paul committed
8
#define RTG_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
template <class T, class U, class Operator>
Paul's avatar
Paul committed
31
struct expression
Paul's avatar
Paul committed
32
{
Paul's avatar
Paul committed
33
34
35
36
    T lhs;
    U rhs;

    friend std::ostream& operator<<(std::ostream& s, const expression& self)
Paul's avatar
Paul committed
37
    {
Paul's avatar
Paul committed
38
39
        s << " [ " << self.lhs << " " << Operator::as_string() << " " << self.rhs << " ]";
        return s;
Paul's avatar
Paul committed
40
    }
Paul's avatar
Paul committed
41

Paul's avatar
Paul committed
42
43
44
    decltype(auto) value() const { return Operator::call(lhs, rhs); };
};

Paul's avatar
Paul committed
45
46
template <class T, class U, class Operator>
expression<typename std::decay<T>::type, typename std::decay<U>::type, Operator>
Paul's avatar
Paul committed
47
make_expression(T&& rhs, U&& lhs, Operator)
Paul's avatar
Paul committed
48
{
Paul's avatar
Paul committed
49
    return {std::forward<T>(rhs), std::forward<U>(lhs)};
Paul's avatar
Paul committed
50
}
Paul's avatar
Paul committed
51

Paul's avatar
Paul committed
52
template <class T>
Paul's avatar
Paul committed
53
54
struct lhs_expression;

Paul's avatar
Paul committed
55
template <class T>
Paul's avatar
Paul committed
56
57
lhs_expression<typename std::decay<T>::type> make_lhs_expression(T&& lhs)
{
Paul's avatar
Paul committed
58
    return lhs_expression<typename std::decay<T>::type>{std::forward<T>(lhs)};
Paul's avatar
Paul committed
59
60
}

Paul's avatar
Paul committed
61
template <class T>
Paul's avatar
Paul committed
62
63
64
struct lhs_expression
{
    T lhs;
Paul's avatar
Paul committed
65
    explicit lhs_expression(T e) : lhs(e) {}
Paul's avatar
Paul committed
66
67
68
69
70
71
72

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

Paul's avatar
Paul committed
73
    T value() const { return lhs; }
Paul's avatar
Paul committed
74
// NOLINTNEXTLINE
Paul's avatar
Paul committed
75
76
77
78
79
80
81
82
#define TEST_LHS_OPERATOR(op, name)               \
    template <class U>                            \
    auto operator op(const U& rhs) const          \
    {                                             \
        return make_expression(lhs, rhs, name{}); \
    } // NOLINT

    TEST_FOREACH_OPERATOR(TEST_LHS_OPERATOR)
Paul's avatar
Paul committed
83
// NOLINTNEXTLINE
Paul's avatar
Paul committed
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#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
99
100
};

Paul's avatar
Paul committed
101
struct capture
Paul's avatar
Paul committed
102
{
Paul's avatar
Paul committed
103
104
105
106
107
    template <class T>
    auto operator->*(const T& x)
    {
        return make_lhs_expression(x);
    }
Paul's avatar
Paul committed
108
109
};

Paul's avatar
Paul committed
110
template <class T, class F>
Paul's avatar
Paul committed
111
112
void failed(T x, const char* msg, const char* file, int line, F f)
{
Paul's avatar
Paul committed
113
    if(!x.value())
Paul's avatar
Paul committed
114
115
116
117
118
119
    {
        std::cout << file << ":" << line << ":" << std::endl;
        std::cout << "    FAILED: " << msg << " " << x << std::endl;
        f();
    }
}
Paul's avatar
Paul committed
120
121
122
123
124
125
126
127
128
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

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
156
157
158
} // namespace test

// NOLINTNEXTLINE
Paul's avatar
Paul committed
159
160
#define CHECK(...) \
    test::failed(test::capture{}->*__VA_ARGS__, #__VA_ARGS__, __FILE__, __LINE__, [] {})
Paul's avatar
Paul committed
161
// NOLINTNEXTLINE
Paul's avatar
Paul committed
162
163
#define EXPECT(...) \
    test::failed(test::capture{}->*__VA_ARGS__, #__VA_ARGS__, __FILE__, __LINE__, &std::abort)
Paul's avatar
Paul committed
164
165
166
// NOLINTNEXTLINE
#define STATUS(...) EXPECT((__VA_ARGS__) == 0)

Paul's avatar
Paul committed
167
#endif