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