OpenWalnut  1.3.1
WThreadedFunction_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 WTHREADEDFUNCTION_TEST_H
26 #define WTHREADEDFUNCTION_TEST_H
27 
28 #include <string>
29 
30 #include <cxxtest/TestSuite.h>
31 
32 #include "../WThreadedFunction.h"
33 #include "../WSharedObject.h"
34 
35 /**
36  * \class WThreadedFunctionTest
37  *
38  * Tests the WThreadedFunction class.
39  */
40 class WThreadedFunctionTest : public CxxTest::TestSuite
41 {
42  /**
43  * A threaded function.
44  */
45  class FuncType
46  {
47  public:
48  /**
49  * Constructor, initialize some stuff.
50  *
51  * \param value An int value.
52  */
53  FuncType( int value ) // NOLINT
54  : m_input( new int( value ) ) // NOLINT
55  {
56  // init stuff here
57  m_result.getWriteTicket()->get() = 0;
58  m_stopped.getWriteTicket()->get() = false;
59 
60  if( value < 0 )
61  {
62  value = -value;
63  }
64  }
65 
66  /**
67  * This is the actual thread function.
68  *
69  * \param shutdown A flag indicating the thread is supposed to stop.
70  */
71  void operator() ( std::size_t, std::size_t, WBoolFlag const& shutdown )
72  {
73  for( int i = 1; i <= *m_input.get() && !shutdown(); ++i )
74  {
75  m_result.getWriteTicket()->get() += i;
76  }
77  if( shutdown() )
78  {
79  m_stopped.getWriteTicket()->get() = true;
80  }
81  sleep( 1 );
82  }
83 
84  /**
85  * Check if the thread was ordered to stop.
86  *
87  * \return true, if the thread was ordered to stop
88  */
89  bool stopped()
90  {
91  return m_stopped.getReadTicket()->get();
92  }
93 
94  /**
95  * A method to extract the result.
96  *
97  * \return The result of the threaded computation.
98  */
99  int getResult()
100  {
101  return m_result.getReadTicket()->get();
102  }
103 
104  /**
105  * Reset everything.
106  */
107  void reset()
108  {
109  m_result.getWriteTicket()->get() = 0;
110  }
111 
112  private:
113  //! the input data
114  boost::shared_ptr< int const > m_input;
115 
116  //! the result
118 
119  //! thread stopped?
121  };
122 
123  /**
124  * A function that throws exceptions.
125  */
127  {
128  public:
129  /**
130  * The function.
131  */
132  void operator() ( std::size_t, std::size_t, WBoolFlag& )
133  {
134  throw WException( std::string( "Test!" ) );
135  }
136  };
137 
138 public:
139  /**
140  * A function computed by multiple threads should correctly set
141  * its status and compute the correct results.
142  */
144  {
145  boost::shared_ptr< FuncType > func( new FuncType( 5 ) );
146  // test 1 thread
147  {
148  WThreadedFunction< FuncType > f( 1, func );
149 
150  TS_ASSERT_EQUALS( f.status(), W_THREADS_INITIALIZED );
151  f.run();
152  TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING );
153  f.wait();
154  TS_ASSERT_EQUALS( f.status(), W_THREADS_FINISHED );
155 
156  TS_ASSERT_EQUALS( func->getResult(), 15 );
157  func->reset();
158 
159  f.run();
160  TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING );
161  f.wait();
162 
163  TS_ASSERT_EQUALS( func->getResult(), 15 );
164 
165  f.run();
166  TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING );
167  f.wait();
168 
169  TS_ASSERT_EQUALS( func->getResult(), 30 );
170  func->reset();
171  }
172  // test 2 threads
173  {
174  WThreadedFunction< FuncType > f( 2, func );
175 
176  TS_ASSERT_EQUALS( f.status(), W_THREADS_INITIALIZED );
177  f.run();
178  TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING );
179  f.wait();
180  TS_ASSERT_EQUALS( f.status(), W_THREADS_FINISHED );
181 
182  TS_ASSERT_EQUALS( func->getResult(), 30 );
183  func->reset();
184  }
185  // test 5 threads
186  {
187  WThreadedFunction< FuncType > f( 5, func );
188 
189  TS_ASSERT_EQUALS( f.status(), W_THREADS_INITIALIZED );
190  f.run();
191  TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING );
192  f.wait();
193  TS_ASSERT_EQUALS( f.status(), W_THREADS_FINISHED );
194 
195  TS_ASSERT_EQUALS( func->getResult(), 75 );
196  func->reset();
197  }
198  }
199 
200  /**
201  * Status should be set correctly when threads are ordered to stop.
202  */
204  {
205  boost::shared_ptr< FuncType > func( new FuncType( 100000000 ) );
206  WThreadedFunction< FuncType > f( 6, func );
207 
208  TS_ASSERT_EQUALS( f.status(), W_THREADS_INITIALIZED );
209  f.run();
210  TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING );
211  f.stop();
212  TS_ASSERT_EQUALS( f.status(), W_THREADS_STOP_REQUESTED );
213  f.wait();
214  TS_ASSERT_EQUALS( f.status(), W_THREADS_ABORTED );
215 
216  TS_ASSERT( func->stopped() );
217  func->reset();
218  }
219 
220  /**
221  * The stop condition should be notified correctly.
222  */
224  {
225  boost::shared_ptr< FuncType > func( new FuncType( 5 ) );
226  WThreadedFunction< FuncType > f( 6, func );
227 
228  TS_ASSERT_EQUALS( f.status(), W_THREADS_INITIALIZED );
229  f.run();
230  TS_ASSERT_EQUALS( f.status(), W_THREADS_RUNNING );
231  f.getThreadsDoneCondition()->wait();
232  TS_ASSERT_EQUALS( f.status(), W_THREADS_FINISHED );
233 
234  TS_ASSERT_EQUALS( func->getResult(), 90 );
235  func->reset();
236  }
237 
238  /**
239  * Exceptions should lead to the status beeing changed to W_THREADS_ABORTED. Also,
240  * exceptions should be forwarded to the exception handler.
241  */
243  {
244  boost::shared_ptr< ExceptionalFuncType > func( new ExceptionalFuncType );
247 
248  m_exceptionCounter.getWriteTicket()->get() = 0;
249 
250  f.run();
251  f.wait();
252 
253  TS_ASSERT_EQUALS( f.status(), W_THREADS_ABORTED );
254  TS_ASSERT_EQUALS( m_exceptionCounter.getReadTicket()->get(), 7 );
255  }
256 
257 private:
258  /**
259  * Exception callback.
260  */
262  {
264  }
265 
266  //! a counter
268 };
269 
270 #endif // WTHREADEDFUNCTION_TEST_H