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