OpenWalnut  1.2.5
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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 
111  //! the input data
112  boost::shared_ptr< int const > m_input;
113 
114  //! the result
116 
117  //! thread stopped?
119  };
120 
121  /**
122  * A function that throws exceptions.
123  */
125  {
126  public:
127  /**
128  * The function.
129  */
130  void operator() ( std::size_t, std::size_t, WBoolFlag& )
131  {
132  throw WException( std::string( "Test!" ) );
133  }
134  };
135 
136 public:
137 
138  /**
139  * Test if calculation with a single thread works.
140  */
141  void testSingleThread( void )
142  {
143  m_stopped = false;
144 
145  boost::shared_ptr< FuncType > func( new FuncType( 6 ) );
146  WWorkerThread< FuncType > w( func, 0, 1 );
147  w.subscribeStopSignal( boost::bind( &WWorkerThreadTest::stopTestDone, this ) );
148 
149  w.run();
150  w.wait();
151 
152  // the result should be 1 + 2 + .. + 6 = 21
153  TS_ASSERT_EQUALS( func->getResult(), 21 );
154  TS_ASSERT_EQUALS( m_stopped, true );
155  }
156 
157  /**
158  * Test if the thread gets shutdown correctly.
159  */
161  {
162  m_stopped = false;
163 
164  boost::shared_ptr< FuncType > func( new FuncType( 100000000 ) );
165  WWorkerThread< FuncType > w( func, 0, 1 );
166  w.subscribeStopSignal( boost::bind( &WWorkerThreadTest::stopTestDone, this ) );
167 
168  w.run();
169  w.requestStop();
170  w.wait();
171 
172  TS_ASSERT( func->stopped() );
173  TS_ASSERT_EQUALS( m_stopped, true );
174  }
175 
176  /**
177  * Test if multiple threads correctly compute the result.
178  */
180  {
181  boost::shared_ptr< FuncType > func( new FuncType( 5 ) );
182  WWorkerThread< FuncType > w0( func, 0, 3 );
183  WWorkerThread< FuncType > w1( func, 1, 3 );
184  WWorkerThread< FuncType > w2( func, 2, 3 );
185 
186  w0.run();
187  w1.run();
188  w2.run();
189  w0.wait();
190  w1.wait();
191  w2.wait();
192 
193  TS_ASSERT_EQUALS( func->getResult(), 45 );
194  }
195 
196 // unset the WASSERT_AS_CASSERT flag (just in case), so WAssert throws a WException
197 #ifdef WASSERT_AS_CASSERT
198 #define WASSERT_FLAG_CHANGED
199 #undefine WASSERT_AS_CASSERT
200 #endif
201  /**
202  * Providing a zero-Pointer as function should cause an exception.
203  */
205  {
206  boost::shared_ptr< FuncType > func;
207  TS_ASSERT_THROWS( WWorkerThread< FuncType > w( func, 0, 1 ), WException );
208  }
209 
210  /**
211  * An invalid thread id should cause an exception.
212  */
214  {
215  boost::shared_ptr< FuncType > func( new FuncType( 5 ) );
216  TS_ASSERT_THROWS( WWorkerThread< FuncType > w( func, 1, 0 ), WException );
217  }
218 // restore WASSERT_AS_CASSERT flag
219 #ifdef WASSERT_FLAG_CHANGED
220 #define WASSERT_AS_CASSERT
221 #undefine WASSERT_FLAG_CHANGED
222 #endif
223 
224  /**
225  * Test if exceptions get handled correctly.
226  */
228  {
229  m_exceptionHandled = false;
230 
231  boost::shared_ptr< ExceptionalFuncType > func( new ExceptionalFuncType );
232  WWorkerThread< ExceptionalFuncType > w( func, 0, 1 );
233  w.subscribeExceptionSignal( boost::bind( &WWorkerThreadTest::handleException, this, _1 ) );
234 
235  w.run();
236  w.wait();
237 
238  TS_ASSERT_EQUALS( m_exceptionHandled, true );
239  }
240 
241 private:
242  /**
243  * A utility function.
244  */
246  {
247  m_stopped = true;
248  }
249 
250  /**
251  * Another one.
252  *
253  * \param e An exception.
254  */
255  void handleException( WException const& e )
256  {
257  if( strcmp( e.what(), "Test!" ) == 0 )
258  {
259  m_exceptionHandled = true;
260  }
261  }
262 
263  //! the thread was stopped?
264  bool m_stopped;
265 
266  //! the exception was handled?
268 };
269 
270 #endif // WWORKERTHREAD_TEST_H