Main Page | Modules | Namespace List | Class Hierarchy | Data Structures | Directories | File List | Namespace Members | Data Fields | Globals

unit_test.h

Go to the documentation of this file.
00001 /********************************************************************
00002 
00003 Copyright 2006, ACCESS Systems Americas, Inc. All rights reserved.
00004 
00005 The contents of this file are subject to the Mozilla Public License Version
00006 1.1 (the "License"); you may not use this file except in compliance with
00007 the License. You may obtain a copy of the License at
00008 http://www.mozilla.org/MPL/
00009 
00010 Software distributed under the License is distributed on an "AS IS" basis,
00011 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012 for the specific language governing rights and limitations under the
00013 License.
00014 
00015 The Original Code is the entire contents of this file.
00016 
00017 The Initial Developer of the Original Code is ACCESS Systems Americas, Inc.
00018 
00019 Portions created by ACCESS Systems Americas, Inc. are Copyright � 2006. All
00020 Rights Reserved.
00021 
00022 Contributor(s): none.
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         // Constructor for TestCaller. This constructor builds a new Fixture
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         // Constructor for TimeOutTestCaller. 
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         // Constructor for TimeOutTestCaller.
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                 // test timed out
00233                 kill( pThis->m_test_pid, SIGUSR1 );
00234                 
00235                 pthread_exit( NULL );
00236         }
00237         
00238         void runTest()
00239         {
00240                 // get a shared memory segment
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                         // child process                        
00257                         try
00258                         {
00259                                 // run the actual test
00260                                 m_fixture->setUp();
00261                                 ( m_fixture->*m_test )();
00262                             m_fixture->tearDown();
00263                         }
00264                         catch ( Exception &e )
00265                         {
00266                                 // caught CppUnit Exception
00267                                 shmptr->setData( e.what(), e.sourceLine().fileName().c_str(), e.sourceLine().lineNumber() );
00268                     }
00269                     catch ( std::exception &e )
00270                     {
00271                                 // caught std::exception
00272                                 shmptr->setData( e.what() );
00273                     }
00274                     catch ( ... )
00275                     {
00276                         // caught unknown exception
00277                                 shmptr->setData( "uncaught unknown exception" );
00278                     }
00279                     
00280                     // test finished
00281                         exit( 0 );
00282                 }
00283                 else if ( m_test_pid > 0 )
00284                 {
00285                         // parent process
00286                         
00287                         // spawning a wait thread
00288                         pthread_t waitThread;
00289                         pthread_create( &waitThread, NULL, &waitThreadFunc, static_cast<void *>( this ) );
00290                         
00291                         int status = 0, exitCode = 0;
00292                         
00293                         // waiting for child process to finish
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                                 // test exited with a code
00303                                 exitCode = WEXITSTATUS( status );
00304                         }
00305                         else if ( WIFSIGNALED( status ) )
00306                         {
00307                                 // test exited with a signal
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                         // received process finished signal
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

Generated on Sat Dec 16 20:29:47 2006 for hiker-0.9 by  doxygen 1.4.4