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