OpenWalnut  1.4.0
WModuleConnector_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 WMODULECONNECTOR_TEST_H
26 #define WMODULECONNECTOR_TEST_H
27 
28 #include <iostream>
29 #include <string>
30 
31 #include <boost/shared_ptr.hpp>
32 
33 #include <cxxtest/TestSuite.h>
34 
35 #include "../WModuleConnector.h"
36 #include "../WModuleInputData.h"
37 #include "../WModuleOutputData.h"
38 #include "../WModuleInputConnector.h"
39 #include "../WModuleOutputConnector.h"
40 #include "../WModule.h"
41 #include "../../common/WSegmentationFault.h"
42 #include "../../common/WTransferable.h"
43 #include "../../common/WPrototyped.h"
44 #include "../../common/WLogger.h"
45 #include "../exceptions/WModuleConnectorInitFailed.h"
46 #include "../exceptions/WModuleConnectionFailed.h"
47 #include "../exceptions/WModuleConnectorsIncompatible.h"
48 #include "../exceptions/WModuleException.h"
49 #include "../exceptions/WModuleConnectorUnconnected.h"
50 
51 /**
52  * Test class used to test data transfer and compatibility checks.
53  */
55 {
56 friend class WModuleConnectorTest;
57 
58 public:
59  /**
60  * Constructor.
61  */
63  {
64  // do nothing here
65  m_data = 0;
66  };
67 
68  /**
69  * Gets the name of this prototype.
70  *
71  * \return the name.
72  */
73  virtual const std::string getName() const
74  {
75  return "WTestTransferableBase";
76  }
77 
78  /**
79  * Gets the description for this prototype.
80  *
81  * \return the description
82  */
83  virtual const std::string getDescription() const
84  {
85  return "Test class for testing transfer of data.";
86  }
87 
88  /**
89  * Returns a prototype instantiated with the true type of the deriving class.
90  *
91  * \return the prototype.
92  */
93  static boost::shared_ptr< WPrototyped > getPrototype()
94  {
95  return boost::shared_ptr< WPrototyped >( new WTestTransferableBase() );
96  }
97 
98  /**
99  * Gives the magic int.
100  *
101  * \return the currently set data
102  */
103  int get() const
104  {
105  return m_data;
106  }
107 
108  /**
109  * Sets the new int.
110  *
111  * \param i the int used for testing.
112  */
113  void set( int i )
114  {
115  m_data = i;
116  }
117 
118 protected:
119  /**
120  * The data.
121  */
122  int m_data;
123 
124 private:
125 };
126 
127 /**
128  * Derived test class used to test data transfer and compatibility checks, especially the inheritance checks.
129  */
131 {
132 friend class WModuleConnectorTest;
133 
134 public:
135  /**
136  * Constructor.
137  */
139  {
140  };
141 
142  /**
143  * Gets the name of this prototype.
144  *
145  * \return the name.
146  */
147  virtual const std::string getName() const
148  {
149  return "WTestTransferableDerived";
150  }
151 
152  /**
153  * Gets the description for this prototype.
154  *
155  * \return the description
156  */
157  virtual const std::string getDescription() const
158  {
159  return "Test class for testing transfer of data.";
160  }
161 
162  /**
163  * Returns a prototype instantiated with the true type of the deriving class.
164  *
165  * \return the prototype.
166  */
167  static boost::shared_ptr< WPrototyped > getPrototype()
168  {
169  return boost::shared_ptr< WPrototyped >( new WTestTransferableDerived() );
170  }
171 
172 protected:
173 private:
174 };
175 
176 /**
177  * Class implementing a simple module since WModuleConnector itself is not usable for proper
178  * testing itself because it is has pure virtual methods, i.e. is abstract.
179  */
180 class WModuleImpl: public WModule
181 {
182 friend class WModuleConnectorTest;
183 
184 public:
185  /**
186  * Constructor.
187  *
188  * \param n a string to test with (sets initial value).
189  */
190  explicit WModuleImpl( std::string n="?" ): WModule()
191  {
192  this->n = n;
193  }
194 
195  /**
196  * Destructor.
197  */
198  virtual ~WModuleImpl()
199  {
200  }
201 
202  /**
203  * Create instance of this module class.
204  *
205  * \return new instance of this module.
206  */
207  virtual boost::shared_ptr< WModule > factory() const
208  {
209  return boost::shared_ptr< WModule >( new WModuleImpl() );
210  }
211 
212  /**
213  * Returns name of this module.
214  *
215  * \return the name of this module.
216  */
217  virtual const std::string getName() const
218  {
219  return "testmodule";
220  }
221 
222  /**
223  * Returns description of module.
224  *
225  * \return the description.
226  */
227  const std::string getDescription() const
228  {
229  return "testdesc";
230  }
231 
232  /**
233  * Set up connectors.
234  */
235  virtual void connectors()
236  {
237  m_input = boost::shared_ptr< WModuleInputData< WTestTransferableBase > >(
238  new WModuleInputData< WTestTransferableBase > ( shared_from_this(), "in1", "desc1" )
239  );
240  // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
242 
243  m_output = boost::shared_ptr< WModuleOutputData< WTestTransferableBase > >(
244  new WModuleOutputData< WTestTransferableBase > ( shared_from_this(), "out1", "desc2" )
245  );
246  // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
248 
249  // now, the same with the derived class as type
250  m_inputDerived = boost::shared_ptr< WModuleInputData< WTestTransferableDerived > >(
251  new WModuleInputData< WTestTransferableDerived > ( shared_from_this(), "in2", "desc1" )
252  );
253  // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
255 
256  m_outputDerived = boost::shared_ptr< WModuleOutputData< WTestTransferableDerived > >(
257  new WModuleOutputData< WTestTransferableDerived > ( shared_from_this(), "out2", "desc2" )
258  );
259  // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
261  }
262 
263 protected:
264  /**
265  * temporary name string
266  */
267  std::string n;
268 
269  // required since pure virtual
270  virtual void moduleMain()
271  {
272  // Since the modules run in a separate thread: such loops are possible
273  while( !m_shutdownFlag() )
274  {
275  // do fancy stuff
276  sleep( 1 );
277  }
278  }
279 
280  /**
281  * Notifier called whenever a connection got established.
282  */
283  virtual void notifyConnectionEstablished( boost::shared_ptr< WModuleConnector > /*here*/,
284  boost::shared_ptr< WModuleConnector > /*there*/ )
285  {
286  // std::cout << "connection established between " << n << ":" << here->getCanonicalName() << " and "
287  // << there->getCanonicalName() << std::endl;
288  }
289 
290  /**
291  * Notifier called whenever a connection got closed.
292  */
293  virtual void notifyConnectionClosed( boost::shared_ptr< WModuleConnector > /*here*/,
294  boost::shared_ptr< WModuleConnector > /*there*/ )
295  {
296  // std::cout << "connection closed between " << n << ":" << here->getCanonicalName() << " and "
297  // << there->getCanonicalName() << std::endl;
298  }
299 
300  /**
301  * Notifier called whenever a changed data was propagated to one of this modules connectors.
302  *
303  * param input the local connector receiving the event.
304  * \param output the remote connector propagating the event.
305  */
306  virtual void notifyDataChange( boost::shared_ptr< WModuleConnector > /*input */,
307  boost::shared_ptr< WModuleConnector > output )
308  {
309  // just copy the data and add one
310  boost::shared_ptr< WModuleOutputData< WTestTransferableBase > > o =
311  boost::dynamic_pointer_cast< WModuleOutputData< WTestTransferableBase > >( output );
312  if( !o.get() )
313  {
314  return;
315  }
316 
317  boost::shared_ptr< WTestTransferableBase > ds = o->getData();
318  if( ds.get() )
319  {
320  data = ds->get() + 1;
321  }
322 
323  // std::cout << "change to " << data << " in " << input->getCanonicalName() << " from " << output->getCanonicalName()
324  // << std::endl;
325  }
326 
327 private:
328  /**
329  * The data lastly submitted.
330  */
331  int data;
332 
333  /**
334  * Input connection.
335  */
336  boost::shared_ptr< WModuleInputData< WTestTransferableBase > > m_input;
337 
338  /**
339  * Input connection with a derived class as transferable.
340  */
341  boost::shared_ptr< WModuleInputData< WTestTransferableDerived > > m_inputDerived;
342 
343  /**
344  * Output connection.
345  */
346  boost::shared_ptr< WModuleOutputData< WTestTransferableBase > > m_output;
347 
348  /**
349  * Output connection with a derived class as transferable
350  */
351  boost::shared_ptr< WModuleOutputData< WTestTransferableDerived > > m_outputDerived;
352 };
353 
354 /**
355  * Tests the WModuleConnector class. We use WModuleConnector's direct derived classes WModuleInputConnector and
356  * WModuleOutputConnector to test their common functionality implemented in WModuleConnector (which has pure virtual members -> so
357  * can't be instantiated directly).
358  */
359 class WModuleConnectorTest : public CxxTest::TestSuite
360 {
361 public:
362  /**
363  * Setup logger and other stuff for each test.
364  */
365  void setUp()
366  {
368  }
369 
370  /**
371  * Simple module to test with.
372  */
373  boost::shared_ptr< WModuleImpl > m1;
374 
375  /**
376  * Simple module to test with.
377  */
378  boost::shared_ptr< WModuleImpl > m2;
379 
380  /**
381  * Simple module to test with.
382  */
383  boost::shared_ptr< WModuleImpl > m3;
384 
385  /**
386  * Initialized the test modules.
387  */
388  void createModules( void )
389  {
390  // init 3 separate test modules
391  m1 = boost::shared_ptr< WModuleImpl >( new WModuleImpl( "m1" ) );
392  m2 = boost::shared_ptr< WModuleImpl >( new WModuleImpl( "m2" ) );
393  m3 = boost::shared_ptr< WModuleImpl >( new WModuleImpl( "m3" ) );
394  }
395 
396  /**
397  * Initializes modules. This is normally done by the module container.
398  */
399  void initModules( void )
400  {
401  m1->initialize();
402  m2->initialize();
403  m3->initialize();
404  }
405 
406  /**
407  * Initialize some connections.
408  */
409  void initConnections( void )
410  {
411  // connect output with input (cyclic)
412  m1->m_output->connect( m2->m_input );
413  m1->m_input->connect( m2->m_output );
414  }
415 
416  /**
417  * Test whether modules can be created without exception and proper initialization of connection lists.
418  */
419  void testModuleCreation( void )
420  {
421  TS_ASSERT_THROWS_NOTHING( createModules() );
422 
423  // check whether there are NO connectors.
424  // The constructor should now create connectors since shared_ptr are needed -> init in constructor leads to exception
425  // (it is enough to test one of them)
426  TS_ASSERT( m1->m_inputConnectors.size() == 0 );
427  TS_ASSERT( m1->m_outputConnectors.size() == 0 );
428  }
429 
430  /**
431  * Test whether modules can be initialized without problems.
432  */
434  {
435  createModules();
436 
437  TS_ASSERT_THROWS_NOTHING( initModules() );
438 
439  // now there should be 1 everywhere
440  TS_ASSERT( m1->m_inputConnectors.size() == 2 );
441  TS_ASSERT( m1->m_outputConnectors.size() == 2 );
442  TS_ASSERT( m2->m_inputConnectors.size() == 2 );
443  TS_ASSERT( m2->m_outputConnectors.size() == 2 );
444  TS_ASSERT( m3->m_inputConnectors.size() == 2 );
445  TS_ASSERT( m3->m_outputConnectors.size() == 2 );
446 
447  // now we have 3 properly initialized modules?
448  TS_ASSERT( m1->isInitialized()() );
449  TS_ASSERT( m2->isInitialized()() );
450  TS_ASSERT( m3->isInitialized()() );
451  }
452 
453  /**
454  * Test whether module initialization is robust against double init.
455  */
457  {
459 
460  createModules();
461  initModules();
462 
463  // try initializing twice
464  TS_ASSERT_THROWS( m1->initialize(), WModuleConnectorInitFailed );
465  TS_ASSERT( m1->isInitialized()() );
466  }
467 
468  /**
469  * Test whether automatic compatibility check works.
470  */
472  {
474 
475  createModules();
476  initModules();
477 
478  // connect input with input and output with output should fail
479  TS_ASSERT_THROWS( m1->m_input->connect( m2->m_input ), WModuleConnectorsIncompatible );
480  TS_ASSERT_THROWS( m1->m_output->connect( m2->m_output ), WModuleConnectorsIncompatible );
481 
482  // there should be nothing connected.
483  TS_ASSERT( m1->m_output->m_connected.size() == 0 );
484  TS_ASSERT( m1->m_input->m_connected.size() == 0 );
485  TS_ASSERT( m2->m_output->m_connected.size() == 0 );
486  TS_ASSERT( m2->m_input->m_connected.size() == 0 );
487  }
488 
489  /**
490  * Test whether automatic type compatibility check works.
491  */
493  {
495 
496  createModules();
497  initModules();
498 
499  TS_ASSERT( m1->m_input->m_connected.size() == 0 );
500  TS_ASSERT( m1->m_output->m_connected.size() == 0 );
501  TS_ASSERT( m1->m_inputDerived->m_connected.size() == 0 );
502  TS_ASSERT( m1->m_outputDerived->m_connected.size() == 0 );
503 
504  // connect an input with base type to output of derived type
505  TS_ASSERT_THROWS_NOTHING( m1->m_input->connect( m2->m_outputDerived ) );
506  TS_ASSERT( m1->m_input->m_connected.size() == 1 );
507  TS_ASSERT( m2->m_outputDerived->m_connected.size() == 1 );
508 
509  // connect an input of derived type with output of base type
510  TS_ASSERT_THROWS( m1->m_output->connect( m2->m_inputDerived ), WModuleConnectorsIncompatible );
511  TS_ASSERT( m1->m_output->m_connected.size() == 0 );
512  TS_ASSERT( m1->m_inputDerived->m_connected.size() == 0 );
513  }
514 
515  /**
516  * Test whether connection works properly
517  */
518  void testModuleConnection( void )
519  {
520  createModules();
521  initModules();
522 
523  TS_ASSERT_THROWS_NOTHING( initConnections() );
524 
525  // check that every connector has a connection count of 1
526  TS_ASSERT( m1->m_output->m_connected.size() == 1 );
527  TS_ASSERT( m1->m_input->m_connected.size() == 1 );
528  TS_ASSERT( m2->m_output->m_connected.size() == 1 );
529  TS_ASSERT( m2->m_input->m_connected.size() == 1 );
530  }
531 
532  /**
533  * Test whether connecting twice is not possible.
534  */
536  {
537  createModules();
538  initModules();
539  initConnections();
540 
541  // try to connect twice
542  TS_ASSERT_THROWS_NOTHING( m1->m_output->connect( m2->m_input ) );
543  TS_ASSERT_THROWS_NOTHING( m1->m_input->connect( m2->m_output ) );
544  TS_ASSERT( m1->m_output->m_connected.size() == 1 );
545  TS_ASSERT( m1->m_input->m_connected.size() == 1 );
546  TS_ASSERT( m2->m_output->m_connected.size() == 1 );
547  TS_ASSERT( m2->m_input->m_connected.size() == 1 );
548  }
549 
550  /**
551  * Test whether the connection can properly be disconnected.
552  */
553  void testModuleDisconnect( void )
554  {
555  createModules();
556  initModules();
557  initConnections();
558 
559  // Disconnect something not connected
560  TS_ASSERT_THROWS_NOTHING( m1->m_output->disconnect( m1->m_input ) );
561  TS_ASSERT( m1->m_output->m_connected.size() == 1 );
562  TS_ASSERT( m1->m_input->m_connected.size() == 1 );
563 
564  // Disconnect a connected
565  TS_ASSERT_THROWS_NOTHING( m1->m_output->disconnect( m2->m_input ) );
566  TS_ASSERT( m1->m_output->m_connected.size() == 0 );
567  TS_ASSERT( m1->m_input->m_connected.size() == 1 );
568  TS_ASSERT( m2->m_output->m_connected.size() == 1 );
569  TS_ASSERT( m2->m_input->m_connected.size() == 0 );
570  }
571 
572  /**
573  * Test whether all connections can be removed in one step.
574  */
576  {
577  createModules();
578  initModules();
579  initConnections();
580 
581  // connect m3
582  TS_ASSERT_THROWS_NOTHING( m3->m_input->connect( m2->m_output ) );
583 
584  // now m2->out should have 2 connections
585  TS_ASSERT( m2->m_output->m_connected.size() == 2 );
586  TS_ASSERT( m3->m_input->m_connected.size() == 1 );
587 
588  // remove both connections
589  m2->m_output->disconnectAll();
590  TS_ASSERT( m2->m_output->m_connected.size() == 0 );
591  TS_ASSERT( m1->m_input->m_connected.size() == 0 );
592  TS_ASSERT( m3->m_input->m_connected.size() == 0 );
593  }
594 
595  /**
596  * Test whether module clean up is working properly.
597  */
598  void testModuleCleanup( void )
599  {
600  createModules();
601  initModules();
602  initConnections();
603 
604  TS_ASSERT_THROWS_NOTHING( m1->cleanup() );
605  TS_ASSERT( m1->m_inputConnectors.size() == 0 );
606  TS_ASSERT( m1->m_outputConnectors.size() == 0 );
607  }
608 
609  /**
610  * Tests the propagation of data.
611  */
613  {
614  createModules();
615  initModules();
616  initConnections();
617 
618  // set some data, propagate change
619  boost::shared_ptr< WTestTransferableBase > data( new WTestTransferableBase() );
620  int d = 5;
621  data->set( d );
622  TS_ASSERT_THROWS_NOTHING( m1->m_output->updateData( data ) );
623 
624  // got the data transferred?
625  TS_ASSERT( m1->m_output->getData()->get() == d );
626  TS_ASSERT( m2->m_input->getData()->get() == d );
627  TS_ASSERT( m2->data == d + 1 );
628  }
629 
630  /**
631  * Tests several cases of unset data.
632  */
634  {
636 
637  createModules();
638  initModules();
639  initConnections();
640 
641  // try to get data from an unconnected connector
642  TS_ASSERT( !m3->m_input->getData().get() );
643 
644  // try to get uninitialized data -> should return an "NULL" Pointer
645  TS_ASSERT( m2->m_input->getData() == boost::shared_ptr< WTestTransferableBase >() );
646  }
647 };
648 
649 #endif // WMODULECONNECTOR_TEST_H
650 
void createModules(void)
Initialized the test modules.
void setUp()
Setup logger and other stuff for each test.
static void disableBacktrace()
Function disables backtraces.
Definition: WException.cpp:200
static boost::shared_ptr< WPrototyped > getPrototype()
Returns a prototype instantiated with the true type of the deriving class.
void testModuleTwiceInitialization(void)
Test whether module initialization is robust against double init.
Class representing a single module of OpenWalnut.
Definition: WModule.h:71
void testModuleConnection(void)
Test whether connection works properly.
boost::shared_ptr< WModuleImpl > m3
Simple module to test with.
Derived test class used to test data transfer and compatibility checks, especially the inheritance ch...
WTestTransferableBase()
Constructor.
virtual void notifyDataChange(boost::shared_ptr< WModuleConnector >, boost::shared_ptr< WModuleConnector > output)
Notifier called whenever a changed data was propagated to one of this modules connectors.
Class implementing a simple module since WModuleConnector itself is not usable for proper testing its...
void testModuleInitialization(void)
Test whether modules can be initialized without problems.
virtual void notifyConnectionClosed(boost::shared_ptr< WModuleConnector >, boost::shared_ptr< WModuleConnector >)
Notifier called whenever a connection got closed.
virtual ~WModuleImpl()
Destructor.
Class offering an instantiate-able data connection between modules.
Definition: WModule.h:63
const boost::shared_ptr< T > getData() const
Gives back the currently set data.
std::string n
temporary name string
Class offering an instantiate-able data connection between modules.
Definition: WModule.h:65
void testModuleDisconnect(void)
Test whether the connection can properly be disconnected.
void sleep(const int32_t t) const
Sets thread asleep.
virtual const std::string getName() const
Gets the name of this prototype.
boost::shared_ptr< WModuleOutputData< WTestTransferableDerived > > m_outputDerived
Output connection with a derived class as transferable.
General purpose exception and therefore base class for all kernel related exceptions.
boost::shared_ptr< WModuleInputData< WTestTransferableDerived > > m_inputDerived
Input connection with a derived class as transferable.
static void startup(std::ostream &output=std::cout, LogLevel level=LL_DEBUG)
Create the first and only instance of the logger as it is a singleton.
Definition: WLogger.cpp:41
virtual void connectors()
Set up connectors.
void testModuleCreation(void)
Test whether modules can be created without exception and proper initialization of connection lists...
boost::shared_ptr< WModuleInputData< WTestTransferableBase > > m_input
Input connection.
void testModuleCleanup(void)
Test whether module clean up is working properly.
Class building the interface for classes that might be transferred using WModuleConnector.
Definition: WTransferable.h:37
Tests the WModuleConnector class.
void testModuleInvalidData(void)
Tests several cases of unset data.
virtual const std::string getName() const
Gets the name of this prototype.
virtual void moduleMain()
Entry point after loading the module.
void testModulePropagateDataChange(void)
Tests the propagation of data.
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
virtual const std::string getName() const
Returns name of this module.
virtual void notifyConnectionEstablished(boost::shared_ptr< WModuleConnector >, boost::shared_ptr< WModuleConnector >)
Notifier called whenever a connection got established.
void initConnections(void)
Initialize some connections.
virtual const std::string getDescription() const
Gets the description for this prototype.
WModuleImpl(std::string n="?")
Constructor.
virtual boost::shared_ptr< WModule > factory() const
Create instance of this module class.
Test class used to test data transfer and compatibility checks.
void testModuleConnectorCompatibility(void)
Test whether automatic compatibility check works.
int data
The data lastly submitted.
void set(int i)
Sets the new int.
void initModules(void)
Initializes modules.
const std::string getDescription() const
Returns description of module.
void testModuleTwiceConnection(void)
Test whether connecting twice is not possible.
boost::shared_ptr< WModuleImpl > m1
Simple module to test with.
void testModuleConnectorTypeCompatibility(void)
Test whether automatic type compatibility check works.
void testModuleDisconnectAll(void)
Test whether all connections can be removed in one step.
void addConnector(boost::shared_ptr< WModuleInputConnector > con)
Adds the specified connector to the list of inputs.
Definition: WModule.cpp:109
boost::shared_ptr< WModuleOutputData< WTestTransferableBase > > m_output
Output connection.
General purpose exception and therefore base class for all kernel related exceptions.
virtual const std::string getDescription() const
Gets the description for this prototype.
boost::shared_ptr< WModuleImpl > m2
Simple module to test with.
static boost::shared_ptr< WPrototyped > getPrototype()
Returns a prototype instantiated with the true type of the deriving class.