]> git.stg.codes - stg.git/blob - tests/tut/tut_assert.hpp
More std::jthread
[stg.git] / tests / tut / tut_assert.hpp
1 #ifndef TUT_ASSERT_H_GUARD
2 #define TUT_ASSERT_H_GUARD
3 #include <tut/tut_config.hpp>
4
5 #include <limits>
6 #include <iomanip>
7 #include <iterator>
8 #include <cassert>
9 #include <cmath>
10
11 #if defined(TUT_USE_POSIX)
12 #include <errno.h>
13 #include <cstring>
14 #endif
15
16 #include "tut_exception.hpp"
17
18 namespace tut
19 {
20
21     namespace detail
22     {
23         template<typename M>
24         std::ostringstream &msg_prefix(std::ostringstream &str, const M &msg)
25         {
26             std::ostringstream ss;
27             ss << msg;
28
29             if(!ss.str().empty())
30             {
31                 str << msg << ": ";
32             }
33
34             return str;
35         }
36     }
37
38
39 namespace
40 {
41
42 /**
43  * Tests provided condition.
44  * Throws if false.
45  */
46 void ensure(bool cond)
47 {
48     if (!cond)
49     {
50         // TODO: default ctor?
51         throw failure("");
52     }
53 }
54
55 /**
56  * Tests provided condition.
57  * Throws if true.
58  */
59 void ensure_not(bool cond)
60 {
61     ensure(!cond);
62 }
63
64 /**
65  * Tests provided condition.
66  * Throws if false.
67  */
68 template <typename M>
69 void ensure(const M& msg, bool cond)
70 {
71     if (!cond)
72     {
73         throw failure(msg);
74     }
75 }
76
77 /**
78  * Tests provided condition.
79  * Throws if true.
80  */
81 template <typename M>
82 void ensure_not(const M& msg, bool cond)
83 {
84     ensure(msg, !cond);
85 }
86
87 /**
88  * Tests two objects for being equal.
89  * Throws if false.
90  *
91  * NB: both LHS and RHS must have operator << defined somewhere, or
92  * client code will not compile at all!
93  */
94 template <typename M, typename LHS, typename RHS>
95 void ensure_equals(const M& msg, const LHS& actual, const RHS& expected)
96 {
97     if (expected != actual)
98     {
99         std::ostringstream ss;
100         detail::msg_prefix(ss,msg)
101            << "expected `"
102            << expected
103            << "` actual `"
104            << actual
105            << "`";
106         throw failure(ss.str());
107     }
108 }
109
110 /**
111  * Tests two pointers for being equal.
112  * Throws if false.
113  *
114  * NB: both T and Q must have operator << defined somewhere, or
115  * client code will not compile at all!
116  */
117 template <typename M, typename LHS, typename RHS>
118 void ensure_equals(const M& msg, const LHS * const actual, const RHS * const expected)
119 {
120     if (expected != actual)
121     {
122         std::ostringstream ss;
123         detail::msg_prefix(ss,msg)
124            << "expected `"
125            << (void*)expected
126            << "` actual `"
127            << (void*)actual
128            << "`";
129         throw failure(ss.str());
130     }
131 }
132
133 template<typename M>
134 void ensure_equals(const M& msg, const double& actual, const double& expected, const double& epsilon)
135 {
136     const double diff = actual - expected;
137
138     if ( (actual != expected) && !((diff <= epsilon) && (diff >= -epsilon )) )
139     {
140         std::ostringstream ss;
141         detail::msg_prefix(ss,msg)
142            << std::scientific
143            << std::showpoint
144            << std::setprecision(16)
145            << "expected `" << expected
146            << "` actual `" << actual
147            << "` with precision `" << epsilon << "`";
148         throw failure(ss.str());
149     }
150 }
151
152 template<typename M>
153 void ensure_equals(const M& msg, const double& actual, const double& expected)
154 {
155     ensure_equals(msg, actual, expected, std::numeric_limits<double>::epsilon());
156 }
157
158 template <typename LHS, typename RHS>
159 void ensure_equals(const LHS& actual, const RHS& expected)
160 {
161     ensure_equals("Values are not equal", actual, expected);
162 }
163
164
165 template<typename LhsIterator, typename RhsIterator>
166 void ensure_equals(const std::string &msg,
167                    const LhsIterator &lhs_begin, const LhsIterator &lhs_end,
168                    const RhsIterator &rhs_begin, const RhsIterator &rhs_end)
169 {
170     typename std::iterator_traits<LhsIterator>::difference_type lhs_size = std::distance(lhs_begin, lhs_end);
171     typename std::iterator_traits<RhsIterator>::difference_type rhs_size = std::distance(rhs_begin, rhs_end);
172
173     if(lhs_size < rhs_size)
174     {
175         ensure_equals(msg + ": range is too short", lhs_size, rhs_size);
176     }
177
178     if(lhs_size > rhs_size)
179     {
180         ensure_equals(msg + ": range is too long", lhs_size, rhs_size);
181     }
182
183     assert(lhs_size == rhs_size);
184
185     LhsIterator lhs_i = lhs_begin;
186     RhsIterator rhs_i = rhs_begin;
187     while( (lhs_i != lhs_end) && (rhs_i != rhs_end) )
188     {
189         if(*lhs_i != *rhs_i)
190         {
191             std::ostringstream ss;
192             detail::msg_prefix(ss,msg)
193                 << "expected `" << *rhs_i
194                 << "` actual `" << *lhs_i
195                 << "` at offset " << std::distance(lhs_begin, lhs_i);
196             throw failure(ss.str());
197         }
198
199         lhs_i++;
200         rhs_i++;
201     }
202
203     assert(lhs_i == lhs_end);
204     assert(rhs_i == rhs_end);
205 }
206
207 template<typename LhsIterator, typename RhsIterator>
208 void ensure_equals(const LhsIterator &lhs_begin, const LhsIterator &lhs_end,
209                    const RhsIterator &rhs_begin, const RhsIterator &rhs_end)
210 {
211     ensure_equals("Ranges are not equal", lhs_begin, lhs_end, rhs_begin, rhs_end);
212 }
213
214 template<typename LhsType, typename RhsType>
215 void ensure_equals(const LhsType *lhs_begin, const LhsType *lhs_end,
216                    const RhsType *rhs_begin, const RhsType *rhs_end)
217 {
218     ensure_equals("Ranges are not equal", lhs_begin, lhs_end, rhs_begin, rhs_end);
219 }
220
221 /**
222  * Tests two objects for being at most in given distance one from another.
223  * Borders are excluded.
224  * Throws if false.
225  *
226  * NB: T must have operator << defined somewhere, or
227  * client code will not compile at all! Also, T shall have
228  * operators + and -, and be comparable.
229  *
230  * TODO: domains are wrong, T - T might not yield T, but Q
231  */
232 template <typename M, class T>
233 void ensure_distance(const M& msg, const T& actual, const T& expected, const T& distance)
234 {
235     if (expected-distance >= actual || expected+distance <= actual)
236     {
237         std::ostringstream ss;
238         detail::msg_prefix(ss,msg)
239             << " expected `"
240             << expected-distance
241             << "` - `"
242             << expected+distance
243             << "` actual `"
244             << actual
245             << "`";
246         throw failure(ss.str());
247     }
248 }
249
250 template <class T>
251 void ensure_distance(const T& actual, const T& expected, const T& distance)
252 {
253     ensure_distance<>("Distance is wrong", actual, expected, distance);
254 }
255
256 template<typename M>
257 void ensure_errno(const M& msg, bool cond)
258 {
259     if(!cond)
260     {
261 #if defined(TUT_USE_POSIX)
262         char e[512];
263         std::ostringstream ss;
264         detail::msg_prefix(ss,msg)
265            << strerror_r(errno, e, sizeof(e));
266         throw failure(ss.str());
267 #else
268         throw failure(msg);
269 #endif
270     }
271 }
272
273 /**
274  * Unconditionally fails with message.
275  */
276 void fail(const char* msg = "")
277 {
278     throw failure(msg);
279 }
280
281 template<typename M>
282 void fail(const M& msg)
283 {
284     throw failure(msg);
285 }
286
287 /**
288  * Mark test case as known failure and skip execution.
289  */
290 void skip(const char* msg = "")
291 {
292     throw skipped(msg);
293 }
294
295 template<typename M>
296 void skip(const M& msg)
297 {
298     throw skipped(msg);
299 }
300
301 } // end of namespace
302
303 }
304
305 #endif
306