]> git.stg.codes - stg.git/blob - tests/tut/tut_assert.hpp
Merge branch 'master' into full-month-stats
[stg.git] / tests / tut / tut_assert.hpp
1 #ifndef TUT_ASSERT_H_GUARD
2 #define TUT_ASSERT_H_GUARD
3
4 #include "tut_exception.hpp"
5 #include <limits>
6 #include <iomanip>
7
8 #if defined(TUT_USE_POSIX)
9 #include <errno.h>
10 #include <cstring>
11 #endif
12
13 namespace tut
14 {
15
16     namespace detail
17     {
18         template<typename M>
19         std::ostream &msg_prefix(std::ostream &str, const M &msg)
20         {
21             std::stringstream ss;
22             ss << msg;
23
24             if(!ss.str().empty())
25             {
26                 str << ss.rdbuf() << ": ";
27             }
28
29             return str;
30         }
31     }
32
33
34 namespace
35 {
36
37 /**
38  * Tests provided condition.
39  * Throws if false.
40  */
41 void ensure(bool cond)
42 {
43     if (!cond)
44     {
45         // TODO: default ctor?
46         throw failure("");
47     }
48 }
49
50 /**
51  * Tests provided condition.
52  * Throws if true.
53  */
54 void ensure_not(bool cond)
55 {
56     ensure(!cond);
57 }
58
59 /**
60  * Tests provided condition.
61  * Throws if false.
62  */
63 template <typename M>
64 void ensure(const M& msg, bool cond)
65 {
66     if (!cond)
67     {
68         throw failure(msg);
69     }
70 }
71
72 /**
73  * Tests provided condition.
74  * Throws if true.
75  */
76 template <typename M>
77 void ensure_not(const M& msg, bool cond)
78 {
79     ensure(msg, !cond);
80 }
81
82 /**
83  * Tests two objects for being equal.
84  * Throws if false.
85  *
86  * NB: both T and Q must have operator << defined somewhere, or
87  * client code will not compile at all!
88  */
89 template <typename M, typename LHS, typename RHS>
90 void ensure_equals(const M& msg, const LHS& actual, const RHS& expected)
91 {
92     if (expected != actual)
93     {
94         std::stringstream ss;
95         detail::msg_prefix(ss,msg)
96            << "expected '"
97            << expected
98            << "' actual '"
99            << actual
100            << '\'';
101         throw failure(ss.str());
102     }
103 }
104
105 template <typename LHS, typename RHS>
106 void ensure_equals(const LHS& actual, const RHS& expected)
107 {
108     ensure_equals("Values are not equal", actual, expected);
109 }
110
111 template<typename M>
112 void ensure_equals(const M& msg, const double& actual, const double& expected,
113                    const double& epsilon = std::numeric_limits<double>::epsilon())
114 {
115     const double diff = actual - expected;
116
117     if ( !((diff <= epsilon) && (diff >= -epsilon )) )
118     {
119         std::stringstream ss;
120         detail::msg_prefix(ss,msg)
121            << std::scientific
122            << std::showpoint
123            << std::setprecision(16)
124            << "expected " << expected
125            << " actual " << actual
126            << " with precision " << epsilon;
127         throw failure(ss.str());
128     }
129 }
130 /**
131  * Tests two objects for being at most in given distance one from another.
132  * Borders are excluded.
133  * Throws if false.
134  *
135  * NB: T must have operator << defined somewhere, or
136  * client code will not compile at all! Also, T shall have
137  * operators + and -, and be comparable.
138  *
139  * TODO: domains are wrong, T - T might not yield T, but Q
140  */
141 template <typename M, class T>
142 void ensure_distance(const M& msg, const T& actual, const T& expected, const T& distance)
143 {
144     if (expected-distance >= actual || expected+distance <= actual)
145     {
146         std::stringstream ss;
147         detail::msg_prefix(ss,msg)
148             << " expected ("
149             << expected-distance
150             << " - "
151             << expected+distance
152             << ") actual '"
153             << actual
154             << '\'';
155         throw failure(ss.str());
156     }
157 }
158
159 template <class T>
160 void ensure_distance(const T& actual, const T& expected, const T& distance)
161 {
162     ensure_distance<>("Distance is wrong", actual, expected, distance);
163 }
164
165 template<typename M>
166 void ensure_errno(const M& msg, bool cond)
167 {
168     if(!cond)
169     {
170 #if defined(TUT_USE_POSIX)
171         char e[512];
172         std::stringstream ss;
173         detail::msg_prefix(ss,msg)
174            << strerror_r(errno, e, sizeof(e));
175         throw failure(ss.str());
176 #else
177         throw failure(msg);
178 #endif
179     }
180 }
181
182 /**
183  * Unconditionally fails with message.
184  */
185 void fail(const char* msg = "")
186 {
187     throw failure(msg);
188 }
189
190 template<typename M>
191 void fail(const M& msg)
192 {
193     throw failure(msg);
194 }
195
196 } // end of namespace
197
198 }
199
200 #endif
201