00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00033 #ifndef UNIT_TEST_H
00034 #define UNIT_TEST_H
00035
00036 #ifndef WIN32
00037 #include <dlfcn.h>
00038 #include <stdarg.h>
00039 #endif // WIN32
00040
00041 #include <cppunit/extensions/TestFactoryRegistry.h>
00042 #include <cppunit/extensions/HelperMacros.h>
00043
00044 #ifdef CPPUNIT_MAKE_UNIQUE_NAME
00045 #undef CPPUNIT_MAKE_UNIQUE_NAME
00046 #define CPPUNIT_MAKE_UNIQUE_NAME( prefix ) CPPUNIT_JOIN( prefix##Type__, __LINE__ )
00047 #endif
00048
00049 #define CPPUNIT_REGISTRY_TYPE_AUTO "Auto"
00050 #define CPPUNIT_REGISTRY_TYPE_MANUAL "Manual"
00051 #define CPPUNIT_REGISTRY_TYPE_STRESS "Stress"
00052
00053 CPPUNIT_REGISTRY_ADD_TO_DEFAULT( CPPUNIT_REGISTRY_TYPE_AUTO );
00054 CPPUNIT_REGISTRY_ADD_TO_DEFAULT( CPPUNIT_REGISTRY_TYPE_MANUAL );
00055 CPPUNIT_REGISTRY_ADD_TO_DEFAULT( CPPUNIT_REGISTRY_TYPE_STRESS );
00056
00057 #undef CPPUNIT_MAKE_UNIQUE_NAME
00058 #define CPPUNIT_MAKE_UNIQUE_NAME( prefix ) CPPUNIT_JOIN( autoRegisterRegistry__, __LINE__ )
00059
00060 #define ALP_ROOT_TEST_SUITE_REGISTRATION( registryName, registryType ) \
00061 extern "C" int AddSuite( void ) \
00062 {\
00063 CPPUNIT_NS::TestFactoryRegistry::getRegistry( registryName );\
00064 return 0;\
00065 }\
00066 CPPUNIT_REGISTRY_ADD( registryName, registryType );
00067
00068 #define CPPUNIT_NOFORK_TEST( testMethod ) \
00069 CPPUNIT_TEST_SUITE_ADD_TEST( \
00070 ( new CPPUNIT_NS::TestCaller<TestFixtureType>( \
00071 context.getTestNameFor( #testMethod), \
00072 &TestFixtureType::testMethod, \
00073 context.makeFixture() ) ) )
00074
00075 #ifndef WIN32
00076
00077 #define MAX_TEST_TIME_IN_SECONDS 15
00078
00079 #define CPPUNIT_TIMED_TEST( testMethod, timeLimit ) \
00080 CPPUNIT_TEST_SUITE_ADD_TEST( \
00081 ( new CPPUNIT_NS::TimeOutTestCaller<TestFixtureType>( \
00082 context.getTestNameFor( #testMethod ), \
00083 &TestFixtureType::testMethod, \
00084 context.makeFixture(), \
00085 timeLimit ) ) )
00086
00087 #define CPPUNIT_TIMED_EXCEPTION_TEST( testMethod, timeLimit, ExceptionType ) \
00088 CPPUNIT_TEST_SUITE_ADD_TEST( \
00089 (new CPPUNIT_NS::ExceptionTestCaseDecorator< ExceptionType >( \
00090 new CPPUNIT_NS::TimeOutTestCaller< TestFixtureType >( \
00091 context.getTestNameFor( #testMethod ), \
00092 &TestFixtureType::testMethod, \
00093 context.makeFixture(), \
00094 timeLimit ) ) ) )
00095
00096 #ifdef CPPUNIT_TEST
00097 #undef CPPUNIT_TEST
00098 #endif
00099 #define CPPUNIT_TEST( testMethod ) \
00100 CPPUNIT_TIMED_TEST( testMethod, MAX_TEST_TIME_IN_SECONDS )
00101
00102 #ifdef CPPUNIT_TEST_FAIL
00103 #undef CPPUNIT_TEST_FAIL
00104 #endif
00105 #define CPPUNIT_TEST_FAIL( testMethod ) \
00106 CPPUNIT_TIMED_EXCEPTION_TEST( testMethod, MAX_TEST_TIME_IN_SECONDS, CPPUNIT_NS::Exception )
00107
00108 #ifdef CPPUNIT_TEST_EXCEPTION
00109 #undef CPPUNIT_TEST_EXCEPTION
00110 #endif
00111 #define CPPUNIT_TEST_EXCEPTION( testMethod, ExceptionType ) \
00112 CPPUNIT_TIMED_EXCEPTION_TEST( testMethod, MAX_TEST_TIME_IN_SECONDS, ExceptionType )
00113
00114 #include <cppunit/Exception.h>
00115 #include <cppunit/TestCase.h>
00116 #include <pthread.h>
00117 #include <signal.h>
00118 #include <sys/errno.h>
00119 #include <sys/shm.h>
00120 #include <sys/time.h>
00121 #include <sys/wait.h>
00122 #include <unistd.h>
00123
00124 #if CPPUNIT_USE_TYPEINFO_NAME
00125 # include <cppunit/extensions/TypeInfoHelper.h>
00126 #endif
00127
00128 CPPUNIT_NS_BEGIN
00129
00130 class ExceptionData
00131 {
00132 public:
00133 ExceptionData() {};
00134 ~ExceptionData() {};
00135
00136 void setData( const char *sd )
00137 {
00138 m_isValid = true;
00139 strcpy( m_shortDescription, sd );
00140 };
00141
00142 void setData( const char *sd, const char *fn, int ln )
00143 {
00144 m_isValid = true;
00145 strcpy( m_shortDescription, sd );
00146 strcpy( m_fileName, fn );
00147 m_lineNumber = ln;
00148 };
00149
00150 void clearData()
00151 {
00152 m_isValid = false;
00153 strcpy( m_shortDescription, "" );
00154 strcpy( m_fileName, "" );
00155 m_lineNumber = 0;
00156 }
00157
00158 bool m_isValid;
00159 char m_shortDescription[ 255 ];
00160 char m_fileName[ 255 ];
00161 int m_lineNumber;
00162 };
00163
00164 static int shmid;
00165 static ExceptionData *shmptr;
00166
00167 template <class Fixture>
00168 class TimeOutTestCaller : public TestCase
00169 {
00170 typedef void ( Fixture::*TestMethod )();
00171
00172 public:
00173
00174 TimeOutTestCaller( std::string name, TestMethod test, double time ) :
00175 TestCase( name ),
00176 m_exception( NULL ),
00177 m_ownFixture( true ),
00178 m_fixture( new Fixture() ),
00179 m_test( test ),
00180 m_time( time )
00181 {
00182 pthread_mutex_init( &m_test_mutex, NULL );
00183 pthread_cond_init( &m_test_cond, NULL );
00184 pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
00185 }
00186
00187
00188 TimeOutTestCaller( std::string name, TestMethod test, Fixture& fixture, double time ) :
00189 TestCase( name ),
00190 m_exception( NULL ),
00191 m_ownFixture( false ),
00192 m_fixture( &fixture ),
00193 m_test( test ),
00194 m_time( time )
00195 {
00196 pthread_mutex_init( &m_test_mutex, NULL );
00197 pthread_cond_init( &m_test_cond, NULL );
00198 pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
00199 }
00200
00201
00202 TimeOutTestCaller( std::string name, TestMethod test, Fixture* fixture, double time ) :
00203 TestCase( name ),
00204 m_exception( NULL ),
00205 m_ownFixture( true ),
00206 m_fixture( fixture ),
00207 m_test( test ),
00208 m_time( time )
00209 {
00210 pthread_mutex_init( &m_test_mutex, NULL );
00211 pthread_cond_init( &m_test_cond, NULL );
00212 pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
00213 }
00214
00215 ~TimeOutTestCaller()
00216 {
00217 pthread_cond_destroy( &m_test_cond );
00218 pthread_mutex_destroy( &m_test_mutex );
00219
00220 if ( m_ownFixture )
00221 delete m_fixture;
00222
00223 if ( m_exception )
00224 delete m_exception;
00225 }
00226
00227 static void * waitThreadFunc( void *ptr )
00228 {
00229 TimeOutTestCaller<Fixture> *pThis = static_cast<TimeOutTestCaller<Fixture> *>( ptr );
00230
00231 sleep( static_cast<unsigned int>( pThis->m_time ) );
00232
00233 kill( pThis->m_test_pid, SIGUSR1 );
00234
00235 pthread_exit( NULL );
00236 }
00237
00238 void runTest()
00239 {
00240
00241 if ( ( shmid = shmget( IPC_PRIVATE, sizeof( ExceptionData ), 0666 ) ) < 0 )
00242 {
00243 perror( "shmget" );
00244 exit( 1 );
00245 }
00246 shmptr = static_cast<ExceptionData *>( shmat( shmid, 0, 0 ) );
00247 if ( shmptr == reinterpret_cast<ExceptionData *>( -1 ) )
00248 {
00249 perror( "shmat" );
00250 exit( 1 );
00251 }
00252 shmptr->clearData();
00253
00254 if ( ( m_test_pid = fork() ) == 0 )
00255 {
00256
00257 try
00258 {
00259
00260 m_fixture->setUp();
00261 ( m_fixture->*m_test )();
00262 m_fixture->tearDown();
00263 }
00264 catch ( Exception &e )
00265 {
00266
00267 shmptr->setData( e.what(), e.sourceLine().fileName().c_str(), e.sourceLine().lineNumber() );
00268 }
00269 catch ( std::exception &e )
00270 {
00271
00272 shmptr->setData( e.what() );
00273 }
00274 catch ( ... )
00275 {
00276
00277 shmptr->setData( "uncaught unknown exception" );
00278 }
00279
00280
00281 exit( 0 );
00282 }
00283 else if ( m_test_pid > 0 )
00284 {
00285
00286
00287
00288 pthread_t waitThread;
00289 pthread_create( &waitThread, NULL, &waitThreadFunc, static_cast<void *>( this ) );
00290
00291 int status = 0, exitCode = 0;
00292
00293
00294 pid_t pid = waitpid( m_test_pid, &status, 0 );
00295 if ( pid == -1 )
00296 perror( "wait error" );
00297
00298 pthread_cancel( waitThread );
00299
00300 if ( WIFEXITED( status ) )
00301 {
00302
00303 exitCode = WEXITSTATUS( status );
00304 }
00305 else if ( WIFSIGNALED( status ) )
00306 {
00307
00308 exitCode = WTERMSIG( status );
00309 }
00310
00311 char buf[255];
00312 if ( exitCode == SIGUSR1 )
00313 {
00314 sprintf( buf, "Test timed out after %i seconds", static_cast<unsigned int>( m_time ) );
00315 shmptr->setData( buf );
00316 }
00317 else if ( exitCode != 0 )
00318 {
00319 sprintf( buf, "Test crashed with exit code = %i", exitCode );
00320 shmptr->setData( buf );
00321 }
00322
00323
00324 pthread_join( waitThread, NULL );
00325
00326 int retVal = 0;
00327 waitpid( -1, &retVal, WNOHANG );
00328
00329 if ( shmptr->m_isValid )
00330 m_exception = new Exception(
00331 Message( shmptr->m_shortDescription ),
00332 SourceLine( shmptr->m_fileName, shmptr->m_lineNumber ) );
00333
00334 if ( shmctl( shmid, IPC_RMID, 0 ) < 0 )
00335 printf( "shmctl error" );
00336
00337 if ( m_exception )
00338 throw *m_exception;
00339 }
00340 else
00341 printf( "fork error" );
00342 }
00343
00344 void setUp()
00345 {
00346 }
00347
00348 void tearDown()
00349 {
00350 }
00351
00352 std::string toString() const
00353 {
00354 return "TimeOutTestCaller " + getName();
00355 }
00356
00357 private:
00358 TimeOutTestCaller( const TimeOutTestCaller &other );
00359 TimeOutTestCaller &operator =( const TimeOutTestCaller &other );
00360
00361 pid_t m_test_pid;
00362 pthread_mutex_t m_test_mutex;
00363 pthread_cond_t m_test_cond;
00364 Exception *m_exception;
00365 bool m_ownFixture;
00366 Fixture *m_fixture;
00367 TestMethod m_test;
00368 double m_time;
00369 };
00370
00371 class BundleLoader
00372 {
00373 public:
00374 BundleLoader(const char * bundle1, ...)
00375 {
00376 bundlemgr_handle = dlopen("libalp_bundlemgr.so", RTLD_LAZY|RTLD_LOCAL);
00377
00378 if (!bundlemgr_handle) {
00379 throw Exception(Message(dlerror()));
00380 }
00381
00382 typedef int (*init_f_t)(void);
00383 init_f_t init_f = (init_f_t)dlsym(bundlemgr_handle, "alp_bundle_init");
00384
00385 if (!init_f) {
00386 throw Exception(Message("Unable to find alp_bundle_init symbol"));
00387 }
00388
00389 if (init_f() != 0) {
00390 throw Exception(Message("alp_bundle_init returned failure"));
00391 }
00392
00393 struct index_t {
00394 unsigned int value;
00395 };
00396
00397 typedef index_t (*find_by_name_f_t)(const char*);
00398 find_by_name_f_t find_by_name_f = (find_by_name_f_t)dlsym(bundlemgr_handle, "alp_bundle_by_name");
00399
00400 if (!find_by_name_f) {
00401 throw Exception(Message("Unable to find alp_bundle_by_name"));
00402 }
00403
00404 typedef void * (*open_f_t)(index_t);
00405 open_f_t open_f = (open_f_t)dlsym(bundlemgr_handle, "alp_bundle_open");
00406
00407 if (!open_f) {
00408 throw Exception(Message("Unable to find alp_bundle_open"));
00409 }
00410
00411 va_list ap;
00412 va_start(ap, bundle1);
00413
00414 for (const char * bundle = bundle1; bundle; bundle = va_arg(ap, const char*)) {
00415
00416 index_t index = find_by_name_f(bundle);
00417
00418 if (index.value == 0) {
00419 throw Exception(Message("Unable to find bundle"));
00420 }
00421 void * ref = open_f(index);
00422 if (ref == 0) {
00423 throw Exception(Message("Unable to open bundle"));
00424 }
00425
00426 }
00427 }
00428
00429 ~BundleLoader()
00430 {
00431 typedef int (*fini_f_t)(void);
00432 fini_f_t fini_f = (fini_f_t)dlsym(bundlemgr_handle, "alp_bundle_fini");
00433
00434 if (!fini_f) {
00435 throw "Unable to find alp_bundle_fini symbol";
00436 }
00437
00438 if (fini_f() != 0) {
00439 throw "alp_bundle_fini returned failure";
00440 }
00441
00442 dlclose(bundlemgr_handle);
00443 }
00444
00445 private:
00446 void * bundlemgr_handle;
00447
00448 };
00449
00450 CPPUNIT_NS_END
00451 #endif // WIN32
00452
00453 #endif