OpenWalnut
1.4.0
|
00001 //--------------------------------------------------------------------------- 00002 // 00003 // Project: OpenWalnut ( http://www.openwalnut.org ) 00004 // 00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS 00006 // For more information see http://www.openwalnut.org/copying 00007 // 00008 // This file is part of OpenWalnut. 00009 // 00010 // OpenWalnut is free software: you can redistribute it and/or modify 00011 // it under the terms of the GNU Lesser General Public License as published by 00012 // the Free Software Foundation, either version 3 of the License, or 00013 // (at your option) any later version. 00014 // 00015 // OpenWalnut is distributed in the hope that it will be useful, 00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 // GNU Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public License 00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>. 00022 // 00023 //--------------------------------------------------------------------------- 00024 00025 #ifndef WMODULECONNECTOR_TEST_H 00026 #define WMODULECONNECTOR_TEST_H 00027 00028 #include <iostream> 00029 #include <string> 00030 00031 #include <boost/shared_ptr.hpp> 00032 00033 #include <cxxtest/TestSuite.h> 00034 00035 #include "../WModuleConnector.h" 00036 #include "../WModuleInputData.h" 00037 #include "../WModuleOutputData.h" 00038 #include "../WModuleInputConnector.h" 00039 #include "../WModuleOutputConnector.h" 00040 #include "../WModule.h" 00041 #include "../../common/WSegmentationFault.h" 00042 #include "../../common/WTransferable.h" 00043 #include "../../common/WPrototyped.h" 00044 #include "../../common/WLogger.h" 00045 #include "../exceptions/WModuleConnectorInitFailed.h" 00046 #include "../exceptions/WModuleConnectionFailed.h" 00047 #include "../exceptions/WModuleConnectorsIncompatible.h" 00048 #include "../exceptions/WModuleException.h" 00049 #include "../exceptions/WModuleConnectorUnconnected.h" 00050 00051 /** 00052 * Test class used to test data transfer and compatibility checks. 00053 */ 00054 class WTestTransferableBase: public WTransferable 00055 { 00056 friend class WModuleConnectorTest; 00057 00058 public: 00059 /** 00060 * Constructor. 00061 */ 00062 WTestTransferableBase(): WTransferable() 00063 { 00064 // do nothing here 00065 m_data = 0; 00066 }; 00067 00068 /** 00069 * Gets the name of this prototype. 00070 * 00071 * \return the name. 00072 */ 00073 virtual const std::string getName() const 00074 { 00075 return "WTestTransferableBase"; 00076 } 00077 00078 /** 00079 * Gets the description for this prototype. 00080 * 00081 * \return the description 00082 */ 00083 virtual const std::string getDescription() const 00084 { 00085 return "Test class for testing transfer of data."; 00086 } 00087 00088 /** 00089 * Returns a prototype instantiated with the true type of the deriving class. 00090 * 00091 * \return the prototype. 00092 */ 00093 static boost::shared_ptr< WPrototyped > getPrototype() 00094 { 00095 return boost::shared_ptr< WPrototyped >( new WTestTransferableBase() ); 00096 } 00097 00098 /** 00099 * Gives the magic int. 00100 * 00101 * \return the currently set data 00102 */ 00103 int get() const 00104 { 00105 return m_data; 00106 } 00107 00108 /** 00109 * Sets the new int. 00110 * 00111 * \param i the int used for testing. 00112 */ 00113 void set( int i ) 00114 { 00115 m_data = i; 00116 } 00117 00118 protected: 00119 /** 00120 * The data. 00121 */ 00122 int m_data; 00123 00124 private: 00125 }; 00126 00127 /** 00128 * Derived test class used to test data transfer and compatibility checks, especially the inheritance checks. 00129 */ 00130 class WTestTransferableDerived: public WTestTransferableBase 00131 { 00132 friend class WModuleConnectorTest; 00133 00134 public: 00135 /** 00136 * Constructor. 00137 */ 00138 WTestTransferableDerived(): WTestTransferableBase() 00139 { 00140 }; 00141 00142 /** 00143 * Gets the name of this prototype. 00144 * 00145 * \return the name. 00146 */ 00147 virtual const std::string getName() const 00148 { 00149 return "WTestTransferableDerived"; 00150 } 00151 00152 /** 00153 * Gets the description for this prototype. 00154 * 00155 * \return the description 00156 */ 00157 virtual const std::string getDescription() const 00158 { 00159 return "Test class for testing transfer of data."; 00160 } 00161 00162 /** 00163 * Returns a prototype instantiated with the true type of the deriving class. 00164 * 00165 * \return the prototype. 00166 */ 00167 static boost::shared_ptr< WPrototyped > getPrototype() 00168 { 00169 return boost::shared_ptr< WPrototyped >( new WTestTransferableDerived() ); 00170 } 00171 00172 protected: 00173 private: 00174 }; 00175 00176 /** 00177 * Class implementing a simple module since WModuleConnector itself is not usable for proper 00178 * testing itself because it is has pure virtual methods, i.e. is abstract. 00179 */ 00180 class WModuleImpl: public WModule 00181 { 00182 friend class WModuleConnectorTest; 00183 00184 public: 00185 /** 00186 * Constructor. 00187 * 00188 * \param n a string to test with (sets initial value). 00189 */ 00190 explicit WModuleImpl( std::string n="?" ): WModule() 00191 { 00192 this->n = n; 00193 } 00194 00195 /** 00196 * Destructor. 00197 */ 00198 virtual ~WModuleImpl() 00199 { 00200 } 00201 00202 /** 00203 * Create instance of this module class. 00204 * 00205 * \return new instance of this module. 00206 */ 00207 virtual boost::shared_ptr< WModule > factory() const 00208 { 00209 return boost::shared_ptr< WModule >( new WModuleImpl() ); 00210 } 00211 00212 /** 00213 * Returns name of this module. 00214 * 00215 * \return the name of this module. 00216 */ 00217 virtual const std::string getName() const 00218 { 00219 return "testmodule"; 00220 } 00221 00222 /** 00223 * Returns description of module. 00224 * 00225 * \return the description. 00226 */ 00227 const std::string getDescription() const 00228 { 00229 return "testdesc"; 00230 } 00231 00232 /** 00233 * Set up connectors. 00234 */ 00235 virtual void connectors() 00236 { 00237 m_input = boost::shared_ptr< WModuleInputData< WTestTransferableBase > >( 00238 new WModuleInputData< WTestTransferableBase > ( shared_from_this(), "in1", "desc1" ) 00239 ); 00240 // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected. 00241 addConnector( m_input ); 00242 00243 m_output = boost::shared_ptr< WModuleOutputData< WTestTransferableBase > >( 00244 new WModuleOutputData< WTestTransferableBase > ( shared_from_this(), "out1", "desc2" ) 00245 ); 00246 // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected. 00247 addConnector( m_output ); 00248 00249 // now, the same with the derived class as type 00250 m_inputDerived = boost::shared_ptr< WModuleInputData< WTestTransferableDerived > >( 00251 new WModuleInputData< WTestTransferableDerived > ( shared_from_this(), "in2", "desc1" ) 00252 ); 00253 // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected. 00254 addConnector( m_inputDerived ); 00255 00256 m_outputDerived = boost::shared_ptr< WModuleOutputData< WTestTransferableDerived > >( 00257 new WModuleOutputData< WTestTransferableDerived > ( shared_from_this(), "out2", "desc2" ) 00258 ); 00259 // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected. 00260 addConnector( m_outputDerived ); 00261 } 00262 00263 protected: 00264 /** 00265 * temporary name string 00266 */ 00267 std::string n; 00268 00269 // required since pure virtual 00270 virtual void moduleMain() 00271 { 00272 // Since the modules run in a separate thread: such loops are possible 00273 while( !m_shutdownFlag() ) 00274 { 00275 // do fancy stuff 00276 sleep( 1 ); 00277 } 00278 } 00279 00280 /** 00281 * Notifier called whenever a connection got established. 00282 */ 00283 virtual void notifyConnectionEstablished( boost::shared_ptr< WModuleConnector > /*here*/, 00284 boost::shared_ptr< WModuleConnector > /*there*/ ) 00285 { 00286 // std::cout << "connection established between " << n << ":" << here->getCanonicalName() << " and " 00287 // << there->getCanonicalName() << std::endl; 00288 } 00289 00290 /** 00291 * Notifier called whenever a connection got closed. 00292 */ 00293 virtual void notifyConnectionClosed( boost::shared_ptr< WModuleConnector > /*here*/, 00294 boost::shared_ptr< WModuleConnector > /*there*/ ) 00295 { 00296 // std::cout << "connection closed between " << n << ":" << here->getCanonicalName() << " and " 00297 // << there->getCanonicalName() << std::endl; 00298 } 00299 00300 /** 00301 * Notifier called whenever a changed data was propagated to one of this modules connectors. 00302 * 00303 * param input the local connector receiving the event. 00304 * \param output the remote connector propagating the event. 00305 */ 00306 virtual void notifyDataChange( boost::shared_ptr< WModuleConnector > /*input */, 00307 boost::shared_ptr< WModuleConnector > output ) 00308 { 00309 // just copy the data and add one 00310 boost::shared_ptr< WModuleOutputData< WTestTransferableBase > > o = 00311 boost::dynamic_pointer_cast< WModuleOutputData< WTestTransferableBase > >( output ); 00312 if( !o.get() ) 00313 { 00314 return; 00315 } 00316 00317 boost::shared_ptr< WTestTransferableBase > ds = o->getData(); 00318 if( ds.get() ) 00319 { 00320 data = ds->get() + 1; 00321 } 00322 00323 // std::cout << "change to " << data << " in " << input->getCanonicalName() << " from " << output->getCanonicalName() 00324 // << std::endl; 00325 } 00326 00327 private: 00328 /** 00329 * The data lastly submitted. 00330 */ 00331 int data; 00332 00333 /** 00334 * Input connection. 00335 */ 00336 boost::shared_ptr< WModuleInputData< WTestTransferableBase > > m_input; 00337 00338 /** 00339 * Input connection with a derived class as transferable. 00340 */ 00341 boost::shared_ptr< WModuleInputData< WTestTransferableDerived > > m_inputDerived; 00342 00343 /** 00344 * Output connection. 00345 */ 00346 boost::shared_ptr< WModuleOutputData< WTestTransferableBase > > m_output; 00347 00348 /** 00349 * Output connection with a derived class as transferable 00350 */ 00351 boost::shared_ptr< WModuleOutputData< WTestTransferableDerived > > m_outputDerived; 00352 }; 00353 00354 /** 00355 * Tests the WModuleConnector class. We use WModuleConnector's direct derived classes WModuleInputConnector and 00356 * WModuleOutputConnector to test their common functionality implemented in WModuleConnector (which has pure virtual members -> so 00357 * can't be instantiated directly). 00358 */ 00359 class WModuleConnectorTest : public CxxTest::TestSuite 00360 { 00361 public: 00362 /** 00363 * Setup logger and other stuff for each test. 00364 */ 00365 void setUp() 00366 { 00367 WLogger::startup(); 00368 } 00369 00370 /** 00371 * Simple module to test with. 00372 */ 00373 boost::shared_ptr< WModuleImpl > m1; 00374 00375 /** 00376 * Simple module to test with. 00377 */ 00378 boost::shared_ptr< WModuleImpl > m2; 00379 00380 /** 00381 * Simple module to test with. 00382 */ 00383 boost::shared_ptr< WModuleImpl > m3; 00384 00385 /** 00386 * Initialized the test modules. 00387 */ 00388 void createModules( void ) 00389 { 00390 // init 3 separate test modules 00391 m1 = boost::shared_ptr< WModuleImpl >( new WModuleImpl( "m1" ) ); 00392 m2 = boost::shared_ptr< WModuleImpl >( new WModuleImpl( "m2" ) ); 00393 m3 = boost::shared_ptr< WModuleImpl >( new WModuleImpl( "m3" ) ); 00394 } 00395 00396 /** 00397 * Initializes modules. This is normally done by the module container. 00398 */ 00399 void initModules( void ) 00400 { 00401 m1->initialize(); 00402 m2->initialize(); 00403 m3->initialize(); 00404 } 00405 00406 /** 00407 * Initialize some connections. 00408 */ 00409 void initConnections( void ) 00410 { 00411 // connect output with input (cyclic) 00412 m1->m_output->connect( m2->m_input ); 00413 m1->m_input->connect( m2->m_output ); 00414 } 00415 00416 /** 00417 * Test whether modules can be created without exception and proper initialization of connection lists. 00418 */ 00419 void testModuleCreation( void ) 00420 { 00421 TS_ASSERT_THROWS_NOTHING( createModules() ); 00422 00423 // check whether there are NO connectors. 00424 // The constructor should now create connectors since shared_ptr are needed -> init in constructor leads to exception 00425 // (it is enough to test one of them) 00426 TS_ASSERT( m1->m_inputConnectors.size() == 0 ); 00427 TS_ASSERT( m1->m_outputConnectors.size() == 0 ); 00428 } 00429 00430 /** 00431 * Test whether modules can be initialized without problems. 00432 */ 00433 void testModuleInitialization( void ) 00434 { 00435 createModules(); 00436 00437 TS_ASSERT_THROWS_NOTHING( initModules() ); 00438 00439 // now there should be 1 everywhere 00440 TS_ASSERT( m1->m_inputConnectors.size() == 2 ); 00441 TS_ASSERT( m1->m_outputConnectors.size() == 2 ); 00442 TS_ASSERT( m2->m_inputConnectors.size() == 2 ); 00443 TS_ASSERT( m2->m_outputConnectors.size() == 2 ); 00444 TS_ASSERT( m3->m_inputConnectors.size() == 2 ); 00445 TS_ASSERT( m3->m_outputConnectors.size() == 2 ); 00446 00447 // now we have 3 properly initialized modules? 00448 TS_ASSERT( m1->isInitialized()() ); 00449 TS_ASSERT( m2->isInitialized()() ); 00450 TS_ASSERT( m3->isInitialized()() ); 00451 } 00452 00453 /** 00454 * Test whether module initialization is robust against double init. 00455 */ 00456 void testModuleTwiceInitialization( void ) 00457 { 00458 WException::disableBacktrace(); 00459 00460 createModules(); 00461 initModules(); 00462 00463 // try initializing twice 00464 TS_ASSERT_THROWS( m1->initialize(), WModuleConnectorInitFailed ); 00465 TS_ASSERT( m1->isInitialized()() ); 00466 } 00467 00468 /** 00469 * Test whether automatic compatibility check works. 00470 */ 00471 void testModuleConnectorCompatibility( void ) 00472 { 00473 WException::disableBacktrace(); 00474 00475 createModules(); 00476 initModules(); 00477 00478 // connect input with input and output with output should fail 00479 TS_ASSERT_THROWS( m1->m_input->connect( m2->m_input ), WModuleConnectorsIncompatible ); 00480 TS_ASSERT_THROWS( m1->m_output->connect( m2->m_output ), WModuleConnectorsIncompatible ); 00481 00482 // there should be nothing connected. 00483 TS_ASSERT( m1->m_output->m_connected.size() == 0 ); 00484 TS_ASSERT( m1->m_input->m_connected.size() == 0 ); 00485 TS_ASSERT( m2->m_output->m_connected.size() == 0 ); 00486 TS_ASSERT( m2->m_input->m_connected.size() == 0 ); 00487 } 00488 00489 /** 00490 * Test whether automatic type compatibility check works. 00491 */ 00492 void testModuleConnectorTypeCompatibility( void ) 00493 { 00494 WException::disableBacktrace(); 00495 00496 createModules(); 00497 initModules(); 00498 00499 TS_ASSERT( m1->m_input->m_connected.size() == 0 ); 00500 TS_ASSERT( m1->m_output->m_connected.size() == 0 ); 00501 TS_ASSERT( m1->m_inputDerived->m_connected.size() == 0 ); 00502 TS_ASSERT( m1->m_outputDerived->m_connected.size() == 0 ); 00503 00504 // connect an input with base type to output of derived type 00505 TS_ASSERT_THROWS_NOTHING( m1->m_input->connect( m2->m_outputDerived ) ); 00506 TS_ASSERT( m1->m_input->m_connected.size() == 1 ); 00507 TS_ASSERT( m2->m_outputDerived->m_connected.size() == 1 ); 00508 00509 // connect an input of derived type with output of base type 00510 TS_ASSERT_THROWS( m1->m_output->connect( m2->m_inputDerived ), WModuleConnectorsIncompatible ); 00511 TS_ASSERT( m1->m_output->m_connected.size() == 0 ); 00512 TS_ASSERT( m1->m_inputDerived->m_connected.size() == 0 ); 00513 } 00514 00515 /** 00516 * Test whether connection works properly 00517 */ 00518 void testModuleConnection( void ) 00519 { 00520 createModules(); 00521 initModules(); 00522 00523 TS_ASSERT_THROWS_NOTHING( initConnections() ); 00524 00525 // check that every connector has a connection count of 1 00526 TS_ASSERT( m1->m_output->m_connected.size() == 1 ); 00527 TS_ASSERT( m1->m_input->m_connected.size() == 1 ); 00528 TS_ASSERT( m2->m_output->m_connected.size() == 1 ); 00529 TS_ASSERT( m2->m_input->m_connected.size() == 1 ); 00530 } 00531 00532 /** 00533 * Test whether connecting twice is not possible. 00534 */ 00535 void testModuleTwiceConnection( void ) 00536 { 00537 createModules(); 00538 initModules(); 00539 initConnections(); 00540 00541 // try to connect twice 00542 TS_ASSERT_THROWS_NOTHING( m1->m_output->connect( m2->m_input ) ); 00543 TS_ASSERT_THROWS_NOTHING( m1->m_input->connect( m2->m_output ) ); 00544 TS_ASSERT( m1->m_output->m_connected.size() == 1 ); 00545 TS_ASSERT( m1->m_input->m_connected.size() == 1 ); 00546 TS_ASSERT( m2->m_output->m_connected.size() == 1 ); 00547 TS_ASSERT( m2->m_input->m_connected.size() == 1 ); 00548 } 00549 00550 /** 00551 * Test whether the connection can properly be disconnected. 00552 */ 00553 void testModuleDisconnect( void ) 00554 { 00555 createModules(); 00556 initModules(); 00557 initConnections(); 00558 00559 // Disconnect something not connected 00560 TS_ASSERT_THROWS_NOTHING( m1->m_output->disconnect( m1->m_input ) ); 00561 TS_ASSERT( m1->m_output->m_connected.size() == 1 ); 00562 TS_ASSERT( m1->m_input->m_connected.size() == 1 ); 00563 00564 // Disconnect a connected 00565 TS_ASSERT_THROWS_NOTHING( m1->m_output->disconnect( m2->m_input ) ); 00566 TS_ASSERT( m1->m_output->m_connected.size() == 0 ); 00567 TS_ASSERT( m1->m_input->m_connected.size() == 1 ); 00568 TS_ASSERT( m2->m_output->m_connected.size() == 1 ); 00569 TS_ASSERT( m2->m_input->m_connected.size() == 0 ); 00570 } 00571 00572 /** 00573 * Test whether all connections can be removed in one step. 00574 */ 00575 void testModuleDisconnectAll( void ) 00576 { 00577 createModules(); 00578 initModules(); 00579 initConnections(); 00580 00581 // connect m3 00582 TS_ASSERT_THROWS_NOTHING( m3->m_input->connect( m2->m_output ) ); 00583 00584 // now m2->out should have 2 connections 00585 TS_ASSERT( m2->m_output->m_connected.size() == 2 ); 00586 TS_ASSERT( m3->m_input->m_connected.size() == 1 ); 00587 00588 // remove both connections 00589 m2->m_output->disconnectAll(); 00590 TS_ASSERT( m2->m_output->m_connected.size() == 0 ); 00591 TS_ASSERT( m1->m_input->m_connected.size() == 0 ); 00592 TS_ASSERT( m3->m_input->m_connected.size() == 0 ); 00593 } 00594 00595 /** 00596 * Test whether module clean up is working properly. 00597 */ 00598 void testModuleCleanup( void ) 00599 { 00600 createModules(); 00601 initModules(); 00602 initConnections(); 00603 00604 TS_ASSERT_THROWS_NOTHING( m1->cleanup() ); 00605 TS_ASSERT( m1->m_inputConnectors.size() == 0 ); 00606 TS_ASSERT( m1->m_outputConnectors.size() == 0 ); 00607 } 00608 00609 /** 00610 * Tests the propagation of data. 00611 */ 00612 void testModulePropagateDataChange( void ) 00613 { 00614 createModules(); 00615 initModules(); 00616 initConnections(); 00617 00618 // set some data, propagate change 00619 boost::shared_ptr< WTestTransferableBase > data( new WTestTransferableBase() ); 00620 int d = 5; 00621 data->set( d ); 00622 TS_ASSERT_THROWS_NOTHING( m1->m_output->updateData( data ) ); 00623 00624 // got the data transferred? 00625 TS_ASSERT( m1->m_output->getData()->get() == d ); 00626 TS_ASSERT( m2->m_input->getData()->get() == d ); 00627 TS_ASSERT( m2->data == d + 1 ); 00628 } 00629 00630 /** 00631 * Tests several cases of unset data. 00632 */ 00633 void testModuleInvalidData( void ) 00634 { 00635 WException::disableBacktrace(); 00636 00637 createModules(); 00638 initModules(); 00639 initConnections(); 00640 00641 // try to get data from an unconnected connector 00642 TS_ASSERT( !m3->m_input->getData().get() ); 00643 00644 // try to get uninitialized data -> should return an "NULL" Pointer 00645 TS_ASSERT( m2->m_input->getData() == boost::shared_ptr< WTestTransferableBase >() ); 00646 } 00647 }; 00648 00649 #endif // WMODULECONNECTOR_TEST_H 00650