OpenWalnut 1.2.5
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 
00111         //! the input data
00112         boost::shared_ptr< int const > m_input;
00113 
00114         //! the result
00115         WSharedObject< int > m_result;
00116 
00117         //! thread stopped?
00118         WSharedObject< bool > m_stopped;
00119     };
00120 
00121     /**
00122      * A function that throws exceptions.
00123      */
00124     class ExceptionalFuncType
00125     {
00126     public:
00127         /**
00128          * The function.
00129          */
00130         void operator() ( std::size_t, std::size_t, WBoolFlag& )
00131         {
00132             throw WException( std::string( "Test!" ) );
00133         }
00134     };
00135 
00136 public:
00137 
00138     /**
00139      * Test if calculation with a single thread works.
00140      */
00141     void testSingleThread( void )
00142     {
00143         m_stopped = false;
00144 
00145         boost::shared_ptr< FuncType > func( new FuncType( 6 ) );
00146         WWorkerThread< FuncType > w( func, 0, 1 );
00147         w.subscribeStopSignal( boost::bind( &WWorkerThreadTest::stopTestDone, this ) );
00148 
00149         w.run();
00150         w.wait();
00151 
00152         // the result should be 1 + 2 + .. + 6 = 21
00153         TS_ASSERT_EQUALS( func->getResult(), 21 );
00154         TS_ASSERT_EQUALS( m_stopped, true );
00155     }
00156 
00157     /**
00158      * Test if the thread gets shutdown correctly.
00159      */
00160     void testStopThread()
00161     {
00162         m_stopped = false;
00163 
00164         boost::shared_ptr< FuncType > func( new FuncType( 100000000 ) );
00165         WWorkerThread< FuncType > w( func, 0, 1 );
00166         w.subscribeStopSignal( boost::bind( &WWorkerThreadTest::stopTestDone, this ) );
00167 
00168         w.run();
00169         w.requestStop();
00170         w.wait();
00171 
00172         TS_ASSERT( func->stopped() );
00173         TS_ASSERT_EQUALS( m_stopped, true );
00174     }
00175 
00176     /**
00177      * Test if multiple threads correctly compute the result.
00178      */
00179     void testMultipleThreads()
00180     {
00181         boost::shared_ptr< FuncType > func( new FuncType( 5 ) );
00182         WWorkerThread< FuncType > w0( func, 0, 3 );
00183         WWorkerThread< FuncType > w1( func, 1, 3 );
00184         WWorkerThread< FuncType > w2( func, 2, 3 );
00185 
00186         w0.run();
00187         w1.run();
00188         w2.run();
00189         w0.wait();
00190         w1.wait();
00191         w2.wait();
00192 
00193         TS_ASSERT_EQUALS( func->getResult(), 45 );
00194     }
00195 
00196 // unset the WASSERT_AS_CASSERT flag (just in case), so WAssert throws a WException
00197 #ifdef WASSERT_AS_CASSERT
00198 #define WASSERT_FLAG_CHANGED
00199 #undefine WASSERT_AS_CASSERT
00200 #endif
00201     /**
00202      * Providing a zero-Pointer as function should cause an exception.
00203      */
00204     void testNoFunction()
00205     {
00206         boost::shared_ptr< FuncType > func;
00207         TS_ASSERT_THROWS( WWorkerThread< FuncType > w( func, 0, 1 ), WException );
00208     }
00209 
00210     /**
00211      * An invalid thread id should cause an exception.
00212      */
00213     void testThreadId()
00214     {
00215         boost::shared_ptr< FuncType > func( new FuncType( 5 ) );
00216         TS_ASSERT_THROWS( WWorkerThread< FuncType > w( func, 1, 0 ), WException );
00217     }
00218 // restore WASSERT_AS_CASSERT flag
00219 #ifdef WASSERT_FLAG_CHANGED
00220 #define WASSERT_AS_CASSERT
00221 #undefine WASSERT_FLAG_CHANGED
00222 #endif
00223 
00224     /**
00225      * Test if exceptions get handled correctly.
00226      */
00227     void testExceptions()
00228     {
00229         m_exceptionHandled = false;
00230 
00231         boost::shared_ptr< ExceptionalFuncType > func( new ExceptionalFuncType );
00232         WWorkerThread< ExceptionalFuncType > w( func, 0, 1 );
00233         w.subscribeExceptionSignal( boost::bind( &WWorkerThreadTest::handleException, this, _1 ) );
00234 
00235         w.run();
00236         w.wait();
00237 
00238         TS_ASSERT_EQUALS( m_exceptionHandled, true );
00239     }
00240 
00241 private:
00242     /**
00243      * A utility function.
00244      */
00245     void stopTestDone()
00246     {
00247         m_stopped = true;
00248     }
00249 
00250     /**
00251      * Another one.
00252      *
00253      * \param e An exception.
00254      */
00255     void handleException( WException const& e )
00256     {
00257         if( strcmp( e.what(), "Test!" ) == 0 )
00258         {
00259             m_exceptionHandled = true;
00260         }
00261     }
00262 
00263     //! the thread was stopped?
00264     bool m_stopped;
00265 
00266     //! the exception was handled?
00267     bool m_exceptionHandled;
00268 };
00269 
00270 #endif  // WWORKERTHREAD_TEST_H
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends