Robot Simulator of the Robotics Group for Self-Organization of Control: unit_test.hpp Source File

# unit_test.hpp

Go to the documentation of this file.

    00001 /***************************************************************************
    00002  *   Copyright (C) 2004 by Patrick Audley                                  *
    00003  *   paudley@blackcat.ca                                                   *
    00004  *   modified by Georg Martius (georg.martius@web.de)                      *
    00005  ***************************************************************************
    00006 # _______________
    00007 # VERSION HISTORY
    00008 #
    00009 # v1.0 (2004/12/28)
    00010 #  - prelimary version
    00011 # v1.1 (2005/05/30) (By Georg Martius
    00012 #  - improved output
    00013 #  - improved speed measurement
    00014 ##
    00015 */
    00016
    00017 /** @section C++ Unit Testing Framework
    00018  * See implementation in
    00019  * @ref unit_test.h
    00020  *
    00021  * @par
    00022  * @section writing Writing Unit Tests
    00023  * @par
    00024  * Ideally, unit tests are written with the code they test.  The easiest way
    00025  * to do this is to include all the unit tests at the bottom of each source
    00026  * that they relate too.  It's also possible to create source files of nothing
    00027  * but tests to expand coverage across multiple translation modules.
    00028  * @par
    00029  * Let's take a simple example:  we have a new function that adds two numbers.
    00030  * @code
    00031  * int addTwoNumbers( int a, int b ) {
    00032  *   return a + b;
    00033  * }
    00034  * @endcode
    00035  * To write a unit test that checks that @f$addTwoNumbers(x_1,x_2)=x_1+x_2@f$ we
    00036  * would write the unit test like so:
    00037  * @code
    00038  * #ifdef UNITTEST
    00039  * #include "unit_test.h"
    00040  *
    00041  * UNIT_TEST_DEFINES
    00042  *
    00043  * DEFINE_TEST( check_two_plus_two ) {
    00044  *   unit_assert( "2+2=4", addTwoNumbers(2,2)==4 );
    00045  * }
    00046  *
    00047  * UNIT_TEST_RUN( "addTwoNumbers Tests" )
    00048  *   ADD_TEST( check_two_plus_two )
    00049  * UNIT_TEST_END
    00050  *
    00051  * #endif // UNITTEST
    00052  * @endcode
    00053  * @par
    00054  * Now we have a test suite defined that will only be compiled when we define UNITTEST.
    00055  * UNIT_TEST_RUN actually creates a main() function that runs the tests so if we put
    00056  * this code into a file (say add.cpp) then we can compile and run it like so:
    00057 @verbatim
    00058 # gcc -DUNITTEST -o unit_test_add add.cpp
    00059 # ./unit_test_add
    00060 ---[ addTwoNumbers Tests ]---
    00061   2+2=4: PASSED
    00062 @endverbatim
    00063  * @par
    00064  * So far so good, let's add a new test that we think will fail.
    00065  * @code
    00066  * #ifdef UNITTEST
    00067  * #include "unit_test.h"
    00068  *
    00069  * UNIT_TEST_DEFINES
    00070  *
    00071  * DEFINE_TEST( check_two_plus_two ) {
    00072  *   unit_assert( "2+2=4", addTwoNumbers(2,2)==4 );
    00073  *   unit_pass();
    00074  * }
    00075  *
    00076  * DEFINE_TEST( check_bogus ) {
    00077  *   unit_assert( "1+5=9", addTwoNumbers(1,5)==9 );
    00078  *   unit_pass();
    00079  * }
    00080  *
    00081  * UNIT_TEST_RUN( "addTwoNumbers Tests" )
    00082  *   ADD_TEST( check_negatives )
    00083  * UNIT_TEST_END
    00084  *
    00085  * #endif // UNITTEST
    00086  * @endcode
    00087  * Running the unit_test now we get:
    00088 @verbatim
    00089 # gcc -DUNITTEST -o unit_test_add add.cpp
    00090 # ./unit_test_add
    00091 ---[ addTwoNumbers Tests ]---
    00092   2+2=4: PASSED
    00093   1+5=9: FAILED
    00094 @endverbatim
    00095  * @par
    00096  * @section adding Integrating with Automake
    00097  * @par
    00098  * Automake has the ability to define testing targets that get run when
    00099  * issue "make check" command.  Adding these tests are pretty straight
    00100  * forward.  For the above we would add this to our Makefile.am:
    00101 @verbatim
    00102 TESTS = unit_test_add
    00103 noinst_PROGRAMS = unit_test_add
    00104 CLEANFILES = add_unit.cpp
    00105 unit_test_add_SOURCES = add_unit.cpp
    00106
    00107 %_unit.cpp: %.cpp
    00108         $(CXX) -E -o $*_unit.cpp $*.C @CFLAGS@ -DUNITTEST=1
    00109 @endverbatim
    00110  * To add addtional unit tests you just modify the first four lines.  For
    00111  * example: to add a new unit test suite in the file sub.C we might do this.
    00112 @verbatim
    00113 TESTS = unit_test_add unit_test_sub
    00114 noinst_PROGRAMS = unit_test_add unit_test_sub
    00115 CLEANFILES = add_unit.cpp sub_unit.cpp
    00116 unit_test_add_SOURCES = add_unit.cpp
    00117 unit_test_sub_SOURCES = sub_unit.cpp
    00118 @endverbatim
    00119  * @section Notes Implementation Notes
    00120  * @par
    00121  */
    00122
    00123 /**
    00124  * @file unit_test.h Unit Testing framework for C++
    00125  * @author Patrick Audley
    00126  * @date December 2004
    00127  */
    00128
    00129 #ifndef _UNIT_TEST_H
    00130 #define _UNIT_TEST_H
    00131
    00132 #ifdef UNITTEST
    00133 #include <iostream>
    00134 #include <vector>
    00135 #include <sys/time.h>
    00136 #include <sys/resource.h>
    00137 #include <sys/types.h>
    00138 #include <time.h>
    00139 #include <stdio.h>
    00140
    00141
    00142 struct rusage ruse;
    00143 extern int getrusage();
    00144 /** @brief Gets the current CPU time with microsecond accuracy.
    00145  *  @returns microseconds since UNIX epoch
    00146  */
    00147 inline double cputime( void ) {
    00148   getrusage( RUSAGE_SELF, &ruse );
    00149         return ( ruse.ru_utime.tv_sec + ruse.ru_stime.tv_sec + 1e-6 * (ruse.ru_utime.tv_usec + ruse.ru_stime.tv_usec ) );
    00150 }
    00151 /** @brief Calculates the transactions rate.
    00152  *  @param run_time microsecond resolution run time
    00153  *  @param transactions number of transactions handled in run_time seconds
    00154  *  This is useful if you want to guarantee minimun transactional throughputs in unit tests.
    00155  *  @warning This code is obviously very test platform dependent.
    00156  */
    00157 inline double transactions_per_second( double run_time, unsigned long transactions ) {
    00158         return (double)transactions / run_time;
    00159 }
    00160 /** @brief Prints to stdout the results of timing an event.
    00161  *  @param msg to print with the numbers
    00162  *  @param run_time microsecond resolution run time
    00163  *  @param transactions number of transactions handled in run_time seconds, if 0 then transactional output is suppressed
    00164  *  @warning This code is obviously very test platform dependent.
    00165  */
    00166 inline void print_cputime( double run_time, unsigned long transactions = 0 ) {
    00167
    00168   if( transactions == 0 ){
    00169         printf("%7.3f seconds CPU time\n", run_time );
    00170   }else{
    00171     printf("(%li x):  %7.3f seconds CPU time\n", transactions, run_time );
    00172     printf("      (%7.3f transactions/second)\n",
    00173            transactions_per_second( run_time, transactions ) );
    00174   }
    00175 }
    00176
    00177 /// typedef for unittest functions
    00178 typedef bool(*test_func)(void);
    00179 /// typedef for vectors of unittest functions
    00180 typedef std::vector< test_func > test_vector;
    00181
    00182 /** @brief Start of inline Unit Test definitions
    00183  *  Use this to start the list of unit tests.  This should be followed
    00184  *  by one or more DEFINE_TEST entries.
    00185  */
    00186 #define UNIT_TEST_DEFINES \
    00187   test_vector * add_test( test_func x ) { \
    00188     static test_vector unit_tests; \
    00189     if( x != NULL ) unit_tests.push_back( x ); \
    00190     return &unit_tests; \
    00191   }
    00192
    00193 /** @brief Start a new test definition
    00194  *  @param test_name Name of the test - must be unique in this unit test suite.
    00195  */
    00196 #define DEFINE_TEST(test_name) bool unit_test_##test_name (void)
    00197
    00198 /** @brief Adds a defined test to test run.
    00199  *  @param test_name Test name of a previously defined test to add the the current suite.
    00200  *  @sa DEFINE_TEST UNIT_TEST_RUN
    00201  *  This should be called after UNIT_TEST_RUN for each defined test.
    00202  */
    00203 #define ADD_TEST(test_name) add_test( &unit_test_##test_name );
    00204
    00205
    00206 /** @brief Starts the timer for CPU time measurement.
    00207  *  @param msg Message that should be printed
    00208  *  @param times Number of times the Block should be executed
    00209  *  @note Must be terminated with an UNIT_MEASURESTOP statement.
    00210  */
    00211 #define UNIT_MEASURE_START(msg,times) \
    00212   { std::cout << "  -> " <<  msg << std::flush; \
    00213     double measure_t1 = cputime(); \
    00214     int measure_times = times; \
    00215     for(int measure_i=0; measure_i < times; measure_i++){
    00216
    00217 /** @brief Stops the timer for CPU time measurement and prints out result
    00218  *  @note Must be terminated with an UNIT_MEASURESTOP statement.
    00219  */
    00220 #define UNIT_MEASURE_STOP(msg) \
    00221     } /* end for */ \
    00222     print_cputime(cputime()-measure_t1,measure_times); \
    00223   }
    00224
    00225
    00226
    00227 /** @brief Start a Unit test run section.
    00228  *  @param suite Name for this test suite.
    00229  *  @note Must be terminated with an UNIT_TEST_END statement.
    00230  */
    00231 #define UNIT_TEST_RUN( suite ) \
    00232 int main(void) { \
    00233   bool result = true; \
    00234   std::cout << "---[ " << suite << " ]--- " << std::endl;
    00235
    00236 /** @brief Use within a Unit Test to verify a condition.
    00237  *  @warning Terminates test on failure.
    00238  */
    00239 #define unit_assert( msg, cond ) \
    00240   { \
    00241   char buffer[40]; memset(buffer,32,40); \
    00242   int pos = strlen(msg); \
    00243   buffer[40- (pos>40 ? 40 : pos)]=0; \
    00244   std::cout << "    " << msg << ": " << buffer << std::flush; \
    00245   if( !(cond) ) { std::cout << "FAILED!" << std::endl; return false; } \
    00246   std::cout << "PASSED" << std::endl; \
    00247   }
    00248
    00249 /** @brief Use to end a unit test in success.
    00250  *  @note Either unit_pass or unit_fail should end every test.
    00251  */
    00252 #define unit_pass() return true;
    00253
    00254 /** @brief Use to end a unit test in failure.
    00255  *  @note Either unit_pass or unit_fail should end every test.
    00256  */
    00257 #define unit_fail() return false;
    00258
    00259 /** @brief Finish a Unit Test run section.
    00260  */
    00261 #define UNIT_TEST_END \
    00262   test_vector *_vector = add_test( NULL ); \
    00263   for( unsigned short i = 0; i < _vector->size(); i++ ) { \
    00264      bool testresult = (*(*_vector)[i])(); \
    00265      if( result == true && testresult == false ) { result = false; } \
    00266   } \
    00267   return !result; \
    00268 }
    00269
    00270 #endif // UNITTEST
    00271
    00272 #endif // _UNIT_TEST_H