OpenWalnut  1.3.1
WWorkerThread_test.h
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #ifndef WWORKERTHREAD_TEST_H
26 #define WWORKERTHREAD_TEST_H
27 
28 #include <string>
29 
30 #include <cxxtest/TestSuite.h>
31 
32 #include "../WWorkerThread.h"
33 #include "../WSharedObject.h"
34 
35 /**
36  * Tests the WWorkerThread class.
37  */
38 class WWorkerThreadTest : public CxxTest::TestSuite
39 {
40  /**
41  * A threaded function.
42  */
43  class FuncType
44  {
45  public:
46  /**
47  * Constructor, initialize some stuff.
48  *
49  * \param value An int value.
50  */
51  FuncType( int value ) // NOLINT
52  : m_input( new int( value ) ) // NOLINT
53  {
54  // init stuff here
55  m_result.getWriteTicket()->get() = 0;
56  m_stopped.getWriteTicket()->get() = false;
57 
58  if( value < 0 )
59  {
60  value = -value;
61  }
62  }
63 
64  /**
65  * This is the actual thread function.
66  *
67  * \param shutdown A flag indicating the thread is supposed to stop.
68  */
69  void operator() ( std::size_t, std::size_t, WBoolFlag const& shutdown )
70  {
71  for( int i = 1; i <= *m_input.get() && !shutdown(); ++i )
72  {
73  m_result.getWriteTicket()->get() += i;
74  }
75  if( shutdown() )
76  {
77  m_stopped.getWriteTicket()->get() = true;
78  }
79  sleep( 1 );
80  }
81 
82  /**
83  * Check if the thread was ordered to stop.
84  * \return true, if the thread was ordered to stop
85  */
86  bool stopped()
87  {
88  return m_stopped.getReadTicket()->get();
89  }
90 
91  /**
92  * A method to extract the result.
93  *
94  * \return The result of the threaded computation.
95  */
96  int getResult()
97  {
98  return m_result.getReadTicket()->get();
99  }
100 
101  /**
102  * Reset everything.
103  */
104  void reset()
105  {
106  m_result.getWriteTicket()->get() = 0;
107  }
108 
109  private:
110  //! the input data
111  boost::shared_ptr< int const > m_input;
112 
113  //! the result
115 
116  //! thread stopped?
118  };
119 
120  /**
121  * A function that throws exceptions.
122  */
124  {
125  public:
126  /**
127  * The function.
128  */
129  void operator() ( std::size_t, std::size_t, WBoolFlag& )
130  {
131  throw WException( std::string( "Test!" ) );
132  }
133  };
134 
135 public:
136  /**
137  * Test if calculation with a single thread works.
138  */
139  void testSingleThread( void )
140  {
141  m_stopped = false;
142 
143  boost::shared_ptr< FuncType > func( new FuncType( 6 ) );
144  WWorkerThread< FuncType > w( func, 0, 1 );
145  w.subscribeStopSignal( boost::bind( &WWorkerThreadTest::stopTestDone, this ) );
146 
147  w.run();
148  w.wait();
149 
150  // the result should be 1 + 2 + .. + 6 = 21
151  TS_ASSERT_EQUALS( func->getResult(), 21 );
152  TS_ASSERT_EQUALS( m_stopped, true );
153  }
154 
155  /**
156  * Test if the thread gets shutdown correctly.
157  */
159  {
160  m_stopped = false;
161 
162  boost::shared_ptr< FuncType > func( new FuncType( 100000000 ) );
163  WWorkerThread< FuncType > w( func, 0, 1 );
164  w.subscribeStopSignal( boost::bind( &WWorkerThreadTest::stopTestDone, this ) );
165 
166  w.run();
167  w.requestStop();
168  w.wait();
169 
170  TS_ASSERT( func->stopped() );
171  TS_ASSERT_EQUALS( m_stopped, true );
172  }
173 
174  /**
175  * Test if multiple threads correctly compute the result.
176  */
178  {
179  boost::shared_ptr< FuncType > func( new FuncType( 5 ) );
180  WWorkerThread< FuncType > w0( func, 0, 3 );
181  WWorkerThread< FuncType > w1( func, 1, 3 );
182  WWorkerThread< FuncType > w2( func, 2, 3 );
183 
184  w0.run();
185  w1.run();
186  w2.run();
187  w0.wait();
188  w1.wait();
189  w2.wait();
190 
191  TS_ASSERT_EQUALS( func->getResult(), 45 );
192  }
193 
194 // unset the WASSERT_AS_CASSERT flag (just in case), so WAssert throws a WException
195 #ifdef WASSERT_AS_CASSERT
196 #define WASSERT_FLAG_CHANGED
197 #undefine WASSERT_AS_CASSERT
198 #endif
199  /**
200  * Providing a zero-Pointer as function should cause an exception.
201  */
203  {
204  boost::shared_ptr< FuncType > func;
205  TS_ASSERT_THROWS( WWorkerThread< FuncType > w( func, 0, 1 ), WException );
206  }
207 
208  /**
209  * An invalid thread id should cause an exception.
210  */
212  {
213  boost::shared_ptr< FuncType > func( new FuncType( 5 ) );
214  TS_ASSERT_THROWS( WWorkerThread< FuncType > w( func, 1, 0 ), WException );
215  }
216 // restore WASSERT_AS_CASSERT flag
217 #ifdef WASSERT_FLAG_CHANGED
218 #define WASSERT_AS_CASSERT
219 #undefine WASSERT_FLAG_CHANGED
220 #endif
221 
222  /**
223  * Test if exceptions get handled correctly.
224  */
226  {
227  m_exceptionHandled = false;
228 
229  boost::shared_ptr< ExceptionalFuncType > func( new ExceptionalFuncType );
230  WWorkerThread< ExceptionalFuncType > w( func, 0, 1 );
231  w.subscribeExceptionSignal( boost::bind( &WWorkerThreadTest::handleException, this, _1 ) );
232 
233  w.run();
234  w.wait();
235 
236  TS_ASSERT_EQUALS( m_exceptionHandled, true );
237  }
238 
239 private:
240  /**
241  * A utility function.
242  */
244  {
245  m_stopped = true;
246  }
247 
248  /**
249  * Another one.
250  *
251  * \param e An exception.
252  */
253  void handleException( WException const& e )
254  {
255  if( strcmp( e.what(), "Test!" ) == 0 )
256  {
257  m_exceptionHandled = true;
258  }
259  }
260 
261  //! the thread was stopped?
262  bool m_stopped;
263 
264  //! the exception was handled?
266 };
267 
268 #endif // WWORKERTHREAD_TEST_H