HART  0.2.0
High level Audio Regression and Testing
Loading...
Searching...
No Matches
hart_condition.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <ostream>
4#include <sstream>
5#include <string>
6#include <type_traits>
7#include <utility>
8
10#include "hart_utils.hpp" // addCents()
11
12namespace hart
13{
14
15/// @brief A class representing some condition
16/// @details This condition id intended to be used by matcher function or a free-standing assertion macro.
17/// To instantiate, use macros like `HART_EQUAL()` or `HART_FLOAT_IN_RANGE()` - see @ref Conditions.
18/// @ingroup Conditions
20{
21public:
22 /// @private
23 Condition (bool result):
24 Condition (
25 result,
26 "Condition (<bool>)", // tokenRepresentation
27 "Condition (" + toString (result) + ')', // stringRepresentation
28 "", // file
29 -1, // line
30 false // hasDetailedMetadata
31 )
32 {
33 }
34
35 /// @private
36 Condition():
37 Condition (
38 false, // result
39 "Condition()", // tokenRepresentation
40 "Condition()", // stringRepresentation
41 "", // file
42 -1, // line
43 false // hasDetailedMetadata
44 )
45 {
46 }
47
48 /// @private
49 bool getResult() const
50 {
51 return m_result;
52 }
53
54 /// @private
55 const char* getFile() const
56 {
57 return m_file;
58 }
59
60 /// @private
61 int getLine() const
62 {
63 return m_line;
64 }
65
66 /// @brief Returns whether it has rich metadata that's worth displaying on failure.
67 /// @details
68 /// Conditions created via proper macros have some useful diagnostic metadata
69 /// like token representation, or file name and line number where it was defined.
70 /// Default-constructed Conditions and Conditions created from basic `bool` value
71 /// do not have it.
72 /// @private
73 bool hasDetailedMetadata() const
74 {
75 return m_hasDetailedMetadata;
76 }
77
78 /// @private
79 void representWithTokens (std::ostream& stream) const
80 {
81 stream << m_tokenRepresentation;
82 }
83
84 /// @private
85 void representWithStringRepresentations (std::ostream& stream) const
86 {
87 stream << m_stringRepresentation;
88 }
89
90 /// @TODO: Enforce explicit booleans here?
91 /// @private
92 template <typename ValueType>
93 static Condition truth (ValueType&& value, const char* valueTokens, const char* file, int line)
94 {
95 std::ostringstream tokenRepresentationStream;
96 std::ostringstream stringRepresentationStream;
97 tokenRepresentationStream << "HART_TRUE (" << valueTokens << ")";
98 stringRepresentationStream << "HART_TRUE (" << hart::toString (value) << ")";
99 return Condition (static_cast<bool> (value), tokenRepresentationStream.str(), stringRepresentationStream.str(), file, line);
100 }
101
102 /// @TODO: Enforce explicit booleans here?
103 /// @private
104 template <typename ValueType>
105 static Condition falsehood (ValueType&& value, const char* valueTokens, const char* file, int line)
106 {
107 std::ostringstream tokenRepresentationStream;
108 std::ostringstream stringRepresentationStream;
109 tokenRepresentationStream << "HART_FALSE (" << valueTokens << ")";
110 stringRepresentationStream << "HART_FALSE (" << hart::toString (value) << ")";
111 return Condition (! static_cast<bool> (value), tokenRepresentationStream.str(), stringRepresentationStream.str(), file, line);
112 }
113
114 /// @TODO: Do a warning if used with floats?
115 /// @private
116 template <typename LHSType, typename RHSType>
117 static Condition equals (LHSType&& lhs, RHSType&& rhs, const char* lhsTokens, const char* rhsTokens, const char* file, int line)
118 {
119 std::ostringstream tokenRepresentationStream;
120 std::ostringstream stringRepresentationStream;
121 tokenRepresentationStream << "HART_EQUAL (" << lhsTokens << ", " << rhsTokens << ")";
122 stringRepresentationStream << "HART_EQUAL (" << hart::toString (lhs) << ", " << hart::toString (rhs) << ")";
123 return Condition (lhs == rhs, tokenRepresentationStream.str(), stringRepresentationStream.str(), file, line);
124 }
125
126 /// @TODO: Do a warning if used with floats?
127 /// @private
128 template <typename LHSType, typename RHSType>
129 static Condition notEquals (LHSType&& lhs, RHSType&& rhs, const char* lhsTokens, const char* rhsTokens, const char* file, int line)
130 {
131 std::ostringstream tokenRepresentationStream;
132 std::ostringstream stringRepresentationStream;
133 tokenRepresentationStream << "HART_NOT_EQUAL (" << lhsTokens << ", " << rhsTokens << ")";
134 stringRepresentationStream << "HART_NOT_EQUAL (" << hart::toString (lhs) << ", " << hart::toString (rhs) << ")";
135 return Condition (lhs != rhs, tokenRepresentationStream.str(), stringRepresentationStream.str(), file, line);
136 }
137
138 /// @private
139 template <typename FloatType>
140 static typename std::enable_if<std::is_floating_point<FloatType>::value, Condition>::type
141 floatEqual (
142 FloatType lhs,
143 FloatType rhs,
144 FloatType tolerance,
145 const char* lhsTokens,
146 const char* rhsTokens,
147 const char* toleranceTokens,
148 const char* file,
149 int line
150 )
151 {
152 std::ostringstream tokenRepresentationStream;
153 std::ostringstream stringRepresentationStream;
154 tokenRepresentationStream << "HART_FLOAT_EQUAL (" << lhsTokens << ", " << rhsTokens << ", " << toleranceTokens << ")";
155 stringRepresentationStream << "HART_FLOAT_EQUAL (" << hart::toString (lhs) << ", " << hart::toString (rhs) << ", " << hart::toString (tolerance) << ")";
156 return Condition (
157 lhs - tolerance <= rhs && rhs <= lhs + tolerance,
158 tokenRepresentationStream.str(),
159 stringRepresentationStream.str(),
160 file,
161 line
162 );
163 }
164
165 /// @private
166 template <typename FloatType>
167 static typename std::enable_if<std::is_floating_point<FloatType>::value, Condition>::type
168 floatNotEqual (
169 FloatType lhs,
170 FloatType rhs,
171 FloatType tolerance,
172 const char* lhsTokens,
173 const char* rhsTokens,
174 const char* toleranceTokens,
175 const char* file,
176 int line
177 )
178 {
179 std::ostringstream tokenRepresentationStream;
180 std::ostringstream stringRepresentationStream;
181 tokenRepresentationStream << "HART_FLOAT_NOT_EQUAL (" << lhsTokens << ", " << rhsTokens << ", " << toleranceTokens << ")";
182 stringRepresentationStream << "HART_FLOAT_NOT_EQUAL (" << hart::toString (lhs) << ", " << hart::toString (rhs) << ", " << hart::toString (tolerance) << ")";
183 return Condition (
184 lhs - tolerance > rhs || rhs > lhs + tolerance,
185 tokenRepresentationStream.str(),
186 stringRepresentationStream.str(),
187 file,
188 line
189 );
190 }
191
192 ///@private
193 static Condition
194 frequenciesEqual (
195 double observedFrequencyHz,
196 double expectedFrequencyHz,
197 double toleranceCents,
198 const char* observedFrequencyTokens,
199 const char* expectedFrequencyTokens,
200 const char* toleranceTokens,
201 const char* file,
202 int line
203 )
204 {
205 std::ostringstream tokenRepresentationStream;
206 std::ostringstream stringRepresentationStream;
207 tokenRepresentationStream << "HART_FREQUENCIES_EQUAL (" << observedFrequencyTokens << ", " << expectedFrequencyTokens << ", " << toleranceTokens << ')';
208 stringRepresentationStream << "HART_FREQUENCIES_EQUAL (" << hart::toString (observedFrequencyHz) << ", " << hart::toString (expectedFrequencyHz) << ", " << hart::toString (toleranceCents) << ')';
209 return Condition (
210 (observedFrequencyHz >= addCents (expectedFrequencyHz, -toleranceCents)) && (observedFrequencyHz <= addCents (expectedFrequencyHz, toleranceCents)),
211 tokenRepresentationStream.str(),
212 stringRepresentationStream.str(),
213 file,
214 line
215 );
216 }
217
218 ///@private
219 static Condition
220 frequenciesNotEqual (
221 double observedFrequencyHz,
222 double expectedFrequencyHz,
223 double toleranceCents,
224 const char* observedFrequencyTokens,
225 const char* expectedFrequencyTokens,
226 const char* toleranceTokens,
227 const char* file,
228 int line
229 )
230 {
231 std::ostringstream tokenRepresentationStream;
232 std::ostringstream stringRepresentationStream;
233 tokenRepresentationStream << "HART_FREQUENCIES_NOT_EQUAL (" << observedFrequencyTokens << ", " << expectedFrequencyTokens << ", " << toleranceTokens << ')';
234 stringRepresentationStream << "HART_FREQUENCIES_NOT_EQUAL (" << hart::toString (observedFrequencyHz) << ", " << hart::toString (expectedFrequencyHz) << ", " << hart::toString (toleranceCents) << ')';
235 return Condition (
236 ! ((observedFrequencyHz >= addCents (expectedFrequencyHz, -toleranceCents)) && (observedFrequencyHz <= addCents (expectedFrequencyHz, toleranceCents))),
237 tokenRepresentationStream.str(),
238 stringRepresentationStream.str(),
239 file,
240 line
241 );
242 }
243
244 /// @private
245 template <typename LHSType, typename RHSType>
246 static Condition greaterThan (LHSType&& lhs, RHSType&& rhs, const char* lhsTokens, const char* rhsTokens, const char* file, int line)
247 {
248 std::ostringstream tokenRepresentationStream;
249 std::ostringstream stringRepresentationStream;
250 tokenRepresentationStream << "HART_GREATER_THAN (" << lhsTokens << ", " << rhsTokens << ")";
251 stringRepresentationStream << "HART_GREATER_THAN (" << hart::toString (lhs) << ", " << hart::toString (rhs) << ")";
252 return Condition (lhs > rhs, tokenRepresentationStream.str(), stringRepresentationStream.str(), file, line);
253 }
254
255 /// @private
256 template <typename LHSType, typename RHSType>
257 static Condition greaterOrEqual (LHSType&& lhs, RHSType&& rhs, const char* lhsTokens, const char* rhsTokens, const char* file, int line)
258 {
259 std::ostringstream tokenRepresentationStream;
260 std::ostringstream stringRepresentationStream;
261 tokenRepresentationStream << "HART_GREATER_OR_EQUAL (" << lhsTokens << ", " << rhsTokens << ")";
262 stringRepresentationStream << "HART_GREATER_OR_EQUAL (" << hart::toString (lhs) << ", " << hart::toString (rhs) << ")";
263 return Condition (lhs >= rhs, tokenRepresentationStream.str(), stringRepresentationStream.str(), file, line);
264 }
265
266 /// @private
267 template <typename LHSType, typename RHSType>
268 static Condition lessThan (LHSType&& lhs, RHSType&& rhs, const char* lhsTokens, const char* rhsTokens, const char* file, int line)
269 {
270 std::ostringstream tokenRepresentationStream;
271 std::ostringstream stringRepresentationStream;
272 tokenRepresentationStream << "HART_LESS_THAN (" << lhsTokens << ", " << rhsTokens << ")";
273 stringRepresentationStream << "HART_LESS_THAN (" << hart::toString (lhs) << ", " << hart::toString (rhs) << ")";
274 return Condition (lhs < rhs, tokenRepresentationStream.str(), stringRepresentationStream.str(), file, line);
275 }
276
277 /// @private
278 template <typename LHSType, typename RHSType>
279 static Condition lessOrEqual (LHSType&& lhs, RHSType&& rhs, const char* lhsTokens, const char* rhsTokens, const char* file, int line)
280 {
281 std::ostringstream tokenRepresentationStream;
282 std::ostringstream stringRepresentationStream;
283 tokenRepresentationStream << "HART_LESS_OR_EQUAL (" << lhsTokens << ", " << rhsTokens << ")";
284 stringRepresentationStream << "HART_LESS_OR_EQUAL (" << hart::toString (lhs) << ", " << hart::toString (rhs) << ")";
285 return Condition (lhs <= rhs, tokenRepresentationStream.str(), stringRepresentationStream.str(), file, line);
286 }
287
288 /// @private
289 template <typename ValueType, typename BoundType>
290 static Condition inRange (
291 ValueType&& value,
292 BoundType&& minValue,
293 BoundType&& maxValue,
294 const char* valueTokens,
295 const char* minValueTokens,
296 const char* maxValueTokens,
297 const char* file,
298 int line
299 )
300 {
301 std::ostringstream tokenRepresentationStream;
302 std::ostringstream stringRepresentationStream;
303 tokenRepresentationStream << "HART_IN_RANGE (" << valueTokens << ", " << minValueTokens << ", " << maxValueTokens << ")";
304 stringRepresentationStream << "HART_IN_RANGE (" << hart::toString (value) << ", " << hart::toString (minValue) << ", " << hart::toString (maxValue) << ")";
305 return Condition (minValue <= value && value <= maxValue, tokenRepresentationStream.str(), stringRepresentationStream.str(), file, line);
306 }
307
308 /// @private
309 template <typename FloatType>
310 static typename std::enable_if<std::is_floating_point<FloatType>::value, Condition>::type
311 floatInRange (
312 FloatType value,
313 FloatType minValue,
314 FloatType maxValue,
315 FloatType tolerance,
316 const char* valueTokens,
317 const char* minValueTokens,
318 const char* maxValueTokens,
319 const char* toleranceTokens,
320 const char* file,
321 int line
322 )
323 {
324 std::ostringstream tokenRepresentationStream;
325 std::ostringstream stringRepresentationStream;
326 tokenRepresentationStream << "HART_FLOAT_IN_RANGE (" << valueTokens << ", " << minValueTokens << ", " << maxValueTokens << ", " << toleranceTokens << ")";
327 stringRepresentationStream << "HART_FLOAT_IN_RANGE (" << hart::toString (value) << ", " << hart::toString (minValue) << ", " << hart::toString (maxValue) << ", " << hart::toString (tolerance) << ")";
328 return Condition (
329 minValue - tolerance <= value && value <= maxValue + tolerance,
330 tokenRepresentationStream.str(),
331 stringRepresentationStream.str(),
332 file,
333 line
334 );
335 }
336
337private:
338 Condition (bool result, std::string tokenRepresentation, std::string stringRepresentation, const char* file, int line, bool hasDetailedMetadata = true) :
339 m_result (result),
340 m_hasDetailedMetadata (hasDetailedMetadata),
341 m_tokenRepresentation (std::move (tokenRepresentation)),
342 m_stringRepresentation (std::move (stringRepresentation)),
343 m_file (file),
344 m_line (line)
345 {
346 }
347
348 bool m_result;
349 bool m_hasDetailedMetadata;
350 std::string m_tokenRepresentation;
351 std::string m_stringRepresentation;
352 const char* m_file;
353 int m_line;
354};
355
356} // namespace hart
A class representing some condition.
double addCents(double baseFrequencyHz, double cents)
Anns an offset in cents to a frequency in Hz.