OpenWalnut 1.2.5
|
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