Version: SMASH-3.4
unittest.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2018,2020-2022,2025
3  * SMASH Team
4  */
5 
6 /*!
7  * \page doxypage_unit_testing
8  * \tableofcontents
9  *
10  * See also: \ref unittest
11  *
12  * \section unittest_intro Introduction
13  * (The “Introduction” text is adapted from the <a
14  * href="https://en.wikipedia.org/wiki/Unit_testing">Wikipedia article on Unit
15  * testing</a>, for a stronger focus on SMASH and C++.)
16  *
17  * Unit testing is a software testing method by which
18  * individual units of source code
19  * are tested to determine if they are fit for use.
20  * View a unit as the smallest testable part of an application.
21  * Thus, a unit is typically an entire class.
22  *
23  * Ideally, each test case is independent from the others. Substitutes such as
24  * <a href="https://en.wikipedia.org/wiki/Method_stub">method stubs</a> and <a
25  * href="https://en.wikipedia.org/wiki/Mock_object">mock objects</a> can be used
26  * to assist testing a module in isolation. Unit tests are written and
27  * run by software developers to ensure that code meets its design and behaves
28  * as intended.
29  *
30  * \subsection unittest_intro_benefits Benefits
31  * The goal of unit testing is to isolate each part of the program and show that
32  * the individual parts are correct. A unit test provides a strict, written
33  * contract that the piece of code must satisfy. As a result, it affords several
34  * benefits.
35  *
36  * \subsubsection unittest_intro_benefits_find_problems Finds problems early
37  * Unit testing finds problems early in the development cycle.
38  *
39  * In test-driven development, unit tests are created before the code itself is
40  * written. When the tests pass, that code is considered complete. The same unit
41  * tests are run against that function frequently as the larger code base is
42  * developed either as the code is changed or via an automated process with the
43  * build. If the unit tests fail, it is considered to be a bug either in the
44  * changed code or the tests themselves. The unit tests then allow the location
45  * of the fault or failure to be easily traced. Since the unit tests alert the
46  * development team of the problem before handing the code off to testers or
47  * clients, it is still early in the development process.
48  *
49  * \subsubsection unittest_intro_benefits_change Facilitates change
50  * Unit testing allows the programmer to refactor code at a later date, and make
51  * sure the module still works correctly (e.g., in regression testing). The
52  * procedure is to write test cases for all functions and methods so that
53  * whenever a change causes a fault, it can be quickly identified.
54  *
55  * Readily available unit tests make it easy for the programmer to check whether
56  * a piece of code is still working properly.
57  *
58  * \subsubsection unittest_intro_benefits_integration Simplifies integration
59  * Unit testing may reduce uncertainty in the units themselves and can be used
60  * in a bottom-up testing style approach. By testing the parts of a program
61  * first and then testing the sum of its parts, integration testing becomes much
62  * easier.
63  *
64  * \subsubsection unittest_intro_benefits_design Design
65  * When software is developed using a test-driven approach, the combination of
66  * writing the unit test to specify the interface plus the refactoring
67  * activities performed after the test is passing, may take the place of formal
68  * design. Each unit test can be seen as a design element specifying classes,
69  * methods, and observable behaviour.
70  *
71  ******************************************************************************
72  *
73  * \section unittest_smash SMASH Specific Hints and Rules
74  * The typical unit test in SMASH is centered around one C++ class.
75  * But many of the classes in SMASH rely on specific data to do any useful
76  * operations.
77  * The obvious candidates are
78  * - \ref smash::ParticleData
79  * - \ref smash::ParticleType
80  * - \ref smash::Particles
81  * - \ref smash::Configuration
82  * - \ref smash::ProcessBranch
83  *
84  * Each of these are interfaces to data that most classes in SMASH read,
85  * modify, or create. For example, consider testing smash::DecayAction. The
86  * class is created with a const-ref to a smash::ParticleData object. This
87  * class in turn requires a smash::ParticleType object for its constructor. To
88  * make things worse, the smash::DecayAction::perform function requires a
89  * pointer to smash::Particles (which contains a map of all existing
90  * smash::ParticleData objects). The \c perform function further calls
91  * smash::Action::choose_channel which requires a std::vector of
92  * smash::ProcessBranch to determine the the final state particles.
93  *
94  * \subsection unittest_smash_compromise Compromise
95  * We see that testing \c DecayAction in isolation will be hard. If we'd want to
96  * follow the purist rules for unit testing we'd have to mock all those classes.
97  * Up to now we have not used mocking, as it would create even more work when
98  * the design of SMASH changes. We should consider mocking on a case by case
99  * basis, but feel free to just use the real thing for now.
100  *
101  * Instead of creating complete mock classes we can use the BUILD_TESTS macro in
102  * actual SMASH classes to easily construct mock objects
103  *
104  * See \ref doxypage_unit_testing_mocking.
105  *
106  * \subsection unittest_smash_good_example Good Example
107  * While implementing the initial conditions (see
108  * \c src/test/initial_conditions.cc at the very end), the test to verify
109  * momentum conservation was written first and then the code has been adjusted,
110  * until the test passed successfully. This can serve as a positive example of
111  * test-driven development.
112  *
113  ******************************************************************************
114  * \section unittest_run Running tests & Test-driven development
115  * Tests are built with cmake. They can be disabled via the BUILD_TESTING option
116  * of cmake; per default tests are enabled.
117  *
118  * Once a test is built you will find an executable in the top-level build
119  * directory. Every test has a name that is used for the \c .cc file, the
120  * executable name, and the \c make target names. Take for example the \c
121  * pdgcode test:
122  * - The source for the test is in \c src/tests/pdgcode.cc.
123  * - The executable will be in \c ${CMAKE_BINARY_DIR}/pdgcode.
124  * - The make file will have two targets: \c pdgcode and \c run_pdgcode. The
125  * former will only build the executable, the latter will build and run it.
126  *
127  * For test-driven development, the run target can be quite handy, since it
128  * requires a single command to compile and run a unit test. A vim user, for
129  * example, will be able to call `:make run_pdgcode` (possibly mapped to a key,
130  * such as F10) and get compiler output and test output into the Quickfix
131  * buffer.
132  *
133  * Finally, if you want to run all tests in the test suite you can first build
134  * all tests with
135  *
136  * make -j4 all
137  *
138  * and then run all tests with
139  *
140  * ctest -j4
141  *
142  * . Using \c ctest instead of `make test` allows you to run tests in parallel
143  * with the \c -j flag. (Use a number that corresponds to the number of cores on
144  * the machine where you're working on, instead of \c -j4.)
145  * If you run \c ctest with the \c -V flag you will see more output from the
146  * tests. The test output is always captured in a file, so that you don't
147  * necessarily have to rerun a failed test to see what happened. You can find it
148  * in the \c Testing directory in the build dir.
149  *
150  ******************************************************************************
151  *
152  * \section unittest_getstarted Get started
153  * In SMASH we use a unit testing framework that was originally developed for
154  * the [Vc library](http://code.compeng.uni-frankfurt.de/projects/vc). It
155  * simplifies test creation to the bare minimum. The following code suffices to
156  * run a test:
157  * \code
158  * #include "unittest.h"
159  *
160  * TEST(test_name) {
161  * int test = 1 + 1;
162  * COMPARE(test, 2) << "more details";
163  * VERIFY(1 > 0);
164  * }
165  * \endcode
166  * This creates one test function (called "test_name"). This function is called
167  * without any further code and executes two checks. If, for some reason, the
168  * compiler would determine that test needs to have the value 3, then the output
169  * would be:
170  \verbatim
171  FAIL: ┍ at /home/mkretz/src/smash/src/tests/testfile.cc:5 (0x40451f):
172  FAIL: │ test (3) == 2 (2) -> false more details
173  FAIL: ┕ test_name
174 
175  Testing done. 0 tests passed. 1 tests failed.
176  \endverbatim
177  * Let's take a look at what this tells us.
178  * 1. The test macro that failed was in testfile.cc in line 5.
179  * 2. If you want to look at the disassembly, the failure was at 0x40451f.
180  * 3. The \ref COMPARE macro compared the expression `test` against the
181  expression
182  * `2`. It shows that `test` had a value of `3` while `2` had a value of `2`
183  * (what a surprise). Since the values are not equal `test == 2` returns \c
184  * false.
185  * 4. The \ref COMPARE, \ref FUZZY_COMPARE, \ref VERIFY, and \ref FAIL macros
186  can be used as
187  * streams. The output will only appear on failure and will be printed right
188  * after the normal output of the macro.
189  * 5. Finally the name of the failed test (the name specified inside the \ref
190  TEST()
191  * macro) is printed.
192  * 6. At the end of the run, a summary of the test results is shown. This may be
193  * important when there are many \ref TEST functions.
194  *
195  * If the test passed you'll see:
196  \verbatim
197  PASS: test_name
198 
199  Testing done. 1 tests passed. 0 tests failed.
200  \endverbatim
201  *
202  * You can compile tests with the \c smash_add_unittest macro. You only need to
203  * pass it the name of the \c .cc file (without the file extension). So, if your
204  * test code above was saved in tests/testfile.cc, then you'd add the line
205  * \code
206  * smash_add_unittest(testfile)
207  * \endcode
208  * to the \c CMakeLists.txt .
209  * You will then get two new targets that you can build with make: \c testfile
210  * and \c run_testtest . The latter can be used to build and run a test quickly
211  * in "code - compile - test" cycles in test-driven development.
212  */
213 
214 /**
215  * \page doxypage_unit_testing_mocking
216  *
217  * This is a list of functions and classes that can be useful in unit tests for
218  * creating objects that are necessary for testing a class in (more or less)
219  * isolation.
220  */
221 
222 /**
223  * \addtogroup unittest
224  * @{
225  */
226 
227 /**
228  * \brief Defines a test function.
229  *
230  * Consider this to expand to `void
231  * function_name()`. The function_name will also be the name that appears in the
232  * output after PASS/FAIL.
233  */
234 #define TEST(function_name)
235 
236 /**
237  * \brief Same as above, but expects the code to throw an exception of type \p
238  * ExceptionType.
239  *
240  * If the code does not throw (or throws a different exception),
241  * the test is considered failed.
242  */
243 #define TEST_CATCH(function_name, ExceptionType)
244 
245 /**
246  * \brief Define a test function template, with type parameter T, which is
247  * specialized for all types in the \p typelist.
248  */
249 #define TEST_TYPES(T, test_name, typelist)
250 
251 /**
252  * \brief Verifies that \p condition is \c true.
253  */
254 #define VERIFY(condition)
255 
256 /**
257  * \brief Verifies that \p test_value is equal to \p reference.
258  */
259 #define COMPARE(test_value, reference)
260 
261 /**
262  * \brief Verifies that the difference between \p test_value and \p reference is
263  * smaller than \p allowed_difference.
264  *
265  * If the test fails the output will show the actual difference between \p
266  * test_value and \p reference. If this value is positive \p test_value is too
267  * large. If it is negative \p test_value is too small.
268  */
269 #define COMPARE_ABSOLUTE_ERROR(test_value, reference, allowed_difference)
270 
271 /**
272  * \brief Verifies that the difference between \p test_value and \p reference is
273  * smaller than `allowed_relative_difference * reference`.
274  *
275  * If the test fails the output will show the actual difference between \p
276  * test_value and \p reference. If this value is positive \p test_value is too
277  * large. If it is negative \p test_value is too small.
278  *
279  * The following example tests that `a` is no more than 1% different from `b`:
280  * \code
281  * COMPARE_ABSOLUTE_ERROR(a, b, 0.01);
282  * \endcode
283  *
284  * \note This test macro still works even if \p reference is set to 0. It will
285  * then compare the difference against `allowed_relative_difference * <smallest
286  * positive normalized value of reference type>`.
287  */
288 #define COMPARE_RELATIVE_ERROR(test_value, reference, \
289  allowed_relative_difference)
290 
291 /**
292  * \brief Verifies that \p test_value is equal to \p reference within a
293  * pre-defined distance in units of least precision (ulp).
294  *
295  * If the test fails it will print the distance in ulp between \p test_value and
296  * \p reference as well as the maximum allowed distance. Often this difference
297  * is not visible in the value because the conversion of a double/float to a
298  * string needs to round the value to a sensible length.
299  *
300  * The allowed distance can be modified by calling:
301  * \code
302  * vir::test::setFuzzyness<float>(4);
303  * vir::test::setFuzzyness<double>(7);
304  * \endcode
305  *
306  * <h3> ulp </h3>
307  * Unit of least precision is a unit that is derived from the the least
308  * significant bit in the mantissa of a floating-point value. Consider a
309  * single-precision number (23 mantissa bits) with exponent \f$e\f$. Then 1
310  * ulp is \f$2^{e-23}\f$. Thus, \f$\log_2(u)\f$ signifies the the number
311  * incorrect mantissa bits (with \f$u\f$ the distance in ulp).
312  *
313  * If \p test_value and \p reference have a different exponent the meaning of
314  * ulp depends on the variable you look at. The FUZZY_COMPARE code always uses
315  * \p reference to determine the magnitude of 1 ulp.
316  *
317  * Example:
318  * The value `1.` is `0x3f800000` in binary. The value
319  * `1.00000011920928955078125` with binary representation `0x3f800001`
320  * therefore has a distance of 1 ulp.
321  * A positive distance means the \p test_value is larger than the \p reference.
322  * A negative distance means the \p test_value is smaller than the \p reference.
323  * * `FUZZY_COMPARE(1.00000011920928955078125, 1.)` will show a distance of 1
324  * * `FUZZY_COMPARE(1., 1.00000011920928955078125)` will show a distance of -1
325  *
326  * The value `0.999999940395355224609375` with binary representation
327  * `0x3f7fffff` has a smaller exponent than `1.`:
328  * * `FUZZY_COMPARE(0.999999940395355224609375, 1.)` will show a distance of
329  * -0.5
330  * * `FUZZY_COMPARE(1., 0.999999940395355224609375)` will show a distance of 1
331  *
332  * <h3> Comparing to 0 </h3>
333  * Distance to 0 is implemented as comparing to
334  * <tt>std::numeric_limits<T>::min()</tt>
335  * instead and adding 1 to the resulting distance.
336  */
337 #define FUZZY_COMPARE(test_value, reference)
338 
339 /**
340  * \brief Call this to fail a test.
341  */
342 #define FAIL()
343 
344 namespace vir {
345 namespace test {
346 
347 /**
348  * \brief Pass code that should fail an assertion to this function.
349  */
350 template <class F>
351 inline void expect_assert_failure(F &&f);
352 
353 /**
354  * \brief Use this to mark that the failure of a following test is
355  * expected.
356  *
357  * \code
358  * TEST(something) {
359  * // this needs to pass
360  * VERIFY(true);
361  * vir::test::expect_failure();
362  * // if this fails, the test will be marked "XFAIL" and the failure
363  * // will not be counted
364  * VERIFY(false);
365  * // this will not be checked anymore, because the TEST stops at the
366  * // (expectedly) failing VERIFY.
367  * VERIFY(true);
368  * }
369  * \endcode
370  */
371 inline void expect_failure();
372 
373 } // namespace test
374 } // namespace vir
375 
376 /**
377  * @}
378  */
void expect_assert_failure(F &&f)
Pass code that should fail an assertion to this function.
void expect_failure()
Use this to mark that the failure of a following test is expected.
Definition: unittest.h:344