Robot Simulator of the Robotics Group for Self-Organization of Control  0.8.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
unit_test.hpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2004 by Patrick Audley *
3  * paudley@blackcat.ca *
4  * modified by Georg Martius (georg.martius@web.de) *
5  ***************************************************************************
6 # _______________
7 # VERSION HISTORY
8 #
9 # v1.0 (2004/12/28)
10 # - prelimary version
11 # v1.1 (2005/05/30) (By Georg Martius
12 # - improved output
13 # - improved speed measurement
14 ##
15 */
16 
17 /** @section C++ Unit Testing Framework
18  * See implementation in
19  * @ref unit_test.h
20  *
21  * @par
22  * @section writing Writing Unit Tests
23  * @par
24  * Ideally, unit tests are written with the code they test. The easiest way
25  * to do this is to include all the unit tests at the bottom of each source
26  * that they relate too. It's also possible to create source files of nothing
27  * but tests to expand coverage across multiple translation modules.
28  * @par
29  * Let's take a simple example: we have a new function that adds two numbers.
30  * @code
31  * int addTwoNumbers( int a, int b ) {
32  * return a + b;
33  * }
34  * @endcode
35  * To write a unit test that checks that @f$addTwoNumbers(x_1,x_2)=x_1+x_2@f$ we
36  * would write the unit test like so:
37  * @code
38  * #ifdef UNITTEST
39  * #include "unit_test.h"
40  *
41  * UNIT_TEST_DEFINES
42  *
43  * DEFINE_TEST( check_two_plus_two ) {
44  * unit_assert( "2+2=4", addTwoNumbers(2,2)==4 );
45  * }
46  *
47  * UNIT_TEST_RUN( "addTwoNumbers Tests" )
48  * ADD_TEST( check_two_plus_two )
49  * UNIT_TEST_END
50  *
51  * #endif // UNITTEST
52  * @endcode
53  * @par
54  * Now we have a test suite defined that will only be compiled when we define UNITTEST.
55  * UNIT_TEST_RUN actually creates a main() function that runs the tests so if we put
56  * this code into a file (say add.cpp) then we can compile and run it like so:
57 @verbatim
58 # gcc -DUNITTEST -o unit_test_add add.cpp
59 # ./unit_test_add
60 ---[ addTwoNumbers Tests ]---
61  2+2=4: PASSED
62 @endverbatim
63  * @par
64  * So far so good, let's add a new test that we think will fail.
65  * @code
66  * #ifdef UNITTEST
67  * #include "unit_test.h"
68  *
69  * UNIT_TEST_DEFINES
70  *
71  * DEFINE_TEST( check_two_plus_two ) {
72  * unit_assert( "2+2=4", addTwoNumbers(2,2)==4 );
73  * unit_pass();
74  * }
75  *
76  * DEFINE_TEST( check_bogus ) {
77  * unit_assert( "1+5=9", addTwoNumbers(1,5)==9 );
78  * unit_pass();
79  * }
80  *
81  * UNIT_TEST_RUN( "addTwoNumbers Tests" )
82  * ADD_TEST( check_negatives )
83  * UNIT_TEST_END
84  *
85  * #endif // UNITTEST
86  * @endcode
87  * Running the unit_test now we get:
88 @verbatim
89 # gcc -DUNITTEST -o unit_test_add add.cpp
90 # ./unit_test_add
91 ---[ addTwoNumbers Tests ]---
92  2+2=4: PASSED
93  1+5=9: FAILED
94 @endverbatim
95  * @par
96  * @section adding Integrating with Automake
97  * @par
98  * Automake has the ability to define testing targets that get run when
99  * issue "make check" command. Adding these tests are pretty straight
100  * forward. For the above we would add this to our Makefile.am:
101 @verbatim
102 TESTS = unit_test_add
103 noinst_PROGRAMS = unit_test_add
104 CLEANFILES = add_unit.cpp
105 unit_test_add_SOURCES = add_unit.cpp
106 
107 %_unit.cpp: %.cpp
108  $(CXX) -E -o $*_unit.cpp $*.C @CFLAGS@ -DUNITTEST=1
109 @endverbatim
110  * To add addtional unit tests you just modify the first four lines. For
111  * example: to add a new unit test suite in the file sub.C we might do this.
112 @verbatim
113 TESTS = unit_test_add unit_test_sub
114 noinst_PROGRAMS = unit_test_add unit_test_sub
115 CLEANFILES = add_unit.cpp sub_unit.cpp
116 unit_test_add_SOURCES = add_unit.cpp
117 unit_test_sub_SOURCES = sub_unit.cpp
118 @endverbatim
119  * @section Notes Implementation Notes
120  * @par
121  */
122 
123 /**
124  * @file unit_test.h Unit Testing framework for C++
125  * @author Patrick Audley
126  * @date December 2004
127  */
128 
129 #ifndef _UNIT_TEST_H
130 #define _UNIT_TEST_H
131 
132 #ifdef UNITTEST
133 #include <iostream>
134 #include <vector>
135 #include <sys/time.h>
136 #include <sys/resource.h>
137 #include <sys/types.h>
138 #include <time.h>
139 #include <stdio.h>
140 
141 
142 struct rusage ruse;
143 extern int getrusage();
144 /** @brief Gets the current CPU time with microsecond accuracy.
145  * @returns microseconds since UNIX epoch
146  */
147 inline double cputime( void ) {
148  getrusage( RUSAGE_SELF, &ruse );
149  return ( ruse.ru_utime.tv_sec + ruse.ru_stime.tv_sec + 1e-6 * (ruse.ru_utime.tv_usec + ruse.ru_stime.tv_usec ) );
150 }
151 /** @brief Calculates the transactions rate.
152  * @param run_time microsecond resolution run time
153  * @param transactions number of transactions handled in run_time seconds
154  * This is useful if you want to guarantee minimun transactional throughputs in unit tests.
155  * @warning This code is obviously very test platform dependent.
156  */
157 inline double transactions_per_second( double run_time, unsigned long transactions ) {
158  return (double)transactions / run_time;
159 }
160 /** @brief Prints to stdout the results of timing an event.
161  * @param msg to print with the numbers
162  * @param run_time microsecond resolution run time
163  * @param transactions number of transactions handled in run_time seconds, if 0 then transactional output is suppressed
164  * @warning This code is obviously very test platform dependent.
165  */
166 inline void print_cputime( double run_time, unsigned long transactions = 0 ) {
167 
168  if( transactions == 0 ){
169  printf("%7.3f seconds CPU time\n", run_time );
170  }else{
171  printf("(%li x): %7.3f seconds CPU time\n", transactions, run_time );
172  printf(" (%7.3f transactions/second)\n",
173  transactions_per_second( run_time, transactions ) );
174  }
175 }
176 
177 /// typedef for unittest functions
178 typedef bool(*test_func)(void);
179 /// typedef for vectors of unittest functions
180 typedef std::vector< test_func > test_vector;
181 
182 /** @brief Start of inline Unit Test definitions
183  * Use this to start the list of unit tests. This should be followed
184  * by one or more DEFINE_TEST entries.
185  */
186 #define UNIT_TEST_DEFINES \
187  test_vector * add_test( test_func x ) { \
188  static test_vector unit_tests; \
189  if( x != NULL ) unit_tests.push_back( x ); \
190  return &unit_tests; \
191  }
192 
193 /** @brief Start a new test definition
194  * @param test_name Name of the test - must be unique in this unit test suite.
195  */
196 #define DEFINE_TEST(test_name) bool unit_test_##test_name (void)
197 
198 /** @brief Adds a defined test to test run.
199  * @param test_name Test name of a previously defined test to add the the current suite.
200  * @sa DEFINE_TEST UNIT_TEST_RUN
201  * This should be called after UNIT_TEST_RUN for each defined test.
202  */
203 #define ADD_TEST(test_name) add_test( &unit_test_##test_name );
204 
205 
206 /** @brief Starts the timer for CPU time measurement.
207  * @param msg Message that should be printed
208  * @param times Number of times the Block should be executed
209  * @note Must be terminated with an UNIT_MEASURESTOP statement.
210  */
211 #define UNIT_MEASURE_START(msg,times) \
212  { std::cout << " -> " << msg << std::flush; \
213  double measure_t1 = cputime(); \
214  int measure_times = times; \
215  for(int measure_i=0; measure_i < times; measure_i++){
216 
217 /** @brief Stops the timer for CPU time measurement and prints out result
218  * @note Must be terminated with an UNIT_MEASURESTOP statement.
219  */
220 #define UNIT_MEASURE_STOP(msg) \
221  } /* end for */ \
222  print_cputime(cputime()-measure_t1,measure_times); \
223  }
224 
225 
226 
227 /** @brief Start a Unit test run section.
228  * @param suite Name for this test suite.
229  * @note Must be terminated with an UNIT_TEST_END statement.
230  */
231 #define UNIT_TEST_RUN( suite ) \
232 int main(void) { \
233  bool result = true; \
234  std::cout << "---[ " << suite << " ]--- " << std::endl;
235 
236 /** @brief Use within a Unit Test to verify a condition.
237  * @warning Terminates test on failure.
238  */
239 #define unit_assert( msg, cond ) \
240  { \
241  char buffer[40]; memset(buffer,32,40); \
242  int pos = strlen(msg); \
243  buffer[40- (pos>40 ? 40 : pos)]=0; \
244  std::cout << " " << msg << ": " << buffer << std::flush; \
245  if( !(cond) ) { std::cout << "FAILED!" << std::endl; return false; } \
246  std::cout << "PASSED" << std::endl; \
247  }
248 
249 /** @brief Use to end a unit test in success.
250  * @note Either unit_pass or unit_fail should end every test.
251  */
252 #define unit_pass() return true;
253 
254 /** @brief Use to end a unit test in failure.
255  * @note Either unit_pass or unit_fail should end every test.
256  */
257 #define unit_fail() return false;
258 
259 /** @brief Finish a Unit Test run section.
260  */
261 #define UNIT_TEST_END \
262  test_vector *_vector = add_test( NULL ); \
263  for( unsigned short i = 0; i < _vector->size(); i++ ) { \
264  bool testresult = (*(*_vector)[i])(); \
265  if( result == true && testresult == false ) { result = false; } \
266  } \
267  return !result; \
268 }
269 
270 #endif // UNITTEST
271 
272 #endif // _UNIT_TEST_H