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