b4e0a8ac36f03c7111785f3e092704407cc8e2fc
[alexxy/gromacs.git] / src / testutils / testasserts.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2013,2014, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 /*! \libinternal \file
36  * \brief
37  * Extra assertions for unit tests.
38  *
39  * This file provides assertion macros that extend/replace Google Test
40  * assertions for:
41  *  - exceptions
42  *  - floating-point comparison
43  *
44  * \if internal
45  * \todo
46  * The implementation is somewhat ugly, and accesses some Google Test
47  * internals.  Could be nice to clean it up a bit.
48  * \endif
49  *
50  * \author Teemu Murtola <teemu.murtola@gmail.com>
51  * \inlibraryapi
52  * \ingroup module_testutils
53  */
54 #ifndef GMX_TESTUTILS_TESTASSERTS_H
55 #define GMX_TESTUTILS_TESTASSERTS_H
56
57 #include <string>
58
59 #include <gtest/gtest.h>
60
61 #include "gromacs/utility/basedefinitions.h"
62 #include "gromacs/utility/exceptions.h"
63 #include "gromacs/utility/real.h"
64
65 namespace gmx
66 {
67 namespace test
68 {
69
70 //! \libinternal \addtogroup module_testutils
71 //! \{
72
73 /*! \name Assertions for exceptions
74  *
75  * These macros replace `(ASSERT|EXPECT)(_NO)?_THROW` from Google Test.
76  * They are used exactly like the Google Test ones, but also print details of
77  * any unexpected exceptions using \Gromacs-specific routines.
78  * This makes it much easier to see at one glance what went wrong.
79  * See Google Test documentation for details on how to use the macros.
80  */
81 //! \{
82
83 //! \cond internal
84 /*! \brief
85  * Internal implementation macro for exception assertations.
86  *
87  * \param statement          Statements to execute.
88  * \param expected_exception Exception type that \p statement should throw.
89  * \param fail               Function/macro to call on failure.
90  *
91  * The implementation is copied and adjusted from
92  * include/gtest/internal/gtest-internal.h in Google Test 1.6.0.
93  */
94 #define GMX_TEST_THROW_(statement, expected_exception, fail) \
95     GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
96     if (::testing::AssertionResult gmx_ar = ::testing::AssertionSuccess()) { \
97         bool gmx_caught_expected = false; \
98         try { \
99             GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
100         } \
101         catch (expected_exception const &) { \
102             gmx_caught_expected = true; \
103         } \
104         catch (std::exception const &ex) { \
105             gmx_ar << "Expected: " #statement " throws an exception of type " \
106             << #expected_exception ".\n  Actual: it throws a different type.\n" \
107             << "Exception details:\n" << ::gmx::formatExceptionMessageToString(ex); \
108             goto GTEST_CONCAT_TOKEN_(gmx_label_testthrow_, __LINE__); \
109         } \
110         catch (...) { \
111             gmx_ar << "Expected: " #statement " throws an exception of type " \
112             << #expected_exception ".\n  Actual: it throws a different type."; \
113             goto GTEST_CONCAT_TOKEN_(gmx_label_testthrow_, __LINE__); \
114         } \
115         if (!gmx_caught_expected) { \
116             gmx_ar << "Expected: " #statement " throws an exception of type " \
117             << #expected_exception ".\n  Actual: it throws nothing."; \
118             goto GTEST_CONCAT_TOKEN_(gmx_label_testthrow_, __LINE__); \
119         } \
120     } else \
121         GTEST_CONCAT_TOKEN_(gmx_label_testthrow_, __LINE__) : \
122             fail(gmx_ar.message())
123
124 /*! \brief
125  * Internal implementation macro for exception assertations.
126  *
127  * \param statement          Statements to execute.
128  * \param fail               Function/macro to call on failure.
129  *
130  * The implementation is copied and adjusted from
131  * include/gtest/internal/gtest-internal.h in Google Test 1.6.0.
132  */
133 #define GMX_TEST_NO_THROW_(statement, fail) \
134     GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
135     if (::testing::AssertionResult gmx_ar = ::testing::AssertionSuccess()) { \
136         try { \
137             GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
138         } \
139         catch (std::exception const &ex) { \
140             gmx_ar << "Expected: " #statement " doesn't throw an exception.\n" \
141             << "  Actual: it throws.\n" \
142             << "Exception details:\n" << ::gmx::formatExceptionMessageToString(ex); \
143             goto GTEST_CONCAT_TOKEN_(gmx_label_testnothrow_, __LINE__); \
144         } \
145         catch (...) { \
146             gmx_ar << "Expected: " #statement " doesn't throw an exception.\n" \
147             << "  Actual: it throws."; \
148             goto GTEST_CONCAT_TOKEN_(gmx_label_testnothrow_, __LINE__); \
149         } \
150     } else \
151         GTEST_CONCAT_TOKEN_(gmx_label_testnothrow_, __LINE__) : \
152             fail(gmx_ar.message())
153 //! \endcond
154
155 /*! \brief
156  * Asserts that a statement throws a given exception.
157  *
158  * \hideinitializer
159  */
160 #define EXPECT_THROW_GMX(statement, expected_exception) \
161     GMX_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_)
162 /*! \brief
163  * Asserts that a statement does not throw.
164  *
165  * \hideinitializer
166  */
167 #define EXPECT_NO_THROW_GMX(statement) \
168     GMX_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_)
169 /*! \brief
170  * Asserts that a statement throws a given exception.
171  *
172  * \hideinitializer
173  */
174 #define ASSERT_THROW_GMX(statement, expected_exception) \
175     GMX_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_)
176 /*! \brief
177  * Asserts that a statement does not throw.
178  *
179  * \hideinitializer
180  */
181 #define ASSERT_NO_THROW_GMX(statement) \
182     GMX_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_)
183
184 //! \}
185
186 /*! \libinternal \brief
187  * Computes and represents a floating-point difference value.
188  *
189  * Methods in this class do not throw, except for toString(), which may throw
190  * std::bad_alloc.
191  *
192  * \see FloatingPointTolerance
193  */
194 class FloatingPointDifference
195 {
196     public:
197         //! Initializes a single-precision difference.
198         FloatingPointDifference(float value1, float value2);
199         //! Initializes a double-precision difference.
200         FloatingPointDifference(double value1, double value2);
201
202         /*! \brief
203          * Whether one or both of the compared values were NaN.
204          *
205          * If this returns `true`, other accessors return meaningless values.
206          */
207         bool isNaN() const;
208         //! Returns the difference as an absolute number (always non-negative).
209         double asAbsolute() const { return absoluteDifference_; }
210         /*! \brief
211          * Returns the difference as ULPs (always non-negative).
212          *
213          * The ULPs are calculated for the type that corresponds to the
214          * constructor used to initialize the difference.
215          * The ULP difference between 0.0 and -0.0 is zero.
216          */
217         gmx_uint64_t asUlps() const { return ulpDifference_; }
218         /*! \brief
219          * Whether the compared values were of different sign.
220          *
221          * 0.0 and -0.0 are treated as positive and negative, respectively.
222          */
223         bool signsDiffer() const { return bSignDifference_; }
224
225         //! Formats the difference as a string for assertion failure messages.
226         std::string toString() const;
227
228     private:
229         //! Stores the absolute difference, or NaN if one or both values were NaN.
230         double       absoluteDifference_;
231         gmx_uint64_t ulpDifference_;
232         bool         bSignDifference_;
233         /*! \brief
234          * Whether the difference was computed for single or double precision.
235          *
236          * This sets the units for `ulpDifference_`.
237          */
238         bool         bDouble_;
239 };
240
241 /*! \libinternal \brief
242  * Specifies a floating-point comparison tolerance and checks whether a
243  * difference is within the tolerance.
244  *
245  * Several types of tolerances are possible:
246  *  - _absolute tolerance_: difference between the values must be smaller than
247  *    the given tolerance for the check to pass.
248  *    Setting the absolute tolerance to zero disables the absolute tolerance
249  *    check.
250  *  - _ULP tolerance_: ULP (units of least precision) difference between the
251  *    values must be smaller than the given tolerance for the check to pass.
252  *    Setting the ULP tolerance to zero requires exact match.
253  *    Setting the ULP tolerance to negative disables the ULP check.
254  *    `0.0` and `-0.0` are treated as equal for the ULP check.
255  *  - _sign check_: if set, any values that are of different signs fail the
256  *    check (note that this also applies to `0.0` and `-0.0`: a value with a
257  *    different sign than the zero will fail the check).
258  *
259  * Either an absolute or a ULP tolerance must always be specified.
260  * If both are specified, then the check passes if either of the tolerances is
261  * satisfied.
262  *
263  * Any combination of absolute and ULP tolerance can be combined with the sign
264  * check.  In this case, the sign check must succeed for the check to pass,
265  * even if other tolerances are satisfied.
266  *
267  * Currently, the ULP tolerance is not in any particular precision, but the
268  * interpretation depends on the compared numbers: if floats are compared, then
269  * the ULP tolerance specifies single-precision ULPs, and if doubles are
270  * compared, then the same number is interpreted as double-precision ULPs.
271  *
272  * The related functions section lists methods that can be construct methods
273  * using less parameters than the full constructor, and with more obvious
274  * semantics.
275  *
276  * Methods in this class do not throw, except for toString(), which may throw
277  * std::bad_alloc.
278  *
279  * \see FloatingPointDifference
280  */
281 class FloatingPointTolerance
282 {
283     public:
284         /*! \brief
285          * Creates a tolerance with the specified values.
286          *
287          * \param[in] absolute       Allowed absolute difference.
288          * \param[in] ulp            Allowed ULP difference.
289          * \param[in] bSignMustMatch Whether sign mismatch fails the comparison.
290          */
291         FloatingPointTolerance(double absolute, int ulp,
292                                bool bSignMustMatch)
293             : absoluteTolerance_(absolute), ulpTolerance_(ulp),
294               bSignMustMatch_(bSignMustMatch)
295         {
296         }
297
298         /*! \brief
299          * Checks whether a difference is within the specified tolerance.
300          *
301          * NaNs are always treated outside the tolerance.
302          */
303         bool isWithin(const FloatingPointDifference &difference) const;
304
305         //! Formats the tolerance as a string for assertion failure messages.
306         std::string toString() const;
307
308     private:
309         double       absoluteTolerance_;
310         int          ulpTolerance_;
311         bool         bSignMustMatch_;
312 };
313
314 /*! \brief
315  * Creates a tolerance that only allows a specified ULP difference.
316  *
317  * \related FloatingPointTolerance
318  */
319 static inline FloatingPointTolerance
320 ulpTolerance(gmx_int64_t ulpDiff)
321 {
322     return FloatingPointTolerance(0.0, ulpDiff, false);
323 }
324
325 /*! \brief
326  * Creates a tolerance that allows a relative difference in a complex
327  * computation.
328  *
329  * \param[in] magnitude  Magnitude of the numbers the computation operates in.
330  * \param[in] ulpDiff    Expected accuracy of the computation (in ULPs).
331  *
332  * In addition to setting the ULP tolerance, this sets the absolute tolerance
333  * such that values close to zero (in general, smaller than \p magnitude) do
334  * not fail the check if they differ by less than \p ulpDiff evaluated at
335  * \p magniture.  This accounts for potential loss of precision for small
336  * values, and should be used when accuracy of values much less than
337  * \p magniture do not matter for correctness.
338  *
339  * \related FloatingPointTolerance
340  */
341 static inline FloatingPointTolerance
342 relativeRealTolerance(double magnitude, gmx_int64_t ulpDiff)
343 {
344     return FloatingPointTolerance(magnitude*ulpDiff*GMX_REAL_EPS, ulpDiff, false);
345 }
346
347 /*! \brief
348  * Returns the default tolerance for comparing `real` numbers.
349  *
350  * \related FloatingPointTolerance
351  */
352 static inline FloatingPointTolerance defaultRealTolerance()
353 {
354     return relativeRealTolerance(1.0, 4);
355 }
356
357 /*! \name Assertions for floating-point comparison
358  *
359  * These routines extend `(EXPECT|ASSERT)_(FLOAT|DOUBLE)_EQ` and
360  * `(EXPECT|ASSERT)_NEAR` from Google Test to provide more flexible assertions
361  * for floating-point values.
362  *
363  * See gmx::test::FloatingPointTolerance for the possible ways to specify the
364  * tolerance, and gmx::test::FloatingPointDifference for some additional
365  * details of the difference calculation.
366  */
367 //! \{
368
369 //! \cond internal
370 /*! \internal \brief
371  * Assertion predicate formatter for comparing two floating-point values.
372  */
373 template <typename FloatType>
374 static inline ::testing::AssertionResult assertEqualWithinTolerance(
375         const char *expr1, const char *expr2, const char * /*exprTolerance*/,
376         FloatType value1, FloatType value2,
377         const FloatingPointTolerance &tolerance)
378 {
379     FloatingPointDifference diff(value1, value2);
380     if (tolerance.isWithin(diff))
381     {
382         return ::testing::AssertionSuccess();
383     }
384     return ::testing::AssertionFailure()
385            << "  Value of: " << expr2 << std::endl
386            << "    Actual: " << value2 << std::endl
387            << "  Expected: " << expr1 << std::endl
388            << "  Which is: " << value1 << std::endl
389            << "Difference: " << diff.toString() << std::endl
390            << " Tolerance: " << tolerance.toString();
391 }
392 //! \endcond
393
394 /*! \brief
395  * Asserts that two single-precision values are within the given tolerance.
396  *
397  * \hideinitializer
398  */
399 #define EXPECT_FLOAT_EQ_TOL(value1, value2, tolerance) \
400     EXPECT_PRED_FORMAT3(::gmx::test::assertEqualWithinTolerance<float>, \
401                         value1, value2, tolerance)
402 /*! \brief
403  * Asserts that two double-precision values are within the given tolerance.
404  *
405  * \hideinitializer
406  */
407 #define EXPECT_DOUBLE_EQ_TOL(value1, value2, tolerance) \
408     EXPECT_PRED_FORMAT3(::gmx::test::assertEqualWithinTolerance<double>, \
409                         value1, value2, tolerance)
410 /*! \def EXPECT_REAL_EQ_TOL
411  * \brief
412  * Asserts that two `real` values are within the given tolerance.
413  *
414  * \hideinitializer
415  */
416 /*! \brief
417  * Asserts that two single-precision values are within the given tolerance.
418  *
419  * \hideinitializer
420  */
421 #define ASSERT_FLOAT_EQ_TOL(value1, value2, tolerance) \
422     ASSERT_PRED_FORMAT3(::gmx::test::assertEqualWithinTolerance<float>, \
423                         value1, value2, tolerance)
424 /*! \brief
425  * Asserts that two double-precision values are within the given tolerance.
426  *
427  * \hideinitializer
428  */
429 #define ASSERT_DOUBLE_EQ_TOL(value1, value2, tolerance) \
430     ASSERT_PRED_FORMAT3(::gmx::test::assertEqualWithinTolerance<double>, \
431                         value1, value2, tolerance)
432 /*! \def ASSERT_REAL_EQ_TOL
433  * \brief
434  * Asserts that two `real` values are within the given tolerance.
435  *
436  * \hideinitializer
437  */
438
439 #ifdef GMX_DOUBLE
440 #define EXPECT_REAL_EQ_TOL(value1, value2, tolerance) \
441     EXPECT_DOUBLE_EQ_TOL(value1, value2, tolerance)
442 #define ASSERT_REAL_EQ_TOL(value1, value2, tolerance) \
443     ASSERT_DOUBLE_EQ_TOL(value1, value2, tolerance)
444 #else
445 #define EXPECT_REAL_EQ_TOL(value1, value2, tolerance) \
446     EXPECT_FLOAT_EQ_TOL(value1, value2, tolerance)
447 #define ASSERT_REAL_EQ_TOL(value1, value2, tolerance) \
448     ASSERT_FLOAT_EQ_TOL(value1, value2, tolerance)
449 #endif
450
451 //! \}
452
453 /*! \name Assertions for NULL comparison
454  *
455  * These macros should be used instead of `(EXPECT|ASSERT)_EQ(NULL, ...)`,
456  * because Google Test doesn't support the NULL comparison with xlC++ 12.1 on
457  * BG/Q.
458  */
459 //! \{
460
461 /*! \brief
462  * Asserts that a pointer is null.
463  *
464  * Works exactly like EXPECT_EQ comparing with a null pointer. */
465 #define EXPECT_NULL(val) EXPECT_EQ((void *) NULL, val)
466 /*! \brief
467  * Asserts that a pointer is null.
468  *
469  * Works exactly like ASSERT_EQ comparing with a null pointer. */
470 #define ASSERT_NULL(val) ASSERT_EQ((void *) NULL, val)
471
472 //! \}
473
474 } // namespace test
475 } // namespace gmx
476
477 #endif