OpenWalnut  1.4.0
WWorkerThread_test.h
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #ifndef WWORKERTHREAD_TEST_H
00026 #define WWORKERTHREAD_TEST_H
00027 
00028 #include <string>
00029 
00030 #include <cxxtest/TestSuite.h>
00031 
00032 #include "../WWorkerThread.h"
00033 #include "../WSharedObject.h"
00034 
00035 /**
00036  * Tests the WWorkerThread class.
00037  */
00038 class WWorkerThreadTest : public CxxTest::TestSuite
00039 {
00040     /**
00041      * A threaded function.
00042      */
00043     class FuncType
00044     {
00045     public:
00046         /**
00047          * Constructor, initialize some stuff.
00048          *
00049          * \param value An int value.
00050          */
00051         FuncType( int value ) // NOLINT
00052             : m_input( new int( value ) ) // NOLINT
00053         {
00054             // init stuff here
00055             m_result.getWriteTicket()->get() = 0;
00056             m_stopped.getWriteTicket()->get() = false;
00057 
00058             if( value < 0 )
00059             {
00060                 value = -value;
00061             }
00062         }
00063 
00064         /**
00065          * This is the actual thread function.
00066          *
00067          * \param shutdown A flag indicating the thread is supposed to stop.
00068          */
00069         void operator() ( std::size_t, std::size_t, WBoolFlag const& shutdown )
00070         {
00071             for( int i = 1; i <= *m_input.get() && !shutdown(); ++i )
00072             {
00073                 m_result.getWriteTicket()->get() += i;
00074             }
00075             if( shutdown() )
00076             {
00077                 m_stopped.getWriteTicket()->get() = true;
00078             }
00079             sleep( 1 );
00080         }
00081 
00082         /**
00083          * Check if the thread was ordered to stop.
00084          * \return true, if the thread was ordered to stop
00085          */
00086         bool stopped()
00087         {
00088             return m_stopped.getReadTicket()->get();
00089         }
00090 
00091         /**
00092          * A method to extract the result.
00093          *
00094          * \return The result of the threaded computation.
00095          */
00096         int getResult()
00097         {
00098             return m_result.getReadTicket()->get();
00099         }
00100 
00101         /**
00102          * Reset everything.
00103          */
00104         void reset()
00105         {
00106             m_result.getWriteTicket()->get() = 0;
00107         }
00108 
00109     private:
00110         //! the input data
00111         boost::shared_ptr< int const > m_input;
00112 
00113         //! the result
00114         WSharedObject< int > m_result;
00115 
00116         //! thread stopped?
00117         WSharedObject< bool > m_stopped;
00118     };
00119 
00120     /**
00121      * A function that throws exceptions.
00122      */
00123     class ExceptionalFuncType
00124     {
00125     public:
00126         /**
00127          * The function.
00128          */
00129         void operator() ( std::size_t, std::size_t, WBoolFlag& )
00130         {
00131             throw WException( std::string( "Test!" ) );
00132         }
00133     };
00134 
00135 public:
00136     /**
00137      * Test if calculation with a single thread works.
00138      */
00139     void testSingleThread( void )
00140     {
00141         m_stopped = false;
00142 
00143         boost::shared_ptr< FuncType > func( new FuncType( 6 ) );
00144         WWorkerThread< FuncType > w( func, 0, 1 );
00145         w.subscribeStopSignal( boost::bind( &WWorkerThreadTest::stopTestDone, this ) );
00146 
00147         w.run();
00148         w.wait();
00149 
00150         // the result should be 1 + 2 + .. + 6 = 21
00151         TS_ASSERT_EQUALS( func->getResult(), 21 );
00152         TS_ASSERT_EQUALS( m_stopped, true );
00153     }
00154 
00155     /**
00156      * Test if the thread gets shutdown correctly.
00157      */
00158     void testStopThread()
00159     {
00160         m_stopped = false;
00161 
00162         boost::shared_ptr< FuncType > func( new FuncType( 100000000 ) );
00163         WWorkerThread< FuncType > w( func, 0, 1 );
00164         w.subscribeStopSignal( boost::bind( &WWorkerThreadTest::stopTestDone, this ) );
00165 
00166         w.run();
00167         w.requestStop();
00168         w.wait();
00169 
00170         TS_ASSERT( func->stopped() );
00171         TS_ASSERT_EQUALS( m_stopped, true );
00172     }
00173 
00174     /**
00175      * Test if multiple threads correctly compute the result.
00176      */
00177     void testMultipleThreads()
00178     {
00179         boost::shared_ptr< FuncType > func( new FuncType( 5 ) );
00180         WWorkerThread< FuncType > w0( func, 0, 3 );
00181         WWorkerThread< FuncType > w1( func, 1, 3 );
00182         WWorkerThread< FuncType > w2( func, 2, 3 );
00183 
00184         w0.run();
00185         w1.run();
00186         w2.run();
00187         w0.wait();
00188         w1.wait();
00189         w2.wait();
00190 
00191         TS_ASSERT_EQUALS( func->getResult(), 45 );
00192     }
00193 
00194 // unset the WASSERT_AS_CASSERT flag (just in case), so WAssert throws a WException
00195 #ifdef WASSERT_AS_CASSERT
00196 #define WASSERT_FLAG_CHANGED
00197 #undefine WASSERT_AS_CASSERT
00198 #endif
00199     /**
00200      * Providing a zero-Pointer as function should cause an exception.
00201      */
00202     void testNoFunction()
00203     {
00204         boost::shared_ptr< FuncType > func;
00205         TS_ASSERT_THROWS( WWorkerThread< FuncType > w( func, 0, 1 ), WException );
00206     }
00207 
00208     /**
00209      * An invalid thread id should cause an exception.
00210      */
00211     void testThreadId()
00212     {
00213         boost::shared_ptr< FuncType > func( new FuncType( 5 ) );
00214         TS_ASSERT_THROWS( WWorkerThread< FuncType > w( func, 1, 0 ), WException );
00215     }
00216 // restore WASSERT_AS_CASSERT flag
00217 #ifdef WASSERT_FLAG_CHANGED
00218 #define WASSERT_AS_CASSERT
00219 #undefine WASSERT_FLAG_CHANGED
00220 #endif
00221 
00222     /**
00223      * Test if exceptions get handled correctly.
00224      */
00225     void testExceptions()
00226     {
00227         m_exceptionHandled = false;
00228 
00229         boost::shared_ptr< ExceptionalFuncType > func( new ExceptionalFuncType );
00230         WWorkerThread< ExceptionalFuncType > w( func, 0, 1 );
00231         w.subscribeExceptionSignal( boost::bind( &WWorkerThreadTest::handleException, this, _1 ) );
00232 
00233         w.run();
00234         w.wait();
00235 
00236         TS_ASSERT_EQUALS( m_exceptionHandled, true );
00237     }
00238 
00239 private:
00240     /**
00241      * A utility function.
00242      */
00243     void stopTestDone()
00244     {
00245         m_stopped = true;
00246     }
00247 
00248     /**
00249      * Another one.
00250      *
00251      * \param e An exception.
00252      */
00253     void handleException( WException const& e )
00254     {
00255         if( strcmp( e.what(), "Test!" ) == 0 )
00256         {
00257             m_exceptionHandled = true;
00258         }
00259     }
00260 
00261     //! the thread was stopped?
00262     bool m_stopped;
00263 
00264     //! the exception was handled?
00265     bool m_exceptionHandled;
00266 };
00267 
00268 #endif  // WWORKERTHREAD_TEST_H